Python2与Python3中gmpy2计算RSA的q结果不一致问题
RSA挑战中Python2与Python3 gmpy2计算q的差异原因
这个问题的核心并不是gmpy2在Python3中有问题,而是Python2和Python3中除法运算符/的行为差异,以及大整数转浮点数的精度限制导致的。
为什么Python2的代码能得到正确结果?
在Python2中,当你对两个整数(包括Python原生的长整数)使用/运算符时,默认执行的是整数除法(地板除),直接返回精确的整数商。你的Python2代码里,n和p都是原生的大整数,n/p会直接计算出准确的q,后续的assert p*q==n自然能通过。
为什么Python3的代码得到错误结果?
在Python3中,/运算符对所有数值类型(包括gmpy2的mpz对象)都会执行浮点除法,返回一个float类型的结果。但你的n和p都是非常大的RSA模数和素数,远超过了双精度浮点数(Python的float)能精确表示的范围(双精度只能精确存储53位以内的整数)。当你执行n/p时,结果会被转成一个近似的浮点数,再用gmpy2.mpz()转换时,就会丢失大量精度,得到错误的q,最终p*q自然不等于n。
修正后的Python3代码
要在Python3中用gmpy2得到准确的q,你需要使用整数除法,有两种可靠方式:
- 使用
//运算符(Python3中专门用于整数地板除的运算符) - 使用gmpy2提供的
gmpy2.div()函数
下面是修正后的代码:
import gmpy2 n = gmpy2.mpz(0x9aeb7f60ababfd1c1a23f033068a5f5397832567fd116dd468bf2607ddc0ce34e172cc6029cf9f1c4ed9bc50ce228a164e6c2a9c5f9a6c2d98b8dd762cfc9cc08228c8e5b6327054d992afad9a49655e20f7822d3cc5e55ae0810851694d118a2efaa1658a14d9575facbec5aa0be21bfeb9c2a0e19344841664e40847ab865b5c1170744436fa5150b8e0e560beb67115c511b811875f91ace6d243cf44de0af8cc68c469df938dbbba378e05a9285ee0b5fd6d8cf9fb3b742061404096ad2a37bbf9aec7b944be3252e531eebaf44e127e3395ef870d378681b1db9c9996943e204fd0467b091995edc837d9056a09900c85e10e424d3be069fbc08e5463a7) e = gmpy2.mpz(0x10001) p = gmpy2.mpz(0xd60447478bf0d9f65c0795df7b71e676f2adc839e4381e845e91cd9026386f580bf146b43bf6309478ddd30c2339b3022f567ed1c437ebb30c04563f88261ea6fdec76f79debcb9835513fd28f9c07e9f2a4117ab1b20450f9acdc01c0cf66b4ae0ec2331f3fb34dbd4709321744a1eac86b19b2f89f4cba5e808808ddabcc89) # 方法1:使用//运算符做整数除法 q = n // p # 方法2:使用gmpy2.div() # q = gmpy2.div(n, p) print(q) assert p*q == n
运行这段代码,就能得到正确的q,并且assert会顺利通过。
总结
- Python2中
/对整数是整数除法,Python3中/是浮点除法,这是核心差异点 - 超大整数转浮点数会丢失精度,直接导致错误结果
- 在Python3中处理gmpy2大整数的除法,必须用整数除法运算符
//或者gmpy2的专门除法函数
内容的提问来源于stack exchange,提问作者naonaonao
相关产品推荐
相关产品推荐

