中国剩余定理模数不互素的情况

中国剩余定理

模数不互素的情况

当中国剩余定理在应用中模数不互素时,在求解 M i M_i Mi对模数 m i m_i mi的逆元 M i ′ M_i' Mi时可能会报错说:两个数不是互素的,无法进行求解逆元的操作(我这里用的封装函数gmpy2.invert()求解逆元)

那么假定现在有一组同余式需要用到中国剩余定理求解,但是模数不互素;

将式1: x ≡ c 1 ( m o d   m 1 ) x\equiv c_1(mod~m_1) xc1(mod m1) 式2: x ≡ c 2 ( m o d   m 2 ) x\equiv c_2(mod~m_2) xc2(mod m2)​ 转换为

x = c 1 + x 1 ∗ m 1 x = c_1 +x_1*m_1 x=c1+x1m1​, x = c 2 + x 2 ∗ m 2 x=c_2+x_2*m_2 x=c2+x2m2(为什么这里乘数要写作 x i x_i xi呢,因为在之后的推导公式中 x i x_i xi会作为新的一轮值再次计算)​

联立得

c 1 + x 1 ∗ m 1 = c 2 + x 2 ∗ m 2 c_1+x_1*m_1=c_2+x_2*m_2 c1+x1m1=c2+x2m2

移项

x 1 ∗ m 1 = c 2 − c 1 + x 2 ∗ m 2 x_1*m_1=c_2-c_1+x_2*m_2 x1m1=c2c1+x2m2

转换为同余式形式

x 1 ∗ m 1 ≡ c 2 − c 1 ( m o d   m 2 ) x_1*m_1\equiv c_2-c_1(mod~m_2) x1m1c2c1(mod m2)​​​

这里就类似于 a ∗ x ≡ b ( m o d   m ) a*x\equiv b(mod~m) axb(mod m)​​(这里 x 1 x_1 x1​是 x x x​, m 1 m_1 m1​是 a a a​)

所以该同余式要有解需要满足 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1

所以求 d = g c d ( m 1 , m 2 ) d=gcd(m_1,m_2) d=gcd(m1,m2)

所以同余式两边同时除以 d d d

得到 x 1 ∗ m 1 d ≡ c 2 − c 1 d ( m o d   m 2 d ) x_1*\frac{m_1}{d}\equiv \frac{c_2-c_1}{d}(mod~\frac{m_2}{d}) x1dm1dc2c1(mod dm2)

那么求解 x 1 ≡ ( m 1 d ) − 1 ∗ c 2 − c 1 d ( m o d   m 2 d ) x_1 \equiv (\frac{m_1}{d})^{-1}*\frac{c_2-c_1}{d}(mod~\frac{m_2}{d}) x1(dm1)1dc2c1(mod dm2)


这里有一点就是求 m 1 d \frac{m_1}{d} dm1对模数 m 2 d \frac{m_2}{d} dm2的逆元

可以这样来推导:

m 1 d ∗ ( m 1 d ) − 1 ≡ 1 ( m o d   m 2 d ) \frac{m_1}{d}*(\frac{m_1}{d})^{-1}\equiv 1 (mod~\frac{m_2}{d}) dm1(dm1)11(mod dm2)

相当于:

m 1 d ∗ ( m 1 d ) − 1 = 1 + k ∗ m 2 d \frac{m_1}{d}*(\frac{m_1}{d})^{-1}=1+k*\frac{m_2}{d} dm1(dm1)1=1+kdm2

写到关于 m 1 , m 2 m_1,m_2 m1,m2的扩展欧几里得算法

k 1 ∗ m 1 + k 2 ∗ m 2 = d k_1*m_1+k_2*m_2=d k1m1+k2m2=d

同时除以 d d d并移项

k 1 ∗ m 1 d = 1 − k 2 ∗ m 2 d k_1*\frac{m_1}{d}=1-k_2*\frac{m_2}{d} k1dm1=1k2dm2

对比一下这两个等式,是不是项都一样呢?那么 m 1 d \frac{m_1}{d} dm1的系数 k 1 k_1 k1实际上就是等于 ( m 1 d ) − 1 (\frac{m_1}{d})^{-1} (dm1)1

另外如果直接求解ta的逆元,可能会得到不正确的值~~(我试过但是不知道为什么)~~


那么 x 1 ≡ k 1 ∗ c 2 − c 1 d ( m o d   m 2 d ) x_1\equiv k_1*\frac{c_2-c_1}{d}(mod~\frac{m_2}{d}) x1k1dc2c1(mod dm2)

X = k 1 ∗ c 2 − c 1 d X=k_1*\frac{c_2-c_1}{d} X=k1dc2c1

x 1 = m 2 d ∗ y + X x_1=\frac{m_2}{d}*y+X x1=dm2y+X

又因为 x = c 1 + m 1 ∗ x 1 x=c_1+m_1*x_1 x=c1+m1x1

代入后,

x = c 1 + m 1 ∗ m 2 d ∗ y + X ∗ m 1 x=c_1+\frac{m_1*m_2}{d}*y+X*m_1 x=c1+dm1m2y+Xm1

也就相当于同余式,

x ≡ c 1 + X ∗ m 1 ( m o d   m 1 ∗ m 2 d ) x\equiv c_1+X*m_1(mod~\frac{m_1*m_2}{d}) xc1+Xm1(mod dm1m2)

那么这就是成功合并完了两个同余式的结果,成为一个新的同余式,其中 c 1 + X ∗ m 1 c_1+X*m_1 c1+Xm1重新作为新的同余式里的 c c c m 1 ∗ m 2 d \frac{m_1*m_2}{d} dm1m2也是新的同余式里的 m m m


另外这里 m 1 ∗ m 2 d \frac{m_1*m_2}{d} dm1m2实际上也就是 l c m [ m 1 , m 2 ] = m 1 ∗ m 2 g c d ( m 1 , m 2 ) lcm[m_1,m_2]=\frac{m_1*m_2}{gcd(m_1,m_2)} lcm[m1,m2]=gcd(m1,m2)m1m2

所以可以直接求 m 1 , m 2 m_1,m_2 m1,m2的最小公倍数去代替 m 1 ∗ m 2 d \frac{m_1*m_2}{d} dm1m2


将这个新的同余式和剩下没有合并的同余式依次代入相同的计算中,就可以得到最后的结果

Python代码实现

i = 0  # 这里我使用了一个i作为全局变量
# 我定义的函数需要重复执行且在不同同余式组进行求解的时候i要重新赋值
def CRT(cl,ml):
    global i
    clist = cl
    moudlelist = ml
    if i == 0:
        m1,m2 = ml[i],ml[i+1]
        c1,c2 = cl[i],cl[i+1]
    else:
        m1,m2 = ml[i],ml[len(ml)-1]
        c1,c2 = cl[i],cl[len(cl)-1]
    d = gmpy2.gcd(m1,m2)
    print(d)
    c = c2 - c1
    assert c % d == 0
    # 这里代码的注释部分是最初的写法,但是结果会出错,我不知道为什么
    # X = c // d * gmpy2.invert(m1 // d,m2 // d)
    _,k1,k2 = gmpy2.gcdext(m1,m2) 
    X = c // d * k1 * m1
    if i == 0:
        clist.append((X + c1) % gmpy2.lcm(m1,m2))
        # moudlelist.append(m1*m2 // d)
        moudlelist.append(gmpy2.lcm(m1,m2))
        i += 2
    else:
        clist[len(clist)-1] = (X + c1) % gmpy2.lcm(m1,m2)
        # moudlelist[len(moudlelist)-1] = m1*m2 // d
        moudlelist[len(moudlelist)-1] = gmpy2.lcm(m1,m2)
        i += 1
    return clist,moudlelist

例题

e = 7
cl1 = [int(powmod(bytes_to_long(m1), e, x)) for x in ul]
cl2 = [int(powmod(bytes_to_long(m2), e, y)) for y in vl]
# ul,vl已知

很显然这里使用低加密指数广播攻击

但是在使用中国剩余定理的过程出现了报错:两数不互素

所以应用模数不互素的情况来求解

代码实现

import gmpy2
from Crypto.Util.number import *

ml1 = [10537190383977432819948602717449313819513015810464463348450662860435011008001132238851729268032889296600248226221086420035262540732157097949791756421026015741477785995033447663038515248071740991264311479066137102975721041822067496462240009190564238288281272874966280,121723653124334943327337351369224143389428692536182586690052931548156177466437320964701609590004825981378294358781446032392886186351422728173975231719924841105480990927174913175897972732532233,1440176324831562539183617425199117363244429114385437232965257039323873256269894716229817484088631407074328498896710966713912857642565350306252498754145253802734893404773499918668829576304890397994277568525506501428687843547083479356423917301477033624346211335450]
ml2 = [168450500310972930707208583777353845862723614274337696968629340838437927919365973736431467737825931894403582133125917579196621697175572833671789075169621831768398654909584273636143519940165648838850012943578686057625415421266321405275952938776845012046586285747,1921455776649552079281304558665818887261070948261008212148121820969448652705855804423423681848341600084863078530401518931263150887409200101780191600802601105030806253998955929263882382004,25220695816897075916217095856631009012504127590059436393692101250418226097323331193222730091563032067314889286051745468263446649323295355350101318199942950223572194027189199046045156046295274639977052585768365501640340023356756783359924935106074017605019787]
cl1 = [2852589223779928796266540600421678790889067284911682578924216186052590393595645322161563386615512475256726384365091711034449682791268994623758937752874750918200961888997082477100811025721898720783666868623498246219677221106227660895519058631965055790709130207760704, 21115849906180139656310664607458425637670520081983248258984166026222898753505008904136688820075720411004158264138659762101873588583686473388951744733936769732617279649797085152057880233721961, 301899179092185964785847705166950181255677272294377823045011205035318463496682788289651177635341894308537787449148199583490117059526971759804426977947952721266880757177055335088777693134693713345640206540670123872210178680306100865355059146219281124303460105424] 
cl2 = [148052450029409767056623510365366602228778431569288407577131980435074529632715014971133452626021226944632282479312378667353792117133452069972334169386837227285924011187035671874758901028719505163887789382835770664218045743465222788859258272826217869877607314144, 1643631850318055151946938381389671039738824953272816402371095118047179758846703070931850238668262625444826564833452294807110544441537830199752050040697440948146092723713661125309994275256, 10949587016016795940445976198460149258144635366996455598605244743540728764635947061037779912661207322820180541114179612916018317600403816027703391110922112311910900034442340387304006761589708943814396303183085858356961537279163175384848010568152485779372842]

i = 0
def CRT(cl,ml):
    global i
    clist = cl
    moudlelist = ml
    if i == 0:
        m1,m2 = ml[i],ml[i+1]
        c1,c2 = cl[i],cl[i+1]
    else:
        m1,m2 = ml[i],ml[len(ml)-1]
        c1,c2 = cl[i],cl[len(cl)-1]
    d = gmpy2.gcd(m1,m2)
    print(d)
    c = c2 - c1
    assert c % d == 0
    # X = c // d * gmpy2.invert(m1 // d,m2 // d)
    _,k1,k2 = gmpy2.gcdext(m1,m2) 
    X = c // d * k1 * m1
    if i == 0:
        clist.append((X + c1) % gmpy2.lcm(m1,m2))
        # moudlelist.append(m1*m2 // d)
        moudlelist.append(gmpy2.lcm(m1,m2))
        i += 2
    else:
        clist[len(clist)-1] = (X + c1) % gmpy2.lcm(m1,m2)
        # moudlelist[len(moudlelist)-1] = m1*m2 // d
        moudlelist[len(moudlelist)-1] = gmpy2.lcm(m1,m2)
        i += 1
    return clist,moudlelist
ii = 3
temp_cl,temp_ml = CRT(cl1,ml1)
while len(cl1) - ii > 0:
    temp_cl,temp_ml = CRT(temp_cl,temp_ml)
    ii += 1
final_c = temp_cl[len(temp_cl)-1]
print(long_to_bytes(gmpy2.iroot(final_c,7)[0]))
ii = 3
i = 0
temp_cl,temp_ml = CRT(cl2,ml2)
while len(cl2) - ii > 0:
    temp_cl,temp_ml = CRT(temp_cl,temp_ml)
    ii += 1
final_c = temp_cl[len(temp_cl)-1]
print(long_to_bytes(gmpy2.iroot(final_c,7)[0]))

参考文章

(12条消息) 中国剩余定理算法详解(互质与不互质情况)_codeswarrior的博客-CSDN博客_中国剩余算法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

M3ng@L

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

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

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

打赏作者

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

抵扣说明:

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

余额充值