49 Commits

Author SHA1 Message Date
arnaucube
de34085109 PR #19 https://github.com/iden3/circomlib/pull/19
Merge branch 'master' of https://github.com/iden3/circomlib
2020-12-25 12:49:07 +01:00
arnaucube
e9b5da742a add MiMC7 & Poseidon test vectors, add Poseidon multiHash & hashBuffer, add MiMC7 hashBuffer 2019-09-05 18:00:40 +02:00
Jordi Baylina
f9e0484663 0.0.15 2019-09-05 17:12:56 +02:00
Jordi Baylina
7bdb254f4f deps snarkjs 2019-09-05 17:12:47 +02:00
Jordi Baylina
024188b638 Support mutiply by point 0 in scalarmulany 2019-09-05 17:10:20 +02:00
Jordi Baylina
ebbeaebc73 Merge branch 'arnaucube-master' 2019-09-05 16:51:29 +02:00
Jordi Baylina
25f392c8ae sha256 with number of bits as a paramter 2019-09-05 16:41:58 +02:00
Jordi Baylina
52a1fb895d 0.0.14 2019-08-30 10:38:19 +02:00
Jordi Baylina
1621483d3b deps 2019-08-30 10:38:04 +02:00
arnaucube
ae362ec61b add tests for babyjub eddsa poseidon sign & verify 2019-08-29 17:44:44 +02:00
Jordi Baylina
425f50a9ed 0.0.13 2019-08-24 19:53:41 +02:00
Jordi Baylina
173c17dedc Change to a standard generator for Baby Jub 2019-08-03 12:46:21 +02:00
Jordi Baylina
23616427cd 0.0.12 2019-07-30 20:16:38 +02:00
Jordi Baylina
7c743659db Fix escalarfix 2019-07-30 20:16:06 +02:00
Jordi Baylina
f04a318800 0.0.11 2019-07-30 19:35:35 +02:00
Jordi Baylina
b15c7c8089 FIX: escalarmul fix 2019-07-30 19:35:19 +02:00
Jordi Baylina
9282ffe8c3 0.0.10 2019-07-08 17:43:05 +02:00
Jordi Baylina
d5f02256f9 Merge branch 'feature/jstests' 2019-07-08 17:41:24 +02:00
Jordi Baylina
88acd49c0b Merge branch 'master' into feature/jstests 2019-07-08 17:30:53 +02:00
Jordi Baylina
59f6e971cf Merge branch 'arnaucube-master' 2019-07-08 17:28:11 +02:00
Jordi Baylina
da1cceed85 Merge branch 'master' of https://github.com/arnaucube/circomlib into arnaucube-master 2019-07-08 17:19:42 +02:00
Jordi Baylina
61c9703fb2 0.0.9 2019-07-08 14:42:56 +02:00
Jordi Baylina
c84f6da970 Merge branch 'kobigurk-feature/mimcsponge' 2019-07-08 14:34:15 +02:00
Jordi Baylina
42ff01fb3b Some format and fixes from the last version 2019-07-08 14:33:37 +02:00
Jordi Baylina
861a75e0cb Merge branch 'feature/mimcsponge' of https://github.com/kobigurk/circomlib into kobigurk-feature/mimcsponge 2019-07-08 14:21:43 +02:00
Jordi Baylina
7cce66b4d8 Merge branch 'master' of github.com:iden3/circomlib 2019-07-08 14:08:13 +02:00
Jordi Baylina
a9227b7b58 Update web3 2019-07-08 14:08:04 +02:00
Jordi Baylina
f91ed9793c Merge pull request #15 from kobigurk/feature/expose_pedersen
Exposes Pedersen hashes
2019-07-08 13:09:00 +02:00
Kobi Gurkan
b0861bfe66 feat: exposes pedersen hash 2019-07-08 13:56:04 +03:00
Kobi Gurkan
1483abaa2f feat: makes mimcsponge contract act like the circuit version 2019-07-08 13:55:01 +03:00
Kobi Gurkan
324b8bf8cc fix: makes mimcsponge act like the paper description
* last constant is 0
* no swap at the last round
2019-07-08 13:54:46 +03:00
arnaucube
3bc864f110 update poseidon with blake2b 2019-06-28 10:50:49 +02:00
Kobi Gurkan
9e078dc299 fix: makes mimcsponge usable 2019-06-26 22:41:07 +03:00
Kobi Gurkan
17cb959364 Adds a sponge hash function based on MiMC2n-n 2019-06-26 22:41:07 +03:00
Jordi Baylina
d689f737d8 0.0.8 2019-06-04 17:55:28 +02:00
Jordi Baylina
154a9bcbae Merge branch 'master' of github.com:iden3/circomlib 2019-06-04 17:36:54 +02:00
Jordi Baylina
c4490b2ce9 Poseidon in SMT 2019-06-04 17:32:28 +02:00
Jordi Baylina
590d62a07c Poseidon 2019-06-04 13:40:15 +02:00
Eduard S
0aabe6447d Add babyjub and EdDSA js tests
Add tests with vectors for javascript implementation of babyjub and EdDSA.
2019-05-16 13:16:59 +02:00
Jordi Baylina
d91afa804a Merge pull request #5 from udibr/multiplexer
fixed Multiplexer name and usage of old syntax
2019-05-11 21:04:17 +02:00
Jordi Baylina
1da1f5886f Merge pull request #6 from udibr/circuits-readme
readme for circuits:
2019-05-11 21:00:43 +02:00
Jordi Baylina
fdce2a96e3 Merge pull request #7 from iden3/feature/babypbk
Add babyjub pvk->pbk circuit
2019-05-11 21:00:09 +02:00
Jordi Baylina
e7c4a979a0 Merge pull request #10 from kobigurk/fix_babyjubjub
fixes babyjubjub addition to use generic bigint interfaces
2019-05-11 20:45:27 +02:00
Jordi Baylina
efc77065e7 0.0.7 2019-05-08 19:09:28 +02:00
Kobi Gurkan
0503ec9de9 fixes babyjubjub addition to use generic bigint interfaces 2019-04-22 17:19:39 +03:00
adriamb
d9d6e43143 added pvk->pbk circuit 2019-03-17 10:38:36 +01:00
adriamb
8cb7b46603 fix missing deps 2019-03-17 10:36:14 +01:00
Ehud Ben-Reuven
39bb716785 fixed Multiplexer name and usage of old syntax 2019-02-23 20:16:06 -05:00
Ehud Ben-Reuven
b14eef4d90 readme for circuits: 2019-02-23 14:25:43 -05:00
87 changed files with 7144 additions and 7995 deletions

3
.gitignore vendored
View File

@@ -60,9 +60,6 @@ typings/
# next.js build output
.next
# Visual code configuration
.vscode
tmp
.DS_Store

View File

@@ -64,8 +64,8 @@ function generatePoint(S) {
const g = [
bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")];
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")];
// Sanity check
if (!babyJub.inCurve(g)) {

14
circuits/README.md Normal file
View File

@@ -0,0 +1,14 @@
* compconstant - Returns 1 if `in` (expanded to binary array) > `ct`
* aliascheck - check if `in` (expanded to binary array) oveflowed its 254 bits (<= -1)
* babyjub - twisted Edwards curve 168700.x^2 + y^2 = 1 + 168696.x^2.y^2
* BabyAdd - (`xout`,`yout`) = (`x1`,`y1`) + (`x2`,`y2`)
* BabyDbl - (`xout`,`yout`) = 2*(`x`,`y`)
* BabyCheck - check that (`x`,`y`) is on the curve
* binsub - binary subtraction
* gates - logical gates
* mimc - SNARK-friendly hash Minimal Multiplicative Complexity.
* https://eprint.iacr.org/2016/492.pdf
* zcash/zcash#2233
* smt - Sparse Merkle Tree
* https://ethresear.ch/t/optimizing-sparse-merkle-trees/3751
* montgomery https://en.wikipedia.org/wiki/Montgomery_curve

View File

@@ -17,6 +17,9 @@
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
include "bitify.circom";
include "escalarmulfix.circom";
template BabyAdd() {
signal input x1;
signal input y1;
@@ -77,3 +80,27 @@ template BabyCheck() {
a*x2 + y2 === 1 + d*x2*y2;
}
// Extracts the public key from private key
template BabyPbk() {
signal private input in;
signal output Ax;
signal output Ay;
var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component pvkBits = Num2Bits(253);
pvkBits.in <== in;
component mulFix = EscalarMulFix(253, BASE8);
var i;
for (i=0; i<253; i++) {
mulFix.e[i] <== pvkBits.out[i];
}
Ax <== mulFix.out[0];
Ay <== mulFix.out[1];
}

View File

@@ -55,7 +55,7 @@ template ForceEqualIfEnabled() {
(1 - isz.out)*enabled === 0;
}
/*
// N is the number of bits the input have.
// The MSF is the sign bit.
template LessThan(n) {
@@ -83,3 +83,57 @@ template LessThan(n) {
adder.out[n-1] ==> out;
}
*/
template LessThan(n) {
signal input in[2];
signal output out;
component n2b = Num2Bits(n*2+1);
n2b.in <== in[0]+ (1<<n) - in[1];
out <== 1-n2b.out[n];
}
// N is the number of bits the input have.
// The MSF is the sign bit.
template LessEqThan(n) {
signal input in[2];
signal output out;
component lt = LessThan(n);
lt.in[0] <== in[0];
lt.in[1] <== in[1]+1;
lt.out ==> out;
}
// N is the number of bits the input have.
// The MSF is the sign bit.
template GreaterThan(n) {
signal input in[2];
signal output out;
component lt = LessThan(n);
lt.in[0] <== in[1];
lt.in[1] <== in[0];
lt.out ==> out;
}
// N is the number of bits the input have.
// The MSF is the sign bit.
template GreaterEqThan(n) {
signal input in[2];
signal output out;
component lt = LessThan(n);
lt.in[0] <== in[1];
lt.in[1] <== in[0]+1;
lt.out ==> out;
}

View File

@@ -123,8 +123,8 @@ template EdDSAVerifier(n) {
// Calculate left side of equation left = S*B8
var BASE8 = [
17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(256, BASE8);
for (i=0; i<256; i++) {

View File

@@ -101,8 +101,8 @@ template EdDSAMiMCVerifier() {
// Calculate left side of equation left = S*B8
var BASE8 = [
17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<253; i++) {

View File

@@ -0,0 +1,123 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
include "compconstant.circom";
include "pointbits.circom";
include "mimcsponge.circom";
include "bitify.circom";
include "escalarmulany.circom";
include "escalarmulfix.circom";
template EdDSAMiMCSpongeVerifier() {
signal input enabled;
signal input Ax;
signal input Ay;
signal input S;
signal input R8x;
signal input R8y;
signal input M;
var i;
// Ensure S<Subgroup Order
component snum2bits = Num2Bits(253);
snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
for (i=0; i<253; i++) {
snum2bits.out[i] ==> compConstant.in[i];
}
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg)
component hash = MiMCSponge(5, 220, 1);
hash.ins[0] <== R8x;
hash.ins[1] <== R8y;
hash.ins[2] <== Ax;
hash.ins[3] <== Ay;
hash.ins[4] <== M;
hash.k <== 0;
component h2bits = Num2Bits_strict();
h2bits.in <== hash.outs[0];
// Calculate second part of the right side: right2 = h*8*A
// Multiply by 8 by adding it 3 times. This also ensure that the result is in
// the subgroup.
component dbl1 = BabyDbl();
dbl1.x <== Ax;
dbl1.y <== Ay;
component dbl2 = BabyDbl();
dbl2.x <== dbl1.xout;
dbl2.y <== dbl1.yout;
component dbl3 = BabyDbl();
dbl3.x <== dbl2.xout;
dbl3.y <== dbl2.yout;
// We check that A is not zero.
component isZero = IsZero();
isZero.in <== dbl3.x;
isZero.out === 0;
component mulAny = EscalarMulAny(254);
for (i=0; i<254; i++) {
mulAny.e[i] <== h2bits.out[i];
}
mulAny.p[0] <== dbl3.xout;
mulAny.p[1] <== dbl3.yout;
// Compute the right side: right = R8 + right2
component addRight = BabyAdd();
addRight.x1 <== R8x;
addRight.y1 <== R8y;
addRight.x2 <== mulAny.out[0];
addRight.y2 <== mulAny.out[1];
// Calculate left side of equation left = S*B8
var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<253; i++) {
mulFix.e[i] <== snum2bits.out[i];
}
// Do the comparation left == right if enabled;
component eqCheckX = ForceEqualIfEnabled();
eqCheckX.enabled <== enabled;
eqCheckX.in[0] <== mulFix.out[0];
eqCheckX.in[1] <== addRight.xout;
component eqCheckY = ForceEqualIfEnabled();
eqCheckY.enabled <== enabled;
eqCheckY.in[0] <== mulFix.out[1];
eqCheckY.in[1] <== addRight.yout;
}

View File

@@ -0,0 +1,122 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
include "compconstant.circom";
include "poseidon.circom";
include "bitify.circom";
include "escalarmulany.circom";
include "escalarmulfix.circom";
template EdDSAPoseidonVerifier() {
signal input enabled;
signal input Ax;
signal input Ay;
signal input S;
signal input R8x;
signal input R8y;
signal input M;
var i;
// Ensure S<Subgroup Order
component snum2bits = Num2Bits(253);
snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
for (i=0; i<253; i++) {
snum2bits.out[i] ==> compConstant.in[i];
}
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg)
component hash = Poseidon(5, 6, 8, 57);
hash.inputs[0] <== R8x;
hash.inputs[1] <== R8y;
hash.inputs[2] <== Ax;
hash.inputs[3] <== Ay;
hash.inputs[4] <== M;
component h2bits = Num2Bits_strict();
h2bits.in <== hash.out;
// Calculate second part of the right side: right2 = h*8*A
// Multiply by 8 by adding it 3 times. This also ensure that the result is in
// the subgroup.
component dbl1 = BabyDbl();
dbl1.x <== Ax;
dbl1.y <== Ay;
component dbl2 = BabyDbl();
dbl2.x <== dbl1.xout;
dbl2.y <== dbl1.yout;
component dbl3 = BabyDbl();
dbl3.x <== dbl2.xout;
dbl3.y <== dbl2.yout;
// We check that A is not zero.
component isZero = IsZero();
isZero.in <== dbl3.x;
isZero.out === 0;
component mulAny = EscalarMulAny(254);
for (i=0; i<254; i++) {
mulAny.e[i] <== h2bits.out[i];
}
mulAny.p[0] <== dbl3.xout;
mulAny.p[1] <== dbl3.yout;
// Compute the right side: right = R8 + right2
component addRight = BabyAdd();
addRight.x1 <== R8x;
addRight.y1 <== R8y;
addRight.x2 <== mulAny.out[0];
addRight.y2 <== mulAny.out[1];
// Calculate left side of equation left = S*B8
var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<253; i++) {
mulFix.e[i] <== snum2bits.out[i];
}
// Do the comparation left == right if enabled;
component eqCheckX = ForceEqualIfEnabled();
eqCheckX.enabled <== enabled;
eqCheckX.in[0] <== mulFix.out[0];
eqCheckX.in[1] <== addRight.xout;
component eqCheckY = ForceEqualIfEnabled();
eqCheckY.enabled <== enabled;
eqCheckY.in[0] <== mulFix.out[1];
eqCheckY.in[1] <== addRight.yout;
}

View File

@@ -19,6 +19,7 @@
include "montgomery.circom";
include "babyjub.circom";
include "comparators.circom";
template Multiplexor2() {
signal input sel;
@@ -138,6 +139,8 @@ template EscalarMulAny(n) {
component doublers[nsegments-1];
component m2e[nsegments-1];
component adders[nsegments-1];
component zeropoint = IsZero();
zeropoint.in <== p[0];
var s;
var i;
@@ -154,8 +157,9 @@ template EscalarMulAny(n) {
}
if (s==0) {
p[0] ==> segments[s].p[0];
p[1] ==> segments[s].p[1];
// force G8 point if input point is zero
segments[s].p[0] <== p[0] + (5299619240641551281634865583518297030282874472190772894086521144482721001553 - p[0])*zeropoint.out;
segments[s].p[1] <== p[1] + (16950150798460657717958625567821834550301663161624707787222815936182638968203 - p[1])*zeropoint.out;
} else {
doublers[s-1] = MontgomeryDouble();
m2e[s-1] = Montgomery2Edwards();
@@ -183,10 +187,10 @@ template EscalarMulAny(n) {
}
if (nsegments == 1) {
segments[0].out[0] ==> out[0];
segments[0].out[1] ==> out[1];
segments[0].out[0]*(1-zeropoint.out) ==> out[0];
segments[0].out[1]+(1-segments[0].out[1])*zeropoint.out ==> out[1];
} else {
adders[nsegments-2].xout ==> out[0];
adders[nsegments-2].yout ==> out[1];
adders[nsegments-2].xout*(1-zeropoint.out) ==> out[0];
adders[nsegments-2].yout+(1-adders[nsegments-2].yout)*zeropoint.out ==> out[1];
}
}

View File

@@ -28,6 +28,22 @@ include "babyjub.circom";
The result should be compensated.
*/
/*
The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
And Finaly we compute the result: RES = SQ - Q
As you can see the input of the adders cannot be equal nor zero, except for the last
substraction that it's done in montgomery.
A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
is the output of the windows that it's going to be <= 2^246*B
*/
template WindowMulFix() {
signal input in[3];
signal input base[2];
@@ -140,54 +156,60 @@ template SegmentMulFix(nWindows) {
e2m.in[1] <== base[1];
component windows[nWindows];
component adders[nWindows-1];
component cadders[nWindows-1];
component adders[nWindows];
component cadders[nWindows];
// In the last step we add an extra doubler so that numbers do not match.
component dblLast = MontgomeryDouble();
for (i=0; i<nWindows; i++) {
windows[i] = WindowMulFix();
cadders[i] = MontgomeryAdd();
if (i==0) {
windows[i].base[0] <== e2m.out[0];
windows[i].base[1] <== e2m.out[1];
cadders[i].in1[0] <== e2m.out[0];
cadders[i].in1[1] <== e2m.out[1];
} else {
windows[i].base[0] <== windows[i-1].out8[0];
windows[i].base[1] <== windows[i-1].out8[1];
adders[i-1] = MontgomeryAdd();
cadders[i-1] = MontgomeryAdd();
if (i==1) {
adders[i-1].in1[0] <== windows[0].out[0];
adders[i-1].in1[1] <== windows[0].out[1];
cadders[i-1].in1[0] <== e2m.out[0];
cadders[i-1].in1[1] <== e2m.out[1];
} else {
adders[i-1].in1[0] <== adders[i-2].out[0];
adders[i-1].in1[1] <== adders[i-2].out[1];
cadders[i-1].in1[0] <== cadders[i-2].out[0];
cadders[i-1].in1[1] <== cadders[i-2].out[1];
}
adders[i-1].in2[0] <== windows[i].out[0];
adders[i-1].in2[1] <== windows[i].out[1];
cadders[i-1].in2[0] <== windows[i-1].out8[0];
cadders[i-1].in2[1] <== windows[i-1].out8[1];
cadders[i].in1[0] <== cadders[i-1].out[0];
cadders[i].in1[1] <== cadders[i-1].out[1];
}
if (i<nWindows-1) {
cadders[i].in2[0] <== windows[i].out8[0];
cadders[i].in2[1] <== windows[i].out8[1];
} else {
dblLast.in[0] <== windows[i].out8[0];
dblLast.in[1] <== windows[i].out8[1];
cadders[i].in2[0] <== dblLast.out[0];
cadders[i].in2[1] <== dblLast.out[1];
}
for (j=0; j<3; j++) {
windows[i].in[j] <== e[3*i+j];
}
}
for (i=0; i<nWindows; i++) {
adders[i] = MontgomeryAdd();
if (i==0) {
adders[i].in1[0] <== dblLast.out[0];
adders[i].in1[1] <== dblLast.out[1];
} else {
adders[i].in1[0] <== adders[i-1].out[0];
adders[i].in1[1] <== adders[i-1].out[1];
}
adders[i].in2[0] <== windows[i].out[0];
adders[i].in2[1] <== windows[i].out[1];
}
component m2e = Montgomery2Edwards();
component cm2e = Montgomery2Edwards();
if (nWindows > 1) {
m2e.in[0] <== adders[nWindows-2].out[0];
m2e.in[1] <== adders[nWindows-2].out[1];
cm2e.in[0] <== cadders[nWindows-2].out[0];
cm2e.in[1] <== cadders[nWindows-2].out[1];
} else {
m2e.in[0] <== windows[0].out[0];
m2e.in[1] <== windows[0].out[1];
cm2e.in[0] <== e2m.out[0];
cm2e.in[1] <== e2m.out[1];
}
m2e.in[0] <== adders[nWindows-1].out[0];
m2e.in[1] <== adders[nWindows-1].out[1];
cm2e.in[0] <== cadders[nWindows-1].out[0];
cm2e.in[1] <== cadders[nWindows-1].out[1];
component cAdd = BabyAdd();
cAdd.x1 <== m2e.out[0];
@@ -195,7 +217,6 @@ template SegmentMulFix(nWindows) {
cAdd.x2 <== -cm2e.out[0];
cAdd.y2 <== cm2e.out[1];
cAdd.xout ==> out[0];
cAdd.yout ==> out[1];
@@ -214,7 +235,7 @@ template EscalarMulFix(n, BASE) {
signal input e[n]; // Input in binary format
signal output out[2]; // Point (Twisted format)
var nsegments = (n-1)\249 +1;
var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
var nlastsegment = n - (nsegments-1)*249;
component segments[nsegments];
@@ -225,7 +246,7 @@ template EscalarMulFix(n, BASE) {
var s;
var i;
var nseg;
var nWindows
var nWindows;
for (s=0; s<nsegments; s++) {

283
circuits/mimcsponge.circom Normal file
View File

@@ -0,0 +1,283 @@
// implements MiMC-2n/n as hash using a sponge construction.
// log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110
// => nRounds should be 220
template MiMCSponge(nInputs, nRounds, nOutputs) {
signal input ins[nInputs];
signal input k;
signal output outs[nOutputs];
// S = R||C
component S[nInputs + nOutputs - 1];
for (var i = 0; i < nInputs; i++) {
S[i] = MiMCFeistel(nRounds);
S[i].k <== k;
if (i == 0) {
S[i].xL_in <== ins[0];
S[i].xR_in <== 0;
} else {
S[i].xL_in <== S[i-1].xL_out + ins[i];
S[i].xR_in <== S[i-1].xR_out;
}
}
outs[0] = S[nInputs - 1].xL_out;
for (var i = 0; i < nOutputs - 1; i++) {
S[nInputs + i] = MiMCFeistel(nRounds);
S[nInputs + i].k <== k;
S[nInputs + i].xL_in <== S[nInputs + i - 1].xL_out;
S[nInputs + i].xR_in <== S[nInputs + i - 1].xR_out;
outs[i + 1] <== S[nInputs + i].xL_out;
}
}
template MiMCFeistel(nrounds) {
signal input xL_in;
signal input xR_in;
signal input k;
signal output xL_out;
signal output xR_out;
var c = [
0,
7120861356467848435263064379192047478074060781135320967663101236819528304084,
5024705281721889198577876690145313457398658950011302225525409148828000436681,
17980351014018068290387269214713820287804403312720763401943303895585469787384,
19886576439381707240399940949310933992335779767309383709787331470398675714258,
1213715278223786725806155661738676903520350859678319590331207960381534602599,
18162138253399958831050545255414688239130588254891200470934232514682584734511,
7667462281466170157858259197976388676420847047604921256361474169980037581876,
7207551498477838452286210989212982851118089401128156132319807392460388436957,
9864183311657946807255900203841777810810224615118629957816193727554621093838,
4798196928559910300796064665904583125427459076060519468052008159779219347957,
17387238494588145257484818061490088963673275521250153686214197573695921400950,
10005334761930299057035055370088813230849810566234116771751925093634136574742,
11897542014760736209670863723231849628230383119798486487899539017466261308762,
16771780563523793011283273687253985566177232886900511371656074413362142152543,
749264854018824809464168489785113337925400687349357088413132714480582918506,
3683645737503705042628598550438395339383572464204988015434959428676652575331,
7556750851783822914673316211129907782679509728346361368978891584375551186255,
20391289379084797414557439284689954098721219201171527383291525676334308303023,
18146517657445423462330854383025300323335289319277199154920964274562014376193,
8080173465267536232534446836148661251987053305394647905212781979099916615292,
10796443006899450245502071131975731672911747129805343722228413358507805531141,
5404287610364961067658660283245291234008692303120470305032076412056764726509,
4623894483395123520243967718315330178025957095502546813929290333264120223168,
16845753148201777192406958674202574751725237939980634861948953189320362207797,
4622170486584704769521001011395820886029808520586507873417553166762370293671,
16688277490485052681847773549197928630624828392248424077804829676011512392564,
11878652861183667748838188993669912629573713271883125458838494308957689090959,
2436445725746972287496138382764643208791713986676129260589667864467010129482,
1888098689545151571063267806606510032698677328923740058080630641742325067877,
148924106504065664829055598316821983869409581623245780505601526786791681102,
18875020877782404439294079398043479420415331640996249745272087358069018086569,
15189693413320228845990326214136820307649565437237093707846682797649429515840,
19669450123472657781282985229369348220906547335081730205028099210442632534079,
5521922218264623411380547905210139511350706092570900075727555783240701821773,
4144769320246558352780591737261172907511489963810975650573703217887429086546,
10097732913112662248360143041019433907849917041759137293018029019134392559350,
1720059427972723034107765345743336447947522473310069975142483982753181038321,
6302388219880227251325608388535181451187131054211388356563634768253301290116,
6745410632962119604799318394592010194450845483518862700079921360015766217097,
10858157235265583624235850660462324469799552996870780238992046963007491306222,
20241898894740093733047052816576694435372877719072347814065227797906130857593,
10165780782761211520836029617746977303303335603838343292431760011576528327409,
2832093654883670345969792724123161241696170611611744759675180839473215203706,
153011722355526826233082383360057587249818749719433916258246100068258954737,
20196970640587451358539129330170636295243141659030208529338914906436009086943,
3180973917010545328313139835982464870638521890385603025657430208141494469656,
17198004293191777441573635123110935015228014028618868252989374962722329283022,
7642160509228669138628515458941659189680509753651629476399516332224325757132,
19346204940546791021518535594447257347218878114049998691060016493806845179755,
11501810868606870391127866188394535330696206817602260610801897042898616817272,
3113973447392053821824427670386252797811804954746053461397972968381571297505,
6545064306297957002139416752334741502722251869537551068239642131448768236585,
5203908808704813498389265425172875593837960384349653691918590736979872578408,
2246692432011290582160062129070762007374502637007107318105405626910313810224,
11760570435432189127645691249600821064883781677693087773459065574359292849137,
5543749482491340532547407723464609328207990784853381797689466144924198391839,
8837549193990558762776520822018694066937602576881497343584903902880277769302,
12855514863299373699594410385788943772765811961581749194183533625311486462501,
5363660674689121676875069134269386492382220935599781121306637800261912519729,
13162342403579303950549728848130828093497701266240457479693991108217307949435,
916941639326869583414469202910306428966657806899788970948781207501251816730,
15618589556584434434009868216186115416835494805174158488636000580759692174228,
8959562060028569701043973060670353733575345393653685776974948916988033453971,
16390754464333401712265575949874369157699293840516802426621216808905079127650,
168282396747788514908709091757591226095443902501365500003618183905496160435,
8327443473179334761744301768309008451162322941906921742120510244986704677004,
17213012626801210615058753489149961717422101711567228037597150941152495100640,
10394369641533736715250242399198097296122982486516256408681925424076248952280,
17784386835392322654196171115293700800825771210400152504776806618892170162248,
16533189939837087893364000390641148516479148564190420358849587959161226782982,
18725396114211370207078434315900726338547621160475533496863298091023511945076,
7132325028834551397904855671244375895110341505383911719294705267624034122405,
148317947440800089795933930720822493695520852448386394775371401743494965187,
19001050671757720352890779127693793630251266879994702723636759889378387053056,
18824274411769830274877839365728651108434404855803844568234862945613766611460,
12771414330193951156383998390424063470766226667986423961689712557338777174205,
11332046574800279729678603488745295198038913503395629790213378101166488244657,
9607550223176946388146938069307456967842408600269548190739947540821716354749,
8756385288462344550200229174435953103162307705310807828651304665320046782583,
176061952957067086877570020242717222844908281373122372938833890096257042779,
12200212977482648306758992405065921724409841940671166017620928947866825250857,
10868453624107875516866146499877130701929063632959660262366632833504750028858,
2016095394399807253596787752134573207202567875457560571095586743878953450738,
21815578223768330433802113452339488275704145896544481092014911825656390567514,
4923772847693564777744725640710197015181591950368494148029046443433103381621,
1813584943682214789802230765734821149202472893379265320098816901270224589984,
10810123816265612772922113403831964815724109728287572256602010709288980656498,
1153669123397255702524721206511185557982017410156956216465120456256288427021,
5007518659266430200134478928344522649876467369278722765097865662497773767152,
2511432546938591792036639990606464315121646668029252285288323664350666551637,
32883284540320451295484135704808083452381176816565850047310272290579727564,
10484856914279112612610993418405543310546746652738541161791501150994088679557,
2026733759645519472558796412979210009170379159866522399881566309631434814953,
14731806221235869882801331463708736361296174006732553130708107037190460654379,
14740327483193277147065845135561988641238516852487657117813536909482068950652,
18787428285295558781869865751953016580493190547148386433580291216673009884554,
3804047064713122820157099453648459188816376755739202017447862327783289895072,
16709604795697901641948603019242067672006293290826991671766611326262532802914,
11061717085931490100602849654034280576915102867237101935487893025907907250695,
2821730726367472966906149684046356272806484545281639696873240305052362149654,
17467794879902895769410571945152708684493991588672014763135370927880883292655,
1571520786233540988201616650622796363168031165456869481368085474420849243232,
10041051776251223165849354194892664881051125330236567356945669006147134614302,
3981753758468103976812813304477670033098707002886030847251581853700311567551,
4365864398105436789177703571412645548020537580493599380018290523813331678900,
2391801327305361293476178683853802679507598622000359948432171562543560193350,
214219368547551689972421167733597094823289857206402800635962137077096090722,
18192064100315141084242006659317257023098826945893371479835220462302399655674,
15487549757142039139328911515400805508248576685795694919457041092150651939253,
10142447197759703415402259672441315777933858467700579946665223821199077641122,
11246573086260753259993971254725613211193686683988426513880826148090811891866,
6574066859860991369704567902211886840188702386542112593710271426704432301235,
11311085442652291634822798307831431035776248927202286895207125867542470350078,
20977948360215259915441258687649465618185769343138135384346964466965010873779,
792781492853909872425531014397300057232399608769451037135936617996830018501,
5027602491523497423798779154966735896562099398367163998686335127580757861872,
14595204575654316237672764823862241845410365278802914304953002937313300553572,
13973538843621261113924259058427434053808430378163734641175100160836376897004,
16395063164993626722686882727042150241125309409717445381854913964674649318585,
8465768840047024550750516678171433288207841931251654898809033371655109266663,
21345603324471810861925019445720576814602636473739003852898308205213912255830,
21171984405852590343970239018692870799717057961108910523876770029017785940991,
10761027113757988230637066281488532903174559953630210849190212601991063767647,
6678298831065390834922566306988418588227382406175769592902974103663687992230,
4993662582188632374202316265508850988596880036291765531885657575099537176757,
18364168158495573675698600238443218434246806358811328083953887470513967121206,
3506345610354615013737144848471391553141006285964325596214723571988011984829,
248732676202643792226973868626360612151424823368345645514532870586234380100,
10090204501612803176317709245679152331057882187411777688746797044706063410969,
21297149835078365363970699581821844234354988617890041296044775371855432973500,
16729368143229828574342820060716366330476985824952922184463387490091156065099,
4467191506765339364971058668792642195242197133011672559453028147641428433293,
8677548159358013363291014307402600830078662555833653517843708051504582990832,
1022951765127126818581466247360193856197472064872288389992480993218645055345,
1888195070251580606973417065636430294417895423429240431595054184472931224452,
4221265384902749246920810956363310125115516771964522748896154428740238579824,
2825393571154632139467378429077438870179957021959813965940638905853993971879,
19171031072692942278056619599721228021635671304612437350119663236604712493093,
10780807212297131186617505517708903709488273075252405602261683478333331220733,
18230936781133176044598070768084230333433368654744509969087239465125979720995,
16901065971871379877929280081392692752968612240624985552337779093292740763381,
146494141603558321291767829522948454429758543710648402457451799015963102253,
2492729278659146790410698334997955258248120870028541691998279257260289595548,
2204224910006646535594933495262085193210692406133533679934843341237521233504,
16062117410185840274616925297332331018523844434907012275592638570193234893570,
5894928453677122829055071981254202951712129328678534592916926069506935491729,
4947482739415078212217504789923078546034438919537985740403824517728200332286,
16143265650645676880461646123844627780378251900510645261875867423498913438066,
397690828254561723549349897112473766901585444153303054845160673059519614409,
11272653598912269895509621181205395118899451234151664604248382803490621227687,
15566927854306879444693061574322104423426072650522411176731130806720753591030,
14222898219492484180162096141564251903058269177856173968147960855133048449557,
16690275395485630428127725067513114066329712673106153451801968992299636791385,
3667030990325966886479548860429670833692690972701471494757671819017808678584,
21280039024501430842616328642522421302481259067470872421086939673482530783142,
15895485136902450169492923978042129726601461603404514670348703312850236146328,
7733050956302327984762132317027414325566202380840692458138724610131603812560,
438123800976401478772659663183448617575635636575786782566035096946820525816,
814913922521637742587885320797606426167962526342166512693085292151314976633,
12368712287081330853637674140264759478736012797026621876924395982504369598764,
2494806857395134874309386694756263421445039103814920780777601708371037591569,
16101132301514338989512946061786320637179843435886825102406248183507106312877,
6252650284989960032925831409804233477770646333900692286731621844532438095656,
9277135875276787021836189566799935097400042171346561246305113339462708861695,
10493603554686607050979497281838644324893776154179810893893660722522945589063,
8673089750662709235894359384294076697329948991010184356091130382437645649279,
9558393272910366944245875920138649617479779893610128634419086981339060613250,
19012287860122586147374214541764572282814469237161122489573881644994964647218,
9783723818270121678386992630754842961728702994964214799008457449989291229500,
15550788416669474113213749561488122552422887538676036667630838378023479382689,
15016165746156232864069722572047169071786333815661109750860165034341572904221,
6506225705710197163670556961299945987488979904603689017479840649664564978574,
10796631184889302076168355684722130903785890709107732067446714470783437829037,
19871836214837460419845806980869387567383718044439891735114283113359312279540,
20871081766843466343749609089986071784031203517506781251203251608363835140622,
5100105771517691442278432864090229416166996183792075307747582375962855820797,
8777887112076272395250620301071581171386440850451972412060638225741125310886,
5300440870136391278944213332144327695659161151625757537632832724102670898756,
1205448543652932944633962232545707633928124666868453915721030884663332604536,
5542499997310181530432302492142574333860449305424174466698068685590909336771,
11028094245762332275225364962905938096659249161369092798505554939952525894293,
19187314764836593118404597958543112407224947638377479622725713735224279297009,
17047263688548829001253658727764731047114098556534482052135734487985276987385,
19914849528178967155534624144358541535306360577227460456855821557421213606310,
2929658084700714257515872921366736697080475676508114973627124569375444665664,
15092262360719700162343163278648422751610766427236295023221516498310468956361,
21578580340755653236050830649990190843552802306886938815497471545814130084980,
1258781501221760320019859066036073675029057285507345332959539295621677296991,
3819598418157732134449049289585680301176983019643974929528867686268702720163,
8653175945487997845203439345797943132543211416447757110963967501177317426221,
6614652990340435611114076169697104582524566019034036680161902142028967568142,
19212515502973904821995111796203064175854996071497099383090983975618035391558,
18664315914479294273286016871365663486061896605232511201418576829062292269769,
11498264615058604317482574216318586415670903094838791165247179252175768794889,
10814026414212439999107945133852431304483604215416531759535467355316227331774,
17566185590731088197064706533119299946752127014428399631467913813769853431107,
14016139747289624978792446847000951708158212463304817001882956166752906714332,
8242601581342441750402731523736202888792436665415852106196418942315563860366,
9244680976345080074252591214216060854998619670381671198295645618515047080988,
12216779172735125538689875667307129262237123728082657485828359100719208190116,
10702811721859145441471328511968332847175733707711670171718794132331147396634,
6479667912792222539919362076122453947926362746906450079329453150607427372979,
15117544653571553820496948522381772148324367479772362833334593000535648316185,
6842203153996907264167856337497139692895299874139131328642472698663046726780,
12732823292801537626009139514048596316076834307941224506504666470961250728055,
6936272626871035740815028148058841877090860312517423346335878088297448888663,
17297554111853491139852678417579991271009602631577069694853813331124433680030,
16641596134749940573104316021365063031319260205559553673368334842484345864859,
7400481189785154329569470986896455371037813715804007747228648863919991399081,
2273205422216987330510475127669563545720586464429614439716564154166712854048,
15162538063742142685306302282127534305212832649282186184583465569986719234456,
5628039096440332922248578319648483863204530861778160259559031331287721255522,
16085392195894691829567913404182676871326863890140775376809129785155092531260,
14227467863135365427954093998621993651369686288941275436795622973781503444257,
18224457394066545825553407391290108485121649197258948320896164404518684305122,
274945154732293792784580363548970818611304339008964723447672490026510689427,
11050822248291117548220126630860474473945266276626263036056336623671308219529,
2119542016932434047340813757208803962484943912710204325088879681995922344971,
0
];
var t;
signal t2[nrounds];
signal t4[nrounds];
signal xL[nrounds-1];
signal xR[nrounds-1];
for (var i=0; i<nrounds; i++) {
t = (i==0) ? k+xL_in : k + xL[i-1] + c[i];
t2[i] <== t*t;
t4[i] <== t2[i]*t2[i];
if (i<nrounds-1) {
xL[i] <== ((i==0) ? xR_in : xR[i-1]) + t4[i]*t;
xR[i] = (i==0) ? xL_in : xL[i-1];
} else {
xR_out <== xR[i-1] + t4[i]*t;
xL_out <== xL[i-1];
}
}
}

View File

@@ -90,12 +90,17 @@ template Decoder(w) {
}
template Multiplexor(wIn, nIn) {
template Multiplexer(wIn, nIn) {
signal input inp[nIn][wIn];
signal input sel;
signal output out[wIn];
component Decoder(nIn) dec;
component EscalarProduct(nIn) ep[wIn];
component dec = Decoder(nIn);
component ep[wIn];
for (var k=0; k<wIn; k++) {
ep[k] = EscalarProduct(nIn);
}
sel ==> dec.inp;
for (var j=0; j<wIn; j++) {
for (var k=0; k<nIn; k++) {
@@ -106,7 +111,3 @@ template Multiplexor(wIn, nIn) {
}
dec.success === 1;
}
component Multiplexor(8,3) main;

47
circuits/mux1.circom Normal file
View File

@@ -0,0 +1,47 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
template MultiMux1(n) {
signal input c[n][2]; // Constants
signal input s; // Selector
signal output out[n];
for (var i=0; i<n; i++) {
out[i] <== (c[i][1] - c[i][0])*s + c[i][0];
}
}
template Mux1() {
var i;
signal input c[2]; // Constants
signal input s; // Selector
signal output out;
component mux = MultiMux1(1);
for (i=0; i<2; i++) {
mux.c[0][i] <== c[i];
}
s ==> mux.s;
mux.out[0] ==> out;
}

62
circuits/mux2.circom Normal file
View File

@@ -0,0 +1,62 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
template MultiMux2(n) {
signal input c[n][4]; // Constants
signal input s[2]; // Selector
signal output out[n];
signal a10[n];
signal a1[n];
signal a0[n];
signal a[n];
signal s10;
s10 <== s[1] * s[0];
for (var i=0; i<n; i++) {
a10[i] <== ( c[i][ 3]-c[i][ 2]-c[i][ 1]+c[i][ 0] ) * s10;
a1[i] <== ( c[i][ 2]-c[i][ 0] ) * s[1];
a0[i] <== ( c[i][ 1]-c[i][ 0] ) * s[0];
a[i] <== ( c[i][ 0] )
out[i] <== ( a10[i] + a1[i] + a0[i] + a[i] );
}
}
template Mux2() {
var i;
signal input c[4]; // Constants
signal input s[2]; // Selector
signal output out;
component mux = MultiMux2(1);
for (i=0; i<4; i++) {
mux.c[0][i] <== c[i];
}
for (i=0; i<2; i++) {
s[i] ==> mux.s[i];
}
mux.out[0] ==> out;
}

203
circuits/poseidon.circom Normal file
View File

@@ -0,0 +1,203 @@
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) {
signal input in[t];
signal output out[t];
for (var i=0; i<t; i++) {
out[i] <== in[i] + C;
}
}
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 = lc + M[i][j]*in[j];
}
out[i] <== lc;
}
}
// var nRoundsF = 8;
// var nRoundsP = 57;
// var t = 6;
template Poseidon(nInputs, t, nRoundsF, nRoundsP) {
var C = [
14397397413755236225575615486459253198602422701513067526754101844196324375522,
10405129301473404666785234951972711717481302463898292859783056520670200613128,
5179144822360023508491245509308555580251733042407187134628755730783052214509,
9132640374240188374542843306219594180154739721841249568925550236430986592615,
20360807315276763881209958738450444293273549928693737723235350358403012458514,
17933600965499023212689924809448543050840131883187652471064418452962948061619,
3636213416533737411392076250708419981662897009810345015164671602334517041153,
2008540005368330234524962342006691994500273283000229509835662097352946198608,
16018407964853379535338740313053768402596521780991140819786560130595652651567,
20653139667070586705378398435856186172195806027708437373983929336015162186471,
17887713874711369695406927657694993484804203950786446055999405564652412116765,
4852706232225925756777361208698488277369799648067343227630786518486608711772,
8969172011633935669771678412400911310465619639756845342775631896478908389850,
20570199545627577691240476121888846460936245025392381957866134167601058684375,
16442329894745639881165035015179028112772410105963688121820543219662832524136,
20060625627350485876280451423010593928172611031611836167979515653463693899374,
16637282689940520290130302519163090147511023430395200895953984829546679599107,
15599196921909732993082127725908821049411366914683565306060493533569088698214,
16894591341213863947423904025624185991098788054337051624251730868231322135455,
1197934381747032348421303489683932612752526046745577259575778515005162320212,
6172482022646932735745595886795230725225293469762393889050804649558459236626,
21004037394166516054140386756510609698837211370585899203851827276330669555417,
15262034989144652068456967541137853724140836132717012646544737680069032573006,
15017690682054366744270630371095785995296470601172793770224691982518041139766,
15159744167842240513848638419303545693472533086570469712794583342699782519832,
11178069035565459212220861899558526502477231302924961773582350246646450941231,
21154888769130549957415912997229564077486639529994598560737238811887296922114,
20162517328110570500010831422938033120419484532231241180224283481905744633719,
2777362604871784250419758188173029886707024739806641263170345377816177052018,
15732290486829619144634131656503993123618032247178179298922551820261215487562,
6024433414579583476444635447152826813568595303270846875177844482142230009826,
17677827682004946431939402157761289497221048154630238117709539216286149983245,
10716307389353583413755237303156291454109852751296156900963208377067748518748,
14925386988604173087143546225719076187055229908444910452781922028996524347508,
8940878636401797005293482068100797531020505636124892198091491586778667442523,
18911747154199663060505302806894425160044925686870165583944475880789706164410,
8821532432394939099312235292271438180996556457308429936910969094255825456935,
20632576502437623790366878538516326728436616723089049415538037018093616927643,
71447649211767888770311304010816315780740050029903404046389165015534756512,
2781996465394730190470582631099299305677291329609718650018200531245670229393,
12441376330954323535872906380510501637773629931719508864016287320488688345525,
2558302139544901035700544058046419714227464650146159803703499681139469546006,
10087036781939179132584550273563255199577525914374285705149349445480649057058,
4267692623754666261749551533667592242661271409704769363166965280715887854739,
4945579503584457514844595640661884835097077318604083061152997449742124905548,
17742335354489274412669987990603079185096280484072783973732137326144230832311,
6266270088302506215402996795500854910256503071464802875821837403486057988208,
2716062168542520412498610856550519519760063668165561277991771577403400784706,
19118392018538203167410421493487769944462015419023083813301166096764262134232,
9386595745626044000666050847309903206827901310677406022353307960932745699524,
9121640807890366356465620448383131419933298563527245687958865317869840082266,
3078975275808111706229899605611544294904276390490742680006005661017864583210,
7157404299437167354719786626667769956233708887934477609633504801472827442743,
14056248655941725362944552761799461694550787028230120190862133165195793034373,
14124396743304355958915937804966111851843703158171757752158388556919187839849,
11851254356749068692552943732920045260402277343008629727465773766468466181076,
9799099446406796696742256539758943483211846559715874347178722060519817626047,
10156146186214948683880719664738535455146137901666656566575307300522957959544,
19908645952733301583346063785055921934459499091029406575311417879963332475861,
11766105336238068471342414351862472329437473380853789942065610694000443387471,
11002137593249972174092192767251572171769044073555430468487809799220351297047,
284136377911685911941431040940403846843630064858778505937392780738953624163,
19448733709802908339787967270452055364068697565906862913410983275341804035680,
14423660424692802524250720264041003098290275890428483723270346403986712981505,
10635360132728137321700090133109897687122647659471659996419791842933639708516
];
var M = [
[
19167410339349846567561662441069598364702008768579734801591448511131028229281,
14183033936038168803360723133013092560869148726790180682363054735190196956789,
9067734253445064890734144122526450279189023719890032859456830213166173619761,
16378664841697311562845443097199265623838619398287411428110917414833007677155,
12968540216479938138647596899147650021419273189336843725176422194136033835172,
3636162562566338420490575570584278737093584021456168183289112789616069756675
],[
17034139127218860091985397764514160131253018178110701196935786874261236172431,
2799255644797227968811798608332314218966179365168250111693473252876996230317,
2482058150180648511543788012634934806465808146786082148795902594096349483974,
16563522740626180338295201738437974404892092704059676533096069531044355099628,
10468644849657689537028565510142839489302836569811003546969773105463051947124,
3328913364598498171733622353010907641674136720305714432354138807013088636408
],[
18985203040268814769637347880759846911264240088034262814847924884273017355969,
8652975463545710606098548415650457376967119951977109072274595329619335974180,
970943815872417895015626519859542525373809485973005165410533315057253476903,
19406667490568134101658669326517700199745817783746545889094238643063688871948,
17049854690034965250221386317058877242629221002521630573756355118745574274967,
4964394613021008685803675656098849539153699842663541444414978877928878266244
],[
19025623051770008118343718096455821045904242602531062247152770448380880817517,
9077319817220936628089890431129759976815127354480867310384708941479362824016,
4770370314098695913091200576539533727214143013236894216582648993741910829490,
4298564056297802123194408918029088169104276109138370115401819933600955259473,
6905514380186323693285869145872115273350947784558995755916362330070690839131,
4783343257810358393326889022942241108539824540285247795235499223017138301952
],[
16205238342129310687768799056463408647672389183328001070715567975181364448609,
8303849270045876854140023508764676765932043944545416856530551331270859502246,
20218246699596954048529384569730026273241102596326201163062133863539137060414,
1712845821388089905746651754894206522004527237615042226559791118162382909269,
13001155522144542028910638547179410124467185319212645031214919884423841839406,
16037892369576300958623292723740289861626299352695838577330319504984091062115
],[
15162889384227198851506890526431746552868519326873025085114621698588781611738,
13272957914179340594010910867091459756043436017766464331915862093201960540910,
9416416589114508529880440146952102328470363729880726115521103179442988482948,
8035240799672199706102747147502951589635001418759394863664434079699838251138,
21642389080762222565487157652540372010968704000567605990102641816691459811717,
20261355950827657195644012399234591122288573679402601053407151083849785332516
]
];
signal input inputs[nInputs];
signal output out;
component ark[nRoundsF + nRoundsP];
component sigmaF[nRoundsF][t];
component sigmaP[nRoundsP];
component mix[nRoundsF + nRoundsP];
var k;
for (var i=0; i<(nRoundsF + nRoundsP); i++) {
ark[i] = Ark(t, C[i]);
mix[i] = Mix(t, M);
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);
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;
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];
}
}
}
out <== mix[nRoundsF + nRoundsP -1].out[0];
}

View File

@@ -0,0 +1,81 @@
include "constants.circom";
include "sha256compression.circom";
template Sha256(nBits) {
signal input in[nBits];
signal output out[256];
var i;
var k;
var nBlocks;
var bitsLastBlock;
nBlocks = ((nBits + 64)\512)+1;
signal paddedIn[nBlocks*512];
for (k=0; k<nBits; k++) {
paddedIn[k] <== in[k];
}
paddedIn[nBits] <== 1;
for (k=nBits+1; k<nBlocks*512-64; k++) {
paddedIn[k] <== 0;
}
for (k = 0; k< 64; k++) {
paddedIn[nBlocks*512 - k -1] <== (nBits >> k)&1;
}
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component hf0 = H(5);
component hg0 = H(6);
component hh0 = H(7);
component sha256compression[nBlocks];
for (i=0; i<nBlocks; i++) {
sha256compression[i] = Sha256compression() ;
if (i==0) {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[0*32+k] <== ha0.out[k];
sha256compression[i].hin[1*32+k] <== hb0.out[k];
sha256compression[i].hin[2*32+k] <== hc0.out[k];
sha256compression[i].hin[3*32+k] <== hd0.out[k];
sha256compression[i].hin[4*32+k] <== he0.out[k];
sha256compression[i].hin[5*32+k] <== hf0.out[k];
sha256compression[i].hin[6*32+k] <== hg0.out[k];
sha256compression[i].hin[7*32+k] <== hh0.out[k];
}
} else {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[32*0+k] <== sha256compression[i-1].out[32*0+31-k];
sha256compression[i].hin[32*1+k] <== sha256compression[i-1].out[32*1+31-k];
sha256compression[i].hin[32*2+k] <== sha256compression[i-1].out[32*2+31-k];
sha256compression[i].hin[32*3+k] <== sha256compression[i-1].out[32*3+31-k];
sha256compression[i].hin[32*4+k] <== sha256compression[i-1].out[32*4+31-k];
sha256compression[i].hin[32*5+k] <== sha256compression[i-1].out[32*5+31-k];
sha256compression[i].hin[32*6+k] <== sha256compression[i-1].out[32*6+31-k];
sha256compression[i].hin[32*7+k] <== sha256compression[i-1].out[32*7+31-k];
}
}
for (k=0; k<512; k++) {
sha256compression[i].inp[k] <== paddedIn[i*512+k];
}
}
for (k=0; k<256; k++) {
out[k] <== sha256compression[nBlocks-1].out[k];
}
}

View File

@@ -17,6 +17,7 @@
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
include "constants.circom";
include "sha256compression.circom";
include "../bitify.circom"
@@ -25,6 +26,9 @@ template Sha256_2() {
signal input b;
signal output out;
var i;
var k;
component bits2num = Bits2Num(216);
component num2bits[2];
@@ -34,9 +38,28 @@ template Sha256_2() {
num2bits[0].in <== a;
num2bits[1].in <== b;
component sha256compression = Sha256compression() ;
var i;
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component hf0 = H(5);
component hg0 = H(6);
component hh0 = H(7);
for (k=0; k<32; k++ ) {
sha256compression.hin[0*32+k] <== ha0.out[k];
sha256compression.hin[1*32+k] <== hb0.out[k];
sha256compression.hin[2*32+k] <== hc0.out[k];
sha256compression.hin[3*32+k] <== hd0.out[k];
sha256compression.hin[4*32+k] <== he0.out[k];
sha256compression.hin[5*32+k] <== hf0.out[k];
sha256compression.hin[6*32+k] <== hg0.out[k];
sha256compression.hin[7*32+k] <== hh0.out[k];
}
for (i=0; i<216; i++) {
sha256compression.inp[i] <== num2bits[0].out[215-i];

View File

@@ -24,6 +24,7 @@ include "../binsum.circom";
include "sigmaplus.circom";
template Sha256compression() {
signal input hin[256];
signal input inp[512];
signal output out[256];
signal a[65][32];
@@ -44,15 +45,6 @@ template Sha256compression() {
component ct_k[64];
for (i=0; i<64; i++) ct_k[i] = K(i);
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component hf0 = H(5);
component hg0 = H(6);
component hh0 = H(7);
component t1[64];
for (i=0; i<64; i++) t1[i] = T1();
@@ -88,14 +80,14 @@ template Sha256compression() {
}
for (k=0; k<32; k++ ) {
a[0][k] <== ha0.out[k]
b[0][k] <== hb0.out[k]
c[0][k] <== hc0.out[k]
d[0][k] <== hd0.out[k]
e[0][k] <== he0.out[k]
f[0][k] <== hf0.out[k]
g[0][k] <== hg0.out[k]
h[0][k] <== hh0.out[k]
a[0][k] <== hin[k];
b[0][k] <== hin[32*1 + k];
c[0][k] <== hin[32*2 + k];
d[0][k] <== hin[32*3 + k];
e[0][k] <== hin[32*4 + k];
f[0][k] <== hin[32*5 + k];
g[0][k] <== hin[32*6 + k];
h[0][k] <== hin[32*7 + k];
}
for (t = 0; t<64; t++) {
@@ -133,21 +125,21 @@ template Sha256compression() {
}
for (k=0; k<32; k++) {
fsum[0].in[0][k] <== ha0.out[k];
fsum[0].in[0][k] <== hin[32*0+k];
fsum[0].in[1][k] <== a[64][k];
fsum[1].in[0][k] <== hb0.out[k];
fsum[1].in[0][k] <== hin[32*1+k];
fsum[1].in[1][k] <== b[64][k];
fsum[2].in[0][k] <== hc0.out[k];
fsum[2].in[0][k] <== hin[32*2+k];
fsum[2].in[1][k] <== c[64][k];
fsum[3].in[0][k] <== hd0.out[k];
fsum[3].in[0][k] <== hin[32*3+k];
fsum[3].in[1][k] <== d[64][k];
fsum[4].in[0][k] <== he0.out[k];
fsum[4].in[0][k] <== hin[32*4+k];
fsum[4].in[1][k] <== e[64][k];
fsum[5].in[0][k] <== hf0.out[k];
fsum[5].in[0][k] <== hin[32*5+k];
fsum[5].in[1][k] <== f[64][k];
fsum[6].in[0][k] <== hg0.out[k];
fsum[6].in[0][k] <== hin[32*6+k];
fsum[6].in[1][k] <== g[64][k];
fsum[7].in[0][k] <== hh0.out[k];
fsum[7].in[0][k] <== hin[32*7+k];
fsum[7].in[1][k] <== h[64][k];
}

View File

@@ -0,0 +1,56 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
include "../poseidon.circom";
/*
Hash1 = H(1 | key | value)
*/
template SMTHash1() {
signal input key;
signal input value;
signal output out;
component h = Poseidon(3, 6, 8, 57); // Constant
h.inputs[0] <== key;
h.inputs[1] <== value;
h.inputs[2] <== 1;
out <== h.out;
}
/*
This component is used to create the 2 nodes.
Hash2 = H(Hl | Hr)
*/
template SMTHash2() {
signal input L;
signal input R;
signal output out;
component h = Poseidon(2, 6, 8, 57); // Constant
h.inputs[0] <== L;
h.inputs[1] <== R;
out <== h.out;
}

View File

@@ -135,7 +135,7 @@ include "../switcher.circom";
include "smtlevins.circom";
include "smtprocessorlevel.circom";
include "smtprocessorsm.circom";
include "smthash.circom";
include "smthash_poseidon.circom";
template SMTProcessor(nLevels) {
signal input oldRoot;

View File

@@ -35,7 +35,7 @@ include "../switcher.circom";
include "smtlevins.circom";
include "smtverifierlevel.circom";
include "smtverifiersm.circom";
include "smthash.circom";
include "smthash_poseidon.circom";
template SMTVerifier(nLevels) {
signal input enabled;

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,6 @@
exports.smt = require("./src/smt");
exports.eddsa = require("./src/eddsa");
exports.mimc7 = require("./src/mimc7");
exports.mimcsponge = require("./src/mimcsponge");
exports.babyJub = require("./src/babyjub");
exports.pedersenHash = require("./src/pedersenHash");

11071
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "circomlib",
"version": "0.0.6",
"version": "0.0.15",
"description": "Basic circuits library for Circom",
"main": "index.js",
"directories": {
@@ -25,13 +25,15 @@
"license": "GPL-3.0",
"dependencies": {
"blake-hash": "^1.1.0",
"snarkjs": "0.1.11",
"web3": "^1.0.0-beta.36"
"blake2b": "^2.1.3",
"snarkjs": "^0.1.19",
"typedarray-to-buffer": "^3.1.5",
"web3": "^1.0.0-beta.55"
},
"devDependencies": {
"circom": "0.0.24",
"circom": "0.0.28",
"eslint-plugin-mocha": "^5.2.0",
"ganache-cli": "^6.2.3",
"ganache-cli": "^6.4.4",
"mocha": "^5.2.0"
}
}

View File

@@ -7,23 +7,33 @@ exports.inCurve = inCurve;
exports.inSubgroup = inSubgroup;
exports.packPoint = packPoint;
exports.unpackPoint = unpackPoint;
exports.Generator = [
bigInt("995203441582195749578291179787384436505546430278305826713579947235728471134"),
bigInt("5472060717959818805561601436314318772137091100104008585924551046643952123905")
];
exports.Base8 = [
bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
];
exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328");
exports.subOrder = exports.order.shr(3);
exports.p = bn128.r;
exports.A = bigInt("168700");
exports.D = bigInt("168696");
function addPoint(a,b) {
const q = bn128.r;
const cta = bigInt("168700");
const d = bigInt("168696");
const res = [];
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
/* does the equivalent of:
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
*/
res[0] = bigInt((bigInt(a[0]).mul(b[1]).add(bigInt(b[0]).mul(a[1]))).mul(bigInt(bigInt("1").add(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))).affine(q);
res[1] = bigInt((bigInt(a[1]).mul(b[1]).sub(exports.A.mul(a[0]).mul(b[0]))).mul(bigInt(bigInt("1").sub(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))).affine(q);
return res;
}
@@ -52,15 +62,12 @@ function inSubgroup(P) {
function inCurve(P) {
const F = bn128.Fr;
const a = bigInt("168700");
const d = bigInt("168696");
const x2 = F.square(P[0]);
const y2 = F.square(P[1]);
if (!F.equals(
F.add(F.mul(a, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), d)))) return false;
F.add(F.mul(exports.A, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false;
return true;
}
@@ -86,14 +93,11 @@ function unpackPoint(_buff) {
P[1] = bigInt.leBuff2int(buff);
if (P[1].greaterOrEquals(exports.p)) return null;
const a = bigInt("168700");
const d = bigInt("168696");
const y2 = F.square(P[1]);
let x = F.sqrt(F.div(
F.sub(F.one, y2),
F.sub(a, F.mul(d, y2))));
F.sub(exports.A, F.mul(exports.D, y2))));
if (x == null) return null;

View File

@@ -3,12 +3,18 @@ const bigInt = require("snarkjs").bigInt;
const babyJub = require("./babyjub");
const pedersenHash = require("./pedersenHash").hash;
const mimc7 = require("./mimc7");
const poseidon = require("./poseidon.js");
const mimcsponge = require("./mimcsponge");
exports.prv2pub= prv2pub;
exports.sign = sign;
exports.signMiMC = signMiMC;
exports.signPoseidon = signPoseidon;
exports.signMiMCSponge = signMiMCSponge;
exports.verify = verify;
exports.verifyMiMC = verifyMiMC;
exports.verifyPoseidon = verifyPoseidon;
exports.verifyMiMCSponge = verifyMiMCSponge;
exports.packSignature = packSignature;
exports.unpackSignature = unpackSignature;
exports.pruneBuffer = pruneBuffer;
@@ -69,6 +75,45 @@ function signMiMC(prv, msg) {
};
}
function signMiMCSponge(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32));
const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return {
R8: R8,
S: S
};
}
function signPoseidon(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32));
const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
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 S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return {
R8: R8,
S: S
};
}
function verify(msg, sig, A) {
// Check parameters
if (typeof sig != "object") return false;
@@ -116,6 +161,52 @@ function verifyMiMC(msg, sig, A) {
return true;
}
function verifyPoseidon(msg, sig, A) {
// Check parameters
if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length!= 2) return false;
if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false;
if (A.length!= 2) return false;
if (!babyJub.inCurve(A)) 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 Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false;
return true;
}
function verifyMiMCSponge(msg, sig, A) {
// Check parameters
if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length!= 2) return false;
if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false;
if (A.length!= 2) return false;
if (!babyJub.inCurve(A)) return false;
if (sig.S>= babyJub.subOrder) return false;
const hm = mimcsponge.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false;
return true;
}
function packSignature(sig) {
const R8p = babyJub.packPoint(sig.R8);
const Sp = bigInt.leInt2Buff(sig.S, 32);

View File

@@ -127,12 +127,16 @@ class Contract {
jmp(label) {
this._pushLabel(label);
if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x56);
}
jmpi(label) {
this._pushLabel(label);
if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x57);
}

583
src/g2_gencontract.js Normal file
View File

@@ -0,0 +1,583 @@
// Copyright (c) 2018 Jordi Baylina
// License: LGPL-3.0+
//
const Contract = require("./evmasm");
const G2 = require("snarkjs").bn128.G2;
const bigInt = require("snarkjs").bigInt;
function toHex256(a) {
let S = a.toString(16);
while (S.length < 64) S="0"+S;
return "0x" + S;
}
function createCode(P, w) {
const C = new Contract();
const NPOINTS = 1 << (w-1);
const VAR_POS = C.allocMem(32);
const VAR_POINTS = C.allocMem( (NPOINTS)*4*32);
const savedP = C.allocMem(32);
const savedZ3 = C.allocMem(32);
// Check selector
C.push("0x0100000000000000000000000000000000000000000000000000000000");
C.push(0);
C.calldataload();
C.div();
C.push("b65c7c74"); // mulexp(uint256)
C.eq();
C.jmpi("start");
C.invalid();
C.label("start");
storeVals();
C.push( Math.floor(255/w)*w ); // pos := 255
C.push(VAR_POS);
C.mstore();
C.push("21888242871839275222246405745257275088696311157297823662689037894645226208583");
C.push(0);
C.push(0);
C.push(0);
C.push(0);
C.push(0);
C.push(0);
C.label("begin_loop"); // ACC_X ACC_Y ACC_Z q
C.internalCall("double");
// g = (e>>pos)&MASK
C.push(4);
C.calldataload(); // e ACC_X ACC_Y ACC_Z q
C.push(VAR_POS);
C.mload(); // pos e ACC_X ACC_Y ACC_Z q
C.shr();
C.push(NPOINTS-1);
C.and(); // g ACC_X ACC_Y ACC_Z q
C.internalCall("add"); // acc_x acc_y acc_z
C.push(VAR_POS);
C.mload(); // pos acc_x acc_y acc_z
C.dup(0); // pos pos acc_x acc_y acc_z
C.push(0); // 0 pos pos acc_x acc_y acc_z
C.eq(); // eq pos acc_x acc_y acc_z
C.jmpi("after_loop"); // pos acc_x acc_y acc_z
C.push(w); // 5 pos acc_x acc_y acc_z
C.sub(); // pos acc_x acc_y acc_z
C.push(VAR_POS);
C.mstore(); // acc_x acc_y acc_z
C.jmp("begin_loop");
C.label("after_loop"); // pos acc_x acc_y acc_z
C.pop(); // acc_x acc_y acc_z
C.internalCall("affine"); // acc_x acc_y
C.push(0);
C.mstore();
C.push(20);
C.mstore();
C.push(40);
C.mstore();
C.push(60);
C.mstore();
C.push("0x80");
C.push("0x00");
C.return();
double();
addPoint();
affine();
return C.createTxData();
function add(a,b,q) {
C.dup(q);
C.dup(a+1 + 1);
C.dup(b+1 + 2);
C.addmod();
C.dup(q + 1);
C.dup(a + 2);
C.dup(b + 3);
C.addmod();
}
function sub(a,b,q) {
C.dup(q); // q
C.dup(a+1 + 1); // ai q
C.dub(q + 2); // q ai q
C.dup(b+1 + 3); // bi q ai q
C.sub(); // -bi ai q
C.addmod(); // ci
C.dup(q + 1); // q ci
C.dup(a + 2); // ar q ci
C.dup(q + 3); // q ar q ci
C.dup(b + 4); // br q ar q ci
C.sub(); // -br ar q ci
C.addmod(); // cr ci
}
function mul(a, b, q) {
C.dup(q); // q
C.dup(q + 1); // q q
C.dup(a + 2); // ar q q
C.dup(b+1 + 3); // bi ar q q
C.mulmod(); // ci1 q
C.dup(q + 2); // q ci1 q
C.dup(a+1 + 3); // ai q ci1 q
C.dup(b + 4); // ar ai q ci1 q
C.mulmod(); // ci2 ci1 q
C.addmod(); // ci
C.dup(q + 1); // q ci
C.dup(q + 2); // q q ci
C.dup(q + 3); // q q q ci
C.dup(a+1 + 4); // ai q q ci
C.dup(b+1 + 5); // bi ai q q ci
C.mulmod(); // cr2 q q ci
C.sub(); // -cr2 q ci
C.dup(q + 3); // q -cr2 q ci
C.dup(a + 4); // ar q -cr2 q ci
C.dup(b + 5); // br ar q -cr2 q ci
C.mulmod(); // cr1 -cr2 q ci
C.addmod(); // cr ci
}
function square(a, q) {
C.dup(q); // q
C.dup(q + 1); // q q
C.dup(a + 2); // ar q q
C.dup(a+1 + 3); // ai ar q q
C.mulmod(); // arai q
C.dup(0); // arai arai q
C.addmod(); // ci
C.dup(q + 1); // q ci
C.dup(q + 2); // q q ci
C.dup(q + 3); // q q q ci
C.dup(a+1 + 4); // ai q q ci
C.dup(a+1 + 5); // ai ai q q ci
C.mulmod(); // cr2 q q ci
C.sub(); // -cr2 q ci
C.dup(q + 3); // q -cr2 q ci
C.dup(a + 4); // ar q -cr2 q ci
C.dup(a + 5); // br ar q -cr2 q ci
C.mulmod(); // cr1 -cr2 q ci
C.addmod(); // cr ci
}
function add1(a, q) {
C.dup(a+1); // im
C.dup(1 + q); // q
C.dup(2 + a); // re q im
C.push(1); // 1 re q im
C.addmod();
}
function cmp(a, b) {
C.dup(a);
C.dup(b);
C.eq();
C.dup(a+1);
C.dup(a+1);
C.and();
}
function rm(a) {
if (a>0) C.swap(a);
C.pop();
if (a>0) C.swap(a);
C.pop();
}
function double() {
C.label("double"); // xR, xI, yR, yI, zR zI, q
C.dup(4);
C.iszero();
C.dup(6);
C.iszero();
C.and();
C.jumpi("enddouble"); // X Y Z q
// Z3 = 2*Y*Z // Remove Z
mul(2, 4, 6); // yz X Y Z q
rm(6); // X Y yz q
add(4, 4, 6); // 2yz X Y yz q
rm(6); // X Y Z3 q
// A = X^2
square(0,6); // A X Y Z3 q
// B = Y^2 // Remove Y
square(4,8); // B A X Y Z3 q
rm(6); // A X B Z3 q
// C = B^2
square(4,8); // C A X B Z3 q
// D = (X+B)^2-A-C // Remove X, Remove B
add(4,6, 10); // X+B C A X B Z3 q
rm(6); // C A X+B B Z3 q
rm(6); // A X+B C Z3 q
square(2,8); // (X+B)^2 A X+B C Z3 q
rm(4); // A (X+B)^2 C Z3 q
sub(2, 0, 8); // (X+B)^2-A A (X+B)^2 C Z3 q
rm(4); // A (X+B)^2-A C Z3 q
sub(2, 4, 8); // (X+B)^2-A-C A (X+B)^2-A C Z3 q
rm(4); // A D C Z3 q
// D = D+D
add(2,2, 8); // D+D A D C Z3 q
rm(4); // A D C Z3 q
// E=A+A+A
add(0, 0, 8); // 2A A D C Z3 q
add(0, 2, 10); // 3A 2A A D C Z3 q
rm(4); // 2A 3A D C Z3 q
rm(0); // E D C Z3 q
// F=E^2
square(0, 8); // F E D C Z3 q
// X3= F - 2*D // Remove F
add(4, 4, 10); // 2D F E D C Z3 q
sub(2, 0, 12); // F-2D 2D F E D C Z3 q
rm(4); // 2D X3 E D C Z3 q
rm(0); // X3 E D C Z3 q
// Y3 = E * (D - X3) - 8 * C // Remove D C E
sub(4, 0, 10); // D-X3 X3 E D C Z3 q
rm(6); // X3 E D-X3 C Z3 q
mul(2, 4, 10); // E*(D-X3) X3 E D-X3 C Z3 q
rm(6); // X3 E E*(D-X3) C Z3 q
rm(2); // X3 E*(D-X3) C Z3 q
add(4, 4, 8); // 2C X3 E*(D-X3) C Z3 q
rm(6); // X3 E*(D-X3) 2C Z3 q
add(4, 4, 8); // 4C X3 E*(D-X3) 2C Z3 q
rm(6); // X3 E*(D-X3) 4C Z3 q
add(4, 4, 8); // 8C X3 E*(D-X3) 4C Z3 q
rm(6); // X3 E*(D-X3) 8C Z3 q
sub(2, 4, 8); // E*(D-X3)-8C X3 E*(D-X3) 8C Z3 q
rm(6); // X3 E*(D-X3) Y3 Z3 q
rm(2); // X3 Y3 Z3 q
C.label("enddouble");
C.returnCall();
}
function addPoint() { // p, xR, xI, yR, yI, zR zI, q
C.dup(0); // p p X2 Y2 Z2 q
C.push(savedP);
C.mstore();
C.iszero(); // X2 Y2 Z2 q
C.jumpi("endpadd");
C.dup(4);
C.iszero();
C.dup(6);
C.iszero();
C.and();
C.jumpi("returnP"); // X2 Y2 Z2 q
// lastZ3 = (Z2+1)^2 - Z2^2
add1(4, 6); // Z2+1 X2 Y2 Z2 q
square(0, 8); // (Z2+1)^2 Z2+1 X2 Y2 Z2 q
rm(2); // (Z2+1)^2 X2 Y2 Z2 q
square(6, 8); // Z2^2 (Z2+1)^2 X2 Y2 Z2 q
sub(2, 0, 10); // (Z2+1)^2-Z2^2 Z2^2 (Z2+1)^2 X2 Y2 Z2 q
saveZ3(); // Z2^2 (Z2+1)^2 X2 Y2 Z2 q
rm(2); // Z2^2 X2 Y2 Z2 q
// U2 = X2
// S2 = Y2 // Z2^2 U2 S2 Z2 q
// U1 = X1 * Z2^2
loadX(); // X1 Z2^2 U2 S2 Z2 q
mul(0, 2, 10); // X1*Z2^2 X1 Z2^2 U2 S2 Z2 q
rm(2); // X1*Z2^2 Z2^2 U2 S2 Z2 q
mul(2, 8, 10); // Z2^3 U1 Z2^2 U2 S2 Z2 q
rm(4); // U1 Z2^3 U2 S2 Z2 q
rm(8); // Z2^3 U2 S2 U1 q
// S1 = Y1 * Z1^3
loadY(); // Y1 Z2^3 U2 S2 U1 q
mul(0, 2, 10); // S1 Y1 Z2^3 U2 S2 U1 q
rm(4); // Y1 S1 U2 S2 U1 q
rm(0); // S1 U2 S2 U1 q
cmp(0, 4); // c1 S1 U2 S2 U1 q
cmp(3, 7); // c2 c1 S1 U2 S2 U1 q
C.and(); // c2&c1 S1 U2 S2 U1 q
C.jumpi("double1"); // S1 U2 S2 U1 q
// Returns the double
// H = U2-U1 // Remove U2
C.sub(4, 8, 10); // H S1 U2 S2 U1 q
rm(4); // S1 H S2 U1 q
// // r = 2 * (S2-S1) // Remove S2
C.sub(4, 4, 8); // S1-S2 S1 H S2 U1 q
rm(6); // S1 H S1-S2 U1 q
C.add(4, 4, 8); // 2*(S1-S2) S1 H S1-S2 U1 q
rm(6); // S1 H r U1 q
// I = (2 * H)^2
C.add(2, 2, 8); // 2*H S1 H r U1 q
C.square(0, 10); // (2*H)^2 2*H S1 H r U1 q
rm(2); // I S1 H r U1 q
// V = U1 * I
mul(8, 0, 10); // V I S1 H r U1 q
rm(10); // I S1 H r V q
// J = H * I // Remove I
mul(4, 0, 10); // J I S1 H r V q
rm(2); // J S1 H r V q
// X3 = r^2 - J - 2 * V
// S1J2 = (S1*J)*2 // Remove S1
mul(2, 0, 10); // S1*J J S1 H r V q
rm(4); // J S1*J H r V q
add(2,2, 10); // (S1*J)*2 J S1*J H r V q
rm(4); // J S1J2 H r V q
// X3 = r^2 - J - 2 * V
square(6, 10); // r^2 J S1J2 H r V q
sub(0, 2, 12); // r^2-J r^2 J S1J2 H r V q
rm(2); // r^2-J J S1J2 H r V q
rm(2); // r^2-J S1J2 H r V q
add(8, 8, 10); // 2*V r^2-J S1J2 H r V q
sub(2, 0, 12); // r^2-J-2*V 2*V r^2-J S1J2 H r V q
rm(4); // 2*V X3 S1J2 H r V q
rm(0); // X3 S1J2 H r V q
// Y3 = r * (V-X3)-S1J2
sub(8, 0, 10); // V-X3 X3 S1J2 H r V q
rm(10); // X3 S1J2 H r V-X3 q
mul(6, 8, 10); // r*(V-X3) X3 S1J2 H r V-X3 q
rm(8); // X3 S1J2 H r*(V-X3) V-X3 q
rm(8); // S1J2 H r*(V-X3) X3 q
sub(4, 0, 8); // Y3 S1J2 H r*(V-X3) X3 q
rm(6); // S1J2 H Y3 X3 q
rm(0); // H Y3 X3 q
// Z3 = lastZ * H
loadZ3(); // lastZ3 H Y3 X3 q
mul(0, 2, 8); // Z3 lastZ3 H Y3 X3 q
rm(4); // lastZ3 Z3 Y3 X3 q
rm(0); // Z3 Y3 X3 q
C.swap(1);
C.swap(5);
C.swap(1);
C.swap(4); // X3 Y3 Z3 q
// returns the point in memory
C.label("returnP"); // X Y Z q
rm(0);
rm(0);
rm(0);
C.push(0);
C.push(1);
loadX();
loadY();
C.jump("endpadd");
C.label("double1"); // S1 U2 S2 U1 q
rm(0);
rm(0);
rm(0);
rm(0);
C.push(0);
C.push(1);
loadX();
loadY();
C.jump("double");
C.label("endpadd");
C.returnCall();
function loadX() {
C.push(savedP);
C.mload(); // p
C.push(32);
C.mul(); // P*32
C.push(VAR_POINTS+32);
C.add(); // P*32+32
C.dup(); // P*32+32 P*32+32
C.mload(); // im P*32+32
C.swap(1); // P*32+32 im
C.push(0x20); // 32 P*32+32 im
C.sub(); // P*32 im
C.mload(); // re im
}
function loadY() {
C.push(savedP);
C.mload(); // p
C.push(32);
C.mul(); // P*32
C.push(VAR_POINTS+32*3);
C.add(); // P*32+32
C.dup(); // P*32+32 P*32+32
C.mload(); // im P*32+32
C.swap(1); // P*32+32 im
C.push(0x20); // 32 P*32+32 im
C.sub(); // P*32 im
C.mload(); // re im
}
function loadZ3() {
C.push(savedZ3+32);
C.mload(); // p
C.push(savedZ3);
C.mload();
}
function saveZ3() {
C.push(savedZ3);
C.mstore();
C.push(savedZ3+32);
C.mstore();
}
}
function affine() { // X Y Z q
// If Z2=0 return 0
C.label("affine");
C.dup(4);
C.dup(5 + 1);
C.or();
C.jumpi("notZero"); // X Y Z q
rm(0);
rm(0);
C.push(0);
C.push(0);
C.jmp("endAffine");
C.label("notZero");
inverse2(4,6); // Z_inv X Y Z q
square(2, 8); // Z2_inv Z_inv X Y Z q
mul(0, 2, 10); // Z3_inv Z2_inv Z_inv X Y Z q
rm(4); // Z2_inv Z3_inv X Y Z q
C.push(1);
C.push(0); // 1 Z2_inv Z3_inv X Y Z q
rm(10); // Z2_inv Z3_inv X Y 1 q
mul(2, 6, 10); // YI Z2_inv Z3_inv X Y 1 q
rm(8); // Z2_inv Z3_inv X YI 1 q
mul(0, 4, 10); // XI Z2_inv Z3_inv X YI 1 q
rm(6); // Z2_inv Z3_inv XI YI 1 q
rm(0); // Z3_inv XI YI 1 q
rm(0); // XI YI 1 q
C.label("endAffine");
C.returnCall();
}
function inverse2(a, q) {
C.dup(q); // q
C.dup(q + 1); // q q
C.push(2); // 2 q q
C.sub(); // q-2 q
C.dup(q + 2); // q q-2 q
C.dup(q + 3); // q q q-2 q
C.dup(a + 4); // ar q q q-2 q
C.dup(a + 5); // ar ar q q q-2 q
C.mulmod(); // t0 q q-2 q
C.dup(q + 4); // q t0 q q-2 q
C.dup(a+1 + 5); // ai q t0 q q-2 q
C.dup(a+1 + 6); // ai ai q t0 q q-2 q
C.mulmod(); // t1 t0 q q-2 q
C.addmod(); // t2 q-2 q
C.expmod(); // t3
C.dup(q + 1); // q t3
C.dup(q + 2); // q q t3
C.dup(q + 3); // q q q t3
C.dup(1); // t3 q q q t3
C.sub(); // -t3 q q t3
C.dup(a+1 + 3); // ai -t3 q q t3
C.mulmod(); // ii q t3
C.swap(2); // t3 q ii
C.dup(a + 3); // ar t3 q ii
C.mulmod(); // ir ii
}
function storeVals() {
C.push(VAR_POINTS); // p
for (let i=0; i<NPOINTS; i++) {
const MP = G2.affine(G2.mulScalar(P, bigInt(i)));
for (let j=0; j<2; j++) {
for (let k=0; k<2; k++) {
C.push(toHex256(MP[j][k])); // MP[0][0] p
C.dup(1); // p MP[0][0] p
C.mstore(); // p
C.push(32); // 32 p
C.add(); // p+32
}
}
}
}
}
module.exports.abi = [
{
"constant": true,
"inputs": [
{
"name": "escalar",
"type": "uint256"
}
],
"name": "mulexp",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
];
module.exports.createCode = createCode;

View File

@@ -62,3 +62,21 @@ exports.multiHash = (arr, key) => {
}
return F.affine(r);
};
// hashBuffer performs the MiMC7 hash over a buffer array, splitting the bytes into 31 bytes bigints,
// and making chunks of two bigints to perform the MiMC7 hash
exports.hashBuffer = (msgBuff) => {
const n = 31;
const msgArray = [];
const fullParts = Math.floor(msgBuff.length / n);
for (let i = 0; i < fullParts; i++) {
const v = bigInt.leBuff2int(msgBuff.slice(n * i, n * (i + 1)));
msgArray.push(v);
}
if (msgBuff.length % n !== 0) {
const v = bigInt.leBuff2int(msgBuff.slice(fullParts * n));
msgArray.push(v);
}
return exports.multiHash(msgArray);
};

86
src/mimcsponge.js Normal file
View File

@@ -0,0 +1,86 @@
const bn128 = require("snarkjs").bn128;
const bigInt = require("snarkjs").bigInt;
const Web3Utils = require("web3-utils");
const F = bn128.Fr;
const SEED = "mimcsponge";
const NROUNDS = 220;
exports.getIV = (seed) => {
if (typeof seed === "undefined") seed = SEED;
const c = Web3Utils.keccak256(seed+"_iv");
const cn = bigInt(Web3Utils.toBN(c).toString());
const iv = cn.mod(F.q);
return iv;
};
exports.getConstants = (seed, nRounds) => {
if (typeof seed === "undefined") seed = SEED;
if (typeof nRounds === "undefined") nRounds = NROUNDS;
const cts = new Array(nRounds);
let c = Web3Utils.keccak256(SEED);
for (let i=1; i<nRounds; i++) {
c = Web3Utils.keccak256(c);
const n1 = Web3Utils.toBN(c).mod(Web3Utils.toBN(F.q.toString()));
const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64);
cts[i] = bigInt(Web3Utils.toBN(c2).toString());
}
cts[0] = bigInt(0);
cts[cts.length - 1] = bigInt(0);
return cts;
};
const cts = exports.getConstants(SEED, NROUNDS);
exports.hash = (_xL_in, _xR_in, _k) =>{
let xL = bigInt(_xL_in);
let xR = bigInt(_xR_in);
const k = bigInt(_k);
for (let i=0; i<NROUNDS; i++) {
const c = cts[i];
const t = (i==0) ? F.add(xL, k) : F.add(F.add(xL, k), c);
const xR_tmp = bigInt(xR);
if (i < (NROUNDS - 1)) {
xR = xL;
xL = F.add(xR_tmp, F.exp(t, 5));
} else {
xR = F.add(xR_tmp, F.exp(t, 5));
}
}
return {
xL: F.affine(xL),
xR: F.affine(xR),
};
};
exports.multiHash = (arr, key, numOutputs) => {
if (typeof(numOutputs) === "undefined") {
numOutputs = 1;
}
if (typeof(key) === "undefined") {
key = F.zero;
}
let R = F.zero;
let C = F.zero;
for (let i=0; i<arr.length; i++) {
R = F.add(R, bigInt(arr[i]));
const S = exports.hash(R, C, key);
R = S.xL;
C = S.xR;
}
let outputs = [R];
for (let i=1; i < numOutputs; i++) {
const S = exports.hash(R, C, key);
R = S.xL;
C = S.xR;
outputs.push(R);
}
if (numOutputs == 1) {
return F.affine(outputs[0]);
} else {
return outputs.map(x => F.affine(x));
}
};

View File

@@ -0,0 +1,128 @@
// Copyright (c) 2018 Jordi Baylina
// License: LGPL-3.0+
//
const Web3Utils = require("web3-utils");
const Contract = require("./evmasm");
function createCode(seed, n) {
let ci = Web3Utils.keccak256(seed);
const C = new Contract();
C.push(0x64);
C.push("0x00");
C.push("0x00");
C.calldatacopy();
C.push("0x0100000000000000000000000000000000000000000000000000000000");
C.push("0x00");
C.mload();
C.div();
C.push("0x3f1a1187"); // MiMCSponge(uint256,uint256,uint256)
C.eq();
C.jmpi("start");
C.invalid();
C.label("start");
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
C.push("0x44");
C.mload(); // k q
C.push("0x04");
C.mload(); // xL k q
C.dup(2); // q xL k q
C.push("0x24");
C.mload(); // xR q xL k q
C.dup(1); // q xR q xL k q
C.dup(0); // q q xR q xL k q
C.dup(4); // xL q q xR q xL k q
C.dup(6); // k xL q q xR q xL k q
C.addmod(); // t=k+xL q xR q xL k q
C.dup(1); // q t q xR q xL k q
C.dup(0); // q q t q xR q xL k q
C.dup(2); // t q q t q xR q xL k q
C.dup(0); // t t q q t q xR q xL k q
C.mulmod(); // b=t^2 q t q xR q xL k q
C.dup(0); // b b q t q xR q xL k q
C.mulmod(); // c=t^4 t q xR q xL k q
C.mulmod(); // d=t^5 xR q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
for (let i=0; i<n-1; i++) {
if (i < n-2) {
ci = Web3Utils.keccak256(ci);
} else {
ci = "0x00";
}
C.swap(1); // xR xL k q
C.dup(3); // q xR xL k q
C.dup(3); // k q xR xL k q
C.dup(1); // q k q xR xL k q
C.dup(4); // xL q k q xR xL k q
C.push(ci); // ci xL q k q xR xL k q
C.addmod(); // a=ci+xL k q xR xL k q
C.addmod(); // t=a+k xR xL k q
C.dup(4); // q t xR xL k q
C.swap(1); // t q xR xL k q
C.dup(1); // q t q xR xL k q
C.dup(0); // q q t q xR xL k q
C.dup(2); // t q q t q xR xL k q
C.dup(0); // t t q q t q xR xL k q
C.mulmod(); // b=t^2 q t q xR xL k q
C.dup(0); // b b q t q xR xL k q
C.mulmod(); // c=t^4 t q xR xL k q
C.mulmod(); // d=t^5 xR xL k q
C.dup(4); // q d xR xL k q
C.swap(2); // xR d q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
}
C.push("0x20");
C.mstore(); // Save it to pos 0;
C.push("0x00");
C.mstore(); // Save it to pos 1;
C.push("0x40");
C.push("0x00");
C.return();
return C.createTxData();
}
module.exports.abi = [
{
"constant": true,
"inputs": [
{
"name": "xL_in",
"type": "uint256"
},
{
"name": "xR_in",
"type": "uint256"
},
{
"name": "k",
"type": "uint256"
}
],
"name": "MiMCSponge",
"outputs": [
{
"name": "xL",
"type": "uint256"
},
{
"name": "xR",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
];
module.exports.createCode = createCode;

View File

@@ -0,0 +1,13 @@
const mimcsponge = require("./mimcsponge.js");
const nRounds = 220;
let S = "[\n";
const cts = mimcsponge.getConstants();
for (let i=0; i<nRounds; i++) {
S = S + cts[i].toString();
if (i<nRounds-1) S = S + ",";
S=S+"\n";
}
S = S + "]\n";
console.log(S);

View File

@@ -0,0 +1,13 @@
const mimcGenContract = require("./mimcsponge_gencontract");
const SEED = "mimcsponge";
let nRounds;
if (typeof process.argv[2] != "undefined") {
nRounds = parseInt(process.argv[2]);
} else {
nRounds = 220;
}
console.log(mimcGenContract.createCode(SEED, nRounds));

157
src/poseidon.js Normal file
View File

@@ -0,0 +1,157 @@
const bn128 = require("snarkjs").bn128;
const bigInt = require("snarkjs").bigInt;
const blake2b = require('blake2b');
const assert = require("assert");
const F = bn128.Fr;
const SEED = "poseidon";
const NROUNDSF = 8;
const NROUNDSP = 57;
const T = 6;
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.affine(bigInt.leBuff2int(h));
res.push(n);
h = blake2b(32).update(h).digest()
}
return res;
}
function allDifferent(v) {
for (let i=0; i<v.length; i++) {
if (v[i].isZero()) return false;
for (let j=i+1; j<v.length; j++) {
if (v[i].equals(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;
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.affine(F.inverse(F.sub(cmatrix[i], cmatrix[t+j])));
}
}
return M;
};
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;
};
function ark(state, c) {
for (let j=0; j<state.length; j++ ) {
state[j] = F.add(state[j], c);
}
}
function sigma(a) {
return F.mul(a, F.square(F.square(a,a)));
}
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]) );
}
}
for (let i=0; i<state.length; i++) state[i] = newState[i];
}
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] = bigInt(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.affine(state[0]);
};
};
// hash exposes the generic Poseidon hash function
// with nRoundsF:8, nRoundsP: 57, t: 6
exports.hash = (arr) => {
const poseidonHash = exports.createHash(6, 8, 57);
return poseidonHash(arr);
}
// multiHash splits the bigint array into chunks of five elements
// and performs the Poseidon hash over the five elements chunks
exports.multiHash = (arr) => {
let r = bigInt(0);
for (let i=0; i<arr.length; i = i+5) {
let fiveElems = [];
for (let j=0; j<5; j++) {
if (i+j < arr.length) {
fiveElems.push(arr[i+j]);
} else {
fiveElems.push(bigInt(0));
}
}
const ph = exports.hash(fiveElems);
r = F.add(r, ph);
}
return F.affine(r);
};
// hashBuffer performs the Poseidon hash over a buffer array, splitting the bytes into 31 bytes bigints,
// and making chunks of five bigints to perform the Poseidon hash
exports.hashBuffer = (msgBuff) => {
const n = 31;
const msgArray = [];
const fullParts = Math.floor(msgBuff.length / n);
for (let i = 0; i < fullParts; i++) {
const v = bigInt.leBuff2int(msgBuff.slice(n * i, n * (i + 1)));
msgArray.push(v);
}
if (msgBuff.length % n !== 0) {
const v = bigInt.leBuff2int(msgBuff.slice(fullParts * n));
msgArray.push(v);
}
return exports.multiHash(msgArray);
};

180
src/poseidon_gencontract.js Normal file
View File

@@ -0,0 +1,180 @@
// Copyright (c) 2018 Jordi Baylina
// License: LGPL-3.0+
//
const Poseidon = require("./poseidon.js");
const Contract = require("./evmasm");
const SEED = "poseidon";
const NROUNDSF = 8;
const NROUNDSP = 57;
const T = 6;
function toHex256(a) {
let S = a.toString(16);
while (S.length < 64) S="0"+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;
const K = Poseidon.getConstants(t, seed, nRoundsP + nRoundsF);
const M = Poseidon.getMatrix(t, seed, nRoundsP + nRoundsF);
const C = new Contract();
function saveM() {
for (let i=0; i<t; i++) {
for (let j=0; j<t; j++) {
C.push(toHex256(M[i][j]));
C.push((1+i*t+j)*32);
C.mstore();
}
}
}
function ark(r) {
C.push(toHex256(K[r])); // K, st, q
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.pop();
}
C.pop();
}
function sigma(p) {
// sq, q
C.dup(t); // q, st, q
C.dup(1+p); // st[p] , q , st, q
C.dup(1); // q, st[p] , q , st, q
C.dup(0); // q, q, st[p] , q , st, q
C.dup(2); // st[p] , q, q, st[p] , q , st, q
C.dup(0); // st[p] , st[p] , q, q, st[p] , q , st, q
C.mulmod(); // st2[p], q, st[p] , q , st, q
C.dup(0); // st2[p], st2[p], q, st[p] , q , st, q
C.mulmod(); // st4[p], st[p] , q , st, q
C.mulmod(); // st5[p], st, q
C.swap(1+p);
C.pop(); // newst, q
}
function mix() {
C.label("mix");
for (let i=0; i<t; i++) {
for (let j=0; j<t; j++) {
if (j==0) {
C.dup(i+t); // q, newSt, oldSt, q
C.push((1+i*t+j)*32);
C.mload(); // M, q, newSt, oldSt, q
C.dup(2+i+j); // oldSt[j], M, q, newSt, oldSt, q
C.mulmod(); // acc, newSt, oldSt, q
} else {
C.dup(1+i+t); // q, acc, newSt, oldSt, q
C.push((1+i*t+j)*32);
C.mload(); // M, q, acc, newSt, oldSt, q
C.dup(3+i+j); // oldSt[j], M, q, acc, newSt, oldSt, q
C.mulmod(); // aux, acc, newSt, oldSt, q
C.dup(2+i+t); // q, aux, acc, newSt, oldSt, q
C.swap(2); // acc, aux, q, newSt, oldSt, q
C.addmod(); // acc, newSt, oldSt, q
}
}
}
for (let i=0; i<t; i++) {
C.swap((t -i) + (t -i-1));
C.pop();
}
C.push(0);
C.mload();
C.jmp();
}
// Check selector
C.push("0x0100000000000000000000000000000000000000000000000000000000");
C.push(0);
C.calldataload();
C.div();
C.push("0xc4420fb4"); // poseidon(uint256[])
C.eq();
C.jmpi("start");
C.invalid();
C.label("start");
saveM();
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
// Load 6 values from the call data.
// The function has a single array param param
// [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.
for (let i=0; i<t; i++) {
C.push(0x44+(0x20*(5-i)));
C.calldataload();
}
for (let i=0; i<nRoundsF+nRoundsP; i++) {
ark(i);
if ((i<nRoundsF/2) || (i>=nRoundsP+nRoundsF/2)) {
for (let j=0; j<t; j++) {
sigma(j);
}
} else {
sigma(0);
}
const strLabel = "aferMix"+i;
C._pushLabel(strLabel);
C.push(0);
C.mstore();
C.jmp("mix");
C.label(strLabel);
}
C.push("0x00");
C.mstore(); // Save it to pos 0;
C.push("0x20");
C.push("0x00");
C.return();
mix();
return C.createTxData();
}
module.exports.abi = [
{
"constant": true,
"inputs": [
{
"name": "input",
"type": "uint256[]"
}
],
"name": "poseidon",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
];
module.exports.createCode = createCode;

View File

@@ -0,0 +1,16 @@
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);

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
const bigInt = require("snarkjs").bigInt;
const SMTMemDB = require("./smt_memdb");
const mimc7 = require("./mimc7");
const {hash0, hash1} = require("./smt_hashes_poseidon");
class SMT {
@@ -46,8 +46,8 @@ class SMT {
const ins = [];
const dels = [];
let rtOld = mimc7.multiHash([key, resFind.foundValue], bigInt.one);
let rtNew = mimc7.multiHash([key, newValue], bigInt.one);
let rtOld = hash1(key, resFind.foundValue);
let rtNew = hash1(key, newValue);
ins.push([rtNew, [1, key, newValue ]]);
dels.push(rtOld);
@@ -62,8 +62,8 @@ class SMT {
oldNode = [rtOld, sibling];
newNode = [rtNew, sibling];
}
rtOld = mimc7.multiHash(oldNode, bigInt.zero);
rtNew = mimc7.multiHash(newNode, bigInt.zero);
rtOld = hash0(oldNode[0], oldNode[1]);
rtNew = hash0(newNode[0], newNode[1]);
dels.push(rtOld);
ins.push([rtNew, newNode]);
}
@@ -92,7 +92,7 @@ class SMT {
const dels = [];
const ins = [];
let rtOld = mimc7.multiHash([key, resFind.foundValue], bigInt.one);
let rtOld = hash1(key, resFind.foundValue);
let rtNew;
dels.push(rtOld);
@@ -130,9 +130,9 @@ class SMT {
}
const oldSibling = resFind.siblings[level];
if (keyBits[level]) {
rtOld = mimc7.multiHash([oldSibling, rtOld], bigInt.zero);
rtOld = hash0(oldSibling, rtOld);
} else {
rtOld = mimc7.multiHash([rtOld, oldSibling], bigInt.zero);
rtOld = hash0(rtOld, oldSibling);
}
dels.push(rtOld);
if (!newSibling.isZero()) {
@@ -147,7 +147,7 @@ class SMT {
} else {
newNode = [rtNew, newSibling];
}
rtNew = mimc7.multiHash(newNode, bigInt.zero);
rtNew = hash0(newNode[0], newNode[1]);
ins.push([rtNew, newNode]);
}
}
@@ -185,7 +185,7 @@ class SMT {
for (let i= res.siblings.length; oldKeyits[i] == newKeyBits[i]; i++) {
res.siblings.push(bigInt.zero);
}
rtOld = mimc7.multiHash([resFind.notFoundKey, resFind.notFoundValue], bigInt.one);
rtOld = hash1(resFind.notFoundKey, resFind.notFoundValue);
res.siblings.push(rtOld);
addedOne = true;
mixed = false;
@@ -197,7 +197,7 @@ class SMT {
const inserts = [];
const dels = [];
let rt = mimc7.multiHash([key, value], bigInt.one);
let rt = hash1(key, value);
inserts.push([rt,[1, key, value]] );
for (let i=res.siblings.length-1; i>=0; i--) {
@@ -207,9 +207,9 @@ class SMT {
if (mixed) {
const oldSibling = resFind.siblings[i];
if (newKeyBits[i]) {
rtOld = mimc7.multiHash([oldSibling, rtOld], bigInt.zero);
rtOld = hash0(oldSibling, rtOld);
} else {
rtOld = mimc7.multiHash([rtOld, oldSibling], bigInt.zero);
rtOld = hash0(rtOld, oldSibling);
}
dels.push(rtOld);
}
@@ -217,10 +217,10 @@ class SMT {
let newRt;
if (newKeyBits[i]) {
newRt = mimc7.multiHash([res.siblings[i], rt], bigInt.zero);
newRt = hash0(res.siblings[i], rt);
inserts.push([newRt,[res.siblings[i], rt]] );
} else {
newRt = mimc7.multiHash([rt, res.siblings[i]], bigInt.zero);
newRt = hash0(rt, res.siblings[i]);
inserts.push([newRt,[rt, res.siblings[i]]] );
}
rt = newRt;

10
src/smt_hashes_mimc.js Normal file
View File

@@ -0,0 +1,10 @@
const mimc7 = require("./mimc7");
const bigInt = require("snarkjs").bigInt;
exports.hash0 = function (left, right) {
return mimc7.multiHash(left, right);
};
exports.hash1 = function(key, value) {
return mimc7.multiHash([key, value], bigInt.one);
};

View File

@@ -0,0 +1,12 @@
const Poseidon = require("./poseidon");
const bigInt = require("snarkjs").bigInt;
const hash = Poseidon.createHash(6, 8, 57);
exports.hash0 = function (left, right) {
return hash([left, right]);
};
exports.hash1 = function(key, value) {
return hash([key, value, bigInt.one]);
};

View File

@@ -3,10 +3,12 @@ const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const createBlakeHash = require("blake-hash");
const eddsa = require("../src/eddsa.js");
const assert = chai.assert;
const bigInt = require("big-integer");
const bigInt = require("snarkjs").bigInt;
describe("Baby Jub test", function () {
let circuitAdd;
@@ -22,6 +24,11 @@ describe("Baby Jub test", function () {
const cirDefTest = await compiler(path.join(__dirname, "circuits", "babycheck_test.circom"));
circuitTest = new snarkjs.Circuit(cirDefTest);
console.log("NConstrains BabyTest: " + circuitTest.nConstraints);
const cirDefPbk = await compiler(path.join(__dirname, "circuits", "babypbk_test.circom"));
circuitPbk = new snarkjs.Circuit(cirDefPbk);
console.log("NConstrains BabyPbk: " + circuitPbk.nConstraints);
});
it("Should add point (0,1) and (0,1)", async () => {
@@ -97,4 +104,22 @@ describe("Baby Jub test", function () {
}
});
it("Should extract the public key from the private one", async () => {
const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex");
const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0,32));
const S = bigInt.leBuff2int(pvk).shr(3);
const A = eddsa.prv2pub(rawpvk);
const input = {
in : S,
Ax : A[0],
Ay : A[1]
}
const w = circuitPbk.calculateWitness(input);
assert(circuitPbk.checkWitness(w));
});
});

166
test/babyjub_js.js Normal file
View File

@@ -0,0 +1,166 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const babyjub = require("../src/babyjub.js");
const assert = chai.assert;
// const bigInt = require("big-integer");
describe("Baby Jub js test", function () {
this.timeout(100000);
it("Should add point (0,1) and (0,1)", () => {
const p1 = [
snarkjs.bigInt(0),
snarkjs.bigInt(1)];
const p2 = [
snarkjs.bigInt(0),
snarkjs.bigInt(1)
];
const out = babyjub.addPoint(p1, p2)
assert(out[0].equals(0));
assert(out[1].equals(1));
});
it("Should base be 8*generator", () => {
let res;
res = babyjub.addPoint(babyjub.Generator, babyjub.Generator);
res = babyjub.addPoint(res, res);
res = babyjub.addPoint(res, res);
assert(res[0].equals(babyjub.Base8[0]));
assert(res[1].equals(babyjub.Base8[1]));
});
it("Should add 2 same numbers", () => {
const p1 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
const p2 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
const out = babyjub.addPoint(p1, p2)
assert(out[0].equals(snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365")));
assert(out[1].equals(snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889")));
});
it("Should add 2 different numbers", () => {
const p1 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
const p2 = [
snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"),
snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"),
];
const out = babyjub.addPoint(p1, p2)
assert(out[0].equals(snarkjs.bigInt("7916061937171219682591368294088513039687205273691143098332585753343424131937")));
assert(out[1].equals(snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499")));
});
it("should mulPointEscalar 0", () => {
const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("3"));
let r2 = babyjub.addPoint(p, p);
r2 = babyjub.addPoint(r2, p);
assert.equal(r2[0].toString(), r[0].toString());
assert.equal(r2[1].toString(), r[1].toString());
assert.equal(r[0].toString(), "19372461775513343691590086534037741906533799473648040012278229434133483800898");
assert.equal(r[1].toString(), "9458658722007214007257525444427903161243386465067105737478306991484593958249");
});
it("should mulPointEscalar 1", () => {
const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499"));
assert.equal(r[0].toString(), "17070357974431721403481313912716834497662307308519659060910483826664480189605");
assert.equal(r[1].toString(), "4014745322800118607127020275658861516666525056516280575712425373174125159339");
});
it("should mulPointEscalar 2", () => {
const p = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
];
const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"));
assert.equal(r[0].toString(), "13563888653650925984868671744672725781658357821216877865297235725727006259983");
assert.equal(r[1].toString(), "8442587202676550862664528699803615547505326611544120184665036919364004251662");
});
it("should inCurve 1", () => {
const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
assert(babyjub.inCurve(p));
});
it("should inCurve 2", () => {
const p = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
];
assert(babyjub.inCurve(p));
});
it("should inSubgroup 1", () => {
const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
assert(babyjub.inSubgroup(p));
});
it("should inSubgroup 2", () => {
const p = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
];
assert(babyjub.inSubgroup(p));
});
it("should packPoint - unpackPoint 1", () => {
const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
];
const buf = babyjub.packPoint(p);
assert.equal(buf.toString('hex'), '53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85');
const p2 = babyjub.unpackPoint(buf);
assert.equal(p2[0].toString(), "17777552123799933955779906779655732241715742912184938656739573121738514868268");
assert.equal(p2[1].toString(), "2626589144620713026669568689430873010625803728049924121243784502389097019475");
});
it("should packPoint - unpackPoint 2", () => {
const p = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
];
const buf = babyjub.packPoint(p);
assert.equal(buf.toString('hex'), 'e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709');
const p2 = babyjub.unpackPoint(buf);
assert.equal(p2[0].toString(), "6890855772600357754907169075114257697580319025794532037257385534741338397365");
assert.equal(p2[1].toString(), "4338620300185947561074059802482547481416142213883829469920100239455078257889");
});
});

View File

@@ -0,0 +1,3 @@
include "../../circuits/babyjub.circom";
component main = BabyPbk();

View File

@@ -0,0 +1,3 @@
include "../../circuits/eddsaposeidon.circom";
component main = EdDSAPoseidonVerifier();

View File

@@ -7,8 +7,8 @@ template Main() {
var i;
var base = [17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475]
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]
component escalarMul = EscalarMul(256, base);

View File

@@ -6,8 +6,8 @@ template Main() {
signal input in;
signal output out[2];
var base = [17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475]
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]
component n2b = Num2Bits(253);

View File

@@ -7,8 +7,8 @@ template Main() {
var i;
var base = [17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475]
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]
component escalarMul = EscalarMul(256, base);

View File

@@ -6,8 +6,8 @@ template Main() {
signal input e;
signal output out[2];
var base = [17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475]
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]
component n2b = Num2Bits(253);

View File

@@ -1,6 +1,6 @@
include "../../circuits/escalarmulw4table.circom";
var base = [17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475]
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]
component main = EscalarMulW4Table(base, 0);

View File

@@ -1,6 +1,17 @@
include "../../circuits/escalarmulw4table.circom";
var base = [17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475];
component main = EscalarMulW4Table(base, 0);
template Main() {
signal input in;
signal output out[16][2];
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203];
component escalarMul = EscalarMulW4Table(base, 0);
for (var i=0; i<16; i++) {
out[i][0] <== escalarMul.out[i][0]*in;
out[i][1] <== escalarMul.out[i][1]*in;
}
}
component main = Main();

View File

@@ -1,6 +1,17 @@
include "../../circuits/escalarmulw4table.circom";
var base = [17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475]
component main = EscalarMulW4Table(base, 3);
template Main() {
signal input in;
signal output out[16][2];
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203];
component escalarMul = EscalarMulW4Table(base, 3);
for (var i=0; i<16; i++) {
out[i][0] <== escalarMul.out[i][0]*in;
out[i][1] <== escalarMul.out[i][1]*in;
}
}
component main = Main();

View File

@@ -0,0 +1,4 @@
include "../../circuits/comparators.circom";
component main = GreaterEqThan(32);

View File

@@ -0,0 +1,4 @@
include "../../circuits/comparators.circom";
component main = GreaterThan(32);

View File

@@ -0,0 +1,4 @@
include "../../circuits/comparators.circom";
component main = LessEqThan(32);

View File

@@ -0,0 +1,3 @@
include "../../circuits/mimcsponge.circom"
component main = MiMCSponge(2, 220, 3);

View File

@@ -0,0 +1,3 @@
include "../../circuits/mimcsponge.circom"
component main = MiMCFeistel(220);

View File

@@ -0,0 +1,31 @@
include "../../circuits/mux1.circom";
include "../../circuits/bitify.circom";
template Constants() {
var i;
signal output out[2];
out[0] <== 37;
out[1] <== 47;
}
template Main() {
var i;
signal private input selector;
signal output out;
component mux = Mux1();
component n2b = Num2Bits(1);
component cst = Constants();
selector ==> n2b.in;
n2b.out[0] ==> mux.s;
for (i=0; i<2; i++) {
cst.out[i] ==> mux.c[i];
}
mux.out ==> out;
}
component main = Main();

View File

@@ -0,0 +1,35 @@
include "../../circuits/mux2.circom";
include "../../circuits/bitify.circom";
template Constants() {
var i;
signal output out[4];
out[0] <== 37;
out[1] <== 47;
out[2] <== 53;
out[3] <== 71;
}
template Main() {
var i;
signal private input selector;
signal output out;
component mux = Mux2();
component n2b = Num2Bits(2);
component cst = Constants();
selector ==> n2b.in;
for (i=0; i<2; i++) {
n2b.out[i] ==> mux.s[i];
}
for (i=0; i<4; i++) {
cst.out[i] ==> mux.c[i];
}
mux.out ==> out;
}
component main = Main();

View File

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

View File

@@ -0,0 +1,3 @@
include "../../circuits/sha256/sha256.circom";
component main = Sha256(448);

View File

@@ -0,0 +1,3 @@
include "../../circuits/sha256/sha256.circom";
component main = Sha256(512);

View File

@@ -36,7 +36,7 @@ describe("Sum test", () => {
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
});
it("Should create a comparison", async() => {
it("Should create a comparison lessthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "lessthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
@@ -74,4 +74,120 @@ describe("Sum test", () => {
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
});
it("Should create a comparison lesseqthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "lesseqthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
let witness;
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
});
it("Should create a comparison greaterthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "greaterthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
let witness;
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
});
it("Should create a comparison greatereqthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "greatereqthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstraints BalancesUpdater: " + circuit.nConstraints);
let witness;
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt(1)));
});
});

82
test/eddsa_js.js Normal file
View File

@@ -0,0 +1,82 @@
const chai = require("chai");
const snarkjs = require("snarkjs");
const eddsa = require("../src/eddsa.js");
const babyJub = require("../src/babyjub.js");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
describe("EdDSA js test", function () {
this.timeout(100000);
it("Sign (using Mimc7) a single 10 bytes from 0 to 9", () => {
const msgBuf = Buffer.from("00010203040506070809", "hex");
const msg = bigInt.leBuff2int(msgBuf);
// const prvKey = crypto.randomBytes(32);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
assert.equal(pubKey[0].toString(),
"13277427435165878497778222415993513565335242147425444199013288855685581939618");
assert.equal(pubKey[1].toString(),
"13622229784656158136036771217484571176836296686641868549125388198837476602820");
const pPubKey = babyJub.packPoint(pubKey);
const signature = eddsa.signMiMC(prvKey, msg);
assert.equal(signature.R8[0].toString(),
"11384336176656855268977457483345535180380036354188103142384839473266348197733");
assert.equal(signature.R8[1].toString(),
"15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(),
"2523202440825208709475937830811065542425109372212752003460238913256192595070");
const pSignature = eddsa.packSignature(signature);
assert.equal(pSignature.toString("hex"), ""+
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"7ed40dab29bf993c928e789d007387998901a24913d44fddb64b1f21fc149405");
const uSignature = eddsa.unpackSignature(pSignature);
assert(eddsa.verifyMiMC(msg, uSignature, pubKey));
});
it("Sign (using Poseidon) a single 10 bytes from 0 to 9", () => {
const msgBuf = Buffer.from("00010203040506070809", "hex");
const msg = bigInt.leBuff2int(msgBuf);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
assert.equal(pubKey[0].toString(),
"13277427435165878497778222415993513565335242147425444199013288855685581939618");
assert.equal(pubKey[1].toString(),
"13622229784656158136036771217484571176836296686641868549125388198837476602820");
const pPubKey = babyJub.packPoint(pubKey);
const signature = eddsa.signPoseidon(prvKey, msg);
assert.equal(signature.R8[0].toString(),
"11384336176656855268977457483345535180380036354188103142384839473266348197733");
assert.equal(signature.R8[1].toString(),
"15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(),
"248298168863866362217836334079793350221620631973732197668910946177382043688");
const pSignature = eddsa.packSignature(signature);
assert.equal(pSignature.toString("hex"), ""+
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00");
const uSignature = eddsa.unpackSignature(pSignature);
assert(eddsa.verifyPoseidon(msg, uSignature, pubKey));
});
});

View File

@@ -19,7 +19,7 @@ describe("EdDSA MiMC test", function () {
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains EdDSA: " + circuit.nConstraints);
console.log("NConstrains EdDSA MiMC: " + circuit.nConstraints);
});
it("Sign a single number", async () => {

98
test/eddsaposeidon.js Normal file
View File

@@ -0,0 +1,98 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const eddsa = require("../src/eddsa.js");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
describe("EdDSA Poseidon test", function () {
let circuit;
this.timeout(100000);
before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "eddsaposeidon_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains EdDSA Poseidon: " + circuit.nConstraints);
});
it("Sign a single number", async () => {
const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signPoseidon(prvKey, msg);
assert(eddsa.verifyPoseidon(msg, signature, pubKey));
const w = circuit.calculateWitness({
enabled: 1,
Ax: pubKey[0],
Ay: pubKey[1],
R8x: signature.R8[0],
R8y: signature.R8[1],
S: signature.S,
M: msg});
assert(circuit.checkWitness(w));
});
it("Detect Invalid signature", async () => {
const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signPoseidon(prvKey, msg);
assert(eddsa.verifyPoseidon(msg, signature, pubKey));
try {
circuit.calculateWitness({
enabled: 1,
Ax: pubKey[0],
Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1],
S: signature.S,
M: msg});
assert(false);
} catch(err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0");
}
});
it("Test a dissabled circuit with a bad signature", async () => {
const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signPoseidon(prvKey, msg);
assert(eddsa.verifyPoseidon(msg, signature, pubKey));
const w = circuit.calculateWitness({
enabled: 0,
Ax: pubKey[0],
Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1],
S: signature.S,
M: msg});
assert(circuit.checkWitness(w));
});
});

View File

@@ -36,10 +36,10 @@ describe("Exponentioation test", () => {
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({});
const w = circuit.calculateWitness({in: 1});
let g = [bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")]
let g = [bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
dbl= [bigInt("0"), snarkjs.bigInt("1")];
@@ -72,10 +72,10 @@ describe("Exponentioation test", () => {
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({});
const w = circuit.calculateWitness({in: 1});
let g = [snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")]
let g = [snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
for (let i=0; i<12;i++) {
g = addPoint(g,g);
@@ -116,8 +116,8 @@ describe("Exponentioation test", () => {
assert(circuit.checkWitness(w));
let g = [snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")]
let g = [snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
let c = [0n, 1n];

View File

@@ -18,8 +18,8 @@ describe("Escalarmul test", function () {
this.timeout(100000);
let g = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
];
before( async() => {

View File

@@ -50,6 +50,51 @@ describe("Escalarmul test", function () {
assert(yout.equals(babyjub.Base8[1]));
});
it("Should generate scalar mul of a specific constant", async () => {
const s = bigInt("2351960337287830298912035165133676222414898052661454064215017316447594616519");
const base8 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
];
const w = circuit.calculateWitness({"e": s});
assert(circuit.checkWitness(w));
const xout = w[circuit.getSignalIdx("main.out[0]")];
const yout = w[circuit.getSignalIdx("main.out[1]")];
const expectedRes = babyjub.mulPointEscalar(base8, s);
assert(xout.equals(expectedRes[0]));
assert(yout.equals(expectedRes[1]));
});
it("Should generate scalar mul of the firsts 50 elements", async () => {
const base8 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
];
for (let i=0; i<50; i++) {
const s = bigInt(i);
const w = circuit.calculateWitness({"e": s});
assert(circuit.checkWitness(w));
const xout = w[circuit.getSignalIdx("main.out[0]")];
const yout = w[circuit.getSignalIdx("main.out[1]")];
const expectedRes = babyjub.mulPointEscalar(base8, s);
assert(xout.equals(expectedRes[0]));
assert(yout.equals(expectedRes[1]));
}
});
it("If multiply by order should return 0", async () => {
const w = circuit.calculateWitness({"e": babyjub.subOrder });

32
test/mimc7.js Normal file
View File

@@ -0,0 +1,32 @@
const chai = require("chai");
const assert = chai.assert;
const bigInt = require("snarkjs").bigInt;
const mimc7 = require("../src/mimc7.js");
describe('mimc7 primitives', () => {
it('hash two bigInt', () => {
const h = mimc7.hash(bigInt(12), bigInt(45));
assert.equal(h.toString(), '19746142529723647765530752502670948774458299263315590587358840390982005703908');
});
it('hash bigInt array (multiHash)', () => {
const h1 = mimc7.multiHash([bigInt(12)]);
assert.equal(h1.toString(), '16051049095595290701999129793867590386356047218708919933694064829788708231421');
const h2 = mimc7.multiHash([bigInt(78), bigInt(41)]);
assert.equal(h2.toString(), '2938611815373543102852102540059918590261345652613741345181300284995514063984');
const h4 = mimc7.multiHash([bigInt(12), bigInt(45)]);
assert.equal(h4.toString(), '9949998637984578981906561631883120271399801229641312099559043216173958006905');
const h5 = mimc7.multiHash([bigInt(12), bigInt(45), bigInt(78), bigInt(41)]);
assert.equal(h5.toString(), '18226366069841799622585958305961373004333097209608110160936134895615261821931');
});
it('mimc7 hash buffer', () => {
const msg = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
const msgBuff = Buffer.from(msg, 'utf-8');
let h = mimc7.hashBuffer(msgBuff);
assert.equal(h.toString(), '16855787120419064316734350414336285711017110414939748784029922801367685456065');
});
});

View File

@@ -1,4 +1,4 @@
const TestRPC = require("ganache-cli");
const ganache = require("ganache-cli");
const Web3 = require("web3");
const chai = require("chai");
const mimcGenContract = require("../src/mimc_gencontract.js");
@@ -10,35 +10,31 @@ const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); };
const SEED = "mimc";
describe("MiMC Smart contract test", () => {
describe("MiMC Smart contract test", function () {
let testrpc;
let web3;
let mimc;
let accounts;
this.timeout(100000);
before(async () => {
testrpc = TestRPC.server({
ws: true,
gasLimit: 5800000,
total_accounts: 10,
});
testrpc.listen(8546, "127.0.0.1");
web3 = new Web3("ws://127.0.0.1:8546");
web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 });
accounts = await web3.eth.getAccounts();
});
after(async () => testrpc.close());
it("Should deploy the contract", async () => {
const C = new web3.eth.Contract(mimcGenContract.abi);
mimc = await C.deploy({
data: mimcGenContract.createCode(SEED, 91)
data: mimcGenContract.createCode(SEED, 91),
arguments: []
}).send({
gas: 1500000,
gasPrice: '30000000000000',
from: accounts[0]
}).on("error", (error) => {
console.log("ERROR: "+error);
});
});

58
test/mimcspongecircuit.js Normal file
View File

@@ -0,0 +1,58 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const mimcjs = require("../src/mimcsponge.js");
const assert = chai.assert;
describe("MiMC Sponge Circuit test", function () {
let circuit;
this.timeout(100000);
it("Should check permutation", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_sponge_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("MiMC Feistel constraints: " + circuit.nConstraints);
const w = circuit.calculateWitness({xL_in: 1, xR_in: 2, k: 3});
const xLout = w[circuit.getSignalIdx("main.xL_out")];
const xRout = w[circuit.getSignalIdx("main.xR_out")];
const out2 = mimcjs.hash(1,2,3);
assert.equal(xLout.toString(), out2.xL.toString());
assert.equal(xRout.toString(), out2.xR.toString());
assert(circuit.checkWitness(w));
});
it("Should check hash", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_sponge_hash_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("MiMC Sponge constraints: " + circuit.nConstraints);
const w = circuit.calculateWitness({ins: [1, 2], k: 0});
const o1 = w[circuit.getSignalIdx("main.outs[0]")];
const o2 = w[circuit.getSignalIdx("main.outs[1]")];
const o3 = w[circuit.getSignalIdx("main.outs[2]")];
const out2 = mimcjs.multiHash([1,2], 0, 3);
assert.equal(o1.toString(), out2[0].toString());
assert.equal(o2.toString(), out2[1].toString());
assert.equal(o3.toString(), out2[2].toString());
assert(circuit.checkWitness(w));
});
});

View File

@@ -0,0 +1,43 @@
const ganache = require("ganache-cli");
const Web3 = require("web3");
const chai = require("chai");
const mimcGenContract = require("../src/mimcsponge_gencontract.js");
const mimcjs = require("../src/mimcsponge.js");
const assert = chai.assert;
const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); };
const SEED = "mimcsponge";
describe("MiMC Sponge Smart contract test", () => {
let testrpc;
let web3;
let mimc;
let accounts;
before(async () => {
web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 });
accounts = await web3.eth.getAccounts();
});
it("Should deploy the contract", async () => {
const C = new web3.eth.Contract(mimcGenContract.abi);
mimc = await C.deploy({
data: mimcGenContract.createCode(SEED, 220)
}).send({
gas: 3500000,
from: accounts[0]
});
});
it("Shold calculate the mimc correctly", async () => {
const res = await mimc.methods.MiMCSponge(1,2,3).call();
const res2 = await mimcjs.hash(1,2,3);
assert.equal(res.xL.toString(), res2.xL.toString());
assert.equal(res.xR.toString(), res2.xR.toString());
});
});

View File

@@ -1,51 +0,0 @@
const chai = require("chai");
const snarkjs = require("snarkjs");
const mimcjs = require("../src/mimc7.js");
const expect = chai.expect;
const bigInt = snarkjs.bigInt;
function bytesToHex(buff) {
return `0x${buff.toString("hex")}`;
}
function bigIntToBuffer(number) {
const buff = Buffer.alloc(32);
let pos = buff.length - 1;
while (!number.isZero()) {
buff[pos] = number.and(255);
number = number.shiftRight(8);
pos -= 1;
}
return buff;
}
describe("[mimc hash] Javascript test", function () {
this.timeout(100000);
before( async () => {
});
it("Mimc7 hash with 1 entry", () => {
const entries = [bigInt(12)];
const hash = mimcjs.multiHash(entries);
const hashHex = bytesToHex(bigIntToBuffer(hash));
expect(hashHex).to.be.equal("0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd");
});
it("Mimc7 hash with 2 entries", () => {
const entries = [bigInt(12), bigInt(45), bigInt(78), bigInt(41)];
const hi = mimcjs.multiHash(entries.slice(2));
const hiHex = bytesToHex(bigIntToBuffer(hi));
expect(hiHex).to.be.equal("0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70");
const hv = mimcjs.multiHash(entries.slice(0, 2));
const hvHex = bytesToHex(bigIntToBuffer(hv));
expect(hvHex).to.be.equal("0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879");
});
it("Mimc7 hash with 4 entries", () => {
const entries = [bigInt(12), bigInt(45), bigInt(78), bigInt(41)];
const hash = mimcjs.multiHash(entries);
const hashHex = bytesToHex(bigIntToBuffer(hash));
expect(hashHex).to.be.equal("0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb");
});
});

View File

@@ -15,8 +15,8 @@ describe("Montgomery test", function () {
let circuitMDouble;
let g = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")];
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")];
let mg, mg2, g2, g3, mg3;

View File

@@ -9,7 +9,7 @@ const bigInt = snarkjs.bigInt;
describe("Mux4 test", () => {
it("Should create a constant multiplexer", async () => {
it("Should create a constant multiplexer 4", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mux4_1.circom"));
@@ -50,7 +50,7 @@ describe("Mux4 test", () => {
}
});
it("Should create a constant multiplexer", async () => {
it("Should create a constant multiplexer 3", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mux3_1.circom"));
@@ -74,6 +74,52 @@ describe("Mux4 test", () => {
assert(w[0].equals(bigInt(1)));
// console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());
assert(w[circuit.getSignalIdx("main.out")].equals(ct8[i]));
}
});
it("Should create a constant multiplexer 2", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mux2_1.circom"));
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Mux2: " + circuit.nConstraints);
const ct8 = [
bigInt("37"),
bigInt("47"),
bigInt("53"),
bigInt("71"),
];
for (let i=0; i<4; i++) {
const w = circuit.calculateWitness({ "selector": i });
assert(w[0].equals(bigInt(1)));
// console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());
assert(w[circuit.getSignalIdx("main.out")].equals(ct8[i]));
}
});
it("Should create a constant multiplexer 1", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mux1_1.circom"));
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Mux1: " + circuit.nConstraints);
const ct8 = [
bigInt("37"),
bigInt("47"),
];
for (let i=0; i<2; i++) {
const w = circuit.calculateWitness({ "selector": i });
assert(w[0].equals(bigInt(1)));
// console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());
assert(w[circuit.getSignalIdx("main.out")].equals(ct8[i]));
}

41
test/poseidon.js Normal file
View File

@@ -0,0 +1,41 @@
const chai = require("chai");
const assert = chai.assert;
const bigInt = require("snarkjs").bigInt;
const poseidon = require("../src/poseidon.js");
describe('poseidon primitives', () => {
it('poseidon two bigInt', () => {
const poseidonHash = poseidon.createHash();
const h1 = poseidonHash([bigInt(1), bigInt(2)]);
assert.equal(h1.toString(), '12242166908188651009877250812424843524687801523336557272219921456462821518061');
const h2 = poseidonHash([bigInt(3), bigInt(4)]);
assert.equal(h2.toString(), '17185195740979599334254027721507328033796809509313949281114643312710535000993');
});
it('poseidon bigInt array (multiHash)', () => {
const msg = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
const msgBuff = Buffer.from(msg, 'utf-8');
const n = 31;
const msgArray = [];
const fullParts = Math.floor(msgBuff.length / n);
for (let i = 0; i < fullParts; i++) {
const v = bigInt.leBuff2int(msgBuff.slice(n * i, n * (i + 1)));
msgArray.push(v);
}
if (msgBuff.length % n !== 0) {
const v = bigInt.leBuff2int(msgBuff.slice(fullParts * n));
msgArray.push(v);
}
let h = poseidon.multiHash(msgArray);
assert.equal(h.toString(), '11821124228916291136371255062457365369197326845706357273715164664419275913793');
});
it('poseidon hash buffer', () => {
const msg = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
const msgBuff = Buffer.from(msg, 'utf-8');
let h = poseidon.hashBuffer(msgBuff);
assert.equal(h.toString(), '11821124228916291136371255062457365369197326845706357273715164664419275913793');
});
});

60
test/poseidoncircuit.js Normal file
View File

@@ -0,0 +1,60 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
var blake2b = require('blake2b');
const poseidon = require("../src/poseidon.js");
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');
h = blake2b(output.length).update(input).digest('hex')
assert.equal('e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1', h);
});
});
describe("Poseidon Circuit test", function () {
let circuit;
this.timeout(100000);
before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "poseidon_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("Poseidon constraints: " + circuit.nConstraints);
});
it("Should check constrain of hash([1, 2])", async () => {
const w = circuit.calculateWitness({inputs: [1, 2]});
const res = w[circuit.getSignalIdx("main.out")];
const hash = poseidon.createHash(6, 8, 57);
const res2 = hash([1,2]);
assert.equal('12242166908188651009877250812424843524687801523336557272219921456462821518061', res2.toString());
assert.equal(res.toString(), res2.toString());
assert(circuit.checkWitness(w));
});
it("Should check constrain of hash([3, 4])", async () => {
const w = circuit.calculateWitness({inputs: [3, 4]});
const res = w[circuit.getSignalIdx("main.out")];
const hash = poseidon.createHash(6, 8, 57);
const res2 = hash([3, 4]);
assert.equal('17185195740979599334254027721507328033796809509313949281114643312710535000993', res2.toString());
assert.equal(res.toString(), res2.toString());
assert(circuit.checkWitness(w));
});
});

49
test/poseidoncontract.js Normal file
View File

@@ -0,0 +1,49 @@
const ganache = require("ganache-cli");
const Web3 = require("web3");
const chai = require("chai");
const poseidonGenContract = require("../src/poseidon_gencontract.js");
const Poseidon = require("../src/poseidon.js");
const bigInt = require("snarkjs").bigInt;
const assert = chai.assert;
const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); };
const SEED = "mimc";
describe("Poseidon Smart contract test", () => {
let testrpc;
let web3;
let mimc;
let accounts;
before(async () => {
web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 });
accounts = await web3.eth.getAccounts();
});
it("Should deploy the contract", async () => {
const C = new web3.eth.Contract(poseidonGenContract.abi);
mimc = await C.deploy({
data: poseidonGenContract.createCode()
}).send({
gas: 2500000,
from: accounts[0]
});
});
it("Shold calculate the mimic correctly", async () => {
const res = await mimc.methods.poseidon([1,2]).call();
// console.log("Cir: " + bigInt(res.toString(16)).toString(16));
const hash = Poseidon.createHash(6, 8, 57);
const res2 = hash([1,2]);
// console.log("Ref: " + bigInt(res2).toString(16));
assert.equal(res.toString(), res2.toString());
});
});

View File

@@ -12,8 +12,43 @@ const sha256 = require("./helpers/sha256");
// const printSignal = require("./helpers/printsignal");
function buffer2bitArray(b) {
const res = [];
for (let i=0; i<b.length; i++) {
for (let j=0; j<8; j++) {
res.push((b[i] >> (7-j) &1));
}
}
return res;
}
function bitArray2buffer(a) {
const len = Math.floor((a.length -1 )/8)+1;
const b = new Buffer.alloc(len);
for (let i=0; i<a.length; i++) {
const p = Math.floor(i/8);
b[p] = b[p] | (Number(a[i]) << ( 7 - (i%8) ));
}
return b;
}
describe("SHA256 test", () => {
it("Should calculate a hash", async () => {
it("Should work bits to array and array to bits", async () => {
const b = new Buffer.alloc(64);
for (let i=0; i<64; i++) {
b[i] = i+1;
}
const a = buffer2bitArray(b);
const b2 = bitArray2buffer(a);
assert.equal(b.toString("hex"), b2.toString("hex"));
});
it("Should calculate a hash of 1 compressor", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_2_test.circom"));
const circuit = new snarkjs.Circuit(cirDef);
@@ -38,5 +73,64 @@ describe("SHA256 test", () => {
assert(witness[1].equals(snarkjs.bigInt(r)));
}).timeout(1000000);
it("Should calculate a hash of 2 compressor", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_test512.circom"), {reduceConstraints:false} );
const circuit = new snarkjs.Circuit(cirDef);
console.log("Vars: "+circuit.nVars);
console.log("Constraints: "+circuit.nConstraints);
/*
const testStr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
const b = Buffer.from(testStr, 'utf8');
*/
const b = new Buffer.alloc(64);
for (let i=0; i<64; i++) {
b[i] = i+1;
}
const hash = crypto.createHash("sha256")
.update(b)
.digest("hex");
const arrIn = buffer2bitArray(b);
const witness = circuit.calculateWitness({ "in": arrIn } /*, {logOutput: true} */);
const arrOut = witness.slice(1, 257);
const hash2 = bitArray2buffer(arrOut).toString("hex");
assert.equal(hash, hash2);
}).timeout(1000000);
it("Should calculate a hash of 2 compressor", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_test448.circom"), {reduceConstraints:false} );
const circuit = new snarkjs.Circuit(cirDef);
console.log("Vars: "+circuit.nVars);
console.log("Constraints: "+circuit.nConstraints);
const testStr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
const b = Buffer.from(testStr, 'utf8');
for (let i=0; i<64; i++) {
b[i] = i+1;
}
const hash = crypto.createHash("sha256")
.update(b)
.digest("hex");
const arrIn = buffer2bitArray(b);
const witness = circuit.calculateWitness({ "in": arrIn } /*, {logOutput: true} */);
const arrOut = witness.slice(1, 257);
const hash2 = bitArray2buffer(arrOut).toString("hex");
assert.equal(hash, hash2);
}).timeout(1000000);
});

View File

@@ -84,7 +84,7 @@ describe("SMT test", function () {
let circuit;
let tree;
this.timeout(100000);
this.timeout(10000000);
before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "smtprocessor10_test.circom"));

View File

@@ -1,147 +0,0 @@
const chai = require("chai");
const snarkjs = require("snarkjs");
const smt = require("../src/smt.js");
const mimcjs = require("../src/mimc7.js");
const expect = chai.expect;
const bigInt = snarkjs.bigInt;
function bytesToHex(buff) {
return `0x${buff.toString("hex")}`;
}
function bigIntToBuffer(number) {
const buff = Buffer.alloc(32);
let pos = buff.length - 1;
while (!number.isZero()) {
buff[pos] = number.and(255);
number = number.shiftRight(8);
pos -= 1;
}
return buff;
}
function newEntry(arr) {
return {
hi: mimcjs.multiHash(arr.slice(2)),
hv: mimcjs.multiHash(arr.slice(0, 2)),
};
}
describe("[sparse-merkle-tree] Javascript test", function () {
this.timeout(100000);
before( async () => {
});
it("Add one claim", async () => {
const claim = [bigInt(12), bigInt(45), bigInt(78), bigInt(41)];
const entries = newEntry(claim);
const tree = await smt.newMemEmptyTrie();
const key1 = entries.hi;
const value1 = entries.hv;
await tree.insert(key1,value1);
const root = tree.root;
const rootBuff = bigIntToBuffer(root);
expect(bytesToHex(rootBuff)).to.be.equal("0x2bf39430aa2482fc1e2f170179c8cab126b0f55f71edc8d333f4c80cb4e798f5");
});
/*
it("Add two claims", async () => {
const firstClaim = [bigInt(12), bigInt(45), bigInt(78), bigInt(41)];
const firstEntries = newEntry(firstClaim);
const secondClaim = [bigInt(33), bigInt(44), bigInt(55), bigInt(66)];
const secondEntries = newEntry(secondClaim);
const tree = await smt.newMemEmptyTrie();
const key1 = firstEntries.hi;
const value1 = firstEntries.hv;
const key2 = secondEntries.hi;
const value2 = secondEntries.hv;
await tree.insert(key1,value1);
await tree.insert(key2,value2);
const root = tree.root;
const rootBuff = bigIntToBuffer(root);
expect(bytesToHex(rootBuff)).to.be.equal("0x1fb755a3677f8fd6c47b5462b69778ef6383c31d2d498b765e953f8cacaa6744");
});
it("Add claims in different orders", async () => {
const tree1 = await smt.newMemEmptyTrie();
for (let i = 0; i < 16; i++) {
const claim = [bigInt(0), bigInt(i), bigInt(0), bigInt(i)];
const entries = newEntry(claim);
await tree1.insert(entries.hi, entries.hv);
}
const tree2 = await smt.newMemEmptyTrie();
for (let i = 0; i < 16; i++) {
const claim = [bigInt(0), bigInt(i), bigInt(0), bigInt(i)];
const entries = newEntry(claim);
await tree2.insert(entries.hi, entries.hv);
}
const root1 = bigIntToBuffer(tree1.root);
const root2 = bigIntToBuffer(tree2.root);
expect(bytesToHex(root1)).to.be.equal(bytesToHex(root2));
expect(bytesToHex(root1)).to.be.equal("0x173fd27f6622526dfb21c4d8d83e3c95adba5d8f46a397113e4e80e629c6de76");
});
it("Insert 3 elements in different order into different trees", async () => {
const claim1 = [bigInt(33), bigInt(44), bigInt(55), bigInt(66)];
const entries1 = newEntry(claim1);
const claim2 = [bigInt(1111), bigInt(2222), bigInt(3333), bigInt(4444)];
const entries2 = newEntry(claim2);
const claim3 = [bigInt(5555), bigInt(6666), bigInt(7777), bigInt(8888)];
const entries3 = newEntry(claim3);
const tree1 = await smt.newMemEmptyTrie();
const tree2 = await smt.newMemEmptyTrie();
const tree3 = await smt.newMemEmptyTrie();
const tree4 = await smt.newMemEmptyTrie();
const tree5 = await smt.newMemEmptyTrie();
const tree6 = await smt.newMemEmptyTrie();
await tree1.insert(entries1.hi,entries1.hv);
await tree1.insert(entries2.hi,entries2.hv);
await tree1.insert(entries3.hi,entries3.hv);
await tree2.insert(entries1.hi,entries1.hv);
await tree2.insert(entries3.hi,entries3.hv);
await tree2.insert(entries2.hi,entries2.hv);
await tree3.insert(entries2.hi,entries2.hv);
await tree3.insert(entries1.hi,entries1.hv);
await tree3.insert(entries3.hi,entries3.hv);
await tree4.insert(entries2.hi,entries2.hv);
await tree4.insert(entries3.hi,entries3.hv);
await tree4.insert(entries1.hi,entries1.hv);
await tree5.insert(entries3.hi,entries3.hv);
await tree5.insert(entries1.hi,entries1.hv);
await tree5.insert(entries2.hi,entries2.hv);
await tree6.insert(entries3.hi,entries3.hv);
await tree6.insert(entries2.hi,entries2.hv);
await tree6.insert(entries1.hi,entries1.hv);
const root1 = bigIntToBuffer(tree1.root);
const root2 = bigIntToBuffer(tree2.root);
const root3 = bigIntToBuffer(tree3.root);
const root4 = bigIntToBuffer(tree4.root);
const root5 = bigIntToBuffer(tree5.root);
const root6 = bigIntToBuffer(tree6.root);
expect(bytesToHex(root1)).to.be.equal(bytesToHex(root2));
expect(bytesToHex(root2)).to.be.equal(bytesToHex(root3));
expect(bytesToHex(root3)).to.be.equal(bytesToHex(root4));
expect(bytesToHex(root4)).to.be.equal(bytesToHex(root5));
expect(bytesToHex(root5)).to.be.equal(bytesToHex(root6));
expect(bytesToHex(root1)).to.be.equal("0x27990ef22656f49f010b2b48b2418c46f2bc93e4afb2e3377a1eb09f129e9802");
});
<<<<<<< HEAD
*/
=======
>>>>>>> 5b7abbc4ec56447e5e2baa31e3b4ce3a0c0617a8
});