Circomlib中简单MiMCSponge哈希断言失败问题排查
问题场景
我基于circom和circomlib搭建了一个MiMCSponge哈希电路,配置为2输入、220轮运算、1输出。在前端用circomlibjs计算哈希值后填入input.json,执行witness生成脚本时触发o===hasher.outs[0]断言失败。已确认电路和JS实现都使用220轮运算,求其他可能导致结果不一致的原因。
电路代码
template sponge_test() { signal input l; signal input r; signal input o; // instantiate - 2 inputs 220 rounds of hashing and 1 output component hasher = MiMCSponge(2, 220, 1); // signals in hasher hasher.ins[0] <== l; hasher.ins[1] <== r; // addition constant hasher.k <== 0; o === hasher.outs[0]; } component main = sponge_test();
JS前端代码
import { buildMimcSponge } from 'circomlibjs'; function toHexString(byteArray) { return Array.from(byteArray, function(byte) { return ('0' + (byte & 0xFF).toString(16)).slice(-2); }).join('') } export async function getProof(message) { var hasher = await buildMimcSponge(); var h = hasher.multiHash([BigInt("0x3"), BigInt("0x4")]); // returns byte array console.log(h); // back to hexstring console.log(toHexString(h)); }
input.json内容
{ "l": "0x3", "r": "0x4", "o": "0x690f48aba976f2786371b7fa3e941df623e96329e0570dc610f59b7fcfa94723" }
执行脚本
# Compile the circuit circom ${CIRCUIT}.circom --r1cs --wasm --sym --c # Generate the witness.wtns node ${CIRCUIT}_js/generate_witness.js ${CIRCUIT}_js/${CIRCUIT}.wasm input.json ${CIRCUIT}_js/witness.wtns
可能的排查方向
1. MiMCSponge加法常量k不匹配
电路中明确设置hasher.k <== 0,但circomlibjs的buildMimcSponge默认使用预设加法常量(而非0)。两边k值不一致会导致每轮运算的中间结果全部偏差,最终哈希值必然不同。
验证方法:JS初始化hasher时手动指定k=0,与电路保持一致:
var hasher = await buildMimcSponge({ k: 0, nRounds: 220 });
2. 字节序转换错误
JS端multiHash返回的Uint8Array字节数组,你的toHexString直接按原顺序转十六进制,但circom中的信号数值以大端字节序存储,若Uint8Array是小端输出,会导致最终十六进制字符串顺序反转,哈希值错误。
验证方法:反转字节数组后再转十六进制:
function toHexString(byteArray) { return Array.from(byteArray.reverse(), function(byte) { return ('0' + (byte & 0xFF).toString(16)).slice(-2); }).join('') }
或用Buffer简化处理:
console.log(Buffer.from(h).reverse().toString('hex'));
3. 版本不兼容问题
circom、circomlib、circomlibjs的版本差异可能导致MiMCSponge的实现细节(如轮常数生成、模运算逻辑)不一致。比如circom 3.x与2.x编译逻辑有变化,或circomlibjs新版本调整了默认参数。
验证方法:检查三方版本是否匹配:
- 查看项目
package.json中circomlibjs版本 - 执行
circom --version查看circom版本 - 确保circomlib与circomlibjs版本适配
4. 输入/输出模运算差异
circom中的signal会自动模上电路使用的素数(如BabyJubJub素数21888242871839275222246405745257275088548364400416034343698204186575808495617),若JS端multiHash未做相同模运算,会导致结果偏差(虽当前输入值较小,但逻辑上仍需对齐)。
验证方法:JS端手动对输入做模素数处理:
const FIELD_PRIME = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); var h = hasher.multiHash([BigInt("0x3") % FIELD_PRIME, BigInt("0x4") % FIELD_PRIME]);
5. 输出取法不一致
电路取hasher.outs[0]作为结果,需确认JS端multiHash返回值是否对应该输出。部分场景下,multiHash可能返回多个输出的拼接结果,而非单个指定输出。
验证方法:查看circomlibjs中multiHash的实现,确认返回值为单个输出的字节数组,而非多输出组合。
内容的提问来源于stack exchange,提问作者TIZ

