中国剩余定理(CRT)

本文详细介绍了中国剩余定理(孙子定理)的概念和历史,通过解决《孙子算经》中的经典问题来阐述其原理。接着,展示了它在大数据、云计算和RSA密码中的应用。文章提供了实例解析,包括如何使用Python实现求解过程,以及在实际CTF挑战中的应用。
摘要由CSDN通过智能技术生成

一.前言

中国剩余定理,又称中国余数定理,是数论中的一個关于一元线性同余方程组的定理,说明了一元线性同余方程组有解的准则以及求解方法。也称为孙子定理,古有「韩信点兵」、「孙子定理」、「求一术」(宋 沈括)、「鬼谷算」(宋 周密)、「隔墙算」(宋 周密)、「剪管术」(宋 杨辉)、「秦王暗点兵」、「物不知数」之名。目前在大数据、云计算、RSA密码等邻域也发挥着重大作用。

二.例子

物不知数

在《孙子算经》中有这样一个问题“今有物不知其数,三三数之剩二(除以3 余2),
五五数之剩三(除以5 余3),七七数之剩二(除以7 余2),问物几何?”
这个问题称为
子问题”
,该问题的一般解法国际上称为“中国剩余定理”

《孙子算经》中给出了解法,术曰:三三数之剩二,置一百四十;五五数之剩三,置六十三;七七数之剩二,置三十,并之,得二百三十三。以二百一十减之,即得。翻译过来就是:三个三个数还剩下两个,那么算出一百四十;五个五个书还剩下三个,那么算出六十三;七个七个数还剩下两个,那么算出三十,把这三个数加起来,得到二百三十三。最后用二百三十三减去二百一十,就是算出来的答案。

其中一百四十、六十三、二十三、二百一十这几个数却不知道是怎么得出的。要算出这几个数,我们首先需要知道两个定理:

定理1:几个数相加,如果只有一个加数,不能被数a整除,而其他加数均能被数a整除,那么它们的和,就不能被整数a整除。如果有a % b = c,则有(a + kb)%b = c(k为非零整数)或者写成a≡ca≡c (mod b),则有a+kb≡ca+kb≡c(mod b)(k为非零整数)

理2:二数不能整除,若被除数扩大(或缩小)了几倍,而除数不变,则其余数也同时扩大(或缩小)相同的倍数(余数必小于除数)。如果a%b=c,那么(a*k)%b = (a%b+a%b+…a%b)%b = (c+c+c+…+c)%b = k*c%b(k>0)

 我们先把一百四十、六十三、二十三分解成几个质数相乘的形式。

140=2*2*5*7=b₁ * M₁' * m₂ * m₃(可以被5和7整除,但是除以3却余2,下同)

63=3*1*3*7=b₂ * M₂' * m₁ * m₃

30=2*1*3*5=b₃ * M₃' * m₁ * m₂

140+63+30=233(根据定理1,233满足题目条件,但还不是最小的那个数)

bᵢ为余数,mᵢ为模,m=m₁ * m₂ * m₃,,Mᵢ'= mod m₁

为M₁的乘法逆元,下面将用R表示,即MᵢR≡1(mod mᵢ)

这里提一嘴如何求乘法逆元。运用到扩展欧几里得算法:
MᵢR+mᵢy=1,MᵢR+mᵢy=1,变量是R和y,调用ex_gcd(Mᵢ,mᵢ,R,y)

//扩展欧几里得模板
int ex_gcd(int a,int b,int &x,int &y){
    int d;
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    d = ex_gcd(b,a%b,y,x);
    y -= a / b * x;
    return d;
}

210=2*3*5*7,其中3*5*7表示的是模的最小公约数,而2并没有具体含义,是可以根据题意自由变动的数,利用上面求出的233减去210的实际作用是求出符合题目要求的最小数,即23。

下面是中国剩余定理的c代码:

//扩展欧几里得模板
int ex_gcd(int a,int b,int &x,int &y){
    int d;
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    d = ex_gcd(b,a%b,y,x);
    y -= a / b * x;
    return d;
}
int Chinese_Remainder(int a[],int prime[],int len){
    int i,d,R,y,M,m = 1,sum = 0;
    //计算所有除数的积,也就是所有除数的最小公倍数m
    for(i = 0; i < len; i++)
        m *= prime[i];
    //计算符合所有条件的数
    for(i = 0; i < len; i++){
        M = m / prime[i];//计算除去本身的所有除数的积M
        d = ex_gcd(M,prime[i],R,y);
        sum = (sum + R * M * a[i]) % m;
    }
    return (m + sum % m) % m;//满足所有方程的最小解
}

三、例题

1.

#a = flag mod m

a1=2891369521230520600
m1=5539166121540472709
a2=5485400237604727152
m2=9993590208169240051
a3=10305113992248275270
m3=23524210813213316809
a4=15126620242797492888
m4=38726457607077802967
a5=63558232650391605454
m5=134070550878039878083   

从题目中可以明显看出,flag≡(mod )

所以用中国剩余定理可以轻易求出flag的值,python代码如下:

import gmpy2
a1=2891369521230520600
d1=5539166121540472709
a2=5485400237604727152
d2=9993590208169240051
a3=10305113992248275270
d3=23524210813213316809
a4=15126620242797492888
d4=38726457607077802967
a5=63558232650391605454
d5=134070550878039878083

aa = [a1,a2,a3,a4,a5]
dd = [d1,d2,d3,d4,d5]

def GCRT(mi, ai):
    assert (isinstance(mi, list) and isinstance(ai, list))
    curm, cura = mi[0], ai[0]
    for (m, a) in zip(mi[1:], ai[1:]):
        d = gmpy2.gcd(curm, m)
        c = a - cura
        assert (c % d == 0) 
        K = c // d * gmpy2.invert(curm // d, m // d)
        cura += curm * K
        curm = curm * m // d
        cura %= curm
    return (cura % curm, curm) #

s,dd = GCRT(dd,aa)
import libnum

print(libnum.n2s(int(s)))

 结果为actf{wow_are_you_my_CONFIDANT?}

 2.

也可以运用于RSA密码中,例如:buuctf中的RSA4

N = 331310324212000030020214312244232222400142410423413104441140203003243002104333214202031202212403400220031202142322434104143104244241214204444443323000244130122022422310201104411044030113302323014101331214303223312402430402404413033243132101010422240133122211400434023222214231402403403200012221023341333340042343122302113410210110221233241303024431330001303404020104442443120130000334110042432010203401440404010003442001223042211442001413004
c = 310020004234033304244200421414413320341301002123030311202340222410301423440312412440240244110200112141140201224032402232131204213012303204422003300004011434102141321223311243242010014140422411342304322201241112402132203101131221223004022003120002110230023341143201404311340311134230140231412201333333142402423134333211302102413111111424430032440123340034044314223400401224111323000242234420441240411021023100222003123214343030122032301042243
N = 302240000040421410144422133334143140011011044322223144412002220243001141141114123223331331304421113021231204322233120121444434210041232214144413244434424302311222143224402302432102242132244032010020113224011121043232143221203424243134044314022212024343100042342002432331144300214212414033414120004344211330224020301223033334324244031204240122301242232011303211220044222411134403012132420311110302442344021122101224411230002203344140143044114
c = 112200203404013430330214124004404423210041321043000303233141423344144222343401042200334033203124030011440014210112103234440312134032123400444344144233020130110134042102220302002413321102022414130443041144240310121020100310104334204234412411424420321211112232031121330310333414423433343322024400121200333330432223421433344122023012440013041401423202210124024431040013414313121123433424113113414422043330422002314144111134142044333404112240344
N = 332200324410041111434222123043121331442103233332422341041340412034230003314420311333101344231212130200312041044324431141033004333110021013020140020011222012300020041342040004002220210223122111314112124333211132230332124022423141214031303144444134403024420111423244424030030003340213032121303213343020401304243330001314023030121034113334404440421242240113103203013341231330004332040302440011324004130324034323430143102401440130242321424020323
c = 10013444120141130322433204124002242224332334011124210012440241402342100410331131441303242011002101323040403311120421304422222200324402244243322422444414043342130111111330022213203030324422101133032212042042243101434342203204121042113212104212423330331134311311114143200011240002111312122234340003403312040401043021433112031334324322123304112340014030132021432101130211241134422413442312013042141212003102211300321404043012124332013240431242

 由于题目中的数都是由5进制表示的,所以脚本中要先把5进制转换为10进制,又有

 ≡  mod 
 ≡  mod 
 ≡  mod 

 所以可以通过中国剩余定理求解,python代码如下:


import gmpy2
from functools import reduce
import sympy
    
def chinese_remainder(n, a):
    sum = 0
    prod = reduce(lambda a, b: a * b, n)

    for n_i, a_i in zip(n, a):
        p = prod // n_i
        sum += a_i * sympy.invert(p, n_i) * p
    return int(sum % prod)
def wu_shi(n):
    strlen=len(n)
    s=0
    for i in range(0,strlen):
        s+=int(n[i])*pow(5,strlen-i-1)
    return s

n1 = int(str(331310324212000030020214312244232222400142410423413104441140203003243002104333214202031202212403400220031202142322434104143104244241214204444443323000244130122022422310201104411044030113302323014101331214303223312402430402404413033243132101010422240133122211400434023222214231402403403200012221023341333340042343122302113410210110221233241303024431330001303404020104442443120130000334110042432010203401440404010003442001223042211442001413004),5)
c1 = int(str(310020004234033304244200421414413320341301002123030311202340222410301423440312412440240244110200112141140201224032402232131204213012303204422003300004011434102141321223311243242010014140422411342304322201241112402132203101131221223004022003120002110230023341143201404311340311134230140231412201333333142402423134333211302102413111111424430032440123340034044314223400401224111323000242234420441240411021023100222003123214343030122032301042243),5)

n2 = int(str(302240000040421410144422133334143140011011044322223144412002220243001141141114123223331331304421113021231204322233120121444434210041232214144413244434424302311222143224402302432102242132244032010020113224011121043232143221203424243134044314022212024343100042342002432331144300214212414033414120004344211330224020301223033334324244031204240122301242232011303211220044222411134403012132420311110302442344021122101224411230002203344140143044114),5)
c2 = int(str(112200203404013430330214124004404423210041321043000303233141423344144222343401042200334033203124030011440014210112103234440312134032123400444344144233020130110134042102220302002413321102022414130443041144240310121020100310104334204234412411424420321211112232031121330310333414423433343322024400121200333330432223421433344122023012440013041401423202210124024431040013414313121123433424113113414422043330422002314144111134142044333404112240344),5)

n3 = int(str(332200324410041111434222123043121331442103233332422341041340412034230003314420311333101344231212130200312041044324431141033004333110021013020140020011222012300020041342040004002220210223122111314112124333211132230332124022423141214031303144444134403024420111423244424030030003340213032121303213343020401304243330001314023030121034113334404440421242240113103203013341231330004332040302440011324004130324034323430143102401440130242321424020323),5)
c3 = int(str(10013444120141130322433204124002242224332334011124210012440241402342100410331131441303242011002101323040403311120421304422222200324402244243322422444414043342130111111330022213203030324422101133032212042042243101434342203204121042113212104212423330331134311311114143200011240002111312122234340003403312040401043021433112031334324322123304112340014030132021432101130211241134422413442312013042141212003102211300321404043012124332013240431242),5)


n=[n1,n2,n3]
c=[c1,c2,c3]
ans=chinese_remainder(n, c)
ans=gmpy2.iroot(ans,3)[0]
print(bytes.fromhex(hex(ans)[2:]))
#noxCTF{D4mn_y0u_h4s74d_wh47_4_b100dy_b4s74rd!}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuh1n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值