Rust中GMP powm函数返回结果异常问题排查
问题
我正在学习在Rust中集成GMP,克隆了poanetwork的vdf仓库。为验证实现准确性,我写了一段测试代码调用GMP的mpz_powm函数做模幂运算:
let modulushex = hex::decode("c7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5").unwrap(); let modulus = ffi::import_obj(&modulushex); let basehex = hex::decode("007d995c170a8f03887a3d500c61fde4f0b9002299c06cbe8f1c5bbeb92fe879da02ae0490c706ae4ee5e2eb31b460b8f4b558beaf2fc6a614034988b5af17641f9e5fee1d620f30afc6dc4d9bbd3d6566a3a2039dd468d83a08abf5bf88872de0f7320b19605379128bff6cbb4f41336167602b5d2b0ef435a23e4d3dac13b7400036fed32fd376d0b6f1632baed3be16aac1350383de43eb27a90eddb5c52641e9583a93cd5e2bd1242d4ed05737dcf81648f80d30d422b837d7cd3c1467f43fb7c75f06fe1aa13572363dda02151abe448763fe56f74ded851bfacaaf8789a775c0aa625da1c2c18a62cb4be026f781fd8d3d1baf49ac599ace8032da53517b0b").unwrap(); let base = ffi::import_obj(&basehex); let exphex = hex::decode("32f71783ecf103a837c132bfa93ae921").unwrap(); let exp = ffi::import_obj(&exphex); let resultshex = hex::decode("00").unwrap(); let mut results = ffi::import_obj(&resultshex); ffi::mpz_powm(&mut results, &base, &exp, &modulus); println!("results [{results:?}]");
这段代码返回的结果是:
6263682918507965914797445799289859108134103890488175732832898635052307612005730308824743390072513383012259400947965457535695477018975847005106015411057214608601835313194847404520388830993945571946551059770249346550450799679293019212260731875429995408104700787836471924904040903046217160901192277414306953243692570745939155084293970373747868634274159689150356885218721451773167280878150568254478484035380265847143829453206348515440010212597926192674567686562177604430455586964510741165008495200814486437791770994880260554814576029215340442206760818180177707323413999025814877848350881462395129912997094278796497268895
但用在线模幂计算器和JavaScript的BN库计算,得到的结果是:
13290134286600559171336036011744051010975349698089310497613244954971894256159455376070068170969117865603940143950234700490139328324510110590331351375373057750302635253248860322705105526282078955986713129738320950314362163296004383736966075522132464507202444974868495696938214081994773272806795593381322361519649717482608890203601703744375411728441852817229531187473366661448194569129834537136314700647178693515797801638221759683217309314651463861673829648093408577585291858800808060958176326026588397720716615414584950132753461667369058887493888335444980276376067415273068893192825129868694805775390603459613462318603
两者结果不一致,这是Rust集成GMP时出现的问题吗?
分析与解决思路
结果不一致大概率不是GMP本身的问题,更可能是代码在数据导入、字节序处理或者变量初始化环节出了问题,具体排查方向如下:
检查
ffi::import_obj的实现逻辑
GMP的mpz_t存储依赖特定字节序,若import_obj直接将hex解码后的字节数组按原顺序传入,而GMP需要相反的字节序(比如hex是大端表示,GMP期望小端字节流),会导致base、modulus、exp的数值解析错误,最终运算结果偏差。验证初始结果变量的正确性
用hex::decode("00")初始化results再转mpz_t的方式可能存在隐患,若import_obj对全零字节的处理逻辑有问题(比如未正确初始化mpz_t结构),会影响运算。建议改用ffi::mpz_init_set_ui(&mut results, 0)直接初始化结果变量。核对输入数值的准确性
将hex字符串转换为十进制,与在线工具的输入数值逐一对比。如果import_obj解析后的base、modulus、exp和在线工具的输入不一致,运算结果必然错误。直接调用GMP原生接口验证
跳过仓库的ffi封装,直接使用libgmp-sys提供的原生函数实现模幂运算。若原生调用结果与在线工具一致,说明问题出在poanetware仓库的ffi封装层。
内容的提问来源于stack exchange,提问作者keithc

