Browse Source

New Version of Poseidon

master
Jordi Baylina 4 years ago
parent
commit
86c6a2a6f5
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
18 changed files with 3710 additions and 370 deletions
  1. +19
    -19
      circuits/README.md
  2. +1
    -1
      circuits/eddsaposeidon.circom
  3. +124
    -145
      circuits/poseidon.circom
  4. +2
    -2
      circuits/smt/smthash_poseidon.circom
  5. +2
    -4
      src/eddsa.js
  6. +11
    -0
      src/evmasm.js
  7. +33
    -105
      src/poseidon.js
  8. +3449
    -0
      src/poseidon_constants.json
  9. +32
    -26
      src/poseidon_gencontract.js
  10. +0
    -16
      src/poseidon_printconstants.js
  11. +1
    -1
      src/poseidon_printcontract.js
  12. +10
    -5
      src/smt_hashes_poseidon.js
  13. +4
    -2
      src/smt_memdb.js
  14. +1
    -1
      test/circuits/poseidon3_test.circom
  15. +1
    -1
      test/circuits/poseidon6_test.circom
  16. +2
    -2
      test/eddsa_js.js
  17. +10
    -28
      test/poseidoncircuit.js
  18. +8
    -12
      test/poseidoncontract.js

+ 19
- 19
circuits/README.md

@ -49,7 +49,7 @@ Folder containing the circuit implementation of Sparse Merkle Trees.
- OUTPUT - OUTPUT
- BENCHMARKS - BENCHMARKS
- EXAMPLE - EXAMPLE
### babyjub ### babyjub
Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby_jubjub) in twisted Edwards form. (TODO: Expose here the characteristics of the curve?) Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby_jubjub) in twisted Edwards form. (TODO: Expose here the characteristics of the curve?)
@ -58,22 +58,22 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
- `BabyAdd()` - `BabyAdd()`
- DESCRIPTION - DESCRIPTION
It adds two points on the Baby Jubjub curve. More specifically, given two points P1 = (`x1`, `y1`) and P2 = (`x2`, `y2`) it returns a point P3 = (`xout`, `yout`) such that It adds two points on the Baby Jubjub curve. More specifically, given two points P1 = (`x1`, `y1`) and P2 = (`x2`, `y2`) it returns a point P3 = (`xout`, `yout`) such that
(`xout`, `yout`) = (`x1`,`y1`) + (`x2`,`y2`)
(`xout`, `yout`) = (`x1`,`y1`) + (`x2`,`y2`)
= ((`x1y2`+`y1x2`)/(1+`dx1x2y1y2`)),(`y1y2`-`ax1x2`)/(1-`dx1x2y1y2`)) = ((`x1y2`+`y1x2`)/(1+`dx1x2y1y2`)),(`y1y2`-`ax1x2`)/(1-`dx1x2y1y2`))
- SCHEMA - SCHEMA
``` ```
var a var d var a var d
| | | |
| | | |
______v_________v_______
______v_________v_______
input x1 ----> | | input x1 ----> | |
input y1 ----> | BabyAdd() | ----> output xout input y1 ----> | BabyAdd() | ----> output xout
input x2 ----> | | ----> output yout input x2 ----> | | ----> output yout
input y2 ----> |________________________|
input y2 ----> |________________________|
``` ```
- INPUTS - INPUTS
@ -84,16 +84,16 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
| `y1` | Bigint | Field element of Fp | Second coordinate of a point (x1, y1) on E. | | `y1` | Bigint | Field element of Fp | Second coordinate of a point (x1, y1) on E. |
| `x2` | Bigint | Field element of Fp | First coordinate of a point (x2, y2) on E. | | `x2` | Bigint | Field element of Fp | First coordinate of a point (x2, y2) on E. |
| `y2` | Bigint | Field element of Fp | Second coordinate of a point (x2, y2) on E. | | `y2` | Bigint | Field element of Fp | Second coordinate of a point (x2, y2) on E. |
Requirement: at least `x1`!=`x2` or `y1`!=`y2`. Requirement: at least `x1`!=`x2` or `y1`!=`y2`.
- OUTPUT - OUTPUT
| Input | Representation | Description | | | Input | Representation | Description | |
| ------------- | ------------- | ------------- | ------------- | | ------------- | ------------- | ------------- | ------------- |
| `xout` | Bigint | Field element of Fp | First coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). | | `xout` | Bigint | Field element of Fp | First coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). |
| `yout` | Bigint | Field element of Fp | Second coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). | | `yout` | Bigint | Field element of Fp | Second coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). |
- BENCHMARKS (constraints) - BENCHMARKS (constraints)
- EXAMPLE - EXAMPLE
@ -108,7 +108,7 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
- `BabyCheck()` - `BabyCheck()`
- DESCRIPTION : checks if a given point is in the curve.
- DESCRIPTION : checks if a given point is in the curve.
- SCHEMA - SCHEMA
- INPUT - INPUT
- OUTPUT - OUTPUT
@ -127,7 +127,7 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
### binsub ### binsub
- `BinSub(n)`
- `BinSub(n)`
- DESCRIPTION: binary substraction. - DESCRIPTION: binary substraction.
- SCHEMA - SCHEMA
@ -140,7 +140,7 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
- `nbits(a)` - `nbits(a)`
- DESCRIPTION : binary sum.
- DESCRIPTION : binary sum.
- SCHEMA - SCHEMA
- INPUT - INPUT
- OUTPUT - OUTPUT
@ -149,7 +149,7 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
- `BinSum(n, ops)` - `BinSum(n, ops)`
- DESCRIPTION
- DESCRIPTION
- SCHEMA - SCHEMA
- INPUT - INPUT
- OUTPUT - OUTPUT
@ -169,7 +169,7 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
- `Num2Bits_strict()` - `Num2Bits_strict()`
- DESCRIPTION
- DESCRIPTION
- SCHEMA - SCHEMA
- INPUT - INPUT
- OUTPUT - OUTPUT
@ -259,7 +259,7 @@ Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby
- BENCHMARKS - BENCHMARKS
- EXAMPLE - EXAMPLE
### compconstant
### compconstant
- `CompConstant(ct)` - `CompConstant(ct)`
@ -688,7 +688,7 @@ Implementation of MiMC-7 hash in Fp being... (link to description of the hash)
### pedersen_old ### pedersen_old
Old version of the Pedersen hash (do not use any
Old version of the Pedersen hash (do not use any
more?). more?).
### pedersen ### pedersen
@ -720,7 +720,7 @@ more?).
- BENCHMARKS - BENCHMARKS
- EXAMPLE - EXAMPLE
### pointbits
### pointbits
- `sqrt(n)` - `sqrt(n)`
@ -780,7 +780,7 @@ Implementation of Poseidon hash function (LINK)
- BENCHMARKS - BENCHMARKS
- EXAMPLE - EXAMPLE
- `Ark(t, C)`
- `Ark(t, C, r)`
- DESCRIPTION - DESCRIPTION
- SCHEMA - SCHEMA
@ -798,7 +798,7 @@ Implementation of Poseidon hash function (LINK)
- BENCHMARKS - BENCHMARKS
- EXAMPLE - EXAMPLE
- `Poseidon(nInputs, t, nRoundsF, nRoundsP)`
- `Poseidon(nInputs)`
- DESCRIPTION - DESCRIPTION
- SCHEMA - SCHEMA

+ 1
- 1
circuits/eddsaposeidon.circom

@ -51,7 +51,7 @@ template EdDSAPoseidonVerifier() {
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
component hash = Poseidon(5, 6, 8, 57);
component hash = Poseidon(5);
hash.inputs[0] <== R8x; hash.inputs[0] <== R8x;
hash.inputs[1] <== R8y; hash.inputs[1] <== R8y;

+ 124
- 145
circuits/poseidon.circom
File diff suppressed because it is too large
View File


+ 2
- 2
circuits/smt/smthash_poseidon.circom

@ -29,7 +29,7 @@ template SMTHash1() {
signal input value; signal input value;
signal output out; signal output out;
component h = Poseidon(3, 6, 8, 57); // Constant
component h = Poseidon(3); // Constant
h.inputs[0] <== key; h.inputs[0] <== key;
h.inputs[1] <== value; h.inputs[1] <== value;
h.inputs[2] <== 1; h.inputs[2] <== 1;
@ -48,7 +48,7 @@ template SMTHash2() {
signal input R; signal input R;
signal output out; signal output out;
component h = Poseidon(2, 6, 8, 57); // Constant
component h = Poseidon(2); // Constant
h.inputs[0] <== L; h.inputs[0] <== L;
h.inputs[1] <== R; h.inputs[1] <== R;

+ 2
- 4
src/eddsa.js

@ -112,8 +112,7 @@ function signPoseidon(prv, msg) {
const Fr = new F1Field(babyJub.subOrder); const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r); r = Fr.e(r);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r); const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hash = poseidon.createHash(6, 8, 57);
const hm = hash([R8[0], R8[1], A[0], A[1], msg]);
const hm = poseidon([R8[0], R8[1], A[0], A[1], msg]);
const S = Fr.add(r , Fr.mul(hm, s)); const S = Fr.add(r , Fr.mul(hm, s));
return { return {
R8: R8, R8: R8,
@ -180,8 +179,7 @@ function verifyPoseidon(msg, sig, A) {
if (!babyJub.inCurve(A)) return false; if (!babyJub.inCurve(A)) return false;
if (sig.S>= babyJub.subOrder) return false; if (sig.S>= babyJub.subOrder) return false;
const hash = poseidon.createHash(6, 8, 57);
const hm = hash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const hm = poseidon([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S); const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8)); let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));

+ 11
- 0
src/evmasm.js

@ -154,6 +154,17 @@ class Contract {
} }
push(data) { push(data) {
if (typeof data === "number") {
let isNeg;
if (data<0) {
isNeg = true;
data = -data;
}
data = data.toString(16);
if (data.length % 2 == 1) data = "0" + data;
data = "0x" + data;
if (isNeg) data = "-"+data;
}
const d = Web3Utils.hexToBytes(Web3Utils.toHex(data)); const d = Web3Utils.hexToBytes(Web3Utils.toHex(data));
if (d.length == 0 || d.length > 32) { if (d.length == 0 || d.length > 32) {
throw new Error("Assertion failed"); throw new Error("Assertion failed");

+ 33
- 105
src/poseidon.js

@ -1,121 +1,49 @@
const Scalar = require("ffjavascript").Scalar;
const blake2b = require("blake2b");
const assert = require("assert"); const assert = require("assert");
const Scalar = require("ffjavascript").Scalar;
const ZqField = require("ffjavascript").ZqField; const ZqField = require("ffjavascript").ZqField;
const utils = require("ffjavascript").utils;
const { unstringifyBigInts } = require("ffjavascript").utils;
// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617")); const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
exports.F = F;
const SEED = "poseidon";
const NROUNDSF = 8;
const NROUNDSP = 57;
const T = 6;
// Parameters are generated by a reference script https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/generate_parameters_grain.sage
// Used like so: sage generate_parameters_grain.sage 1 0 254 2 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
const { C, M } = unstringifyBigInts(require("./poseidon_constants.json"));
function getPseudoRandom(seed, n) {
const res = [];
let input = Buffer.from(seed);
let h = blake2b(32).update(input).digest();
while (res.length<n) {
const n = F.normalize(utils.leBuff2int(Buffer.from(h)));
res.push(n);
h = blake2b(32).update(h).digest();
}
// 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
const N_ROUNDS_F = 8;
const N_ROUNDS_P = [56, 57, 56, 60, 60, 63, 64, 63];
return res;
}
const pow5 = a => F.mul(a, F.square(F.square(a, a)));
function allDifferent(v) {
for (let i=0; i<v.length; i++) {
if (F.isZero(v[i])) return false;
for (let j=i+1; j<v.length; j++) {
if (F.eq(v[i],v[j])) return false;
}
}
return true;
}
exports.getMatrix = (t, seed, nRounds) => {
if (typeof seed === "undefined") seed = SEED;
if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP;
if (typeof t === "undefined") t = T;
assert(t<=6); // Force the same matrix for all.
t=6;
let nonce = "0000";
let cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2);
while (!allDifferent(cmatrix)) {
nonce = (Number(nonce)+1)+"";
while(nonce.length<4) nonce = "0"+nonce;
cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2);
}
const M = new Array(t);
for (let i=0; i<t; i++) {
M[i] = new Array(t);
for (let j=0; j<t; j++) {
M[i][j] = F.normalize(F.inv(F.sub(cmatrix[i], cmatrix[t+j])));
}
}
return M;
};
function poseidon(inputs) {
assert(inputs.length > 0);
assert(inputs.length < N_ROUNDS_P.length - 1);
exports.getConstants = (t, seed, nRounds) => {
if (typeof seed === "undefined") seed = SEED;
if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP;
if (typeof t === "undefined") t = T;
const cts = getPseudoRandom(seed+"_constants", nRounds);
return cts;
};
const t = inputs.length + 1;
const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P[t - 2];
function ark(state, c) {
for (let j=0; j<state.length; j++ ) {
state[j] = F.add(state[j], c);
}
}
let state = [...inputs.map(a => F.e(a)), F.zero];
for (let r = 0; r < nRoundsF + nRoundsP; r++) {
state = state.map((a, i) => F.add(a, C[t - 2][r * t + i]));
function sigma(a) {
return F.mul(a, F.square(F.square(a,a)));
}
if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
state = state.map(a => pow5(a));
} else {
state[0] = pow5(state[0]);
}
function mix(state, M) {
const newState = new Array(state.length);
for (let i=0; i<state.length; i++) {
newState[i] = F.zero;
for (let j=0; j<state.length; j++) {
newState[i] = F.add(newState[i], F.mul(M[i][j], state[j]) );
// no matrix multiplication in the last round
if (r < nRoundsF + nRoundsP - 1) {
state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(M[t - 2][j][i], a)), F.zero)
);
} }
} }
for (let i=0; i<state.length; i++) state[i] = newState[i];
return F.normalize(state[0]);
} }
exports.createHash = (t, nRoundsF, nRoundsP, seed) => {
if (typeof seed === "undefined") seed = SEED;
if (typeof nRoundsF === "undefined") nRoundsF = NROUNDSF;
if (typeof nRoundsP === "undefined") nRoundsP = NROUNDSP;
if (typeof t === "undefined") t = T;
assert(nRoundsF % 2 == 0);
const C = exports.getConstants(t, seed, nRoundsF + nRoundsP);
const M = exports.getMatrix(t, seed, nRoundsF + nRoundsP);
return function(inputs) {
let state = [];
assert(inputs.length <= t);
assert(inputs.length > 0);
for (let i=0; i<inputs.length; i++) state[i] = F.e(inputs[i]);
for (let i=inputs.length; i<t; i++) state[i] = F.zero;
for (let i=0; i< nRoundsF + nRoundsP; i++) {
ark(state, C[i]);
if ((i<nRoundsF/2) || (i >= nRoundsF/2 + nRoundsP)) {
for (let j=0; j<t; j++) state[j] = sigma(state[j]);
} else {
state[0] = sigma(state[0]);
}
mix(state, M);
}
return F.normalize(state[0]);
};
};
module.exports = poseidon;

+ 3449
- 0
src/poseidon_constants.json
File diff suppressed because it is too large
View File


+ 32
- 26
src/poseidon_gencontract.js

@ -2,14 +2,13 @@
// License: LGPL-3.0+ // License: LGPL-3.0+
// //
const Poseidon = require("./poseidon.js");
const Contract = require("./evmasm"); const Contract = require("./evmasm");
const { unstringifyBigInts } = require("ffjavascript").utils;
const { C:K, M } = unstringifyBigInts(require("./poseidon_constants.json"));
const SEED = "poseidon";
const NROUNDSF = 8;
const NROUNDSP = 57;
const T = 6;
const N_ROUNDS_F = 8;
const N_ROUNDS_P = [56, 57, 56, 60, 60, 63, 64, 63];
function toHex256(a) { function toHex256(a) {
let S = a.toString(16); let S = a.toString(16);
@ -17,38 +16,38 @@ function toHex256(a) {
return "0x" + S; return "0x" + S;
} }
function createCode(t, nRoundsF, nRoundsP, seed) {
if (typeof seed === "undefined") seed = SEED;
if (typeof nRoundsF === "undefined") nRoundsF = NROUNDSF;
if (typeof nRoundsP === "undefined") nRoundsP = NROUNDSP;
if (typeof t === "undefined") t = T;
function createCode(nInputs) {
if (( nInputs<1) || (nInputs>8)) throw new Error("Invalid number of inputs. Must be 1<=nInputs<=8");
const t = nInputs + 1;
const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P[t - 2];
// const nRoundsF = 2;
// const nRoundsP = 2;
const K = Poseidon.getConstants(t, seed, nRoundsP + nRoundsF);
const M = Poseidon.getMatrix(t, seed, nRoundsP + nRoundsF);
const C = new Contract(); const C = new Contract();
function saveM() { function saveM() {
for (let i=0; i<t; i++) { for (let i=0; i<t; i++) {
for (let j=0; j<t; j++) { for (let j=0; j<t; j++) {
C.push(toHex256(M[i][j]));
C.push(toHex256(M[t-2][j][i]));
C.push((1+i*t+j)*32); C.push((1+i*t+j)*32);
C.mstore(); C.mstore();
} }
} }
} }
function ark(r) {
C.push(toHex256(K[r])); // K, st, q
function ark(r) { // st, q
for (let i=0; i<t; i++) { for (let i=0; i<t; i++) {
C.dup(1+t); // q, K, st, q
C.dup(1); // K, q, K, st, q
C.dup(3+i); // st[i], K, q, K, st, q
C.addmod(); // newSt[i], K, st, q
C.swap(2 + i); // xx, K, st, q
C.dup(t); // q, st, q
C.push(toHex256(K[t-2][r*t+i])); // K, q, st, q
C.dup(2+i); // st[i], K, q, st, q
C.addmod(); // newSt[i], st, q
C.swap(1 + i); // xx, st, q
C.pop(); C.pop();
} }
C.pop();
} }
function sigma(p) { function sigma(p) {
@ -115,17 +114,17 @@ function createCode(t, nRoundsF, nRoundsP, seed) {
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
// Load 6 values from the call data.
// Load t values from the call data.
// The function has a single array param param // The function has a single array param param
// [Selector (4)] [Pointer (32)][Length (32)] [data1 (32)] .... // [Selector (4)] [Pointer (32)][Length (32)] [data1 (32)] ....
// We ignore the pointer and the length and just load 6 values to the state
// (Stack positions 0-5) If the array is shorter, we just set zeros.
// We ignore the pointer and the length and just load t values to the state
// (Stack positions 0-{t-1}) If the array is shorter, we just set zeros.
for (let i=0; i<t; i++) { for (let i=0; i<t; i++) {
C.push(0x44+(0x20*(t-1-i))); C.push(0x44+(0x20*(t-1-i)));
C.calldataload(); C.calldataload();
} }
for (let i=0; i<nRoundsF+nRoundsP; i++) {
for (let i=0; i<nRoundsF+nRoundsP-1; i++) {
ark(i); ark(i);
if ((i<nRoundsF/2) || (i>=nRoundsP+nRoundsF/2)) { if ((i<nRoundsF/2) || (i>=nRoundsP+nRoundsF/2)) {
for (let j=0; j<t; j++) { for (let j=0; j<t; j++) {
@ -142,6 +141,13 @@ function createCode(t, nRoundsF, nRoundsP, seed) {
C.label(strLabel); C.label(strLabel);
} }
C.push(toHex256(K[t-2][(nRoundsF+nRoundsP-1)*t])); // K, st, q
C.dup(t+1); // q, K, st, q
C.swap(2); // st[0], K, q, st\st[0]
C.addmod(); // st q
sigma(0);
C.push("0x00"); C.push("0x00");
C.mstore(); // Save it to pos 0; C.mstore(); // Save it to pos 0;
C.push("0x20"); C.push("0x20");

+ 0
- 16
src/poseidon_printconstants.js

@ -1,16 +0,0 @@
const Poseidon = require("./poseidon.js");
const C = Poseidon.getConstants();
let S = "[\n";
for (let i=0; i<C.length; i++) {
S = S + " " + C[i].toString();
if (i<C.length-1) S = S + ",";
S = S + "\n";
}
S=S+ "]\n";
console.log(S);

+ 1
- 1
src/poseidon_printcontract.js

@ -1,5 +1,5 @@
const poseidonGenContract = require("./poseidon_gencontract"); const poseidonGenContract = require("./poseidon_gencontract");
console.log(poseidonGenContract.createCode(6, 8, 57));
console.log(poseidonGenContract.createCode(5));

+ 10
- 5
src/smt_hashes_poseidon.js

@ -1,13 +1,18 @@
const Poseidon = require("./poseidon");
const hash = Poseidon.createHash(6, 8, 57);
const ZqField = require("ffjavascript").ZqField;
const Scalar = require("ffjavascript").Scalar;
const poseidon = require("./poseidon");
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
exports.hash0 = function (left, right) { exports.hash0 = function (left, right) {
return hash([left, right]);
return poseidon([left, right]);
}; };
exports.hash1 = function(key, value) { exports.hash1 = function(key, value) {
return hash([key, value, Poseidon.F.one]);
return poseidon([key, value, F.one]);
}; };
exports.F = Poseidon.F;
exports.F = F;

+ 4
- 2
src/smt_memdb.js

@ -1,7 +1,9 @@
const F = require("./poseidon.js").F;
const Scalar = require("ffjavascript").Scalar; const Scalar = require("ffjavascript").Scalar;
const utils = require("ffjavascript").utils;
const ZqField = require("ffjavascript").ZqField;
// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
class SMTMemDb { class SMTMemDb {
constructor() { constructor() {

+ 1
- 1
test/circuits/poseidon3_test.circom

@ -1,3 +1,3 @@
include "../../circuits/poseidon.circom" include "../../circuits/poseidon.circom"
component main = Poseidon(2, 3, 8, 57);
component main = Poseidon(2);

+ 1
- 1
test/circuits/poseidon6_test.circom

@ -1,3 +1,3 @@
include "../../circuits/poseidon.circom" include "../../circuits/poseidon.circom"
component main = Poseidon(2, 6, 8, 57);
component main = Poseidon(5);

+ 2
- 2
test/eddsa_js.js

@ -67,12 +67,12 @@ describe("EdDSA js test", function () {
assert.equal(signature.R8[1].toString(), assert.equal(signature.R8[1].toString(),
"15383486972088797283337779941324724402501462225528836549661220478783371668959"); "15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(), assert.equal(signature.S.toString(),
"248298168863866362217836334079793350221620631973732197668910946177382043688");
"1398758333392199195742243841591064350253744445503462896781493968760929513778");
const pSignature = eddsa.packSignature(signature); const pSignature = eddsa.packSignature(signature);
assert.equal(pSignature.toString("hex"), ""+ assert.equal(pSignature.toString("hex"), ""+
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+ "dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00");
"32f16b0f2f4c4e1169aa59685637e1429b6581a9531d058d65f4ab224eab1703");
const uSignature = eddsa.unpackSignature(pSignature); const uSignature = eddsa.unpackSignature(pSignature);
assert(eddsa.verifyPoseidon(msg, uSignature, pubKey)); assert(eddsa.verifyPoseidon(msg, uSignature, pubKey));

+ 10
- 28
test/poseidoncircuit.js

@ -1,21 +1,11 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
var blake2b = require("blake2b");
const tester = require("circom").tester; const tester = require("circom").tester;
const poseidon = require("../src/poseidon.js"); const poseidon = require("../src/poseidon.js");
const assert = chai.assert; const assert = chai.assert;
describe("Blake2b version test", function() {
it("Should give the expected output for blake2b version", async () => {
var output = new Uint8Array(32);
var input = Buffer.from("poseidon_constants");
const h = blake2b(output.length).update(input).digest("hex");
assert.equal("e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1", h);
});
});
describe("Poseidon Circuit test", function () { describe("Poseidon Circuit test", function () {
let circuit6; let circuit6;
let circuit3; let circuit3;
@ -28,24 +18,20 @@ describe("Poseidon Circuit test", function () {
}); });
it("Should check constrain of hash([1, 2]) t=6", async () => { it("Should check constrain of hash([1, 2]) t=6", async () => {
const w = await circuit6.calculateWitness({inputs: [1, 2]}, true);
const hash = poseidon.createHash(6, 8, 57);
const w = await circuit6.calculateWitness({inputs: [1, 2, 0,0,0]}, true);
const res2 = hash([1,2]);
assert.equal("12242166908188651009877250812424843524687801523336557272219921456462821518061", res2.toString());
const res2 = poseidon([1,2,0,0,0]);
assert.equal("3975478831357328722254985704342968745327876719981393787143845259590563829094", res2.toString());
await circuit6.assertOut(w, {out : res2}); await circuit6.assertOut(w, {out : res2});
await circuit6.checkConstraints(w); await circuit6.checkConstraints(w);
}); });
it("Should check constrain of hash([3, 4]) t=6", async () => { it("Should check constrain of hash([3, 4]) t=6", async () => {
const w = await circuit6.calculateWitness({inputs: [3, 4]});
const w = await circuit6.calculateWitness({inputs: [3, 4,5,10,23]});
const hash = poseidon.createHash(6, 8, 57);
const res2 = poseidon([3, 4,5,10,23]);
const res2 = hash([3, 4]);
assert.equal("17185195740979599334254027721507328033796809509313949281114643312710535000993", res2.toString());
assert.equal("18540626624821144952552691894137986276337186174352554475896834101336254024067", res2.toString());
await circuit6.assertOut(w, {out : res2}); await circuit6.assertOut(w, {out : res2});
await circuit6.checkConstraints(w); await circuit6.checkConstraints(w);
}); });
@ -54,10 +40,8 @@ describe("Poseidon Circuit test", function () {
it("Should check constrain of hash([1, 2]) t=3", async () => { it("Should check constrain of hash([1, 2]) t=3", async () => {
const w = await circuit3.calculateWitness({inputs: [1, 2]}); const w = await circuit3.calculateWitness({inputs: [1, 2]});
const hash = poseidon.createHash(3, 8, 57);
const res2 = hash([1,2]);
assert.equal("2104035019328376391822106787753454168168617545136592089411833517434990977743", res2.toString());
const res2 = poseidon([1,2]);
assert.equal("17117985411748610629288516079940078114952304104811071254131751175361957805920", res2.toString());
await circuit3.assertOut(w, {out : res2}); await circuit3.assertOut(w, {out : res2});
await circuit3.checkConstraints(w); await circuit3.checkConstraints(w);
}); });
@ -65,10 +49,8 @@ describe("Poseidon Circuit test", function () {
it("Should check constrain of hash([3, 4]) t=3", async () => { it("Should check constrain of hash([3, 4]) t=3", async () => {
const w = await circuit3.calculateWitness({inputs: [3, 4]}); const w = await circuit3.calculateWitness({inputs: [3, 4]});
const hash = poseidon.createHash(3, 8, 57);
const res2 = hash([3, 4]);
assert.equal("12456141564250880945411182508630957604732712316993112736876413121277158512223", res2.toString());
const res2 = poseidon([3, 4]);
assert.equal("21867347236198497199818917118739170715216974132230970409806500217655788551452", res2.toString());
await circuit3.assertOut(w, {out : res2}); await circuit3.assertOut(w, {out : res2});
await circuit3.checkConstraints(w); await circuit3.checkConstraints(w);
}); });

+ 8
- 12
test/poseidoncontract.js

@ -2,7 +2,7 @@ const ganache = require("ganache-cli");
const Web3 = require("web3"); const Web3 = require("web3");
const chai = require("chai"); const chai = require("chai");
const poseidonGenContract = require("../src/poseidon_gencontract.js"); const poseidonGenContract = require("../src/poseidon_gencontract.js");
const Poseidon = require("../src/poseidon.js");
const poseidon = require("../src/poseidon.js");
const assert = chai.assert; const assert = chai.assert;
const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); }; const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); };
@ -24,28 +24,26 @@ describe("Poseidon Smart contract test", function () {
const C = new web3.eth.Contract(poseidonGenContract.abi); const C = new web3.eth.Contract(poseidonGenContract.abi);
poseidon6 = await C.deploy({ poseidon6 = await C.deploy({
data: poseidonGenContract.createCode(6)
data: poseidonGenContract.createCode(5)
}).send({ }).send({
gas: 2500000,
gas: 5000000,
from: accounts[0] from: accounts[0]
}); });
poseidon3 = await C.deploy({ poseidon3 = await C.deploy({
data: poseidonGenContract.createCode(3)
data: poseidonGenContract.createCode(2)
}).send({ }).send({
gas: 2500000,
gas: 5000000,
from: accounts[0] from: accounts[0]
}); });
}); });
it("Shold calculate the poseidon correctly t=6", async () => { it("Shold calculate the poseidon correctly t=6", async () => {
const res = await poseidon6.methods.poseidon([1,2]).call();
const res = await poseidon6.methods.poseidon([1,2, 0, 0, 0]).call();
// console.log("Cir: " + bigInt(res.toString(16)).toString(16)); // console.log("Cir: " + bigInt(res.toString(16)).toString(16));
const hash = Poseidon.createHash(6, 8, 57);
const res2 = hash([1,2]);
const res2 = poseidon([1,2, 0, 0, 0]);
// console.log("Ref: " + bigInt(res2).toString(16)); // console.log("Ref: " + bigInt(res2).toString(16));
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());
@ -56,9 +54,7 @@ describe("Poseidon Smart contract test", function () {
// console.log("Cir: " + bigInt(res.toString(16)).toString(16)); // console.log("Cir: " + bigInt(res.toString(16)).toString(16));
const hash = Poseidon.createHash(3, 8, 57);
const res2 = hash([1,2]);
const res2 = poseidon([1,2]);
// console.log("Ref: " + bigInt(res2).toString(16)); // console.log("Ref: " + bigInt(res2).toString(16));
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());

Loading…
Cancel
Save