Update `mix` to match reference implementation ver
Reference implementation: https://extgit.iaik.tugraz.at/krypto/hadeshash
Tested with `sage code/poseidonperm_x5_254_3.sage` for inputs:
`[1,2,0]`, equivalent to using `circomlib/poseidon.js` with inputs
`[1,2]`, both return as result
`11309872961022349216464221841186646423561022368884850929991258903497301047946`
Tested with `sage code/poseidonperm_x5_254_5.sage` for inputs:
`[1,2,3,4,0]`, equivalent to using `circomlib/poseidon.js` with inputs
`[1,2,3,4]`, both return as result
`18181515143627462196415302348515936346022476168236332098176009127325427112991`
3 years ago |
|
include "./poseidon_constants.circom";
template Sigma() { signal input in; signal output out;
signal in2; signal in4;
in2 <== in*in; in4 <== in2*in2;
out <== in4*in; }
template Ark(t, C, r) { signal input in[t]; signal output out[t];
for (var i=0; i<t; i++) { out[i] <== in[i] + C[i + r]; } }
template Mix(t, M) { signal input in[t]; signal output out[t];
var lc; for (var i=0; i<t; i++) { lc = 0; for (var j=0; j<t; j++) { lc += M[i][j]*in[j]; } out[i] <== lc; } }
template Poseidon(nInputs) { signal input inputs[nInputs]; signal output out;
// Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8) // Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py // And rounded up to nearest integer that divides by t var N_ROUNDS_P[8] = [56, 57, 56, 60, 60, 63, 64, 63]; var t = nInputs + 1; var nRoundsF = 8; var nRoundsP = N_ROUNDS_P[t - 2]; var C[t*(nRoundsF + nRoundsP)] = POSEIDON_C(t); var M[t][t] = POSEIDON_M(t);
component ark[nRoundsF + nRoundsP - 1]; component sigmaF[nRoundsF - 1][t]; component sigmaP[nRoundsP]; component mix[nRoundsF + nRoundsP - 1];
var k;
for (var i=0; i<nRoundsF + nRoundsP - 1; i++) { ark[i] = Ark(t, C, t*i); for (var j=0; j<t; j++) { if (i==0) { if (j<nInputs) { ark[i].in[j] <== inputs[j]; } else { ark[i].in[j] <== 0; } } else { ark[i].in[j] <== mix[i-1].out[j]; } }
if (i < nRoundsF/2 || i >= nRoundsP + nRoundsF/2) { k = i < nRoundsF/2 ? i : i - nRoundsP; mix[i] = Mix(t, M); for (var j=0; j<t; j++) { sigmaF[k][j] = Sigma(); sigmaF[k][j].in <== ark[i].out[j]; mix[i].in[j] <== sigmaF[k][j].out; } } else { k = i - nRoundsF/2; mix[i] = Mix(t, M); sigmaP[k] = Sigma(); sigmaP[k].in <== ark[i].out[0]; mix[i].in[0] <== sigmaP[k].out; for (var j=1; j<t; j++) { mix[i].in[j] <== ark[i].out[j]; } } }
// last round is done only for the first word, so we do it manually to save constraints component lastSigmaF = Sigma(); lastSigmaF.in <== mix[nRoundsF + nRoundsP - 2].out[0] + C[t*(nRoundsF + nRoundsP - 1)]; out <== lastSigmaF.out; }
|