2 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
95 changed files with 5502 additions and 9904 deletions

View File

@@ -1,4 +1,7 @@
module.exports = { module.exports = {
"plugins": [
"mocha"
],
"env": { "env": {
"es6": true, "es6": true,
"node": true, "node": true,
@@ -24,6 +27,7 @@ module.exports = {
"semi": [ "semi": [
"error", "error",
"always" "always"
] ],
"mocha/no-exclusive-tests": "error"
} }
}; };

View File

@@ -1,18 +1,4 @@
# CircomLib # cirpedersen
## Description Pedersen Hash and Exponentiation circuits using Baby Jub Curve in circom language
- This repository contains a library of circuit templates.
- All files are copyrighted under 2018 0KIMS association and part of the free software [circom](https://github.com/iden3/circom) (Zero Knowledge Circuit Compiler).
- You can read more about the circom language in [the circom documentation webpage](https://docs.circom.io/).
## Organisation
This respository contains 5 folders:
- `circuits`: it contains the implementation of different cryptographic primitives in circom language.
- `calcpedersenbases`: set of functions in JavaScript used to find a set of points in [Baby Jubjub](https://github.com/barryWhiteHat/baby_jubjub) elliptic curve that serve as basis for the [Pedersen Hash](https://github.com/zcash/zcash/issues/2234).
- `doc`: it contains some circuit schemes in ASCII (must be opened with Monodraw, an ASCII art editor for Mac).
- `src`: it contains similar implementation of circuits in JavaScript.
- `test`: tests.
A description of the specific circuit templates for the `circuit` folder will be soon updated.

View File

@@ -1,19 +1,3 @@
# CircomLib/Circuits
## Description
- This folder contains circuit templates for standard operations and many cryptographic primitives.
- Below you can find specifications of each function. In the representation of elements, there are three tyes:
- Binary
- String
- Field element (the field is specified in each case. We consider 2 possible fields: Fp and Fr, where p... and r... .)
## Table of Contents
[TOC]
## Jordi
* compconstant - Returns 1 if `in` (expanded to binary array) > `ct` * compconstant - Returns 1 if `in` (expanded to binary array) > `ct`
* aliascheck - check if `in` (expanded to binary array) oveflowed its 254 bits (<= -1) * 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 * babyjub - twisted Edwards curve 168700.x^2 + y^2 = 1 + 168696.x^2.y^2
@@ -27,804 +11,4 @@
* zcash/zcash#2233 * zcash/zcash#2233
* smt - Sparse Merkle Tree * smt - Sparse Merkle Tree
* https://ethresear.ch/t/optimizing-sparse-merkle-trees/3751 * https://ethresear.ch/t/optimizing-sparse-merkle-trees/3751
* montgomery https://en.wikipedia.org/wiki/Montgomery_curve * montgomery https://en.wikipedia.org/wiki/Montgomery_curve
## Circuits
### sha256
Folder containing the implementation of sha256 hash circuit.
### smt
Folder containing the circuit implementation of Sparse Merkle Trees.
### aliascheck
- `AliasCheck()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### babyjub
Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby_jubjub) in twisted Edwards form. (TODO: Expose here the characteristics of the curve?)
- `BabyAdd()`
- DESCRIPTION
It adds two points on the Baby Jubjub curve. More specifically, given two points P1 = (`x1`, `y1`) and P2 = (`x2`, `y2`) it returns a point P3 = (`xout`, `yout`) such that
(`xout`, `yout`) = (`x1`,`y1`) + (`x2`,`y2`)
= ((`x1y2`+`y1x2`)/(1+`dx1x2y1y2`)),(`y1y2`-`ax1x2`)/(1-`dx1x2y1y2`))
- SCHEMA
```
var a var d
| |
| |
______v_________v_______
input x1 ----> | |
input y1 ----> | BabyAdd() | ----> output xout
input x2 ----> | | ----> output yout
input y2 ----> |________________________|
```
- INPUTS
| Input | Representation | Description | |
| ------------- | ------------- | ------------- | ------------- |
| `x1` | Bigint | Field element of Fp | First coordinate of a point (x1, y1) on E. |
| `y1` | Bigint | Field element of Fp | Second coordinate of a point (x1, y1) on E. |
| `x2` | Bigint | Field element of Fp | First coordinate of a point (x2, y2) on E. |
| `y2` | Bigint | Field element of Fp | Second coordinate of a point (x2, y2) on E. |
Requirement: at least `x1`!=`x2` or `y1`!=`y2`.
- OUTPUT
| Input | Representation | Description | |
| ------------- | ------------- | ------------- | ------------- |
| `xout` | Bigint | Field element of Fp | First coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). |
| `yout` | Bigint | Field element of Fp | Second coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). |
- BENCHMARKS (constraints)
- EXAMPLE
- `BabyDbl()`
- DESCRIPTION : doubles a point (`xout`,`yout`) = 2*(`x`,`y`).
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `BabyCheck()`
- DESCRIPTION : checks if a given point is in the curve.
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `BabyPbk()`
- DESCRIPTION: : given a private key, it returns the associated public key.
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### binsub
- `BinSub(n)`
- DESCRIPTION: binary substraction.
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### binsum
- `nbits(a)`
- DESCRIPTION : binary sum.
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `BinSum(n, ops)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### bitify
- `Num2Bits()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Num2Bits_strict()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Bits2Num()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Bits2Num_strict()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Num2BitsNeg()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### comparators
- `IsZero() `
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `IsEqual()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `ForceEqualIfEnabled()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `LessThan()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `GreaterThan()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `GreaterEqThan()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### compconstant
- `CompConstant(ct)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### eddsa
Edwards Digital Signature Algorithm in Baby Jubjbub (link a eddsa)
- `EdDSAVerifier(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### eddsamimc
- `EdDSAMiMCVerifier()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### eddsamimcsponge
- `EdDSAMiMCSpongeVerifier()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### eddsaposeidon
- `EdDSAPoseidonVerifier()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### escalarmul
- `EscalarMulWindow(base, k)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `EscalarMul(n, base)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### escalarmulany
- `Multiplexor2()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `BitElementMulAny()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `SegmentMulAny(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `EscalarMulAny(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### escalarmulfix
- `WindowMulFix()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `SegmentMulFix(nWindows)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `EscalarMulFix(n, BASE)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### escalarmulw4table
- `pointAdd`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `EscalarMulW4Table`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### gates
- `XOR`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `AND`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `OR`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `NOT`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `NAND`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `NOR`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MultiAND`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mimc
Implementation of MiMC-7 hash in Fp being... (link to description of the hash)
- `MiMC7(nrounds)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MultiMiMC7(nInputs, nRounds)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mimcsponge
- `MiMCSponge(nInputs, nRounds, nOutputs)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MiMCFeistel(nrounds)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### montgomery
- `Edwards2Montgomery()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Montgomery2Edwards()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MontgomeryAdd()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MontgomeryDouble()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### multiplexer
- `log2(a)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `EscalarProduct(w)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Decoder(w)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Multiplexer(wIn, nIn)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux1
- `MultiMux1(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux1()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux2
- `MultiMux2(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux2()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux3
- `MultiMux3(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux3()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux4
- `MultiMux4(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux4()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### pedersen_old
Old version of the Pedersen hash (do not use any
more?).
### pedersen
- `Window4()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Segment(nWindows)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Pedersen(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### pointbits
- `sqrt(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Bits2Point()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Bits2Point_Strict()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Point2Bits`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Point2Bits_Strict`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### poseidon
Implementation of Poseidon hash function (LINK)
- `Sigma()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Ark(t, C, r)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mix(t, M)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Poseidon(nInputs)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### sign
- `Sign()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### switcher
- `Switcher()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE

View File

@@ -87,7 +87,7 @@ template BabyPbk() {
signal output Ax; signal output Ax;
signal output Ay; signal output Ay;
var BASE8[2] = [ var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];

View File

@@ -48,14 +48,12 @@ template BinSub(n) {
var lin = 2**n; var lin = 2**n;
var lout = 0; var lout = 0;
var i; for (var i=0; i<n; i++) {
for (i=0; i<n; i++) {
lin = lin + in[0][i]*(2**i); lin = lin + in[0][i]*(2**i);
lin = lin - in[1][i]*(2**i); lin = lin - in[1][i]*(2**i);
} }
for (i=0; i<n; i++) { for (var i=0; i<n; i++) {
out[i] <-- (lin >> i) & 1; out[i] <-- (lin >> i) & 1;
// Ensure out is binary // Ensure out is binary

View File

@@ -72,26 +72,19 @@ template BinSum(n, ops) {
var k; var k;
var j; var j;
var e2;
e2 = 1;
for (k=0; k<n; k++) { for (k=0; k<n; k++) {
for (j=0; j<ops; j++) { for (j=0; j<ops; j++) {
lin += in[j][k] * e2; lin += in[j][k] * 2**k;
} }
e2 = e2 + e2;
} }
e2 = 1;
for (k=0; k<nout; k++) { for (k=0; k<nout; k++) {
out[k] <-- (lin >> k) & 1; out[k] <-- (lin >> k) & 1;
// Ensure out is binary // Ensure out is binary
out[k] * (out[k] - 1) === 0; out[k] * (out[k] - 1) === 0;
lout += out[k] * e2; lout += out[k] * 2**k;
e2 = e2+e2;
} }
// Ensure the sum; // Ensure the sum;

View File

@@ -26,12 +26,10 @@ template Num2Bits(n) {
signal output out[n]; signal output out[n];
var lc1=0; var lc1=0;
var e2=1;
for (var i = 0; i<n; i++) { for (var i = 0; i<n; i++) {
out[i] <-- (in >> i) & 1; out[i] <-- (in >> i) & 1;
out[i] * (out[i] -1 ) === 0; out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * e2; lc1 += out[i] * 2**i;
e2 = e2+e2;
} }
lc1 === in; lc1 === in;
@@ -56,10 +54,8 @@ template Bits2Num(n) {
signal output out; signal output out;
var lc1=0; var lc1=0;
var e2 = 1;
for (var i = 0; i<n; i++) { for (var i = 0; i<n; i++) {
lc1 += in[i] * e2; lc1 += in[i] * 2**i;
e2 = e2 + e2;
} }
lc1 ==> out; lc1 ==> out;

View File

@@ -86,11 +86,10 @@ template LessThan(n) {
*/ */
template LessThan(n) { template LessThan(n) {
assert(n <= 252);
signal input in[2]; signal input in[2];
signal output out; signal output out;
component n2b = Num2Bits(n+1); component n2b = Num2Bits(n*2+1);
n2b.in <== in[0]+ (1<<n) - in[1]; n2b.in <== in[0]+ (1<<n) - in[1];

View File

@@ -46,11 +46,12 @@ template CompConstant(ct) {
slsb = in[i*2]; slsb = in[i*2];
smsb = in[i*2+1]; smsb = in[i*2+1];
if ((cmsb==0)&&(clsb==0)) {
if ((cmsb==0)&(clsb==0)) {
parts[i] <== -b*smsb*slsb + b*smsb + b*slsb; parts[i] <== -b*smsb*slsb + b*smsb + b*slsb;
} else if ((cmsb==0)&&(clsb==1)) { } else if ((cmsb==0)&(clsb==1)) {
parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a; parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a;
} else if ((cmsb==1)&&(clsb==0)) { } else if ((cmsb==1)&(clsb==0)) {
parts[i] <== b*smsb*slsb - a*smsb + a; parts[i] <== b*smsb*slsb - a*smsb + a;
} else { } else {
parts[i] <== -a*smsb*slsb + a; parts[i] <== -a*smsb*slsb + a;

View File

@@ -122,7 +122,7 @@ template EdDSAVerifier(n) {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8[2] = [ var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];

View File

@@ -100,7 +100,7 @@ template EdDSAMiMCVerifier() {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8[2] = [ var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];

View File

@@ -100,7 +100,7 @@ template EdDSAMiMCSpongeVerifier() {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8[2] = [ var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];

View File

@@ -47,11 +47,11 @@ template EdDSAPoseidonVerifier() {
snum2bits.out[i] ==> compConstant.in[i]; snum2bits.out[i] ==> compConstant.in[i];
} }
compConstant.in[253] <== 0; compConstant.in[253] <== 0;
compConstant.out*enabled === 0; compConstant.out === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
component hash = Poseidon(5); component hash = Poseidon(5, 6, 8, 57);
hash.inputs[0] <== R8x; hash.inputs[0] <== R8x;
hash.inputs[1] <== R8y; hash.inputs[1] <== R8y;
@@ -79,7 +79,7 @@ template EdDSAPoseidonVerifier() {
// We check that A is not zero. // We check that A is not zero.
component isZero = IsZero(); component isZero = IsZero();
isZero.in <== dbl3.x; isZero.in <== dbl3.x;
isZero.out*enabled === 0; isZero.out === 0;
component mulAny = EscalarMulAny(254); component mulAny = EscalarMulAny(254);
for (i=0; i<254; i++) { for (i=0; i<254; i++) {
@@ -99,7 +99,7 @@ template EdDSAPoseidonVerifier() {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8[2] = [ var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];

View File

@@ -1,4 +1,4 @@
/* /*
Copyright 2018 0KIMS association. Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler). This file is part of circom (Zero Knowledge Circuit Compiler).
@@ -71,7 +71,7 @@ template EscalarMulWindow(base, k) {
signal input sel[4]; signal input sel[4];
signal output out[2]; signal output out[2];
var table[16][2]; component table;
component mux; component mux;
component adder; component adder;
@@ -86,8 +86,8 @@ template EscalarMulWindow(base, k) {
} }
for (i=0; i<16; i++) { for (i=0; i<16; i++) {
mux.c[0][i] <== table[i][0]; table.out[i][0] ==> mux.c[0][i];
mux.c[1][i] <== table[i][1]; table.out[i][1] ==> mux.c[1][i];
} }
in[0] ==> adder.x1; in[0] ==> adder.x1;

View File

@@ -176,9 +176,6 @@ template SegmentMulFix(nWindows) {
cadders[i].in1[0] <== cadders[i-1].out[0]; cadders[i].in1[0] <== cadders[i-1].out[0];
cadders[i].in1[1] <== cadders[i-1].out[1]; cadders[i].in1[1] <== cadders[i-1].out[1];
} }
for (j=0; j<3; j++) {
windows[i].in[j] <== e[3*i+j];
}
if (i<nWindows-1) { if (i<nWindows-1) {
cadders[i].in2[0] <== windows[i].out8[0]; cadders[i].in2[0] <== windows[i].out8[0];
cadders[i].in2[1] <== windows[i].out8[1]; cadders[i].in2[1] <== windows[i].out8[1];
@@ -188,6 +185,9 @@ template SegmentMulFix(nWindows) {
cadders[i].in2[0] <== dblLast.out[0]; cadders[i].in2[0] <== dblLast.out[0];
cadders[i].in2[1] <== dblLast.out[1]; 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++) { for (i=0; i<nWindows; i++) {

View File

@@ -27,25 +27,23 @@ function pointAdd(x1,y1,x2,y2) {
return res; return res;
} }
function EscalarMulW4Table(base, k) { template EscalarMulW4Table(base, k) {
var out[16][2]; signal output out[16][2];
var i; var i;
var p[2]; var p[2];
var dbl[2] = base; var dbl = base;
for (i=0; i<k*4; i++) { for (i=0; i<k*4; i++) {
dbl = pointAdd(dbl[0], dbl[1], dbl[0], dbl[1]); dbl = pointAdd(dbl[0], dbl[1], dbl[0], dbl[1]);
} }
out[0][0] = 0; out[0][0] <== 0;
out[0][1] = 1; out[0][1] <== 1;
for (i=1; i<16; i++) { for (i=1; i<16; i++) {
p = pointAdd(out[i-1][0], out[i-1][1], dbl[0], dbl[1]); p = pointAdd(out[i-1][0], out[i-1][1], dbl[0], dbl[1]);
out[i][0] = p[0]; out[i][0] <== p[0];
out[i][1] = p[1]; out[i][1] <== p[1];
} }
return out;
} }

View File

@@ -67,7 +67,6 @@ template NOR() {
template MultiAND(n) { template MultiAND(n) {
signal input in[n]; signal input in[n];
signal output out; signal output out;
var i;
if (n==1) { if (n==1) {
out <== in[0]; out <== in[0];
} else if (n==2) { } else if (n==2) {
@@ -82,8 +81,8 @@ template MultiAND(n) {
var n2 = n-n\2; var n2 = n-n\2;
ands[0] = MultiAND(n1); ands[0] = MultiAND(n1);
ands[1] = MultiAND(n2); ands[1] = MultiAND(n2);
for (i=0; i<n1; i++) ands[0].in[i] <== in[i]; for (var i=0; i<n1; i++) ands[0].in[i] <== in[i];
for (i=0; i<n2; i++) ands[1].in[i] <== in[n1+i]; for (var i=0; i<n2; i++) ands[1].in[i] <== in[n1+i];
and2.a <== ands[0].out; and2.a <== ands[0].out;
and2.b <== ands[1].out; and2.b <== ands[1].out;
out <== and2.out; out <== and2.out;

View File

@@ -22,7 +22,7 @@ template MiMC7(nrounds) {
signal input k; signal input k;
signal output out; signal output out;
var c[91] = [ var c = [
0, 0,
20888961410941983456478427210666206549300505294776164667214940546594746570981, 20888961410941983456478427210666206549300505294776164667214940546594746570981,
15265126113435022738560151911929040668591755459209400716467504685752745317193, 15265126113435022738560151911929040668591755459209400716467504685752745317193,

View File

@@ -6,12 +6,10 @@ template MiMCSponge(nInputs, nRounds, nOutputs) {
signal input k; signal input k;
signal output outs[nOutputs]; signal output outs[nOutputs];
var i;
// S = R||C // S = R||C
component S[nInputs + nOutputs - 1]; component S[nInputs + nOutputs - 1];
for (i = 0; i < nInputs; i++) { for (var i = 0; i < nInputs; i++) {
S[i] = MiMCFeistel(nRounds); S[i] = MiMCFeistel(nRounds);
S[i].k <== k; S[i].k <== k;
if (i == 0) { if (i == 0) {
@@ -23,9 +21,9 @@ template MiMCSponge(nInputs, nRounds, nOutputs) {
} }
} }
outs[0] <== S[nInputs - 1].xL_out; outs[0] = S[nInputs - 1].xL_out;
for (i = 0; i < nOutputs - 1; i++) { for (var i = 0; i < nOutputs - 1; i++) {
S[nInputs + i] = MiMCFeistel(nRounds); S[nInputs + i] = MiMCFeistel(nRounds);
S[nInputs + i].k <== k; S[nInputs + i].k <== k;
S[nInputs + i].xL_in <== S[nInputs + i - 1].xL_out; S[nInputs + i].xL_in <== S[nInputs + i - 1].xL_out;
@@ -41,8 +39,8 @@ template MiMCFeistel(nrounds) {
signal output xL_out; signal output xL_out;
signal output xR_out; signal output xR_out;
// doesn't contain the first and last round constants, which are always zero var c = [
var c_partial[218] = [ 0,
7120861356467848435263064379192047478074060781135320967663101236819528304084, 7120861356467848435263064379192047478074060781135320967663101236819528304084,
5024705281721889198577876690145313457398658950011302225525409148828000436681, 5024705281721889198577876690145313457398658950011302225525409148828000436681,
17980351014018068290387269214713820287804403312720763401943303895585469787384, 17980351014018068290387269214713820287804403312720763401943303895585469787384,
@@ -260,7 +258,8 @@ template MiMCFeistel(nrounds) {
18224457394066545825553407391290108485121649197258948320896164404518684305122, 18224457394066545825553407391290108485121649197258948320896164404518684305122,
274945154732293792784580363548970818611304339008964723447672490026510689427, 274945154732293792784580363548970818611304339008964723447672490026510689427,
11050822248291117548220126630860474473945266276626263036056336623671308219529, 11050822248291117548220126630860474473945266276626263036056336623671308219529,
2119542016932434047340813757208803962484943912710204325088879681995922344971 2119542016932434047340813757208803962484943912710204325088879681995922344971,
0
]; ];
var t; var t;
@@ -269,19 +268,13 @@ template MiMCFeistel(nrounds) {
signal xL[nrounds-1]; signal xL[nrounds-1];
signal xR[nrounds-1]; signal xR[nrounds-1];
var c;
for (var i=0; i<nrounds; i++) { for (var i=0; i<nrounds; i++) {
if ((i == 0) || (i == nrounds - 1)) { t = (i==0) ? k+xL_in : k + xL[i-1] + c[i];
c = 0;
} else {
c = c_partial[i - 1];
}
t = (i==0) ? k+xL_in : k + xL[i-1] + c;
t2[i] <== t*t; t2[i] <== t*t;
t4[i] <== t2[i]*t2[i]; t4[i] <== t2[i]*t2[i];
if (i<nrounds-1) { if (i<nrounds-1) {
xL[i] <== ((i==0) ? xR_in : xR[i-1]) + t4[i]*t; xL[i] <== ((i==0) ? xR_in : xR[i-1]) + t4[i]*t;
xR[i] <== (i==0) ? xL_in : xL[i-1]; xR[i] = (i==0) ? xL_in : xL[i-1];
} else { } else {
xR_out <== xR[i-1] + t4[i]*t; xR_out <== xR[i-1] + t4[i]*t;
xL_out <== xL[i-1]; xL_out <== xL[i-1];

View File

@@ -128,9 +128,6 @@ template Segment(nWindows) {
component adders[nWindows-1]; component adders[nWindows-1];
for (i=0; i<nWindows; i++) { for (i=0; i<nWindows; i++) {
windows[i] = Window4(); windows[i] = Window4();
for (j=0; j<4; j++) {
windows[i].in[j] <== in[4*i+j];
}
if (i==0) { if (i==0) {
windows[i].base[0] <== e2m.out[0]; windows[i].base[0] <== e2m.out[0];
windows[i].base[1] <== e2m.out[1]; windows[i].base[1] <== e2m.out[1];
@@ -156,6 +153,9 @@ template Segment(nWindows) {
adders[i-1].in2[0] <== windows[i].out[0]; adders[i-1].in2[0] <== windows[i].out[0];
adders[i-1].in2[1] <== windows[i].out[1]; adders[i-1].in2[1] <== windows[i].out[1];
} }
for (j=0; j<4; j++) {
windows[i].in[j] <== in[4*i+j];
}
} }
component m2e = Montgomery2Edwards(); component m2e = Montgomery2Edwards();
@@ -176,7 +176,7 @@ template Pedersen(n) {
signal input in[n]; signal input in[n];
signal output out[2]; signal output out[2];
var BASE[10][2] = [ var BASE = [
[10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317], [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094], [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896], [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
@@ -187,8 +187,7 @@ template Pedersen(n) {
[6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695], [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
[3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506], [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
[18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481] [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
]
];
var nSegments = ((n-1)\200)+1; var nSegments = ((n-1)\200)+1;

View File

@@ -28,7 +28,7 @@ template Pedersen(n) {
component escalarMuls[nexps]; component escalarMuls[nexps];
var PBASE[10][2] = [ var PBASE = [
[10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317], [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094], [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896], [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
@@ -39,7 +39,6 @@ template Pedersen(n) {
[6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695], [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
[3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506], [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
[18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481] [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
]; ];
var i; var i;

View File

@@ -61,7 +61,7 @@ function sqrt(n) {
r = r*b; r = r*b;
} }
if (r < 0 ) { if (r > ((-1) >> 1)) {
r = -r; r = -r;
} }

View File

@@ -1,4 +1,3 @@
include "./poseidon_constants.circom";
template Sigma() { template Sigma() {
signal input in; signal input in;
@@ -13,52 +12,163 @@ template Sigma() {
out <== in4*in; out <== in4*in;
} }
template Ark(t, C, r) { template Ark(t, C) {
signal input in[t]; signal input in[t];
signal output out[t]; signal output out[t];
for (var i=0; i<t; i++) { for (var i=0; i<t; i++) {
out[i] <== in[i] + C[i + r]; out[i] <== in[i] + C;
} }
} }
template Mix(t, M) { template Mix(t, M) {
signal input in[t]; signal input in[t];
signal output out[t]; signal output out[t];
var lc; var lc;
for (var i=0; i<t; i++) { for (var i=0; i<t; i++) {
lc = 0; lc = 0;
for (var j=0; j<t; j++) { for (var j=0; j<t; j++) {
lc += M[i][j]*in[j]; lc = lc + M[i][j]*in[j];
} }
out[i] <== lc; out[i] <== lc;
} }
} }
template Poseidon(nInputs) { // 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 input inputs[nInputs];
signal output out; signal output out;
// Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8) component ark[nRoundsF + nRoundsP];
// Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py component sigmaF[nRoundsF][t];
// And rounded up to nearest integer that divides by t
var N_ROUNDS_P[8] = [56, 57, 56, 60, 60, 63, 64, 63];
var t = nInputs + 1;
var nRoundsF = 8;
var nRoundsP = N_ROUNDS_P[t - 2];
var C[t*(nRoundsF + nRoundsP)] = POSEIDON_C(t);
var M[t][t] = POSEIDON_M(t);
component ark[nRoundsF + nRoundsP - 1];
component sigmaF[nRoundsF - 1][t];
component sigmaP[nRoundsP]; component sigmaP[nRoundsP];
component mix[nRoundsF + nRoundsP - 1]; component mix[nRoundsF + nRoundsP];
var k; var k;
for (var i=0; i<nRoundsF + nRoundsP - 1; i++) { for (var i=0; i<(nRoundsF + nRoundsP); i++) {
ark[i] = Ark(t, C, t*i); ark[i] = Ark(t, C[i]);
mix[i] = Mix(t, M);
for (var j=0; j<t; j++) { for (var j=0; j<t; j++) {
if (i==0) { if (i==0) {
if (j<nInputs) { if (j<nInputs) {
@@ -71,17 +181,15 @@ template Poseidon(nInputs) {
} }
} }
if (i < nRoundsF/2 || i >= nRoundsP + nRoundsF/2) { if ((i<(nRoundsF/2)) || (i>= (nRoundsP + nRoundsF/2))) {
k = i < nRoundsF/2 ? i : i - nRoundsP; k= i<nRoundsF/2 ? i : (i-nRoundsP);
mix[i] = Mix(t, M);
for (var j=0; j<t; j++) { for (var j=0; j<t; j++) {
sigmaF[k][j] = Sigma(); sigmaF[k][j] = Sigma();
sigmaF[k][j].in <== ark[i].out[j]; sigmaF[k][j].in <== ark[i].out[j];
mix[i].in[j] <== sigmaF[k][j].out; mix[i].in[j] <== sigmaF[k][j].out;
} }
} else { } else {
k = i - nRoundsF/2; k= i-nRoundsF/2;
mix[i] = Mix(t, M);
sigmaP[k] = Sigma(); sigmaP[k] = Sigma();
sigmaP[k].in <== ark[i].out[0]; sigmaP[k].in <== ark[i].out[0];
mix[i].in[0] <== sigmaP[k].out; mix[i].in[0] <== sigmaP[k].out;
@@ -91,8 +199,5 @@ template Poseidon(nInputs) {
} }
} }
// last round is done only for the first word, so we do it manually to save constraints out <== mix[nRoundsF + nRoundsP -1].out[0];
component lastSigmaF = Sigma();
lastSigmaF.in <== mix[nRoundsF + nRoundsP - 2].out[0] + C[t*(nRoundsF + nRoundsP - 1)];
out <== lastSigmaF.out;
} }

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
template H(x) { template H(x) {
signal output out[32]; signal output out[32];
var c[8] = [0x6a09e667, var c = [0x6a09e667,
0xbb67ae85, 0xbb67ae85,
0x3c6ef372, 0x3c6ef372,
0xa54ff53a, 0xa54ff53a,
@@ -35,7 +35,7 @@ template H(x) {
template K(x) { template K(x) {
signal output out[32]; signal output out[32];
var c[64] = [ var c = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,

View File

@@ -22,8 +22,6 @@ include "t1.circom";
include "t2.circom"; include "t2.circom";
include "../binsum.circom"; include "../binsum.circom";
include "sigmaplus.circom"; include "sigmaplus.circom";
include "sha256compression_function.circom";
template Sha256compression() { template Sha256compression() {
signal input hin[256]; signal input hin[256];
@@ -39,11 +37,7 @@ template Sha256compression() {
signal h[65][32]; signal h[65][32];
signal w[64][32]; signal w[64][32];
var outCalc[256] = sha256compression(hin, inp);
var i; var i;
for (i=0; i<256; i++) out[i] <-- outCalc[i];
component sigmaPlus[48]; component sigmaPlus[48];
for (i=0; i<48; i++) sigmaPlus[i] = SigmaPlus(); for (i=0; i<48; i++) sigmaPlus[i] = SigmaPlus();
@@ -80,9 +74,6 @@ template Sha256compression() {
sigmaPlus[t-16].in7[k] <== w[t-7][k]; sigmaPlus[t-16].in7[k] <== w[t-7][k];
sigmaPlus[t-16].in15[k] <== w[t-15][k]; sigmaPlus[t-16].in15[k] <== w[t-15][k];
sigmaPlus[t-16].in16[k] <== w[t-16][k]; sigmaPlus[t-16].in16[k] <== w[t-16][k];
}
for (k=0; k<32; k++) {
w[t][k] <== sigmaPlus[t-16].out[k]; w[t][k] <== sigmaPlus[t-16].out[k];
} }
} }
@@ -153,13 +144,13 @@ template Sha256compression() {
} }
for (k=0; k<32; k++) { for (k=0; k<32; k++) {
out[31-k] === fsum[0].out[k]; out[31-k] <== fsum[0].out[k];
out[32+31-k] === fsum[1].out[k]; out[32+31-k] <== fsum[1].out[k];
out[64+31-k] === fsum[2].out[k]; out[64+31-k] <== fsum[2].out[k];
out[96+31-k] === fsum[3].out[k]; out[96+31-k] <== fsum[3].out[k];
out[128+31-k] === fsum[4].out[k]; out[128+31-k] <== fsum[4].out[k];
out[160+31-k] === fsum[5].out[k]; out[160+31-k] <== fsum[5].out[k];
out[192+31-k] === fsum[6].out[k]; out[192+31-k] <== fsum[6].out[k];
out[224+31-k] === fsum[7].out[k]; out[224+31-k] <== fsum[7].out[k];
} }
} }

View File

@@ -1,112 +0,0 @@
// signal input hin[256];
// signal input inp[512];
// signal output out[256];
function rrot(x, n) {
return ((x >> n) | (x << (32-n))) & 0xFFFFFFFF;
}
function bsigma0(x) {
return rrot(x,2) ^ rrot(x,13) ^ rrot(x,22);
}
function bsigma1(x) {
return rrot(x,6) ^ rrot(x,11) ^ rrot(x,25);
}
function ssigma0(x) {
return rrot(x,7) ^ rrot(x,18) ^ (x >> 3);
}
function ssigma1(x) {
return rrot(x,17) ^ rrot(x,19) ^ (x >> 10);
}
function Maj(x, y, z) {
return (x&y) ^ (x&z) ^ (y&z);
}
function Ch(x, y, z) {
return (x & y) ^ ((0xFFFFFFFF ^x) & z);
}
function sha256K(i) {
var k[64] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
return k[i];
}
function sha256compression(hin, inp) {
var H[8];
var a;
var b;
var c;
var d;
var e;
var f;
var g;
var h;
var out[256];
for (var i=0; i<8; i++) {
H[i] = 0;
for (var j=0; j<32; j++) {
H[i] += hin[i*32+j] << j;
}
}
a=H[0];
b=H[1];
c=H[2];
d=H[3];
e=H[4];
f=H[5];
g=H[6];
h=H[7];
var w[64];
var T1;
var T2;
for (var i=0; i<64; i++) {
if (i<16) {
w[i]=0;
for (var j=0; j<32; j++) {
w[i] += inp[i*32+31-j]<<j;
}
} else {
w[i] = (ssigma1(w[i-2]) + w[i-7] + ssigma0(w[i-15]) + w[i-16]) & 0xFFFFFFFF;
}
T1 = (h + bsigma1(e) + Ch(e,f,g) + sha256K(i) + w[i]) & 0xFFFFFFFF;
T2 = (bsigma0(a) + Maj(a,b,c)) & 0xFFFFFFFF;
h=g;
g=f;
f=e;
e=(d+T1) & 0xFFFFFFFF;
d=c;
c=b;
b=a;
a=(T1+T2) & 0xFFFFFFFF;
}
H[0] = H[0] + a;
H[1] = H[1] + b;
H[2] = H[2] + c;
H[3] = H[3] + d;
H[4] = H[4] + e;
H[5] = H[5] + f;
H[6] = H[6] + g;
H[7] = H[7] + h;
for (var i=0; i<8; i++) {
for (var j=0; j<32; j++) {
out[i*32+31-j] = (H[i] >> j) & 1;
}
}
return out;
}

View File

@@ -24,26 +24,22 @@ include "shift.circom";
template SmallSigma(ra, rb, rc) { template SmallSigma(ra, rb, rc) {
signal input in[32]; signal input in[32];
signal output out[32]; signal output out[32];
var k;
component xor3 = Xor3(32);
component rota = RotR(32, ra); component rota = RotR(32, ra);
component rotb = RotR(32, rb); component rotb = RotR(32, rb);
component shrc = ShR(32, rc); component shrc = ShR(32, rc);
for (k=0; k<32; k++) { for (var k=0; k<32; k++) {
rota.in[k] <== in[k]; rota.in[k] <== in[k];
rotb.in[k] <== in[k]; rotb.in[k] <== in[k];
shrc.in[k] <== in[k]; shrc.in[k] <== in[k];
}
component xor3 = Xor3(32);
for (k=0; k<32; k++) {
xor3.a[k] <== rota.out[k]; xor3.a[k] <== rota.out[k];
xor3.b[k] <== rotb.out[k]; xor3.b[k] <== rotb.out[k];
xor3.c[k] <== shrc.out[k]; xor3.c[k] <== shrc.out[k];
}
for (k=0; k<32; k++) {
out[k] <== xor3.out[k]; out[k] <== xor3.out[k];
} }
} }
@@ -51,26 +47,22 @@ template SmallSigma(ra, rb, rc) {
template BigSigma(ra, rb, rc) { template BigSigma(ra, rb, rc) {
signal input in[32]; signal input in[32];
signal output out[32]; signal output out[32];
var k;
component xor3 = Xor3(32);
component rota = RotR(32, ra); component rota = RotR(32, ra);
component rotb = RotR(32, rb); component rotb = RotR(32, rb);
component rotc = RotR(32, rc); component rotc = RotR(32, rc);
for (k=0; k<32; k++) {
for (var k=0; k<32; k++) {
rota.in[k] <== in[k]; rota.in[k] <== in[k];
rotb.in[k] <== in[k]; rotb.in[k] <== in[k];
rotc.in[k] <== in[k]; rotc.in[k] <== in[k];
}
component xor3 = Xor3(32);
for (k=0; k<32; k++) {
xor3.a[k] <== rota.out[k]; xor3.a[k] <== rota.out[k];
xor3.b[k] <== rotb.out[k]; xor3.b[k] <== rotb.out[k];
xor3.c[k] <== rotc.out[k]; xor3.c[k] <== rotc.out[k];
}
for (k=0; k<32; k++) {
out[k] <== xor3.out[k]; out[k] <== xor3.out[k];
} }
} }

View File

@@ -26,24 +26,20 @@ template SigmaPlus() {
signal input in15[32]; signal input in15[32];
signal input in16[32]; signal input in16[32];
signal output out[32]; signal output out[32];
var k;
component sigma1 = SmallSigma(17,19,10);
component sigma0 = SmallSigma(7, 18, 3);
for (k=0; k<32; k++) {
sigma1.in[k] <== in2[k];
sigma0.in[k] <== in15[k];
}
component sum = BinSum(32, 4); component sum = BinSum(32, 4);
for (k=0; k<32; k++) { component sigma1 = SmallSigma(17,19,10);
component sigma0 = SmallSigma(7, 18, 3);
for (var k=0; k<32; k++) {
sigma1.in[k] <== in2[k];
sigma0.in[k] <== in15[k];
sum.in[0][k] <== sigma1.out[k]; sum.in[0][k] <== sigma1.out[k];
sum.in[1][k] <== in7[k]; sum.in[1][k] <== in7[k];
sum.in[2][k] <== sigma0.out[k]; sum.in[2][k] <== sigma0.out[k];
sum.in[3][k] <== in16[k]; sum.in[3][k] <== in16[k];
}
for (k=0; k<32; k++) {
out[k] <== sum.out[k]; out[k] <== sum.out[k];
} }
} }

View File

@@ -30,28 +30,23 @@ template T1() {
signal input w[32]; signal input w[32];
signal output out[32]; signal output out[32];
var ki; component sum = BinSum(32, 5);
component ch = Ch(32); component ch = Ch(32);
component bigsigma1 = BigSigma(6, 11, 25); component bigsigma1 = BigSigma(6, 11, 25);
for (ki=0; ki<32; ki++) { for (var ki=0; ki<32; ki++) {
bigsigma1.in[ki] <== e[ki]; bigsigma1.in[ki] <== e[ki];
ch.a[ki] <== e[ki]; ch.a[ki] <== e[ki];
ch.b[ki] <== f[ki]; ch.b[ki] <== f[ki];
ch.c[ki] <== g[ki]; ch.c[ki] <== g[ki]
}
component sum = BinSum(32, 5);
for (ki=0; ki<32; ki++) {
sum.in[0][ki] <== h[ki]; sum.in[0][ki] <== h[ki];
sum.in[1][ki] <== bigsigma1.out[ki]; sum.in[1][ki] <== bigsigma1.out[ki];
sum.in[2][ki] <== ch.out[ki]; sum.in[2][ki] <== ch.out[ki];
sum.in[3][ki] <== k[ki]; sum.in[3][ki] <== k[ki];
sum.in[4][ki] <== w[ki]; sum.in[4][ki] <== w[ki];
}
for (ki=0; ki<32; ki++) {
out[ki] <== sum.out[ki]; out[ki] <== sum.out[ki];
} }
} }

View File

@@ -26,25 +26,22 @@ template T2() {
signal input b[32]; signal input b[32];
signal input c[32]; signal input c[32];
signal output out[32]; signal output out[32];
var k;
component sum = BinSum(32, 2);
component bigsigma0 = BigSigma(2, 13, 22); component bigsigma0 = BigSigma(2, 13, 22);
component maj = Maj(32); component maj = Maj(32);
for (k=0; k<32; k++) {
for (var k=0; k<32; k++) {
bigsigma0.in[k] <== a[k]; bigsigma0.in[k] <== a[k];
maj.a[k] <== a[k]; maj.a[k] <== a[k];
maj.b[k] <== b[k]; maj.b[k] <== b[k];
maj.c[k] <== c[k]; maj.c[k] <== c[k];
}
component sum = BinSum(32, 2);
for (k=0; k<32; k++) {
sum.in[0][k] <== bigsigma0.out[k]; sum.in[0][k] <== bigsigma0.out[k];
sum.in[1][k] <== maj.out[k]; sum.in[1][k] <== maj.out[k];
}
for (k=0; k<32; k++) {
out[k] <== sum.out[k]; out[k] <== sum.out[k];
} }
} }

View File

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

View File

@@ -79,11 +79,9 @@ template SMTLevIns(nLevels) {
signal output levIns[nLevels]; signal output levIns[nLevels];
signal done[nLevels-1]; // Indicates if the insLevel has aready been detected. signal done[nLevels-1]; // Indicates if the insLevel has aready been detected.
var i;
component isZero[nLevels]; component isZero[nLevels];
for (i=0; i<nLevels; i++) { for (var i=0; i<nLevels; i++) {
isZero[i] = IsZero(); isZero[i] = IsZero();
isZero[i].in <== siblings[i]; isZero[i].in <== siblings[i];
} }
@@ -93,7 +91,7 @@ template SMTLevIns(nLevels) {
levIns[nLevels-1] <== (1-isZero[nLevels-2].out); levIns[nLevels-1] <== (1-isZero[nLevels-2].out);
done[nLevels-2] <== levIns[nLevels-1]; done[nLevels-2] <== levIns[nLevels-1];
for (i=nLevels-2; i>0; i--) { for (var i=nLevels-2; i>0; i--) {
levIns[i] <== (1-done[i])*(1-isZero[i-1].out) levIns[i] <== (1-done[i])*(1-isZero[i-1].out)
done[i-1] <== levIns[i] + done[i]; done[i-1] <== levIns[i] + done[i];
} }

View File

@@ -150,8 +150,6 @@ template SMTProcessor(nLevels) {
signal enabled; signal enabled;
var i;
enabled <== fnc[0] + fnc[1] - fnc[0]*fnc[1] enabled <== fnc[0] + fnc[1] - fnc[0]*fnc[1]
component hash1Old = SMTHash1(); component hash1Old = SMTHash1();
@@ -169,18 +167,18 @@ template SMTProcessor(nLevels) {
n2bNew.in <== newKey; n2bNew.in <== newKey;
component smtLevIns = SMTLevIns(nLevels); component smtLevIns = SMTLevIns(nLevels);
for (i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i]; for (var i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
smtLevIns.enabled <== enabled; smtLevIns.enabled <== enabled;
component xors[nLevels]; component xors[nLevels];
for (i=0; i<nLevels; i++) { for (var i=0; i<nLevels; i++) {
xors[i] = XOR(); xors[i] = XOR();
xors[i].a <== n2bOld.out[i]; xors[i].a <== n2bOld.out[i];
xors[i].b <== n2bNew.out[i]; xors[i].b <== n2bNew.out[i];
} }
component sm[nLevels]; component sm[nLevels];
for (i=0; i<nLevels; i++) { for (var i=0; i<nLevels; i++) {
sm[i] = SMTProcessorSM(); sm[i] = SMTProcessorSM();
if (i==0) { if (i==0) {
sm[i].prev_top <== enabled; sm[i].prev_top <== enabled;
@@ -206,7 +204,7 @@ template SMTProcessor(nLevels) {
sm[nLevels-1].st_na + sm[nLevels-1].st_new1 + sm[nLevels-1].st_old0 +sm[nLevels-1].st_upd === 1; sm[nLevels-1].st_na + sm[nLevels-1].st_new1 + sm[nLevels-1].st_old0 +sm[nLevels-1].st_upd === 1;
component levels[nLevels]; component levels[nLevels];
for (i=nLevels-1; i != -1; i--) { for (var i=nLevels-1; i != -1; i--) {
levels[i] = SMTProcessorLevel(); levels[i] = SMTProcessorLevel();
levels[i].st_top <== sm[i].st_top; levels[i].st_top <== sm[i].st_top;

View File

@@ -48,8 +48,6 @@ template SMTVerifier(nLevels) {
signal input value; signal input value;
signal input fnc; signal input fnc;
var i;
component hash1Old = SMTHash1(); component hash1Old = SMTHash1();
hash1Old.key <== oldKey; hash1Old.key <== oldKey;
hash1Old.value <== oldValue; hash1Old.value <== oldValue;
@@ -65,11 +63,11 @@ template SMTVerifier(nLevels) {
n2bNew.in <== key; n2bNew.in <== key;
component smtLevIns = SMTLevIns(nLevels); component smtLevIns = SMTLevIns(nLevels);
for (i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i]; for (var i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
smtLevIns.enabled <== enabled; smtLevIns.enabled <== enabled;
component sm[nLevels]; component sm[nLevels];
for (i=0; i<nLevels; i++) { for (var i=0; i<nLevels; i++) {
sm[i] = SMTVerifierSM(); sm[i] = SMTVerifierSM();
if (i==0) { if (i==0) {
sm[i].prev_top <== enabled; sm[i].prev_top <== enabled;
@@ -91,7 +89,7 @@ template SMTVerifier(nLevels) {
sm[nLevels-1].st_na + sm[nLevels-1].st_iold + sm[nLevels-1].st_inew + sm[nLevels-1].st_i0 === 1; sm[nLevels-1].st_na + sm[nLevels-1].st_iold + sm[nLevels-1].st_inew + sm[nLevels-1].st_i0 === 1;
component levels[nLevels]; component levels[nLevels];
for (i=nLevels-1; i != -1; i--) { for (var i=nLevels-1; i != -1; i--) {
levels[i] = SMTVerifierLevel(); levels[i] = SMTVerifierLevel();
levels[i].st_top <== sm[i].st_top; levels[i].st_top <== sm[i].st_top;

View File

@@ -4,9 +4,3 @@ exports.mimc7 = require("./src/mimc7");
exports.mimcsponge = require("./src/mimcsponge"); exports.mimcsponge = require("./src/mimcsponge");
exports.babyJub = require("./src/babyjub"); exports.babyJub = require("./src/babyjub");
exports.pedersenHash = require("./src/pedersenHash"); exports.pedersenHash = require("./src/pedersenHash");
exports.SMT = require("./src/smt").SMT;
exports.SMTMemDB = require("./src/smt_memdb");
exports.poseidon = require("./src/poseidon");

7668
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "circomlib", "name": "circomlib",
"version": "0.3.0", "version": "0.0.15",
"description": "Basic circuits library for Circom", "description": "Basic circuits library for Circom",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@@ -26,13 +26,14 @@
"dependencies": { "dependencies": {
"blake-hash": "^1.1.0", "blake-hash": "^1.1.0",
"blake2b": "^2.1.3", "blake2b": "^2.1.3",
"circom": "0.5.33", "snarkjs": "^0.1.19",
"ffjavascript": "0.1.0" "typedarray-to-buffer": "^3.1.5",
"web3": "^1.0.0-beta.55"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^6.8.0", "circom": "0.0.28",
"ganache-cli": "^6.12.1", "eslint-plugin-mocha": "^5.2.0",
"mocha": "^7.1.1", "ganache-cli": "^6.4.4",
"web3": "^1.3.0" "mocha": "^5.2.0"
} }
} }

View File

@@ -1,6 +1,5 @@
const F1Field = require("ffjavascript").F1Field; const bn128 = require("snarkjs").bn128;
const Scalar = require("ffjavascript").Scalar; const bigInt = require("snarkjs").bigInt;
const utils = require("ffjavascript").utils;
exports.addPoint = addPoint; exports.addPoint = addPoint;
exports.mulPointEscalar = mulPointEscalar; exports.mulPointEscalar = mulPointEscalar;
@@ -8,27 +7,23 @@ exports.inCurve = inCurve;
exports.inSubgroup = inSubgroup; exports.inSubgroup = inSubgroup;
exports.packPoint = packPoint; exports.packPoint = packPoint;
exports.unpackPoint = unpackPoint; exports.unpackPoint = unpackPoint;
exports.p = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const F = new F1Field(exports.p);
exports.F = F;
exports.Generator = [ exports.Generator = [
F.e("995203441582195749578291179787384436505546430278305826713579947235728471134"), bigInt("995203441582195749578291179787384436505546430278305826713579947235728471134"),
F.e("5472060717959818805561601436314318772137091100104008585924551046643952123905") bigInt("5472060717959818805561601436314318772137091100104008585924551046643952123905")
]; ];
exports.Base8 = [ exports.Base8 = [
F.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"), bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
F.e("16950150798460657717958625567821834550301663161624707787222815936182638968203") bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
exports.order = Scalar.fromString("21888242871839275222246405745257275088614511777268538073601725287587578984328"); exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328");
exports.subOrder = Scalar.shiftRight(exports.order, 3); exports.subOrder = exports.order.shr(3);
exports.A = F.e("168700"); exports.p = bn128.r;
exports.D = F.e("168696"); exports.A = bigInt("168700");
exports.D = bigInt("168696");
function addPoint(a,b) { function addPoint(a,b) {
const q = bn128.r;
const res = []; const res = [];
@@ -36,40 +31,23 @@ function addPoint(a,b) {
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[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[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);
const beta = F.mul(a[0],b[1]); 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);
const gamma = F.mul(a[1],b[0]);
const delta = F.mul(
F.sub(a[1], F.mul(exports.A, a[0])),
F.add(b[0], b[1])
);
const tau = F.mul(beta, gamma);
const dtau = F.mul(exports.D, tau);
res[0] = F.div(
F.add(beta, gamma),
F.add(F.one, dtau)
);
res[1] = F.div(
F.add(delta, F.sub(F.mul(exports.A,beta), gamma)),
F.sub(F.one, dtau)
);
return res; return res;
} }
function mulPointEscalar(base, e) { function mulPointEscalar(base, e) {
let res = [F.e("0"),F.e("1")]; let res = [bigInt("0"),bigInt("1")];
let rem = e; let rem = bigInt(e);
let exp = base; let exp = base;
while (! Scalar.isZero(rem)) { while (! rem.isZero()) {
if (Scalar.isOdd(rem)) { if (rem.isOdd()) {
res = addPoint(res, exp); res = addPoint(res, exp);
} }
exp = addPoint(exp, exp); exp = addPoint(exp, exp);
rem = Scalar.shiftRight(rem, 1); rem = rem.shr(1);
} }
return res; return res;
@@ -78,15 +56,16 @@ function mulPointEscalar(base, e) {
function inSubgroup(P) { function inSubgroup(P) {
if (!inCurve(P)) return false; if (!inCurve(P)) return false;
const res= mulPointEscalar(P, exports.subOrder); const res= mulPointEscalar(P, exports.subOrder);
return (F.isZero(res[0]) && F.eq(res[1], F.one)); return (res[0].equals(bigInt(0))) && (res[1].equals(bigInt(1)));
} }
function inCurve(P) { function inCurve(P) {
const F = bn128.Fr;
const x2 = F.square(P[0]); const x2 = F.square(P[0]);
const y2 = F.square(P[1]); const y2 = F.square(P[1]);
if (!F.eq( if (!F.equals(
F.add(F.mul(exports.A, x2), y2), F.add(F.mul(exports.A, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false; F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false;
@@ -94,14 +73,16 @@ function inCurve(P) {
} }
function packPoint(P) { function packPoint(P) {
const buff = utils.leInt2Buff(P[1], 32); const buff = bigInt.leInt2Buff(P[1], 32);
if (F.lt(P[0], F.zero)) { if (P[0].greater(exports.p.shr(1))) {
buff[31] = buff[31] | 0x80; buff[31] = buff[31] | 0x80;
} }
return buff; return buff;
} }
function unpackPoint(_buff) { function unpackPoint(_buff) {
const F = bn128.Fr;
const buff = Buffer.from(_buff); const buff = Buffer.from(_buff);
let sign = false; let sign = false;
const P = new Array(2); const P = new Array(2);
@@ -109,8 +90,8 @@ function unpackPoint(_buff) {
sign = true; sign = true;
buff[31] = buff[31] & 0x7F; buff[31] = buff[31] & 0x7F;
} }
P[1] = utils.leBuff2int(buff); P[1] = bigInt.leBuff2int(buff);
if (Scalar.gt(P[1], exports.p)) return null; if (P[1].greaterOrEquals(exports.p)) return null;
const y2 = F.square(P[1]); const y2 = F.square(P[1]);
@@ -122,7 +103,7 @@ function unpackPoint(_buff) {
if (sign) x = F.neg(x); if (sign) x = F.neg(x);
P[0] = x; P[0] = F.affine(x);
return P; return P;
} }

View File

@@ -1,14 +1,11 @@
const createBlakeHash = require("blake-hash"); const createBlakeHash = require("blake-hash");
const Scalar = require("ffjavascript").Scalar; const bigInt = require("snarkjs").bigInt;
const F1Field = require("ffjavascript").F1Field;
const babyJub = require("./babyjub"); const babyJub = require("./babyjub");
const utils = require("ffjavascript").utils;
const pedersenHash = require("./pedersenHash").hash; const pedersenHash = require("./pedersenHash").hash;
const mimc7 = require("./mimc7"); const mimc7 = require("./mimc7");
const poseidon = require("./poseidon.js"); const poseidon = require("./poseidon.js");
const mimcsponge = require("./mimcsponge"); const mimcsponge = require("./mimcsponge");
exports.prv2pub= prv2pub; exports.prv2pub= prv2pub;
exports.sign = sign; exports.sign = sign;
exports.signMiMC = signMiMC; exports.signMiMC = signMiMC;
@@ -33,27 +30,26 @@ function pruneBuffer(_buff) {
function prv2pub(prv) { function prv2pub(prv) {
const sBuff = pruneBuffer(createBlakeHash("blake512").update(prv).digest().slice(0,32)); const sBuff = pruneBuffer(createBlakeHash("blake512").update(prv).digest().slice(0,32));
let s = utils.leBuff2int(sBuff); let s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s,3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
return A; return A;
} }
function sign(prv, msg) { function sign(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest(); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest(); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest();
let r = utils.leBuff2int(rBuff); let r = bigInt.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); r = r.mod(babyJub.subOrder);
r = Fr.e(r);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r); const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const R8p = babyJub.packPoint(R8); const R8p = babyJub.packPoint(R8);
const Ap = babyJub.packPoint(A); const Ap = babyJub.packPoint(A);
const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg])); const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
const hm = utils.leBuff2int(hmBuff); const hm = bigInt.leBuff2int(hmBuff);
const S = Fr.add(r , Fr.mul(hm, s)); const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return { return {
R8: R8, R8: R8,
S: S S: S
@@ -63,17 +59,16 @@ function sign(prv, msg) {
function signMiMC(prv, msg) { function signMiMC(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest(); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = utils.leInt2Buff(msg, 32); const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest(); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff); let r = bigInt.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); r = r.mod(babyJub.subOrder);
r = Fr.e(r);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r); const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = mimc7.multiHash([R8[0], R8[1], A[0], A[1], msg]); const hm = mimc7.multiHash([R8[0], R8[1], A[0], A[1], msg]);
const S = Fr.add(r , Fr.mul(hm, s)); const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return { return {
R8: R8, R8: R8,
S: S S: S
@@ -83,17 +78,16 @@ function signMiMC(prv, msg) {
function signMiMCSponge(prv, msg) { function signMiMCSponge(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest(); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = utils.leInt2Buff(msg, 32); const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest(); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff); let r = bigInt.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); r = r.mod(babyJub.subOrder);
r = Fr.e(r);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r); const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]); const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]);
const S = Fr.add(r , Fr.mul(hm, s)); const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return { return {
R8: R8, R8: R8,
S: S S: S
@@ -103,17 +97,17 @@ function signMiMCSponge(prv, msg) {
function signPoseidon(prv, msg) { function signPoseidon(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest(); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = utils.leInt2Buff(msg, 32); const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest(); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff); let r = bigInt.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); r = r.mod(babyJub.subOrder);
r = Fr.e(r);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r); const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = poseidon([R8[0], R8[1], A[0], A[1], msg]); const hash = poseidon.createHash(6, 8, 57);
const S = Fr.add(r , Fr.mul(hm, s)); const hm = hash([R8[0], R8[1], A[0], A[1], msg]);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return { return {
R8: R8, R8: R8,
S: S S: S
@@ -134,14 +128,14 @@ function verify(msg, sig, A) {
const R8p = babyJub.packPoint(sig.R8); const R8p = babyJub.packPoint(sig.R8);
const Ap = babyJub.packPoint(A); const Ap = babyJub.packPoint(A);
const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg])); const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
const hm = utils.leBuff2int(hmBuff); const hm = bigInt.leBuff2int(hmBuff);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S); const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm,8)); let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false; if (!Pleft[0].equals(Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],Pright[1])) return false; if (!Pleft[1].equals(Pright[1])) return false;
return true; return true;
} }
@@ -159,11 +153,11 @@ function verifyMiMC(msg, sig, A) {
const hm = mimc7.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]); const hm = mimc7.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S); const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8)); let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false; if (!Pleft[0].equals(Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],Pright[1])) return false; if (!Pleft[1].equals(Pright[1])) return false;
return true; return true;
} }
@@ -179,14 +173,15 @@ function verifyPoseidon(msg, sig, A) {
if (!babyJub.inCurve(A)) return false; if (!babyJub.inCurve(A)) return false;
if (sig.S>= babyJub.subOrder) return false; if (sig.S>= babyJub.subOrder) return false;
const hm = poseidon([sig.R8[0], sig.R8[1], A[0], A[1], msg]); 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); const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8)); let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false; if (!Pleft[0].equals(Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],Pright[1])) return false; if (!Pleft[1].equals(Pright[1])) return false;
return true; return true;
} }
@@ -204,24 +199,24 @@ function verifyMiMCSponge(msg, sig, A) {
const hm = mimcsponge.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]); const hm = mimcsponge.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S); const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.times(bigInt("8"))); let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false; if (!Pleft[0].equals(Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],Pright[1])) return false; if (!Pleft[1].equals(Pright[1])) return false;
return true; return true;
} }
function packSignature(sig) { function packSignature(sig) {
const R8p = babyJub.packPoint(sig.R8); const R8p = babyJub.packPoint(sig.R8);
const Sp = utils.leInt2Buff(sig.S, 32); const Sp = bigInt.leInt2Buff(sig.S, 32);
return Buffer.concat([R8p, Sp]); return Buffer.concat([R8p, Sp]);
} }
function unpackSignature(sigBuff) { function unpackSignature(sigBuff) {
return { return {
R8: babyJub.unpackPoint(sigBuff.slice(0,32)), R8: babyJub.unpackPoint(sigBuff.slice(0,32)),
S: utils.leBuff2int(sigBuff.slice(32,64)) S: bigInt.leBuff2int(sigBuff.slice(32,64))
}; };
} }

View File

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

View File

@@ -4,6 +4,7 @@
const Contract = require("./evmasm"); const Contract = require("./evmasm");
const G2 = require("snarkjs").bn128.G2; const G2 = require("snarkjs").bn128.G2;
const bigInt = require("snarkjs").bigInt;
function toHex256(a) { function toHex256(a) {
@@ -538,7 +539,7 @@ function createCode(P, w) {
function storeVals() { function storeVals() {
C.push(VAR_POINTS); // p C.push(VAR_POINTS); // p
for (let i=0; i<NPOINTS; i++) { for (let i=0; i<NPOINTS; i++) {
const MP = G2.affine(G2.mulScalar(P, i)); const MP = G2.affine(G2.mulScalar(P, bigInt(i)));
for (let j=0; j<2; j++) { for (let j=0; j<2; j++) {
for (let k=0; k<2; k++) { for (let k=0; k<2; k++) {
C.push(toHex256(MP[j][k])); // MP[0][0] p C.push(toHex256(MP[j][k])); // MP[0][0] p

View File

@@ -1,9 +1,7 @@
const Scalar = require("ffjavascript").Scalar; const bn128 = require("snarkjs").bn128;
const ZqField = require("ffjavascript").ZqField; const bigInt = require("snarkjs").bigInt;
const Web3Utils = require("web3-utils"); const Web3Utils = require("web3-utils");
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617")); const F = bn128.Fr;
exports.F = F;
const SEED = "mimc"; const SEED = "mimc";
const NROUNDS = 91; const NROUNDS = 91;
@@ -11,8 +9,8 @@ const NROUNDS = 91;
exports.getIV = (seed) => { exports.getIV = (seed) => {
if (typeof seed === "undefined") seed = SEED; if (typeof seed === "undefined") seed = SEED;
const c = Web3Utils.keccak256(seed+"_iv"); const c = Web3Utils.keccak256(seed+"_iv");
const cn = Scalar.FromString(Web3Utils.toBN(c).toString()); const cn = bigInt(Web3Utils.toBN(c).toString());
const iv = cn.mod(F.p); const iv = cn.mod(F.q);
return iv; return iv;
}; };
@@ -24,26 +22,26 @@ exports.getConstants = (seed, nRounds) => {
for (let i=1; i<nRounds; i++) { for (let i=1; i<nRounds; i++) {
c = Web3Utils.keccak256(c); c = Web3Utils.keccak256(c);
const n1 = Web3Utils.toBN(c).mod(Web3Utils.toBN(F.p.toString())); const n1 = Web3Utils.toBN(c).mod(Web3Utils.toBN(F.q.toString()));
const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64); const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64);
cts[i] = Scalar.fromString(Web3Utils.toBN(c2).toString()); cts[i] = bigInt(Web3Utils.toBN(c2).toString());
} }
cts[0] = F.e(0); cts[0] = bigInt(0);
return cts; return cts;
}; };
const cts = exports.getConstants(SEED, 91); const cts = exports.getConstants(SEED, 91);
exports.hash = (_x_in, _k) =>{ exports.hash = (_x_in, _k) =>{
const x_in = F.e(_x_in); const x_in = bigInt(_x_in);
const k = F.e(_k); const k = bigInt(_k);
let r; let r;
for (let i=0; i<NROUNDS; i++) { for (let i=0; i<NROUNDS; i++) {
const c = cts[i]; const c = cts[i];
const t = (i==0) ? F.add(x_in, k) : F.add(F.add(r, k), c); const t = (i==0) ? F.add(x_in, k) : F.add(F.add(r, k), c);
r = F.pow(t, 7); r = F.exp(t, 7);
} }
return F.add(r, k); return F.affine(F.add(r, k));
}; };
exports.multiHash = (arr, key) => { exports.multiHash = (arr, key) => {
@@ -59,8 +57,26 @@ exports.multiHash = (arr, key) => {
r, r,
arr[i] arr[i]
), ),
exports.hash(F.e(arr[i]), r) exports.hash(bigInt(arr[i]), r)
); );
} }
return r; 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);
}; };

View File

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

View File

@@ -1,7 +1,7 @@
const bn128 = require("snarkjs").bn128;
const bigInt = require("snarkjs").bigInt;
const babyJub = require("./babyjub"); const babyJub = require("./babyjub");
const createBlakeHash = require("blake-hash"); const createBlakeHash = require("blake-hash");
const blake2b = require("blake2b");
const Scalar = require("ffjavascript").Scalar;
const GENPOINT_PREFIX = "PedersenGenerator"; const GENPOINT_PREFIX = "PedersenGenerator";
const windowSize = 4; const windowSize = 4;
@@ -10,23 +10,13 @@ const nWindowsPerSegment = 50;
exports.hash = pedersenHash; exports.hash = pedersenHash;
exports.getBasePoint = getBasePoint; exports.getBasePoint = getBasePoint;
function baseHash(type, S) { function pedersenHash(msg) {
if (type == "blake") {
return createBlakeHash("blake256").update(S).digest();
} else if (type == "blake2b") {
return Buffer.from(blake2b(32).update(Buffer.from(S)).digest());
}
}
function pedersenHash(msg, options) {
options = options || {};
options.baseHash = options.baseHash || "blake";
const bitsPerSegment = windowSize*nWindowsPerSegment; const bitsPerSegment = windowSize*nWindowsPerSegment;
const bits = buffer2bits(msg); const bits = buffer2bits(msg);
const nSegments = Math.floor((bits.length - 1)/(windowSize*nWindowsPerSegment)) +1; const nSegments = Math.floor((bits.length - 1)/(windowSize*nWindowsPerSegment)) +1;
let accP = [babyJub.F.zero,babyJub.F.one]; let accP = [bigInt.zero,bigInt.one];
for (let s=0; s<nSegments; s++) { for (let s=0; s<nSegments; s++) {
let nWindows; let nWindows;
@@ -35,32 +25,32 @@ function pedersenHash(msg, options) {
} else { } else {
nWindows = nWindowsPerSegment; nWindows = nWindowsPerSegment;
} }
let escalar = Scalar.e(0); let escalar = bigInt.zero;
let exp = Scalar.e(1); let exp = bigInt.one;
for (let w=0; w<nWindows; w++) { for (let w=0; w<nWindows; w++) {
let o = s*bitsPerSegment + w*windowSize; let o = s*bitsPerSegment + w*windowSize;
let acc = Scalar.e(1); let acc = bigInt.one;
for (let b=0; ((b<windowSize-1)&&(o<bits.length)) ; b++) { for (let b=0; ((b<windowSize-1)&&(o<bits.length)) ; b++) {
if (bits[o]) { if (bits[o]) {
acc = Scalar.add(acc, Scalar.shl(Scalar.e(1), b) ); acc = acc.add( bigInt.one.shl(b) );
} }
o++; o++;
} }
if (o<bits.length) { if (o<bits.length) {
if (bits[o]) { if (bits[o]) {
acc = Scalar.neg(acc); acc = acc.neg();
} }
o++; o++;
} }
escalar = Scalar.add(escalar, Scalar.mul(acc, exp)); escalar = escalar.add(acc.mul(exp));
exp = Scalar.shl(exp, windowSize+1); exp = exp.shl(windowSize+1);
} }
if (Scalar.lt(escalar, 0)) { if (escalar.lesser(bigInt.zero)) {
escalar = Scalar.add( escalar, babyJub.subOrder); escalar = babyJub.subOrder.add(escalar);
} }
accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(options.baseHash, s), escalar)); accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(s), escalar));
} }
return babyJub.packPoint(accP); return babyJub.packPoint(accP);
@@ -68,13 +58,13 @@ function pedersenHash(msg, options) {
let bases = []; let bases = [];
function getBasePoint(baseHashType, pointIdx) { function getBasePoint(pointIdx) {
if (pointIdx<bases.length) return bases[pointIdx]; if (pointIdx<bases.length) return bases[pointIdx];
let p= null; let p= null;
let tryIdx = 0; let tryIdx = 0;
while (p==null) { while (p==null) {
const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32); const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32);
const h = baseHash(baseHashType, S); const h = createBlakeHash("blake256").update(S).digest();
h[31] = h[31] & 0xBF; // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1) h[31] = h[31] & 0xBF; // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1)
p = babyJub.unpackPoint(h); p = babyJub.unpackPoint(h);
tryIdx++; tryIdx++;

View File

@@ -7,15 +7,7 @@ if (typeof process.argv[2] != "undefined") {
nBases = 5; nBases = 5;
} }
let baseHash;
if (typeof process.argv[3] != "undefined") {
baseHash = process.argv[3];
} else {
baseHash = "blake";
}
for (let i=0; i < nBases; i++) { for (let i=0; i < nBases; i++) {
const p = pedersenHash.getBasePoint(baseHash, i); const p = pedersenHash.getBasePoint(i);
console.log(`[${p[0]},${p[1]}]`); console.log(`[${p[0]},${p[1]}]`);
} }

View File

@@ -1,49 +1,157 @@
const bn128 = require("snarkjs").bn128;
const bigInt = require("snarkjs").bigInt;
const blake2b = require('blake2b');
const assert = require("assert"); const assert = require("assert");
const Scalar = require("ffjavascript").Scalar; const F = bn128.Fr;
const ZqField = require("ffjavascript").ZqField;
const { unstringifyBigInts } = require("ffjavascript").utils;
// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 const SEED = "poseidon";
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617")); const NROUNDSF = 8;
const NROUNDSP = 57;
const T = 6;
// Parameters are generated by a reference script https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/generate_parameters_grain.sage function getPseudoRandom(seed, n) {
// Used like so: sage generate_parameters_grain.sage 1 0 254 2 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 const res = [];
const { C, M } = unstringifyBigInts(require("./poseidon_constants.json")); let input = Buffer.from(seed);
let h = blake2b(32).update(input).digest()
// Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8) while (res.length<n) {
// Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py const n = F.affine(bigInt.leBuff2int(h));
// And rounded up to nearest integer that divides by t res.push(n);
const N_ROUNDS_F = 8; h = blake2b(32).update(h).digest()
const N_ROUNDS_P = [56, 57, 56, 60, 60, 63, 64, 63];
const pow5 = a => F.mul(a, F.square(F.square(a, a)));
function poseidon(inputs) {
assert(inputs.length > 0);
assert(inputs.length < N_ROUNDS_P.length - 1);
const t = inputs.length + 1;
const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P[t - 2];
let state = [...inputs.map(a => F.e(a)), F.zero];
for (let r = 0; r < nRoundsF + nRoundsP; r++) {
state = state.map((a, i) => F.add(a, C[t - 2][r * t + i]));
if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
state = state.map(a => pow5(a));
} else {
state[0] = pow5(state[0]);
}
// no matrix multiplication in the last round
if (r < nRoundsF + nRoundsP - 1) {
state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(M[t - 2][i][j], a)), F.zero)
);
}
} }
return F.normalize(state[0]);
return res;
} }
module.exports = poseidon; 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);
};

File diff suppressed because it is too large Load Diff

View File

@@ -2,14 +2,14 @@
// License: LGPL-3.0+ // License: LGPL-3.0+
// //
const Poseidon = require("./poseidon.js");
const Contract = require("./evmasm"); const Contract = require("./evmasm");
const { unstringifyBigInts } = require("ffjavascript").utils;
const Web3Utils = require("web3-utils");
const { C:K, M } = unstringifyBigInts(require("./poseidon_constants.json")); const SEED = "poseidon";
const NROUNDSF = 8;
const N_ROUNDS_F = 8; const NROUNDSP = 57;
const N_ROUNDS_P = [56, 57, 56, 60, 60, 63, 64, 63]; const T = 6;
function toHex256(a) { function toHex256(a) {
let S = a.toString(16); let S = a.toString(16);
@@ -17,34 +17,38 @@ function toHex256(a) {
return "0x" + S; return "0x" + S;
} }
function createCode(nInputs) { 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;
if (( nInputs<1) || (nInputs>8)) throw new Error("Invalid number of inputs. Must be 1<=nInputs<=8"); const K = Poseidon.getConstants(t, seed, nRoundsP + nRoundsF);
const t = nInputs + 1; const M = Poseidon.getMatrix(t, seed, nRoundsP + nRoundsF);
const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P[t - 2];
const C = new Contract(); const C = new Contract();
function saveM() { function saveM() {
for (let i=0; i<t; i++) { for (let i=0; i<t; i++) {
for (let j=0; j<t; j++) { for (let j=0; j<t; j++) {
C.push(toHex256(M[t-2][i][j])); C.push(toHex256(M[i][j]));
C.push((1+i*t+j)*32); C.push((1+i*t+j)*32);
C.mstore(); C.mstore();
} }
} }
} }
function ark(r) { // st, q function ark(r) {
C.push(toHex256(K[r])); // K, st, q
for (let i=0; i<t; i++) { for (let i=0; i<t; i++) {
C.dup(t); // q, st, q C.dup(1+t); // q, K, st, q
C.push(toHex256(K[t-2][r*t+i])); // K, q, st, q C.dup(1); // K, q, K, st, q
C.dup(2+i); // st[i], K, q, st, q C.dup(3+i); // st[i], K, q, K, st, q
C.addmod(); // newSt[i], st, q C.addmod(); // newSt[i], K, st, q
C.swap(1 + i); // xx, st, q C.swap(2 + i); // xx, K, st, q
C.pop(); C.pop();
} }
C.pop();
} }
function sigma(p) { function sigma(p) {
@@ -100,13 +104,8 @@ function createCode(nInputs) {
C.push(0); C.push(0);
C.calldataload(); C.calldataload();
C.div(); C.div();
C.dup(0); C.push("0xc4420fb4"); // poseidon(uint256[])
C.push(Web3Utils.keccak256(`poseidon(uint256[${nInputs}])`).slice(0, 10)); // poseidon(uint256[n])
C.eq(); C.eq();
C.swap(1);
C.push(Web3Utils.keccak256(`poseidon(bytes32[${nInputs}])`).slice(0, 10)); // poseidon(bytes32[n])
C.eq();
C.or();
C.jmpi("start"); C.jmpi("start");
C.invalid(); C.invalid();
@@ -116,16 +115,17 @@ function createCode(nInputs) {
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
// Load t values from the call data. // Load 6 values from the call data.
// The function has a single array param param // The function has a single array param param
// [Selector (4)] [item1 (32)] [item2 (32)] .... // [Selector (4)] [Pointer (32)][Length (32)] [data1 (32)] ....
// Stack positions 0-nInputs. // 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++) { for (let i=0; i<t; i++) {
C.push(0x04+(0x20*(nInputs-i))); C.push(0x44+(0x20*(5-i)));
C.calldataload(); C.calldataload();
} }
for (let i=0; i<nRoundsF+nRoundsP-1; i++) { for (let i=0; i<nRoundsF+nRoundsP; i++) {
ark(i); ark(i);
if ((i<nRoundsF/2) || (i>=nRoundsP+nRoundsF/2)) { if ((i<nRoundsF/2) || (i>=nRoundsP+nRoundsF/2)) {
for (let j=0; j<t; j++) { for (let j=0; j<t; j++) {
@@ -142,13 +142,6 @@ function createCode(nInputs) {
C.label(strLabel); C.label(strLabel);
} }
C.push(toHex256(K[t-2][(nRoundsF+nRoundsP-1)*t])); // K, st, q
C.dup(t+1); // q, K, st, q
C.swap(2); // st[0], K, q, st\st[0]
C.addmod(); // st q
sigma(0);
C.push("0x00"); C.push("0x00");
C.mstore(); // Save it to pos 0; C.mstore(); // Save it to pos 0;
C.push("0x20"); C.push("0x20");
@@ -160,54 +153,28 @@ function createCode(nInputs) {
return C.createTxData(); return C.createTxData();
} }
function generateABI(nInputs) { module.exports.abi = [
return [ {
{ "constant": true,
"constant": true, "inputs": [
"inputs": [ {
{ "name": "input",
"internalType": `bytes32[${nInputs}]`, "type": "uint256[]"
"name": "input", }
"type": `bytes32[${nInputs}]` ],
} "name": "poseidon",
], "outputs": [
"name": "poseidon", {
"outputs": [ "name": "",
{ "type": "uint256"
"internalType": "bytes32", }
"name": "", ],
"type": "bytes32" "payable": false,
} "stateMutability": "pure",
], "type": "function"
"payable": false, }
"stateMutability": "pure", ];
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": `uint256[${nInputs}]`,
"name": "input",
"type": `uint256[${nInputs}]`
}
],
"name": "poseidon",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
];
}
module.exports.generateABI = generateABI;
module.exports.createCode = createCode; 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

@@ -1,13 +1,5 @@
const poseidonGenContract = require("./poseidon_gencontract"); const poseidonGenContract = require("./poseidon_gencontract");
if (process.argv.length != 3) {
console.log("Usage: node poseidon_gencontract.js [numberOfInputs]");
process.exit(1);
}
const nInputs = Number(process.argv[2]); console.log(poseidonGenContract.createCode(6, 8, 57));
console.log(nInputs);
console.log(poseidonGenContract.createCode(nInputs));

View File

@@ -1,6 +1,7 @@
const Scalar = require("ffjavascript").Scalar; const bigInt = require("snarkjs").bigInt;
const SMTMemDB = require("./smt_memdb"); const SMTMemDB = require("./smt_memdb");
const {hash0, hash1, F} = require("./smt_hashes_poseidon"); const {hash0, hash1} = require("./smt_hashes_poseidon");
class SMT { class SMT {
@@ -10,7 +11,18 @@ class SMT {
} }
_splitBits(_key) { _splitBits(_key) {
const res = Scalar.bits(_key);
let k = bigInt(_key);
const res = [];
while (!k.isZero()) {
if (k.isOdd()) {
res.push(true);
} else {
res.push(false);
}
k = k.shr(1);
}
while (res.length<256) res.push(false); while (res.length<256) res.push(false);
@@ -18,8 +30,8 @@ class SMT {
} }
async update(_key, _newValue) { async update(_key, _newValue) {
const key = Scalar.e(_key); const key = bigInt(_key);
const newValue = F.e(_newValue); const newValue = bigInt(_newValue);
const resFind = await this.find(key); const resFind = await this.find(key);
@@ -58,16 +70,16 @@ class SMT {
res.newRoot = rtNew; res.newRoot = rtNew;
await this.db.multiDel(dels);
await this.db.multiIns(ins); await this.db.multiIns(ins);
await this.db.setRoot(rtNew); await this.db.setRoot(rtNew);
this.root = rtNew; this.root = rtNew;
await this.db.multiDel(dels);
return res; return res;
} }
async delete(_key) { async delete(_key) {
const key = Scalar.e(_key); const key = bigInt(_key);
const resFind = await this.find(key); const resFind = await this.find(key);
if (!resFind.found) throw new Error("Key does not exists"); if (!resFind.found) throw new Error("Key does not exists");
@@ -87,7 +99,7 @@ class SMT {
let mixed; let mixed;
if (resFind.siblings.length > 0) { if (resFind.siblings.length > 0) {
const record = await this.db.get(resFind.siblings[resFind.siblings.length - 1]); const record = await this.db.get(resFind.siblings[resFind.siblings.length - 1]);
if ((record.length == 3)&&(F.eq(record[0], F.one))) { if ((record.length == 3)&&(record[0].equals(bigInt.one))) {
mixed = false; mixed = false;
res.oldKey = record[1]; res.oldKey = record[1];
res.oldValue = record[2]; res.oldValue = record[2];
@@ -96,16 +108,16 @@ class SMT {
} else if (record.length == 2) { } else if (record.length == 2) {
mixed = true; mixed = true;
res.oldKey = key; res.oldKey = key;
res.oldValue = F.zero; res.oldValue = bigInt(0);
res.isOld0 = true; res.isOld0 = true;
rtNew = F.zero; rtNew = bigInt.zero;
} else { } else {
throw new Error("Invalid node. Database corrupted"); throw new Error("Invalid node. Database corrupted");
} }
} else { } else {
rtNew = F.zero; rtNew = bigInt.zero;
res.oldKey = key; res.oldKey = key;
res.oldValue = F.zero; res.oldValue = bigInt(0);
res.isOld0 = true; res.isOld0 = true;
} }
@@ -114,7 +126,7 @@ class SMT {
for (let level = resFind.siblings.length-1; level >=0; level--) { for (let level = resFind.siblings.length-1; level >=0; level--) {
let newSibling = resFind.siblings[level]; let newSibling = resFind.siblings[level];
if ((level == resFind.siblings.length-1)&&(!res.isOld0)) { if ((level == resFind.siblings.length-1)&&(!res.isOld0)) {
newSibling = F.zero; newSibling = bigInt.zero;
} }
const oldSibling = resFind.siblings[level]; const oldSibling = resFind.siblings[level];
if (keyBits[level]) { if (keyBits[level]) {
@@ -123,7 +135,7 @@ class SMT {
rtOld = hash0(rtOld, oldSibling); rtOld = hash0(rtOld, oldSibling);
} }
dels.push(rtOld); dels.push(rtOld);
if (!F.isZero(newSibling)) { if (!newSibling.isZero()) {
mixed = true; mixed = true;
} }
@@ -152,8 +164,8 @@ class SMT {
} }
async insert(_key, _value) { async insert(_key, _value) {
const key = Scalar.e(_key); const key = bigInt(_key);
const value = F.e(_value); const value = bigInt(_value);
let addedOne = false; let addedOne = false;
const res = {}; const res = {};
res.oldRoot = this.root; res.oldRoot = this.root;
@@ -171,7 +183,7 @@ class SMT {
if (!resFind.isOld0) { if (!resFind.isOld0) {
const oldKeyits = this._splitBits(resFind.notFoundKey); const oldKeyits = this._splitBits(resFind.notFoundKey);
for (let i= res.siblings.length; oldKeyits[i] == newKeyBits[i]; i++) { for (let i= res.siblings.length; oldKeyits[i] == newKeyBits[i]; i++) {
res.siblings.push(F.zero); res.siblings.push(bigInt.zero);
} }
rtOld = hash1(resFind.notFoundKey, resFind.notFoundValue); rtOld = hash1(resFind.notFoundKey, resFind.notFoundValue);
res.siblings.push(rtOld); res.siblings.push(rtOld);
@@ -179,7 +191,7 @@ class SMT {
mixed = false; mixed = false;
} else if (res.siblings.length >0) { } else if (res.siblings.length >0) {
mixed = true; mixed = true;
rtOld = F.zero; rtOld = bigInt.zero;
} }
const inserts = []; const inserts = [];
@@ -189,7 +201,7 @@ class SMT {
inserts.push([rt,[1, key, value]] ); inserts.push([rt,[1, key, value]] );
for (let i=res.siblings.length-1; i>=0; i--) { for (let i=res.siblings.length-1; i>=0; i--) {
if ((i<res.siblings.length-1)&&(!F.isZero(res.siblings[i]))) { if ((i<res.siblings.length-1)&&(!res.siblings[i].isZero())) {
mixed = true; mixed = true;
} }
if (mixed) { if (mixed) {
@@ -215,7 +227,7 @@ class SMT {
} }
if (addedOne) res.siblings.pop(); if (addedOne) res.siblings.pop();
while ((res.siblings.length>0) && (F.isZero(res.siblings[res.siblings.length-1]))) { while ((res.siblings.length>0) && (res.siblings[res.siblings.length-1].isZero())) {
res.siblings.pop(); res.siblings.pop();
} }
res.oldKey = resFind.notFoundKey; res.oldKey = resFind.notFoundKey;
@@ -241,12 +253,12 @@ class SMT {
if (typeof root === "undefined") root = this.root; if (typeof root === "undefined") root = this.root;
let res; let res;
if (F.isZero(root)) { if (root.isZero()) {
res = { res = {
found: false, found: false,
siblings: [], siblings: [],
notFoundKey: key, notFoundKey: key,
notFoundValue: F.zero, notFoundValue: bigInt.zero,
isOld0: true isOld0: true
}; };
return res; return res;
@@ -254,8 +266,8 @@ class SMT {
const record = await this.db.get(root); const record = await this.db.get(root);
if ((record.length==3)&&(F.eq(record[0],F.one))) { if ((record.length==3)&&(record[0].equals(bigInt.one))) {
if (F.eq(record[1],key)) { if (record[1].equals(key)) {
res = { res = {
found: true, found: true,
siblings: [], siblings: [],
@@ -297,5 +309,3 @@ async function newMemEmptyTrie() {
module.exports.loadFromFile = loadFromFile; module.exports.loadFromFile = loadFromFile;
module.exports.newMemEmptyTrie = newMemEmptyTrie; module.exports.newMemEmptyTrie = newMemEmptyTrie;
module.exports.SMT = SMT;
module.exports.SMTMemDB = SMTMemDB;

View File

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

View File

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

View File

@@ -1,14 +1,9 @@
const bigInt = require("snarkjs").bigInt;
const Scalar = require("ffjavascript").Scalar;
const ZqField = require("ffjavascript").ZqField;
// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
class SMTMemDb { class SMTMemDb {
constructor() { constructor() {
this.nodes = {}; this.nodes = {};
this.root = F.zero; this.root = bigInt(0);
} }
async getRoot() { async getRoot() {
@@ -17,13 +12,13 @@ class SMTMemDb {
_key2str(k) { _key2str(k) {
// const keyS = bigInt(key).leInt2Buff(32).toString("hex"); // const keyS = bigInt(key).leInt2Buff(32).toString("hex");
const keyS = k.toString(); const keyS = bigInt(k).toString();
return keyS; return keyS;
} }
_normalize(n) { _normalize(n) {
for (let i=0; i<n.length; i++) { for (let i=0; i<n.length; i++) {
n[i] = F.e(n[i]); n[i] = bigInt(n[i]);
} }
} }
@@ -32,14 +27,6 @@ class SMTMemDb {
return this.nodes[keyS]; return this.nodes[keyS];
} }
async multiGet(keys) {
const promises = [];
for (let i=0; i<keys.length; i++) {
promises.push(this.get(keys[i]));
}
return await Promise.all(promises);
}
async setRoot(rt) { async setRoot(rt) {
this.root = rt; this.root = rt;
} }

View File

@@ -1,15 +1,11 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const assert = chai.assert; const assert = chai.assert;
const Scalar = require("ffjavascript").Scalar; const bigInt = snarkjs.bigInt;
const F1Field = require("ffjavascript").F1Field;
const utils = require("ffjavascript").utils;
const q = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const F = new F1Field(q);
const tester = require("circom").tester;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
@@ -18,59 +14,60 @@ function print(circuit, w, s) {
function getBits(v, n) { function getBits(v, n) {
const res = []; const res = [];
for (let i=0; i<n; i++) { for (let i=0; i<n; i++) {
if (Scalar.isOdd(Scalar.shr(v,i))) { if (v.shr(i).isOdd()) {
res.push(F.one); res.push(bigInt.one);
} else { } else {
res.push(F.zero); res.push(bigInt.zero);
} }
} }
return res; return res;
} }
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
describe("Aliascheck test", function () { describe("Aliascheck test", () => {
this.timeout(100000); let circuit;
let cir;
before( async() => { before( async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "aliascheck_test.circom"));
cir = await tester(path.join(__dirname, "circuits", "aliascheck_test.circom")); circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
}); });
it("Satisfy the aliastest 0", async () => { it("Satisfy the aliastest 0", async () => {
const inp = getBits(0, 254); const inp = getBits(bigInt.zero, 254);
await cir.calculateWitness({in: inp}, true); circuit.calculateWitness({in: inp});
}); });
it("Satisfy the aliastest 3", async () => { it("Satisfy the aliastest 3", async () => {
const inp = getBits(3, 254); const inp = getBits(bigInt(3), 254);
await cir.calculateWitness({in: inp}, true); circuit.calculateWitness({in: inp});
}); });
it("Satisfy the aliastest q-1", async () => { it("Satisfy the aliastest q-1", async () => {
const inp = getBits(F.minusone, 254); const inp = getBits(q.sub(bigInt.one), 254);
// console.log(JSON.stringify(utils.stringifyBigInts(inp))); circuit.calculateWitness({in: inp});
await cir.calculateWitness({in: inp}, true);
}); });
it("Should not satisfy an input of q", async () => { it("Nhot not satisfy an input of q", async () => {
const inp = getBits(q, 254); const inp = getBits(q, 254);
try { try {
await cir.calculateWitness({in: inp}, true); circuit.calculateWitness({in: inp});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) ); assert.equal(err.message, "Constraint doesn't match: 1 != 0");
} }
}); });
it("Should not satisfy all ones", async () => { it("Nhot not satisfy all ones", async () => {
const inp = getBits(Scalar.sub(Scalar.shl(1, 254) , 1) , 254); const inp = getBits(bigInt(1).shl(254).sub(bigInt(1)), 254);
try { try {
await cir.calculateWitness({in: inp}, true); circuit.calculateWitness({in: inp});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) ); assert.equal(err.message, "Constraint doesn't match: 1 != 0");
} }
}); });

View File

@@ -1,113 +1,125 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const createBlakeHash = require("blake-hash"); const createBlakeHash = require("blake-hash");
const eddsa = require("../src/eddsa.js"); const eddsa = require("../src/eddsa.js");
const F = require("../src/babyjub.js").F;
const assert = chai.assert; const assert = chai.assert;
const tester = require("circom").tester; const bigInt = require("snarkjs").bigInt;
const utils = require("ffjavascript").utils;
const Scalar = require("ffjavascript").Scalar;
describe("Baby Jub test", function () { describe("Baby Jub test", function () {
let circuitAdd; let circuitAdd;
let circuitTest; let circuitTest;
let circuitPbk;
this.timeout(100000); this.timeout(100000);
before( async() => { before( async() => {
circuitAdd = await tester(path.join(__dirname, "circuits", "babyadd_tester.circom")); const cirDefAdd = await compiler(path.join(__dirname, "circuits", "babyadd_tester.circom"));
circuitAdd = new snarkjs.Circuit(cirDefAdd);
console.log("NConstrains BabyAdd: " + circuitAdd.nConstraints);
circuitTest = await tester(path.join(__dirname, "circuits", "babycheck_test.circom")); 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);
circuitPbk = await tester(path.join(__dirname, "circuits", "babypbk_test.circom"));
}); });
it("Should add point (0,1) and (0,1)", async () => { it("Should add point (0,1) and (0,1)", async () => {
const input={ const input={
x1: F.e(0), x1: snarkjs.bigInt(0),
y1: F.e(1), y1: snarkjs.bigInt(1),
x2: F.e(0), x2: snarkjs.bigInt(0),
y2: F.e(1) y2: snarkjs.bigInt(1)
}; };
const w = await circuitAdd.calculateWitness(input, true); const w = circuitAdd.calculateWitness(input);
await circuitAdd.assertOut(w, {xout: F.e(0), yout: F.e(1)}); const xout = w[circuitAdd.getSignalIdx("main.xout")];
const yout = w[circuitAdd.getSignalIdx("main.yout")];
assert(xout.equals(0));
assert(yout.equals(1));
}); });
it("Should add 2 same numbers", async () => { it("Should add 2 same numbers", async () => {
const input={ const input={
x1: F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
y1: F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
x2: F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), x2: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
y2: F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475") y2: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")
}; };
const w = await circuitAdd.calculateWitness(input, true); const w = circuitAdd.calculateWitness(input);
await circuitAdd.assertOut(w, { const xout = w[circuitAdd.getSignalIdx("main.xout")];
xout: F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"), const yout = w[circuitAdd.getSignalIdx("main.yout")];
yout: F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889")
});
assert(xout.equals(snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365")));
assert(yout.equals(snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889")));
}); });
it("Should add 2 different numbers", async () => { it("Should add 2 different numbers", async () => {
const input={ const input={
x1: F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
y1: F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
x2: F.e("16540640123574156134436876038791482806971768689494387082833631921987005038935"), x2: snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"),
y2: F.e("20819045374670962167435360035096875258406992893633759881276124905556507972311") y2: snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311")
}; };
const w = await circuitAdd.calculateWitness(input, true); const w = circuitAdd.calculateWitness(input);
await circuitAdd.assertOut(w, { const xout = w[circuitAdd.getSignalIdx("main.xout")];
xout: F.e("7916061937171219682591368294088513039687205273691143098332585753343424131937"), const yout = w[circuitAdd.getSignalIdx("main.yout")];
yout: F.e("14035240266687799601661095864649209771790948434046947201833777492504781204499")
});
/*
console.log(xout.toString());
console.log(yout.toString());
*/
assert(xout.equals(snarkjs.bigInt("7916061937171219682591368294088513039687205273691143098332585753343424131937")));
assert(yout.equals(snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499")));
}); });
it("Should check (0,1) is a valid point", async() => { it("Should check 0 is a valid poiny", async() => {
const w = await circuitTest.calculateWitness({x: 0, y:1}, true); const w = circuitTest.calculateWitness({x: 0, y:1});
assert(circuitTest.checkWitness(w));
await circuitTest.checkConstraints(w);
}); });
it("Should check (1,0) is an invalid point", async() => { it("Should check 0 is an invalid poiny", async() => {
try { try {
await circuitTest.calculateWitness({x: 1, y: 0}, true); circuitTest.calculateWitness({x: 1, y: 0});
assert(false, "Should be a valid point"); assert(false, "Should be a valid point");
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)168700\s!=\s1/.test(err.message) ); assert.equal(err.message, "Constraint doesn't match: 168700 != 1");
} }
}); });
it("Should extract the public key from the private one", async () => { it("Should extract the public key from the private one", async () => {
const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex"); const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex");
const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0,32)); const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0,32));
const S = Scalar.shr(utils.leBuff2int(pvk), 3); const S = bigInt.leBuff2int(pvk).shr(3);
const A = eddsa.prv2pub(rawpvk); const A = eddsa.prv2pub(rawpvk);
const input = { const input = {
in : S in : S,
}; Ax : A[0],
Ay : A[1]
}
const w = await circuitPbk.calculateWitness(input, true); const w = circuitPbk.calculateWitness(input);
assert(circuitPbk.checkWitness(w));
await circuitPbk.assertOut(w, {Ax : A[0], Ay: A[1]});
await circuitPbk.checkConstraints(w);
}); });
}); });

View File

@@ -1,6 +1,8 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const babyjub = require("../src/babyjub.js"); const babyjub = require("../src/babyjub.js");
const Scalar = require("ffjavascript").Scalar;
const assert = chai.assert; const assert = chai.assert;
@@ -14,16 +16,16 @@ describe("Baby Jub js test", function () {
it("Should add point (0,1) and (0,1)", () => { it("Should add point (0,1) and (0,1)", () => {
const p1 = [ const p1 = [
babyjub.F.e(0), snarkjs.bigInt(0),
babyjub.F.e(1)]; snarkjs.bigInt(1)];
const p2 = [ const p2 = [
babyjub.F.e(0), snarkjs.bigInt(0),
babyjub.F.e(1) snarkjs.bigInt(1)
]; ];
const out = babyjub.addPoint(p1, p2); const out = babyjub.addPoint(p1, p2)
assert(babyjub.F.eq(out[0], babyjub.F.zero)); assert(out[0].equals(0));
assert(babyjub.F.eq(out[1], babyjub.F.one)); assert(out[1].equals(1));
}); });
it("Should base be 8*generator", () => { it("Should base be 8*generator", () => {
@@ -32,50 +34,50 @@ describe("Baby Jub js test", function () {
res = babyjub.addPoint(res, res); res = babyjub.addPoint(res, res);
res = babyjub.addPoint(res, res); res = babyjub.addPoint(res, res);
assert(babyjub.F.eq(res[0], babyjub.Base8[0])); assert(res[0].equals(babyjub.Base8[0]));
assert(babyjub.F.eq(res[1], babyjub.Base8[1])); assert(res[1].equals(babyjub.Base8[1]));
}); });
it("Should add 2 same numbers", () => { it("Should add 2 same numbers", () => {
const p1 = [ const p1 = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const p2 = [ const p2 = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const out = babyjub.addPoint(p1, p2); const out = babyjub.addPoint(p1, p2)
assert(babyjub.F.eq(out[0], babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"))); assert(out[0].equals(snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365")));
assert(babyjub.F.eq(out[1], babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"))); assert(out[1].equals(snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889")));
}); });
it("Should add 2 different numbers", () => { it("Should add 2 different numbers", () => {
const p1 = [ const p1 = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const p2 = [ const p2 = [
babyjub.F.e("16540640123574156134436876038791482806971768689494387082833631921987005038935"), snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"),
babyjub.F.e("20819045374670962167435360035096875258406992893633759881276124905556507972311"), snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"),
]; ];
const out = babyjub.addPoint(p1, p2); const out = babyjub.addPoint(p1, p2)
assert(babyjub.F.eq(out[0], babyjub.F.e("7916061937171219682591368294088513039687205273691143098332585753343424131937")));
assert(babyjub.F.eq(out[1], babyjub.F.e("14035240266687799601661095864649209771790948434046947201833777492504781204499")));
assert(out[0].equals(snarkjs.bigInt("7916061937171219682591368294088513039687205273691143098332585753343424131937")));
assert(out[1].equals(snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499")));
}); });
it("should mulPointEscalar 0", () => { it("should mulPointEscalar 0", () => {
const p = [ const p = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const r = babyjub.mulPointEscalar(p, 3); const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("3"));
let r2 = babyjub.addPoint(p, p); let r2 = babyjub.addPoint(p, p);
r2 = babyjub.addPoint(r2, p); r2 = babyjub.addPoint(r2, p);
assert.equal(r2[0].toString(), r[0].toString()); assert.equal(r2[0].toString(), r[0].toString());
@@ -86,65 +88,65 @@ describe("Baby Jub js test", function () {
it("should mulPointEscalar 1", () => { it("should mulPointEscalar 1", () => {
const p = [ const p = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const r = babyjub.mulPointEscalar(p, Scalar.fromString("14035240266687799601661095864649209771790948434046947201833777492504781204499")); const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499"));
assert.equal(r[0].toString(), "17070357974431721403481313912716834497662307308519659060910483826664480189605"); assert.equal(r[0].toString(), "17070357974431721403481313912716834497662307308519659060910483826664480189605");
assert.equal(r[1].toString(), "4014745322800118607127020275658861516666525056516280575712425373174125159339"); assert.equal(r[1].toString(), "4014745322800118607127020275658861516666525056516280575712425373174125159339");
}); });
it("should mulPointEscalar 2", () => { it("should mulPointEscalar 2", () => {
const p = [ const p = [
babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"), snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"), snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
const r = babyjub.mulPointEscalar(p, Scalar.fromString("20819045374670962167435360035096875258406992893633759881276124905556507972311")); const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"));
assert.equal(r[0].toString(), "13563888653650925984868671744672725781658357821216877865297235725727006259983"); assert.equal(r[0].toString(), "13563888653650925984868671744672725781658357821216877865297235725727006259983");
assert.equal(r[1].toString(), "8442587202676550862664528699803615547505326611544120184665036919364004251662"); assert.equal(r[1].toString(), "8442587202676550862664528699803615547505326611544120184665036919364004251662");
}); });
it("should inCurve 1", () => { it("should inCurve 1", () => {
const p = [ const p = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
assert(babyjub.inCurve(p)); assert(babyjub.inCurve(p));
}); });
it("should inCurve 2", () => { it("should inCurve 2", () => {
const p = [ const p = [
babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"), snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"), snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
assert(babyjub.inCurve(p)); assert(babyjub.inCurve(p));
}); });
it("should inSubgroup 1", () => { it("should inSubgroup 1", () => {
const p = [ const p = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
assert(babyjub.inSubgroup(p)); assert(babyjub.inSubgroup(p));
}); });
it("should inSubgroup 2", () => { it("should inSubgroup 2", () => {
const p = [ const p = [
babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"), snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"), snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
assert(babyjub.inSubgroup(p)); assert(babyjub.inSubgroup(p));
}); });
it("should packPoint - unpackPoint 1", () => { it("should packPoint - unpackPoint 1", () => {
const p = [ const p = [
babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"), snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const buf = babyjub.packPoint(p); const buf = babyjub.packPoint(p);
assert.equal(buf.toString("hex"), "53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85"); assert.equal(buf.toString('hex'), '53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85');
const p2 = babyjub.unpackPoint(buf); const p2 = babyjub.unpackPoint(buf);
assert.equal(p2[0].toString(), "17777552123799933955779906779655732241715742912184938656739573121738514868268"); assert.equal(p2[0].toString(), "17777552123799933955779906779655732241715742912184938656739573121738514868268");
assert.equal(p2[1].toString(), "2626589144620713026669568689430873010625803728049924121243784502389097019475"); assert.equal(p2[1].toString(), "2626589144620713026669568689430873010625803728049924121243784502389097019475");
@@ -152,11 +154,11 @@ describe("Baby Jub js test", function () {
it("should packPoint - unpackPoint 2", () => { it("should packPoint - unpackPoint 2", () => {
const p = [ const p = [
babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"), snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"), snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
const buf = babyjub.packPoint(p); const buf = babyjub.packPoint(p);
assert.equal(buf.toString("hex"), "e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709"); assert.equal(buf.toString('hex'), 'e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709');
const p2 = babyjub.unpackPoint(buf); const p2 = babyjub.unpackPoint(buf);
assert.equal(p2[0].toString(), "6890855772600357754907169075114257697580319025794532037257385534741338397365"); assert.equal(p2[0].toString(), "6890855772600357754907169075114257697580319025794532037257385534741338397365");
assert.equal(p2[1].toString(), "4338620300185947561074059802482547481416142213883829469920100239455078257889"); assert.equal(p2[1].toString(), "4338620300185947561074059802482547481416142213883829469920100239455078257889");

View File

@@ -1,52 +1,55 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr; const assert = chai.assert;
const Scalar = require("ffjavascript").Scalar;
const tester = require("circom").tester; const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
async function checkSub(_a,_b, circuit) { function checkSub(_a,_b, circuit) {
let a=Scalar.e(_a); let a=bigInt(_a);
let b=Scalar.e(_b); let b=bigInt(_b);
if (Scalar.lt(a, 0)) a = Scalar.add(a, Scalar.shl(1, 16)); if (a.lesser(bigInt.zero)) a = a.add(bigInt.one.shl(16));
if (Scalar.lt(b, 0)) b = Scalar.add(b, Scalar.shl(1, 16)); if (b.lesser(bigInt.zero)) b = b.add(bigInt.one.shl(16));
const w = await circuit.calculateWitness({a: a, b: b}, true); const w = circuit.calculateWitness({a: a, b: b});
let res = Scalar.sub(a, b); let res = a.sub(b);
if (Scalar.lt(res, 0)) res = Scalar.add(res, Scalar.shl(1, 16)); if (res.lesser(bigInt.zero)) res = res.add(bigInt.one.shl(16));
assert( w[circuit.getSignalIdx("main.out")].equals(bigInt(res)) );
await circuit.assertOut(w, {out: res});
} }
describe("BinSub test", function () { describe("BinSub test", () => {
this.timeout(100000);
let circuit; let circuit;
before( async() => { before( async() => {
circuit = await tester(path.join(__dirname, "circuits", "binsub_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "binsub_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains BinSub: " + circuit.nConstraints);
}); });
it("Should check variuos ege cases", async () => { it("Should check variuos ege cases", async () => {
await checkSub(0,0, circuit); checkSub(0,0, circuit);
await checkSub(1,0, circuit); checkSub(1,0, circuit);
await checkSub(-1,0, circuit); checkSub(-1,0, circuit);
await checkSub(2,1, circuit); checkSub(2,1, circuit);
await checkSub(2,2, circuit); checkSub(2,2, circuit);
await checkSub(2,3, circuit); checkSub(2,3, circuit);
await checkSub(2,-1, circuit); checkSub(2,-1, circuit);
await checkSub(2,-2, circuit); checkSub(2,-2, circuit);
await checkSub(2,-3, circuit); checkSub(2,-3, circuit);
await checkSub(-2,-3, circuit); checkSub(-2,-3, circuit);
await checkSub(-2,-2, circuit); checkSub(-2,-2, circuit);
await checkSub(-2,-1, circuit); checkSub(-2,-1, circuit);
await checkSub(-2,0, circuit); checkSub(-2,0, circuit);
await checkSub(-2,1, circuit); checkSub(-2,1, circuit);
await checkSub(-2,2, circuit); checkSub(-2,2, circuit);
await checkSub(-2,3, circuit); checkSub(-2,3, circuit);
}); });

View File

@@ -1,37 +1,35 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const crypto = require("crypto");
const tester = require("circom").tester; const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr;
const assert = chai.assert; const assert = chai.assert;
describe("Binary sum test", function () { describe("Sum test", () => {
this.timeout(100000000);
it("Should create a constant circuit", async () => { it("Should create a constant circuit", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "constants_test.circom"));
await circuit.loadConstraints();
assert.equal(circuit.nVars, 2); const cirDef = await compiler(path.join(__dirname, "circuits", "constants_test.circom"));
assert.equal(circuit.constraints.length, 1); assert.equal(cirDef.nVars, 2);
const witness = await circuit.calculateWitness({ "in": Fr.e("d807aa98", 16)}, true); const circuit = new snarkjs.Circuit(cirDef);
assert(Fr.eq(witness[0],Fr.e(1))); const witness = circuit.calculateWitness({ "in": "0xd807aa98" });
assert(Fr.eq(witness[1],Fr.e("d807aa98", 16)));
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt("0xd807aa98")));
}); });
it("Should create a sum circuit", async () => { it("Should create a sum circuit", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "sum_test.circom"));
await circuit.loadConstraints();
assert.equal(circuit.constraints.length, 97); // 32 (in1) + 32(in2) + 32(out) + 1 (carry) const cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom"));
assert.equal(cirDef.nVars, 101);
const witness = await circuit.calculateWitness({ "a": "111", "b": "222" }, true); const circuit = new snarkjs.Circuit(cirDef);
assert(Fr.eq(witness[0],Fr.e(1))); const witness = circuit.calculateWitness({ "a": "111", "b": "222" });
assert(Fr.eq(witness[1],Fr.e("333")));
assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt("333")));
}); });
}); });

View File

@@ -6,8 +6,6 @@ template A() {
signal input b; signal input b;
signal output out; signal output out;
var i;
component n2ba = Num2Bits(16); component n2ba = Num2Bits(16);
component n2bb = Num2Bits(16); component n2bb = Num2Bits(16);
component sub = BinSub(16); component sub = BinSub(16);
@@ -16,12 +14,9 @@ template A() {
n2ba.in <== a; n2ba.in <== a;
n2bb.in <== b; n2bb.in <== b;
for (i=0; i<16; i++) { for (var i=0; i<16; i++) {
sub.in[0][i] <== n2ba.out[i]; sub.in[0][i] <== n2ba.out[i];
sub.in[1][i] <== n2bb.out[i]; sub.in[1][i] <== n2bb.out[i];
}
for (i=0; i<16; i++) {
b2n.in[i] <== sub.out[i]; b2n.in[i] <== sub.out[i];
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,8 +6,6 @@ template A() {
signal input b; signal input b;
signal output out; signal output out;
var i;
component n2ba = Num2Bits(32); component n2ba = Num2Bits(32);
component n2bb = Num2Bits(32); component n2bb = Num2Bits(32);
component sum = BinSum(32,2); component sum = BinSum(32,2);
@@ -16,12 +14,9 @@ template A() {
n2ba.in <== a; n2ba.in <== a;
n2bb.in <== b; n2bb.in <== b;
for (i=0; i<32; i++) { for (var i=0; i<32; i++) {
sum.in[0][i] <== n2ba.out[i]; sum.in[0][i] <== n2ba.out[i];
sum.in[1][i] <== n2bb.out[i]; sum.in[1][i] <== n2bb.out[i];
}
for (i=0; i<32; i++) {
b2n.in[i] <== sum.out[i]; b2n.in[i] <== sum.out[i];
} }

View File

@@ -1,185 +1,193 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const crypto = require("crypto");
const tester = require("circom").tester; const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr;
const assert = chai.assert; const assert = chai.assert;
describe("Comparators test", function () { describe("Sum test", () => {
this.timeout(100000);
it("Should create a iszero circuit", async() => { it("Should create a iszero circuit", async() => {
const circuit = await tester(path.join(__dirname, "circuits", "iszero.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "iszero.circom"));
const circuit = new snarkjs.Circuit(cirDef);
let witness; let witness;
witness = await circuit.calculateWitness({ "in": 111}, true); witness = circuit.calculateWitness({ "in": 111});
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": 0 }, true); witness = circuit.calculateWitness({ "in": 0 });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
}); });
it("Should create a isequal circuit", async() => { it("Should create a isequal circuit", async() => {
const circuit = await tester(path.join(__dirname, "circuits", "isequal.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "isequal.circom"));
const circuit = new snarkjs.Circuit(cirDef);
let witness; let witness;
witness = await circuit.calculateWitness({ "in": [111,222] }, true); witness = circuit.calculateWitness({ "in[0]": "111", "in[1]": "222" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = circuit.calculateWitness({ "in[0]": "444", "in[1]": "444" });
witness = await circuit.calculateWitness({ "in": [444,444] }, true); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1)));
}); });
it("Should create a comparison lessthan", async() => { it("Should create a comparison lessthan", async() => {
const circuit = await tester(path.join(__dirname, "circuits", "lessthan.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "lessthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
let witness; let witness;
witness = await circuit.calculateWitness({ "in": [333,444] }), true; witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in":[1,1] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [661, 660] }, true); witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [0, 1] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [0, 444] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [1, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [555, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [0, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
}); });
it("Should create a comparison lesseqthan", async() => { it("Should create a comparison lesseqthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "lesseqthan.circom"));
const circuit = await tester(path.join(__dirname, "circuits", "lesseqthan.circom")); const circuit = new snarkjs.Circuit(cirDef);
let witness; let witness;
witness = await circuit.calculateWitness({ "in": [333,444] }, true); witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in":[1,1] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [661, 660] }, true); witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [0, 1] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [0, 444] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [1, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [555, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [0, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
}); });
it("Should create a comparison greaterthan", async() => { it("Should create a comparison greaterthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "greaterthan.circom"));
const circuit = await tester(path.join(__dirname, "circuits", "greaterthan.circom")); const circuit = new snarkjs.Circuit(cirDef);
let witness; let witness;
witness = await circuit.calculateWitness({ "in": [333,444] }, true); witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in":[1,1] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [661, 660] }, true); witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [0, 1] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [0, 444] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [1, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [555, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [0, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
}); });
it("Should create a comparison greatereqthan", async() => { it("Should create a comparison greatereqthan", async() => {
const circuit = await tester(path.join(__dirname, "circuits", "greatereqthan.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "greatereqthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstraints BalancesUpdater: " + circuit.nConstraints);
let witness; let witness;
witness = await circuit.calculateWitness({ "in": [333,444] }, true); witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in":[1,1] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [661, 660] }, true); witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [0, 1] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [0, 444] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(0))); assert(witness[1].equals(snarkjs.bigInt(0)));
witness = await circuit.calculateWitness({ "in": [1, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [555, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
witness = await circuit.calculateWitness({ "in": [0, 0] }, true); witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
assert(Fr.eq(witness[0], Fr.e(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(Fr.eq(witness[1], Fr.e(1))); assert(witness[1].equals(snarkjs.bigInt(1)));
}); });
}); });

View File

@@ -1,14 +1,16 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const tester = require("circom").tester; const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr; // const crypto = require("crypto");
const eddsa = require("../src/eddsa.js"); const eddsa = require("../src/eddsa.js");
const babyJub = require("../src/babyjub.js"); const babyJub = require("../src/babyjub.js");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
@@ -18,9 +20,9 @@ function buffer2bits(buff) {
for (let i=0; i<buff.length; i++) { for (let i=0; i<buff.length; i++) {
for (let j=0; j<8; j++) { for (let j=0; j<8; j++) {
if ((buff[i]>>j)&1) { if ((buff[i]>>j)&1) {
res.push(Fr.one); res.push(bigInt.one);
} else { } else {
res.push(Fr.zero); res.push(bigInt.zero);
} }
} }
} }
@@ -34,7 +36,11 @@ describe("EdDSA test", function () {
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
circuit = await tester(path.join(__dirname, "circuits", "eddsa_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "eddsa_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains EdDSA: " + circuit.nConstraints);
}); });
it("Sign a single 10 bytes from 0 to 9", async () => { it("Sign a single 10 bytes from 0 to 9", async () => {
@@ -60,8 +66,9 @@ describe("EdDSA test", function () {
const sBits = buffer2bits(pSignature.slice(32, 64)); const sBits = buffer2bits(pSignature.slice(32, 64));
const aBits = buffer2bits(pPubKey); const aBits = buffer2bits(pPubKey);
const w = await circuit.calculateWitness({A: aBits, R8: r8Bits, S: sBits, msg: msgBits}, true); const w = circuit.calculateWitness({A: aBits, R8: r8Bits, S: sBits, msg: msgBits});
assert(circuit.checkWitness(w));
await circuit.checkConstraints(w);
}); });
}); });

View File

@@ -1,11 +1,12 @@
const chai = require("chai"); const chai = require("chai");
const snarkjs = require("snarkjs");
const eddsa = require("../src/eddsa.js"); const eddsa = require("../src/eddsa.js");
const babyJub = require("../src/babyjub.js"); const babyJub = require("../src/babyjub.js");
const assert = chai.assert; const assert = chai.assert;
const utils = require("ffjavascript").utils; const bigInt = snarkjs.bigInt;
describe("EdDSA js test", function () { describe("EdDSA js test", function () {
@@ -13,7 +14,7 @@ describe("EdDSA js test", function () {
it("Sign (using Mimc7) a single 10 bytes from 0 to 9", () => { it("Sign (using Mimc7) a single 10 bytes from 0 to 9", () => {
const msgBuf = Buffer.from("00010203040506070809", "hex"); const msgBuf = Buffer.from("00010203040506070809", "hex");
const msg = utils.leBuff2int(msgBuf); const msg = bigInt.leBuff2int(msgBuf);
// const prvKey = crypto.randomBytes(32); // const prvKey = crypto.randomBytes(32);
@@ -48,7 +49,7 @@ describe("EdDSA js test", function () {
it("Sign (using Poseidon) a single 10 bytes from 0 to 9", () => { it("Sign (using Poseidon) a single 10 bytes from 0 to 9", () => {
const msgBuf = Buffer.from("00010203040506070809", "hex"); const msgBuf = Buffer.from("00010203040506070809", "hex");
const msg = utils.leBuff2int(msgBuf); const msg = bigInt.leBuff2int(msgBuf);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@@ -67,12 +68,12 @@ describe("EdDSA js test", function () {
assert.equal(signature.R8[1].toString(), assert.equal(signature.R8[1].toString(),
"15383486972088797283337779941324724402501462225528836549661220478783371668959"); "15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(), assert.equal(signature.S.toString(),
"938949321795232811108166733391487122595698117244126885899082887611217406272"); "248298168863866362217836334079793350221620631973732197668910946177382043688");
const pSignature = eddsa.packSignature(signature); const pSignature = eddsa.packSignature(signature);
assert.equal(pSignature.toString("hex"), ""+ assert.equal(pSignature.toString("hex"), ""+
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+ "dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"40e930f04ce3a13bdca883639e77d1a0cd52b5ed0666df8a201df1fe2d6d1302"); "28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00");
const uSignature = eddsa.unpackSignature(pSignature); const uSignature = eddsa.unpackSignature(pSignature);
assert(eddsa.verifyPoseidon(msg, uSignature, pubKey)); assert(eddsa.verifyPoseidon(msg, uSignature, pubKey));

View File

@@ -1,25 +1,29 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr;
const eddsa = require("../src/eddsa.js"); const eddsa = require("../src/eddsa.js");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
describe("EdDSA MiMC test", function () { describe("EdDSA MiMC test", function () {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "eddsamimc_test.circom"));
circuit = await tester(path.join(__dirname, "circuits", "eddsamimc_test.circom")); circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains EdDSA MiMC: " + circuit.nConstraints);
}); });
it("Sign a single number", async () => { it("Sign a single number", async () => {
const msg = Fr.e(1234); const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@@ -29,22 +33,20 @@ describe("EdDSA MiMC test", function () {
assert(eddsa.verifyMiMC(msg, signature, pubKey)); assert(eddsa.verifyMiMC(msg, signature, pubKey));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
enabled: 1, enabled: 1,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: signature.R8[0], R8x: signature.R8[0],
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg}, true); M: msg});
await circuit.checkConstraints(w);
assert(circuit.checkWitness(w));
}); });
it("Detect Invalid signature", async () => { it("Detect Invalid signature", async () => {
const msg = Fr.e(1234); const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@@ -55,23 +57,23 @@ describe("EdDSA MiMC test", function () {
assert(eddsa.verifyMiMC(msg, signature, pubKey)); assert(eddsa.verifyMiMC(msg, signature, pubKey));
try { try {
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
enabled: 1, enabled: 1,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: Fr.add(signature.R8[0], Fr.e(1)), R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg}, true); M: msg});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) ); assert.equal(err.message, "Constraint doesn't match: 1 != 0");
} }
}); });
it("Test a dissabled circuit with a bad signature", async () => { it("Test a dissabled circuit with a bad signature", async () => {
const msg = Fr.e(1234); const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@@ -82,16 +84,15 @@ describe("EdDSA MiMC test", function () {
assert(eddsa.verifyMiMC(msg, signature, pubKey)); assert(eddsa.verifyMiMC(msg, signature, pubKey));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
enabled: 0, enabled: 0,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: Fr.add(signature.R8[0], Fr.e(1)), R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg}, true); M: msg});
await circuit.checkConstraints(w);
assert(circuit.checkWitness(w));
}); });
}); });

View File

@@ -1,25 +1,29 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const Fr = require("ffjavascript").bn128.Fr; const compiler = require("circom");
const eddsa = require("../src/eddsa.js"); const eddsa = require("../src/eddsa.js");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
describe("EdDSA Poseidon test", function () { describe("EdDSA Poseidon test", function () {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "eddsaposeidon_test.circom"));
circuit = await tester(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 () => { it("Sign a single number", async () => {
const msg = Fr.e(1234); const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@@ -29,25 +33,20 @@ describe("EdDSA Poseidon test", function () {
assert(eddsa.verifyPoseidon(msg, signature, pubKey)); assert(eddsa.verifyPoseidon(msg, signature, pubKey));
const input = { const w = circuit.calculateWitness({
enabled: 1, enabled: 1,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: signature.R8[0], R8x: signature.R8[0],
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg M: msg});
};
// console.log(JSON.stringify(utils.stringifyBigInts(input))); assert(circuit.checkWitness(w));
const w = await circuit.calculateWitness(input, true);
await circuit.checkConstraints(w);
}); });
it("Detect Invalid signature", async () => { it("Detect Invalid signature", async () => {
const msg = Fr.e(1234); const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@@ -58,23 +57,23 @@ describe("EdDSA Poseidon test", function () {
assert(eddsa.verifyPoseidon(msg, signature, pubKey)); assert(eddsa.verifyPoseidon(msg, signature, pubKey));
try { try {
await circuit.calculateWitness({ circuit.calculateWitness({
enabled: 1, enabled: 1,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: Fr.add(signature.R8[0], Fr.e(1)), R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg}, true); M: msg});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) ); assert.equal(err.message, "Constraint doesn't match: 1 != 0");
} }
}); });
it("Test a dissabled circuit with a bad signature", async () => { it("Test a dissabled circuit with a bad signature", async () => {
const msg = Fr.e(1234); const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@@ -85,15 +84,15 @@ describe("EdDSA Poseidon test", function () {
assert(eddsa.verifyPoseidon(msg, signature, pubKey)); assert(eddsa.verifyPoseidon(msg, signature, pubKey));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
enabled: 0, enabled: 0,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: Fr.add(signature.R8[0], Fr.e(1)), R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg}, true); M: msg});
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
}); });
}); });

View File

@@ -1,115 +1,168 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const babyJub = require("../src/babyjub.js"); const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr;
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
const q=bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
function addPoint(a,b) {
const cta = bigInt("168700");
const d = bigInt("168696");
const res = [];
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt.one + 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.one - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
return res;
}
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
describe("Exponentioation test", function () { describe("Exponentioation test", () => {
this.timeout(100000);
it("Should generate the Exponentiation table in k=0", async () => { it("Should generate the Exponentiation table in k=0", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "escalarmulw4table_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulw4table_test.circom"));
const w = await circuit.calculateWitness({in: 1}); // console.log(JSON.stringify(cirDef, null, 1));
await circuit.checkConstraints(w); // assert.equal(cirDef.nVars, 2);
let g = [ const circuit = new snarkjs.Circuit(cirDef);
Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
];
let dbl= [Fr.e("0"), Fr.e("1")]; console.log("NConstrains: " + circuit.nConstraints);
const expectedOut = []; const w = circuit.calculateWitness({in: 1});
let g = [bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
dbl= [bigInt("0"), snarkjs.bigInt("1")];
for (let i=0; i<16; i++) { for (let i=0; i<16; i++) {
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
/*
console.log(xout1.toString());
console.log(yout1.toString());
console.log(dbl[0]);
console.log(dbl[1]);
*/
assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1]));
expectedOut.push(dbl); dbl = addPoint([xout1, yout1],g);
dbl = babyJub.addPoint(dbl,g);
} }
await circuit.assertOut(w, {out: expectedOut});
}); });
it("Should generate the Exponentiation table in k=3", async () => { it("Should generate the Exponentiation table in k=3", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "escalarmulw4table_test3.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulw4table_test3.circom"));
const w = await circuit.calculateWitness({in: 1}); // console.log(JSON.stringify(cirDef, null, 1));
await circuit.checkConstraints(w); // assert.equal(cirDef.nVars, 2);
let g = [ const circuit = new snarkjs.Circuit(cirDef);
Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203") console.log("NConstrains: " + circuit.nConstraints);
];
const w = circuit.calculateWitness({in: 1});
let g = [snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
for (let i=0; i<12;i++) { for (let i=0; i<12;i++) {
g = babyJub.addPoint(g,g); g = addPoint(g,g);
} }
let dbl= [Fr.e("0"), Fr.e("1")]; dbl= [snarkjs.bigInt("0"), snarkjs.bigInt("1")];
const expectedOut = [];
for (let i=0; i<16; i++) { for (let i=0; i<16; i++) {
expectedOut.push(dbl); const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
dbl = babyJub.addPoint(dbl,g); /*
console.log(xout1.toString());
console.log(yout1.toString());
console.log(dbl[0]);
console.log(dbl[1]);
*/
assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1]));
dbl = addPoint([xout1, yout1],g);
} }
await circuit.assertOut(w, {out: expectedOut});
}); });
it("Should exponentiate g^31", async () => { it("Should exponentiate g^31", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmul_test.circom"));
const circuit = await tester(path.join(__dirname, "circuits", "escalarmul_test.circom")); // console.log(JSON.stringify(cirDef, null, 1));
const w = await circuit.calculateWitness({"in": 31}); // assert.equal(cirDef.nVars, 2);
await circuit.checkConstraints(w); const circuit = new snarkjs.Circuit(cirDef);
let g = [ console.log("NConstrains: " + circuit.nConstraints);
Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
];
let c = [Fr.e(0), Fr.e(1)]; const w = circuit.calculateWitness({"in": 31});
assert(circuit.checkWitness(w));
let g = [snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
let c = [0n, 1n];
for (let i=0; i<31;i++) { for (let i=0; i<31;i++) {
c = babyJub.addPoint(c,g); c = addPoint(c,g);
} }
await circuit.assertOut(w, {out: c}); const xout = w[circuit.getSignalIdx(`main.out[0]`)];
const yout = w[circuit.getSignalIdx(`main.out[1]`)];
const w2 = await circuit.calculateWitness({"in": Fr.add(Fr.shl(Fr.e(1), Fr.e(252)),Fr.one)}); /*
console.log(xout.toString());
console.log(yout.toString());
*/
assert(xout.equals(c[0]));
assert(yout.equals(c[1]));
console.log("-------")
const w2 = circuit.calculateWitness({"in": (1n<<252n)+1n});
const xout2 = w2[circuit.getSignalIdx(`main.out[0]`)];
const yout2 = w2[circuit.getSignalIdx(`main.out[1]`)];
c = [g[0], g[1]]; c = [g[0], g[1]];
for (let i=0; i<252;i++) { for (let i=0; i<252;i++) {
c = babyJub.addPoint(c,c); c = addPoint(c,c);
} }
c = babyJub.addPoint(c,g); c = addPoint(c,g);
/*
await circuit.assertOut(w2, {out: c}); console.log(xout2.toString());
console.log(yout2.toString());
console.log(c[0].toString());
console.log(c[1].toString());
*/
assert(xout2.equals(c[0]));
assert(yout2.equals(c[1]));
}).timeout(10000000); }).timeout(10000000);
it("Number of constrains for 256 bits", async () => { it("Number of constrains for 256 bits", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmul_test_min.circom"));
const circuit = await tester(path.join(__dirname, "circuits", "escalarmul_test_min.circom")); const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
}).timeout(10000000); }).timeout(10000000);
}); });

View File

@@ -1,7 +1,11 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const Fr = require("ffjavascript").bn128.Fr; const compiler = require("circom");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
@@ -14,33 +18,41 @@ describe("Escalarmul test", function () {
this.timeout(100000); this.timeout(100000);
let g = [ let g = [
Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"), snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203") snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
before( async() => { before( async() => {
circuitEMulAny = await tester(path.join(__dirname, "circuits", "escalarmulany_test.circom")); const cirDefEMulAny = await compiler(path.join(__dirname, "circuits", "escalarmulany_test.circom"));
circuitEMulAny = new snarkjs.Circuit(cirDefEMulAny);
console.log("NConstrains Escalarmul any: " + circuitEMulAny.nConstraints);
}); });
it("Should generate Same escalar mul", async () => { it("Should generate Same escalar mul", async () => {
const w = await circuitEMulAny.calculateWitness({"e": 1, "p": g}); const w = circuitEMulAny.calculateWitness({"e": 1, "p": g});
await circuitEMulAny.checkConstraints(w); assert(circuitEMulAny.checkWitness(w));
await circuitEMulAny.assertOut(w, {out: g}, true); const xout = w[circuitEMulAny.getSignalIdx("main.out[0]")];
const yout = w[circuitEMulAny.getSignalIdx("main.out[1]")];
assert(xout.equals(g[0]));
assert(yout.equals(g[1]));
}); });
it("If multiply by order should return 0", async () => { it("If multiply by order should return 0", async () => {
const r = Fr.e("2736030358979909402780800718157159386076813972158567259200215660948447373041"); const r = bigInt("2736030358979909402780800718157159386076813972158567259200215660948447373041");
const w = await circuitEMulAny.calculateWitness({"e": r, "p": g}); const w = circuitEMulAny.calculateWitness({"e": r, "p": g});
await circuitEMulAny.checkConstraints(w); assert(circuitEMulAny.checkWitness(w));
await circuitEMulAny.assertOut(w, {out: [0,1]}, true); const xout = w[circuitEMulAny.getSignalIdx("main.out[0]")];
const yout = w[circuitEMulAny.getSignalIdx("main.out[1]")];
assert(xout.equals(bigInt.zero));
assert(yout.equals(bigInt.one));
}); });
}); });

View File

@@ -1,11 +1,14 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const compiler = require("circom");
const babyjub = require("../src/babyjub"); const babyjub = require("../src/babyjub");
const Fr = require("ffjavascript").bn128.Fr;
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
@@ -16,74 +19,93 @@ describe("Escalarmul test", function () {
this.timeout(100000); this.timeout(100000);
before( async() => { before( async() => {
circuit = await tester(path.join(__dirname, "circuits", "escalarmulfix_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulfix_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Escalarmul fix: " + circuit.nConstraints);
}); });
it("Should generate Same escalar mul", async () => { it("Should generate Same escalar mul", async () => {
const w = await circuit.calculateWitness({"e": 0}); const w = circuit.calculateWitness({"e": 0});
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
await circuit.assertOut(w, {out: [0,1]}, true); const xout = w[circuit.getSignalIdx("main.out[0]")];
const yout = w[circuit.getSignalIdx("main.out[1]")];
assert(xout.equals(0));
assert(yout.equals(1));
}); });
it("Should generate Same escalar mul", async () => { it("Should generate Same escalar mul", async () => {
const w = await circuit.calculateWitness({"e": 1}, true); const w = circuit.calculateWitness({"e": 1});
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
await circuit.assertOut(w, {out: babyjub.Base8}); const xout = w[circuit.getSignalIdx("main.out[0]")];
const yout = w[circuit.getSignalIdx("main.out[1]")];
assert(xout.equals(babyjub.Base8[0]));
assert(yout.equals(babyjub.Base8[1]));
}); });
it("Should generate scalar mul of a specific constant", async () => { it("Should generate scalar mul of a specific constant", async () => {
const s = Fr.e("2351960337287830298912035165133676222414898052661454064215017316447594616519"); const s = bigInt("2351960337287830298912035165133676222414898052661454064215017316447594616519");
const base8 = [ const base8 = [
Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"), bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203") bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
const w = await circuit.calculateWitness({"e": s}, true); const w = circuit.calculateWitness({"e": s});
await circuit.checkConstraints(w); 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); const expectedRes = babyjub.mulPointEscalar(base8, s);
await circuit.assertOut(w, {out: expectedRes}); assert(xout.equals(expectedRes[0]));
assert(yout.equals(expectedRes[1]));
}); });
it("Should generate scalar mul of the firsts 50 elements", async () => { it("Should generate scalar mul of the firsts 50 elements", async () => {
const base8 = [ const base8 = [
Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"), bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203") bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
for (let i=0; i<50; i++) { for (let i=0; i<50; i++) {
const s = Fr.e(i); const s = bigInt(i);
const w = await circuit.calculateWitness({"e": s}, true); const w = circuit.calculateWitness({"e": s});
await circuit.checkConstraints(w); 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); const expectedRes = babyjub.mulPointEscalar(base8, s);
await circuit.assertOut(w, {out: expectedRes}); assert(xout.equals(expectedRes[0]));
assert(yout.equals(expectedRes[1]));
} }
}); });
it("If multiply by order should return 0", async () => { it("If multiply by order should return 0", async () => {
const w = await circuit.calculateWitness({"e": babyjub.subOrder }, true); const w = circuit.calculateWitness({"e": babyjub.subOrder });
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
await circuit.assertOut(w, {out: [0,1]}); const xout = w[circuit.getSignalIdx("main.out[0]")];
const yout = w[circuit.getSignalIdx("main.out[1]")];
assert(xout.equals(bigInt.zero));
assert(yout.equals(bigInt.one));
}); });
}); });

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,25 +1,35 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const compiler = require("circom");
const mimcjs = require("../src/mimc7.js"); const mimcjs = require("../src/mimc7.js");
const assert = chai.assert;
describe("MiMC Circuit test", function () { describe("MiMC Circuit test", function () {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
circuit = await tester(path.join(__dirname, "circuits", "mimc_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("MiMC constraints: " + circuit.nConstraints);
}); });
it("Should check constrain", async () => { it("Should check constrain", async () => {
const w = await circuit.calculateWitness({x_in: 1, k: 2}, true); const w = circuit.calculateWitness({x_in: 1, k: 2});
const res = w[circuit.getSignalIdx("main.out")];
const res2 = mimcjs.hash(1,2,91); const res2 = mimcjs.hash(1,2,91);
await circuit.assertOut(w, {out: res2}); assert.equal(res.toString(), res2.toString());
assert(circuit.checkWitness(w));
await circuit.checkConstraints(w);
}); });
}); });

View File

@@ -1,8 +1,11 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const compiler = require("circom");
const mimcjs = require("../src/mimcsponge.js"); const mimcjs = require("../src/mimcsponge.js");
const assert = chai.assert;
describe("MiMC Sponge Circuit test", function () { describe("MiMC Sponge Circuit test", function () {
let circuit; let circuit;
@@ -10,28 +13,46 @@ describe("MiMC Sponge Circuit test", function () {
this.timeout(100000); this.timeout(100000);
it("Should check permutation", async () => { it("Should check permutation", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_sponge_test.circom"));
circuit = await tester(path.join(__dirname, "circuits", "mimc_sponge_test.circom")); circuit = new snarkjs.Circuit(cirDef);
const w = await circuit.calculateWitness({xL_in: 1, xR_in: 2, k: 3}); 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); const out2 = mimcjs.hash(1,2,3);
await circuit.assertOut(w, {xL_out: out2.xL, xR_out: out2.xR}); assert.equal(xLout.toString(), out2.xL.toString());
assert.equal(xRout.toString(), out2.xR.toString());
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
}); });
it("Should check hash", async () => { it("Should check hash", async () => {
circuit = await tester(path.join(__dirname, "circuits", "mimc_sponge_hash_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_sponge_hash_test.circom"));
const w = await circuit.calculateWitness({ins: [1, 2], k: 0}); 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); const out2 = mimcjs.multiHash([1,2], 0, 3);
await circuit.assertOut(w, {outs: out2}); 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));
await circuit.checkConstraints(w);
}); });
}); });

View File

@@ -1,11 +1,13 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const compiler = require("circom");
const babyJub = require("../src/babyjub.js"); const babyJub = require("../src/babyjub.js");
const Fr = require("ffjavascript").bn128.Fr;
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
describe("Montgomery test", function () { describe("Montgomery test", function () {
let circuitE2M; let circuitE2M;
let circuitM2E; let circuitM2E;
@@ -13,80 +15,85 @@ describe("Montgomery test", function () {
let circuitMDouble; let circuitMDouble;
let g = [ let g = [
Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"), snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203") snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")];
];
let mg, mg2, g2, g3, mg3; let mg, mg2, g2, g3, mg3;
this.timeout(100000); this.timeout(100000);
before( async() => { before( async() => {
circuitE2M = await tester(path.join(__dirname, "circuits", "edwards2montgomery.circom")); const cirDefE2M = await compiler(path.join(__dirname, "circuits", "edwards2montgomery.circom"));
await circuitE2M.loadSymbols(); circuitE2M = new snarkjs.Circuit(cirDefE2M);
circuitM2E = await tester(path.join(__dirname, "circuits", "montgomery2edwards.circom")); console.log("NConstrains Edwards -> Montgomery: " + circuitE2M.nConstraints);
await circuitM2E.loadSymbols();
circuitMAdd = await tester(path.join(__dirname, "circuits", "montgomeryadd.circom")); const cirDefM2E = await compiler(path.join(__dirname, "circuits", "montgomery2edwards.circom"));
await circuitMAdd.loadSymbols(); circuitM2E = new snarkjs.Circuit(cirDefM2E);
circuitMDouble = await tester(path.join(__dirname, "circuits", "montgomerydouble.circom")); console.log("NConstrains Montgomery -> Edwards: " + circuitM2E.nConstraints);
await circuitMDouble.loadSymbols();
const cirDefMAdd = await compiler(path.join(__dirname, "circuits", "montgomeryadd.circom"));
circuitMAdd = new snarkjs.Circuit(cirDefMAdd);
console.log("NConstrains Montgomery Add: " + circuitMAdd.nConstraints);
const cirDefMDouble = await compiler(path.join(__dirname, "circuits", "montgomerydouble.circom"));
circuitMDouble = new snarkjs.Circuit(cirDefMDouble);
console.log("NConstrains Montgomery Double: " + circuitMDouble.nConstraints);
}); });
it("Convert Edwards to Montgomery and back again", async () => { it("Convert Edwards to Montgomery and back again", async () => {
let w, xout, yout; let w, xout, yout;
w = await circuitE2M.calculateWitness({ in: g}, true); w = circuitE2M.calculateWitness({ in: g});
xout = w[circuitE2M.symbols["main.out[0]"].varIdx]; xout = w[circuitE2M.getSignalIdx("main.out[0]")];
yout = w[circuitE2M.symbols["main.out[1]"].varIdx]; yout = w[circuitE2M.getSignalIdx("main.out[1]")];
mg = [xout, yout]; mg = [xout, yout];
w = await circuitM2E.calculateWitness({ in: [xout, yout]}, true); w = circuitM2E.calculateWitness({ in: [xout, yout]});
xout = w[circuitM2E.symbols["main.out[0]"].varIdx]; xout = w[circuitM2E.getSignalIdx("main.out[0]")];
yout = w[circuitM2E.symbols["main.out[1]"].varIdx]; yout = w[circuitM2E.getSignalIdx("main.out[1]")];
assert(Fr.eq(xout, g[0])); assert(xout.equals(g[0]));
assert(Fr.eq(yout, g[1])); assert(yout.equals(g[1]));
}); });
it("Should double a point", async () => { it("Should double a point", async () => {
let w, xout, yout; let w, xout, yout;
g2 = babyJub.addPoint(g,g); g2 = babyJub.addPoint(g,g);
w = await circuitMDouble.calculateWitness({ in: mg}, true); w = circuitMDouble.calculateWitness({ in: mg});
xout = w[circuitE2M.symbols["main.out[0]"].varIdx]; xout = w[circuitE2M.getSignalIdx("main.out[0]")];
yout = w[circuitE2M.symbols["main.out[1]"].varIdx]; yout = w[circuitE2M.getSignalIdx("main.out[1]")];
mg2 = [xout, yout]; mg2 = [xout, yout];
w = await circuitM2E.calculateWitness({ in: mg2}, true); w = circuitM2E.calculateWitness({ in: mg2});
xout = w[circuitM2E.symbols["main.out[0]"].varIdx]; xout = w[circuitM2E.getSignalIdx("main.out[0]")];
yout = w[circuitM2E.symbols["main.out[1]"].varIdx]; yout = w[circuitM2E.getSignalIdx("main.out[1]")];
assert(xout.equals(g2[0]));
assert(Fr.eq(xout, g2[0])); assert(yout.equals(g2[1]));
assert(Fr.eq(yout, g2[1]));
}); });
it("Should add a point", async () => { it("Should add a point", async () => {
let w, xout, yout; let w, xout, yout;
g3 = babyJub.addPoint(g,g2); g3 = babyJub.addPoint(g,g2);
w = await circuitMAdd.calculateWitness({ in1: mg, in2: mg2}, true); w = circuitMAdd.calculateWitness({ in1: mg, in2: mg2});
xout = w[circuitMAdd.symbols["main.out[0]"].varIdx]; xout = w[circuitMAdd.getSignalIdx("main.out[0]")];
yout = w[circuitMAdd.symbols["main.out[1]"].varIdx]; yout = w[circuitMAdd.getSignalIdx("main.out[1]")];
mg3 = [xout, yout]; mg3 = [xout, yout];
w = await circuitM2E.calculateWitness({ in: mg3}, true); w = circuitM2E.calculateWitness({ in: mg3});
xout = w[circuitM2E.symbols["main.out[0]"].varIdx]; xout = w[circuitM2E.getSignalIdx("main.out[0]")];
yout = w[circuitM2E.symbols["main.out[1]"].varIdx]; yout = w[circuitM2E.getSignalIdx("main.out[1]")];
assert(Fr.eq(xout, g3[0])); assert(xout.equals(g3[0]));
assert(Fr.eq(yout, g3[1])); assert(yout.equals(g3[1]));
}); });
}); });

View File

@@ -1,98 +1,127 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const Fr = require("ffjavascript").bn128.Fr; const compiler = require("circom");
describe("Mux4 test", function() { const assert = chai.assert;
this.timeout(100000);
const bigInt = snarkjs.bigInt;
describe("Mux4 test", () => {
it("Should create a constant multiplexer 4", async () => { it("Should create a constant multiplexer 4", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "mux4_1.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "mux4_1.circom"));
// console.log(JSON.stringify(cirDef, null, 1));
// assert.equal(cirDef.nVars, 2);
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Mux4: " + circuit.nConstraints);
const ct16 = [ const ct16 = [
Fr.e("123"), bigInt("123"),
Fr.e("456"), bigInt("456"),
Fr.e("789"), bigInt("789"),
Fr.e("012"), bigInt("012"),
Fr.e("111"), bigInt("111"),
Fr.e("222"), bigInt("222"),
Fr.e("333"), bigInt("333"),
Fr.e("4546"), bigInt("4546"),
Fr.e("134523"), bigInt("134523"),
Fr.e("44356"), bigInt("44356"),
Fr.e("15623"), bigInt("15623"),
Fr.e("4566"), bigInt("4566"),
Fr.e("1223"), bigInt("1223"),
Fr.e("4546"), bigInt("4546"),
Fr.e("4256"), bigInt("4256"),
Fr.e("4456") bigInt("4456")
]; ];
for (let i=0; i<16; i++) { for (let i=0; i<16; i++) {
const w = await circuit.calculateWitness({ "selector": i }, true); const w = circuit.calculateWitness({ "selector": i });
await circuit.checkConstraints(w); assert(w[0].equals(bigInt(1)));
await circuit.assertOut(w, {out: ct16[i]}); // console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());
assert(w[circuit.getSignalIdx("main.out")].equals(ct16[i]));
} }
}); });
it("Should create a constant multiplexer 3", async () => { it("Should create a constant multiplexer 3", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "mux3_1.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "mux3_1.circom"));
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Mux3: " + circuit.nConstraints);
const ct8 = [ const ct8 = [
Fr.e("37"), bigInt("37"),
Fr.e("47"), bigInt("47"),
Fr.e("53"), bigInt("53"),
Fr.e("71"), bigInt("71"),
Fr.e("89"), bigInt("89"),
Fr.e("107"), bigInt("107"),
Fr.e("163"), bigInt("163"),
Fr.e("191") bigInt("191")
]; ];
for (let i=0; i<8; i++) { for (let i=0; i<8; i++) {
const w = await circuit.calculateWitness({ "selector": i }, true); const w = circuit.calculateWitness({ "selector": i });
await circuit.checkConstraints(w); assert(w[0].equals(bigInt(1)));
await circuit.assertOut(w, {out: ct8[i]}); // 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 () => { it("Should create a constant multiplexer 2", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "mux2_1.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "mux2_1.circom"));
const ct4 = [ const circuit = new snarkjs.Circuit(cirDef);
Fr.e("37"),
Fr.e("47"), console.log("NConstrains Mux2: " + circuit.nConstraints);
Fr.e("53"),
Fr.e("71"), const ct8 = [
bigInt("37"),
bigInt("47"),
bigInt("53"),
bigInt("71"),
]; ];
for (let i=0; i<4; i++) { for (let i=0; i<4; i++) {
const w = await circuit.calculateWitness({ "selector": i }, true); const w = circuit.calculateWitness({ "selector": i });
await circuit.checkConstraints(w); assert(w[0].equals(bigInt(1)));
await circuit.assertOut(w, {out: ct4[i]}); // 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 () => { it("Should create a constant multiplexer 1", async () => {
const circuit = await tester(path.join(__dirname, "circuits", "mux1_1.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "mux1_1.circom"));
const ct2 = [ const circuit = new snarkjs.Circuit(cirDef);
Fr.e("37"),
Fr.e("47"), console.log("NConstrains Mux1: " + circuit.nConstraints);
const ct8 = [
bigInt("37"),
bigInt("47"),
]; ];
for (let i=0; i<2; i++) { for (let i=0; i<2; i++) {
const w = await circuit.calculateWitness({ "selector": i }, true); const w = circuit.calculateWitness({ "selector": i });
await circuit.checkConstraints(w); assert(w[0].equals(bigInt(1)));
await circuit.assertOut(w, {out: ct2[i]}); // console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());
assert(w[circuit.getSignalIdx("main.out")].equals(ct8[i]));
} }
}); });
}); });

View File

@@ -1,77 +1,100 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr; const assert = chai.assert;
const tester = require("circom").tester;
const bigInt = snarkjs.bigInt;
const babyJub = require("../src/babyjub.js"); const babyJub = require("../src/babyjub.js");
const PBASE = const PBASE =
[ [
[Fr.e("10457101036533406547632367118273992217979173478358440826365724437999023779287"),Fr.e("19824078218392094440610104313265183977899662750282163392862422243483260492317")], [bigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"),bigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317")],
[Fr.e("2671756056509184035029146175565761955751135805354291559563293617232983272177"),Fr.e("2663205510731142763556352975002641716101654201788071096152948830924149045094")], [bigInt("2671756056509184035029146175565761955751135805354291559563293617232983272177"),bigInt("2663205510731142763556352975002641716101654201788071096152948830924149045094")],
[Fr.e("5802099305472655231388284418920769829666717045250560929368476121199858275951"),Fr.e("5980429700218124965372158798884772646841287887664001482443826541541529227896")], [bigInt("5802099305472655231388284418920769829666717045250560929368476121199858275951"),bigInt("5980429700218124965372158798884772646841287887664001482443826541541529227896")],
[Fr.e("7107336197374528537877327281242680114152313102022415488494307685842428166594"),Fr.e("2857869773864086953506483169737724679646433914307247183624878062391496185654")], [bigInt("7107336197374528537877327281242680114152313102022415488494307685842428166594"),bigInt("2857869773864086953506483169737724679646433914307247183624878062391496185654")],
[Fr.e("20265828622013100949498132415626198973119240347465898028410217039057588424236"),Fr.e("1160461593266035632937973507065134938065359936056410650153315956301179689506")] [bigInt("20265828622013100949498132415626198973119240347465898028410217039057588424236"),bigInt("1160461593266035632937973507065134938065359936056410650153315956301179689506")]
]; ];
describe("Double Pedersen test", function() { describe("Double Pedersen test", function() {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before( async() => { before( async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "pedersen_test.circom"));
circuit = await tester(path.join(__dirname, "circuits", "pedersen_test.circom")); circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
}); });
it("Should pedersen at zero", async () => { it("Should pedersen at zero", async () => {
let w; let w, xout, yout;
w = await circuit.calculateWitness({ in: ["0", "0"]}, true); w = circuit.calculateWitness({ in: ["0", "0"]});
await circuit.assertOut(w, {out: [0,1]}); xout = w[circuit.getSignalIdx("main.out[0]")];
yout = w[circuit.getSignalIdx("main.out[1]")];
assert(xout.equals("0"));
assert(yout.equals("1"));
}); });
it("Should pedersen at one first generator", async () => { it("Should pedersen at one first generator", async () => {
let w; let w, xout, yout;
w = await circuit.calculateWitness({ in: ["1", "0"]}, true); w = circuit.calculateWitness({ in: ["1", "0"]});
await circuit.assertOut(w, {out: PBASE[0]}); xout = bigInt(w[circuit.getSignalIdx("main.out[0]")]);
yout = bigInt(w[circuit.getSignalIdx("main.out[1]")]);
assert(xout.equals(PBASE[0][0]));
assert(yout.equals(PBASE[0][1]));
}); });
it("Should pedersen at one second generator", async () => { it("Should pedersen at one second generator", async () => {
let w; let w, xout, yout;
w = await circuit.calculateWitness({ in: ["0", "1"]}, true); w = circuit.calculateWitness({ in: ["0", "1"]});
await circuit.assertOut(w, {out: PBASE[1]}); xout = w[circuit.getSignalIdx("main.out[0]")];
yout = w[circuit.getSignalIdx("main.out[1]")];
assert(xout.equals(PBASE[1][0]));
assert(yout.equals(PBASE[1][1]));
}); });
it("Should pedersen at mixed generators", async () => { it("Should pedersen at mixed generators", async () => {
let w; let w, xout, yout;
w = await circuit.calculateWitness({ in: ["3", "7"]}, true); w = circuit.calculateWitness({ in: ["3", "7"]});
xout = w[circuit.getSignalIdx("main.out[0]")];
yout = w[circuit.getSignalIdx("main.out[1]")];
const r = babyJub.addPoint( const r = babyJub.addPoint(
babyJub.mulPointEscalar(PBASE[0], 3), babyJub.mulPointEscalar(PBASE[0], 3),
babyJub.mulPointEscalar(PBASE[1], 7) babyJub.mulPointEscalar(PBASE[1], 7)
); );
await circuit.assertOut(w, {out: r}); assert(xout.equals(r[0]));
assert(yout.equals(r[1]));
}); });
it("Should pedersen all ones", async () => { it("Should pedersen all ones", async () => {
let w; let w, xout, yout;
const allOnes = Fr.sub(Fr.shl(Fr.e("1"), Fr.e(250)), Fr.e("1")); const allOnes = bigInt("1").shl(250).sub(bigInt("1"));
w = await circuit.calculateWitness({ in: [allOnes, allOnes]}, true); w = circuit.calculateWitness({ in: [allOnes, allOnes]});
xout = w[circuit.getSignalIdx("main.out[0]")];
yout = w[circuit.getSignalIdx("main.out[1]")];
const r2 = babyJub.addPoint( const r2 = babyJub.addPoint(
babyJub.mulPointEscalar(PBASE[0], allOnes), babyJub.mulPointEscalar(PBASE[0], allOnes),
babyJub.mulPointEscalar(PBASE[1], allOnes) babyJub.mulPointEscalar(PBASE[1], allOnes)
); );
await circuit.assertOut(w, {out: r2}); assert(xout.equals(r2[0]));
assert(yout.equals(r2[1]));
}); });
}); });

View File

@@ -1,7 +1,11 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const Fr = require("ffjavascript").bn128.Fr; const assert = chai.assert;
const tester = require("circom").tester;
const bigInt = snarkjs.bigInt;
const babyJub = require("../src/babyjub.js"); const babyJub = require("../src/babyjub.js");
const pedersen = require("../src/pedersenHash.js"); const pedersen = require("../src/pedersenHash.js");
@@ -11,39 +15,60 @@ describe("Pedersen test", function() {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before( async() => { before( async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "pedersen2_test.circom"));
circuit = await tester(path.join(__dirname, "circuits", "pedersen2_test.circom")); circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Pedersen2: " + circuit.nConstraints);
}); });
it("Should pedersen at zero", async () => { it("Should pedersen at zero", async () => {
let w; let w, xout, yout;
w = await circuit.calculateWitness({ in: 0}, true); w = circuit.calculateWitness({ in: 0});
xout = w[circuit.getSignalIdx("main.out[0]")];
yout = w[circuit.getSignalIdx("main.out[1]")];
const b = Buffer.alloc(32); const b = Buffer.alloc(32);
const h = pedersen.hash(b); const h = pedersen.hash(b);
const hP = babyJub.unpackPoint(h); const hP = babyJub.unpackPoint(h);
await circuit.assertOut(w, {out: hP}); /*
console.log(`[${xout.toString()}, ${yout.toString()}]`);
console.log(`[${hP[0].toString()}, ${hP[1].toString()}]`);
*/
assert(xout.equals(hP[0]));
assert(yout.equals(hP[1]));
}); });
it("Should pedersen with 253 ones", async () => { it("Should pedersen with 253 ones", async () => {
let w; let w, xout, yout;
const n = Fr.sub(Fr.shl(Fr.one, Fr.e(253)), Fr.one); const n = bigInt.one.shl(253).sub(bigInt.one);
console.log(n.toString(16));
w = await circuit.calculateWitness({ in: n}, true); w = circuit.calculateWitness({ in: n});
xout = w[circuit.getSignalIdx("main.out[0]")];
yout = w[circuit.getSignalIdx("main.out[1]")];
const b = Buffer.alloc(32); const b = Buffer.alloc(32);
for (let i=0; i<31; i++) b[i] = 0xFF; for (let i=0; i<31; i++) b[i] = 0xFF;
b[31] = 0x1F; b[31] = 0x1F;
const h = pedersen.hash(b); const h = pedersen.hash(b);
const hP = babyJub.unpackPoint(h); const hP = babyJub.unpackPoint(h);
await circuit.assertOut(w, {out: hP}); /*
console.log(`[${xout.toString()}, ${yout.toString()}]`);
console.log(`[${hP[0].toString()}, ${hP[1].toString()}]`);
*/
assert(xout.equals(hP[0]));
assert(yout.equals(hP[1]));
}); });
}); });

View File

@@ -1,5 +1,11 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const compiler = require("circom");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
const babyJub = require("../src/babyjub.js"); const babyJub = require("../src/babyjub.js");
@@ -8,16 +14,20 @@ describe("Point 2 bits test", function() {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before( async() => { before( async() => {
circuit = await tester(path.join(__dirname, "circuits", "pointbits_loopback.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "pointbits_loopback.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Point2Bits loopback: " + circuit.nConstraints);
}); });
it("Should do the both convertions for 8Base", async () => { it("Should do the both convertions for 8Base", async () => {
const w = await circuit.calculateWitness({ in: babyJub.Base8}, true); const w = circuit.calculateWitness({ in: babyJub.Base8});
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
}); });
it("Should do the both convertions for Zero point", async () => { it("Should do the both convertions for Zero point", async () => {
const w = await circuit.calculateWitness({ in: [0, 1]}, true); const w = circuit.calculateWitness({ in: [0, 1]});
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
}); });
}); });

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');
});
});

View File

@@ -1,57 +1,60 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const compiler = require("circom");
var blake2b = require('blake2b');
const poseidon = require("../src/poseidon.js"); const poseidon = require("../src/poseidon.js");
const assert = chai.assert; const assert = chai.assert;
describe("Blake2b version test", function() {
it("Should give the expected output for blake2b version", async () => {
var output = new Uint8Array(32);
var input = Buffer.from('poseidon_constants');
h = blake2b(output.length).update(input).digest('hex')
assert.equal('e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1', h);
});
});
describe("Poseidon Circuit test", function () { describe("Poseidon Circuit test", function () {
let circuit6; let circuit;
let circuit3;
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
circuit6 = await tester(path.join(__dirname, "circuits", "poseidon6_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "poseidon_test.circom"));
circuit3 = await tester(path.join(__dirname, "circuits", "poseidon3_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("Poseidon constraints: " + circuit.nConstraints);
}); });
it("Should check constrain of hash([1, 2]) t=6", async () => { it("Should check constrain of hash([1, 2])", async () => {
const w = await circuit6.calculateWitness({inputs: [1, 2, 0,0,0]}, true); const w = circuit.calculateWitness({inputs: [1, 2]});
const res2 = poseidon([1,2,0,0,0]); const res = w[circuit.getSignalIdx("main.out")];
assert.equal("1944517543886089121158331594914426541694339782056411886233994349799551050705", res2.toString());
await circuit6.assertOut(w, {out : res2}); const hash = poseidon.createHash(6, 8, 57);
await circuit6.checkConstraints(w);
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]) t=6", async () => { it("Should check constrain of hash([3, 4])", async () => {
const w = await circuit6.calculateWitness({inputs: [3, 4,5,10,23]}); const w = circuit.calculateWitness({inputs: [3, 4]});
const res2 = poseidon([3, 4,5,10,23]); const res = w[circuit.getSignalIdx("main.out")];
assert.equal("15043529598202765311255531083507141602555136943545139099151157943137780370931", res2.toString()); const hash = poseidon.createHash(6, 8, 57);
await circuit6.assertOut(w, {out : res2});
await circuit6.checkConstraints(w);
});
const res2 = hash([3, 4]);
assert.equal('17185195740979599334254027721507328033796809509313949281114643312710535000993', res2.toString());
it("Should check constrain of hash([1, 2]) t=3", async () => { assert.equal(res.toString(), res2.toString());
const w = await circuit3.calculateWitness({inputs: [1, 2]});
const res2 = poseidon([1,2]); assert(circuit.checkWitness(w));
assert.equal("11309872961022349216464221841186646423561022368884850929991258903497301047946", res2.toString());
await circuit3.assertOut(w, {out : res2});
await circuit3.checkConstraints(w);
});
it("Should check constrain of hash([3, 4]) t=3", async () => {
const w = await circuit3.calculateWitness({inputs: [3, 4]});
const res2 = poseidon([3, 4]);
assert.equal("5452722186384045185233705092171776011224530037417547968760104202263491217182", res2.toString());
await circuit3.assertOut(w, {out : res2});
await circuit3.checkConstraints(w);
}); });
}); });

View File

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

View File

@@ -1,14 +1,14 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs");
const crypto = require("crypto"); const crypto = require("crypto");
const Fr = require("ffjavascript").bn128.Fr;
const compiler = require("circom");
const assert = chai.assert; const assert = chai.assert;
const sha256 = require("./helpers/sha256"); const sha256 = require("./helpers/sha256");
const tester = require("circom").tester;
// const printSignal = require("./helpers/printsignal"); // const printSignal = require("./helpers/printsignal");
@@ -34,8 +34,7 @@ function bitArray2buffer(a) {
} }
describe("SHA256 test", function () { describe("SHA256 test", () => {
this.timeout(100000);
it("Should work bits to array and array to bits", async () => { it("Should work bits to array and array to bits", async () => {
@@ -46,13 +45,17 @@ describe("SHA256 test", function () {
const a = buffer2bitArray(b); const a = buffer2bitArray(b);
const b2 = bitArray2buffer(a); const b2 = bitArray2buffer(a);
assert.equal(b.toString("hex"), b2.toString("hex"), true); assert.equal(b.toString("hex"), b2.toString("hex"));
}); });
it("Should calculate a hash of 1 compressor", async () => { it("Should calculate a hash of 1 compressor", async () => {
const cir = await tester(path.join(__dirname, "circuits", "sha256_2_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_2_test.circom"));
const circuit = new snarkjs.Circuit(cirDef);
const witness = await cir.calculateWitness({ "a": "1", "b": "2" }, true); console.log("Vars: "+circuit.nVars);
console.log("Constraints: "+circuit.nConstraints);
const witness = circuit.calculateWitness({ "a": "1", "b": "2" });
const b = new Buffer.alloc(54); const b = new Buffer.alloc(54);
b[26] = 1; b[26] = 1;
@@ -67,12 +70,21 @@ describe("SHA256 test", function () {
assert.equal(hash, hash2); assert.equal(hash, hash2);
assert(Fr.eq(witness[1], Fr.e(r))); assert(witness[1].equals(snarkjs.bigInt(r)));
}).timeout(1000000); }).timeout(1000000);
it("Should calculate a hash of 2 compressor", async () => { it("Should calculate a hash of 2 compressor", async () => {
const cir = await tester(path.join(__dirname, "circuits", "sha256_test512.circom")); 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); const b = new Buffer.alloc(64);
for (let i=0; i<64; i++) { for (let i=0; i<64; i++) {
b[i] = i+1; b[i] = i+1;
@@ -83,7 +95,7 @@ describe("SHA256 test", function () {
.digest("hex"); .digest("hex");
const arrIn = buffer2bitArray(b); const arrIn = buffer2bitArray(b);
const witness = await cir.calculateWitness({ "in": arrIn }, true); const witness = circuit.calculateWitness({ "in": arrIn } /*, {logOutput: true} */);
const arrOut = witness.slice(1, 257); const arrOut = witness.slice(1, 257);
const hash2 = bitArray2buffer(arrOut).toString("hex"); const hash2 = bitArray2buffer(arrOut).toString("hex");
@@ -91,25 +103,34 @@ describe("SHA256 test", function () {
assert.equal(hash, hash2); assert.equal(hash, hash2);
}).timeout(1000000); }).timeout(1000000);
it ("Should calculate a hash of 2 compressor", async () => {
const cir = await tester(path.join(__dirname, "circuits", "sha256_test448.circom"));
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 testStr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
const b = Buffer.from(testStr, "utf8"); const b = Buffer.from(testStr, 'utf8');
for (let i=0; i<64; i++) {
b[i] = i+1;
}
const hash = crypto.createHash("sha256") const hash = crypto.createHash("sha256")
.update(b) .update(b)
.digest("hex"); .digest("hex");
const arrIn = buffer2bitArray(b); const arrIn = buffer2bitArray(b);
const witness = circuit.calculateWitness({ "in": arrIn } /*, {logOutput: true} */);
const witness = await cir.calculateWitness({ "in": arrIn }, true);
const arrOut = witness.slice(1, 257); const arrOut = witness.slice(1, 257);
const hash2 = bitArray2buffer(arrOut).toString("hex"); const hash2 = bitArray2buffer(arrOut).toString("hex");
assert.equal(hash, hash2); assert.equal(hash, hash2);
});
}).timeout(1000000);
}); });

View File

@@ -1,7 +1,11 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const Fr = require("ffjavascript").bn128.Fr; const snarkjs = require("snarkjs");
const Scalar = require("ffjavascript").Scalar; const compiler = require("circom");
const tester = require("circom").tester;
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
@@ -10,71 +14,75 @@ function print(circuit, w, s) {
function getBits(v, n) { function getBits(v, n) {
const res = []; const res = [];
for (let i=0; i<n; i++) { for (let i=0; i<n; i++) {
if (Scalar.isOdd(Scalar.shr(v, i))) { if (v.shr(i).isOdd()) {
res.push(Fr.one); res.push(bigInt.one);
} else { } else {
res.push(Fr.zero); res.push(bigInt.zero);
} }
} }
return res; return res;
} }
const q = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
describe("Sign test", function() { describe("Sign test", () => {
let circuit; let circuit;
this.timeout(100000);
before( async() => { before( async() => {
circuit = await tester(path.join(__dirname, "circuits", "sign_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "sign_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
}); });
it("Sign of 0", async () => { it("Sign of 0", async () => {
const inp = getBits(Scalar.e(0), 254); const inp = getBits(bigInt.zero, 254);
const w = await circuit.calculateWitness({in: inp}, true); const w = circuit.calculateWitness({in: inp});
await circuit.assertOut(w, {sign: 0}); assert( w[circuit.getSignalIdx("main.sign")].equals(bigInt(0)) );
}); });
it("Sign of 3", async () => { it("Sign of 3", async () => {
const inp = getBits(Scalar.e(3), 254); const inp = getBits(bigInt(3), 254);
const w = await circuit.calculateWitness({in: inp}, true); const w = circuit.calculateWitness({in: inp});
await circuit.assertOut(w, {sign: 0}); assert( w[circuit.getSignalIdx("main.sign")].equals(bigInt(0)) );
}); });
it("Sign of q/2", async () => { it("Sign of q/2", async () => {
const inp = getBits(Scalar.shr(q, 1), 254); const inp = getBits(q.shr(bigInt.one), 254);
const w = await circuit.calculateWitness({in: inp}, true); const w = circuit.calculateWitness({in: inp});
await circuit.assertOut(w, {sign: 0}); assert( w[circuit.getSignalIdx("main.sign")].equals(bigInt(0)) );
}); });
it("Sign of q/2+1", async () => { it("Sign of q/2+1", async () => {
const inp = getBits(Scalar.add(Scalar.shr(q, 1), 1) , 254); const inp = getBits(q.shr(bigInt.one).add(bigInt.one), 254);
const w = await circuit.calculateWitness({in: inp}, true); const w = circuit.calculateWitness({in: inp});
await circuit.assertOut(w, {sign: 1}); assert( w[circuit.getSignalIdx("main.sign")].equals(bigInt(1)) );
}); });
it("Sign of q-1", async () => { it("Sign of q-1", async () => {
const inp = getBits(Scalar.sub(q, 1), 254); const inp = getBits(q.sub(bigInt.one), 254);
const w = await circuit.calculateWitness({in: inp}, true); const w = circuit.calculateWitness({in: inp});
await circuit.assertOut(w, {sign: 1}); assert( w[circuit.getSignalIdx("main.sign")].equals(bigInt(1)) );
}); });
it("Sign of q", async () => { it("Sign of q", async () => {
const inp = getBits(q, 254); const inp = getBits(q, 254);
const w = await circuit.calculateWitness({in: inp}, true); const w = circuit.calculateWitness({in: inp});
await circuit.assertOut(w, {sign: 1}); assert( w[circuit.getSignalIdx("main.sign")].equals(bigInt(1)) );
}); });
it("Sign of all ones", async () => { it("Sign of all ones", async () => {
const inp = getBits(Scalar.sub(Scalar.shl(1,254),1), 254); const inp = getBits(bigInt(1).shl(254).sub(bigInt(1)), 254);
const w = await circuit.calculateWitness({in: inp}, true); const w = circuit.calculateWitness({in: inp});
await circuit.assertOut(w, {sign: 1}); assert( w[circuit.getSignalIdx("main.sign")].equals(bigInt(1)) );
}); });
}); });

View File

@@ -1,11 +1,29 @@
const chai = require("chai"); const chai = require("chai");
const snarkjs = require("snarkjs");
const Fr = require("ffjavascript").bn128.Fr;
const smt = require("../src/smt.js"); const smt = require("../src/smt.js");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function stringifyBigInts(o) {
if ((typeof(o) == "bigint") || (o instanceof bigInt)) {
return o.toString(10);
} else if (Array.isArray(o)) {
return o.map(stringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = stringifyBigInts(o[k]);
}
return res;
} else {
return o;
}
}
describe("SMT Javascript test", function () { describe("SMT Javascript test", function () {
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
@@ -13,22 +31,22 @@ describe("SMT Javascript test", function () {
it("Should insert 2 elements and empty them", async () => { it("Should insert 2 elements and empty them", async () => {
const tree = await smt.newMemEmptyTrie(); const tree = await smt.newMemEmptyTrie();
const key1 = Fr.e(111); const key1 = bigInt(111);
const value1 = Fr.e(222); const value1 = bigInt(222);
const key2 = Fr.e(333); const key2 = bigInt(333);
const value2 = Fr.e(444); const value2 = bigInt(444);
await tree.insert(key1,value1); await tree.insert(key1,value1);
await tree.insert(key2,value2); await tree.insert(key2,value2);
await tree.delete(key2); await tree.delete(key2);
await tree.delete(key1); await tree.delete(key1);
assert(Fr.isZero(tree.root)); assert(tree.root.isZero());
}); });
it("Should insert 3 elements in dferent order and should be the same", async () => { it("Should insert 3 elements in dferent order and should be the same", async () => {
const keys = [Fr.e(8), Fr.e(9), Fr.e(32)]; const keys = [bigInt(8), bigInt(9), bigInt(32)];
const values = [Fr.e(88), Fr.e(99), Fr.e(3232)]; const values = [bigInt(88), bigInt(99), bigInt(3232)];
const tree1 = await smt.newMemEmptyTrie(); const tree1 = await smt.newMemEmptyTrie();
const tree2 = await smt.newMemEmptyTrie(); const tree2 = await smt.newMemEmptyTrie();
const tree3 = await smt.newMemEmptyTrie(); const tree3 = await smt.newMemEmptyTrie();
@@ -60,11 +78,11 @@ describe("SMT Javascript test", function () {
await tree6.insert(keys[1],values[1]); await tree6.insert(keys[1],values[1]);
await tree6.insert(keys[0],values[0]); await tree6.insert(keys[0],values[0]);
assert(Fr.eq(tree1.root, tree2.root)); assert(tree1.root.equals(tree2.root));
assert(Fr.eq(tree2.root, tree3.root)); assert(tree2.root.equals(tree3.root));
assert(Fr.eq(tree3.root, tree4.root)); assert(tree3.root.equals(tree4.root));
assert(Fr.eq(tree4.root, tree5.root)); assert(tree4.root.equals(tree5.root));
assert(Fr.eq(tree5.root, tree6.root)); assert(tree5.root.equals(tree6.root));
assert.equal(Object.keys(tree1.db.nodes).length, Object.keys(tree2.db.nodes).length); assert.equal(Object.keys(tree1.db.nodes).length, Object.keys(tree2.db.nodes).length);
assert.equal(Object.keys(tree2.db.nodes).length, Object.keys(tree3.db.nodes).length); assert.equal(Object.keys(tree2.db.nodes).length, Object.keys(tree3.db.nodes).length);
@@ -76,19 +94,19 @@ describe("SMT Javascript test", function () {
await tree1.delete(keys[1]); await tree1.delete(keys[1]);
await tree2.delete(keys[1]); await tree2.delete(keys[1]);
await tree2.delete(keys[0]); await tree2.delete(keys[0]);
assert(Fr.eq(tree1.root, tree2.root)); assert(tree1.root.equals(tree2.root));
await tree3.delete(keys[0]); await tree3.delete(keys[0]);
await tree3.delete(keys[2]); await tree3.delete(keys[2]);
await tree4.delete(keys[2]); await tree4.delete(keys[2]);
await tree4.delete(keys[0]); await tree4.delete(keys[0]);
assert(Fr.eq(tree3.root, tree4.root)); assert(tree3.root.equals(tree4.root));
await tree5.delete(keys[1]); await tree5.delete(keys[1]);
await tree5.delete(keys[2]); await tree5.delete(keys[2]);
await tree6.delete(keys[2]); await tree6.delete(keys[2]);
await tree6.delete(keys[1]); await tree6.delete(keys[1]);
assert(Fr.eq(tree5.root, tree6.root)); assert(tree5.root.equals(tree6.root));
await tree1.delete(keys[2]); await tree1.delete(keys[2]);
await tree2.delete(keys[2]); await tree2.delete(keys[2]);
@@ -97,12 +115,12 @@ describe("SMT Javascript test", function () {
await tree5.delete(keys[0]); await tree5.delete(keys[0]);
await tree6.delete(keys[0]); await tree6.delete(keys[0]);
assert(Fr.isZero(tree1.root)); assert(tree1.root.isZero());
assert(Fr.isZero(tree2.root)); assert(tree2.root.isZero());
assert(Fr.isZero(tree3.root)); assert(tree3.root.isZero());
assert(Fr.isZero(tree4.root)); assert(tree4.root.isZero());
assert(Fr.isZero(tree5.root)); assert(tree5.root.isZero());
assert(Fr.isZero(tree6.root)); assert(tree6.root.isZero());
assert.equal(Object.keys(tree1.db.nodes).length, 0); assert.equal(Object.keys(tree1.db.nodes).length, 0);
assert.equal(Object.keys(tree2.db.nodes).length, 0); assert.equal(Object.keys(tree2.db.nodes).length, 0);
@@ -127,7 +145,7 @@ describe("SMT Javascript test", function () {
const arr = []; const arr = [];
const N = 100; const N = 100;
for (let i=0; i<N; i++) { for (let i=0; i<N; i++) {
arr.push(Fr.e(i)); arr.push(bigInt(i));
} }
const insArr = perm(arr); const insArr = perm(arr);
for (let i=0; i<N; i++) { for (let i=0; i<N; i++) {
@@ -138,7 +156,7 @@ describe("SMT Javascript test", function () {
await tree.delete(delArr[i]); await tree.delete(delArr[i]);
} }
assert(Fr.isZero(tree.root)); assert(tree.root.isZero());
assert.equal(Object.keys(tree.db.nodes).length, 0); assert.equal(Object.keys(tree.db.nodes).length, 0);
}); });
@@ -158,16 +176,7 @@ describe("SMT Javascript test", function () {
await tree1.update(9, 999); await tree1.update(9, 999);
await tree1.update(32, 323232); await tree1.update(32, 323232);
assert(Fr.eq(tree1.root, tree2.root)); assert(tree1.root.equals(tree2.root));
}); });
it("Should test update with same key-value", async () => {
const tree1 = await smt.newMemEmptyTrie();
await tree1.insert(8,88);
await tree1.update(8,88);
const res = await tree1.db.get(tree1.root);
assert.notEqual(res, undefined);
});
}); });

View File

@@ -1,23 +1,25 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const tester = require("circom").tester; const snarkjs = require("snarkjs");
const Fr = require("ffjavascript").bn128.Fr; const compiler = require("circom");
const smt = require("../src/smt.js"); const smt = require("../src/smt.js");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
async function testInsert(tree, key, value, circuit ) { async function testInsert(tree, key, value, circuit, log ) {
const res = await tree.insert(key,value); const res = await tree.insert(key,value);
let siblings = res.siblings; let siblings = res.siblings;
while (siblings.length<10) siblings.push(Fr.e(0)); while (siblings.length<10) siblings.push(bigInt(0));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
fnc: [1,0], fnc: [1,0],
oldRoot: res.oldRoot, oldRoot: res.oldRoot,
siblings: siblings, siblings: siblings,
@@ -26,20 +28,19 @@ async function testInsert(tree, key, value, circuit ) {
isOld0: res.isOld0 ? 1 : 0, isOld0: res.isOld0 ? 1 : 0,
newKey: key, newKey: key,
newValue: value newValue: value
}, true); }, log);
await circuit.checkConstraints(w);
await circuit.assertOut(w, {newRoot: res.newRoot});
const root1 = w[circuit.getSignalIdx("main.newRoot")];
assert(circuit.checkWitness(w));
assert(root1.equals(res.newRoot));
} }
async function testDelete(tree, key, circuit) { async function testDelete(tree, key, circuit) {
const res = await tree.delete(key); const res = await tree.delete(key);
let siblings = res.siblings; let siblings = res.siblings;
while (siblings.length<10) siblings.push(Fr.e(0)); while (siblings.length<10) siblings.push(bigInt(0));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
fnc: [1,1], fnc: [1,1],
oldRoot: res.oldRoot, oldRoot: res.oldRoot,
siblings: siblings, siblings: siblings,
@@ -48,19 +49,20 @@ async function testDelete(tree, key, circuit) {
isOld0: res.isOld0 ? 1 : 0, isOld0: res.isOld0 ? 1 : 0,
newKey: res.delKey, newKey: res.delKey,
newValue: res.delValue newValue: res.delValue
}, true); });
await circuit.checkConstraints(w); const root1 = w[circuit.getSignalIdx("main.newRoot")];
await circuit.assertOut(w, {newRoot: res.newRoot}); assert(circuit.checkWitness(w));
assert(root1.equals(res.newRoot));
} }
async function testUpdate(tree, key, newValue, circuit) { async function testUpdate(tree, key, newValue, circuit) {
const res = await tree.update(key, newValue); const res = await tree.update(key, newValue);
let siblings = res.siblings; let siblings = res.siblings;
while (siblings.length<10) siblings.push(Fr.e(0)); while (siblings.length<10) siblings.push(bigInt(0));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
fnc: [0,1], fnc: [0,1],
oldRoot: res.oldRoot, oldRoot: res.oldRoot,
siblings: siblings, siblings: siblings,
@@ -71,47 +73,53 @@ async function testUpdate(tree, key, newValue, circuit) {
newValue: res.newValue newValue: res.newValue
}); });
await circuit.checkConstraints(w); const root1 = w[circuit.getSignalIdx("main.newRoot")];
await circuit.assertOut(w, {newRoot: res.newRoot}); assert(circuit.checkWitness(w));
assert(root1.equals(res.newRoot));
} }
describe("SMT Processor test", function () { describe("SMT test", function () {
let circuit; let circuit;
let tree; let tree;
this.timeout(10000000); this.timeout(10000000);
before( async () => { before( async () => {
circuit = await tester(path.join(__dirname, "circuits", "smtprocessor10_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "smtprocessor10_test.circom"));
await circuit.loadSymbols();
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains SMTProcessor: " + circuit.nConstraints);
tree = await smt.newMemEmptyTrie(); tree = await smt.newMemEmptyTrie();
}); });
it("Should verify an insert to an empty tree", async () => { it("Should verify an insert to an empty tree", async () => {
const key = Fr.e(111); const key = bigInt(111);
const value = Fr.e(222); const value = bigInt(222);
await testInsert(tree, key, value, circuit); await testInsert(tree, key, value, circuit);
}); });
it("It should add another element", async () => { it("It should add another element", async () => {
const key = Fr.e(333); const key = bigInt(333);
const value = Fr.e(444); const value = bigInt(444);
await testInsert(tree, key, value, circuit); await testInsert(tree, key, value, circuit);
}); });
it("Should remove an element", async () => { it("Should remove an element", async () => {
await testDelete(tree, 111, circuit); await testDelete(tree, 111, circuit);
await testDelete(tree, 333, circuit); await testDelete(tree, 333, circuit);
}); });
it("Should test convination of adding and removing 3 elements", async () => { it("Should test convination of adding and removing 3 elements", async () => {
const keys = [Fr.e(8), Fr.e(9), Fr.e(32)]; const keys = [bigInt(8), bigInt(9), bigInt(32)];
const values = [Fr.e(88), Fr.e(99), Fr.e(3232)]; const values = [bigInt(88), bigInt(99), bigInt(3232)];
const tree1 = await smt.newMemEmptyTrie(); const tree1 = await smt.newMemEmptyTrie();
const tree2 = await smt.newMemEmptyTrie(); const tree2 = await smt.newMemEmptyTrie();
const tree3 = await smt.newMemEmptyTrie(); const tree3 = await smt.newMemEmptyTrie();
@@ -170,8 +178,8 @@ describe("SMT Processor test", function () {
it("Should match a NOp with random vals", async () => { it("Should match a NOp with random vals", async () => {
let siblings = []; let siblings = [];
while (siblings.length<10) siblings.push(Fr.e(88)); while (siblings.length<10) siblings.push(bigInt(88));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
fnc: [0,0], fnc: [0,0],
oldRoot: 11, oldRoot: 11,
siblings: siblings, siblings: siblings,
@@ -182,12 +190,12 @@ describe("SMT Processor test", function () {
newValue: 77 newValue: 77
}); });
const root1 = w[circuit.symbols["main.oldRoot"].varIdx]; const root1 = w[circuit.getSignalIdx("main.oldRoot")];
const root2 = w[circuit.symbols["main.newRoot"].varIdx]; const root2 = w[circuit.getSignalIdx("main.newRoot")];
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
assert(root1.equals(root2));
assert(Fr.eq(root1, root2));
}); });
it("Should update an element", async () => { it("Should update an element", async () => {
const tree1 = await smt.newMemEmptyTrie(); const tree1 = await smt.newMemEmptyTrie();
@@ -205,4 +213,5 @@ describe("SMT Processor test", function () {
await testUpdate(tree1, 9, 999, circuit); await testUpdate(tree1, 9, 999, circuit);
await testUpdate(tree1, 32, 323232, circuit); await testUpdate(tree1, 32, 323232, circuit);
}); });
}); });

View File

@@ -1,12 +1,14 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const Fr = require("ffjavascript").bn128.Fr; const snarkjs = require("snarkjs");
const tester = require("circom").tester; const compiler = require("circom");
const smt = require("../src/smt.js"); const smt = require("../src/smt.js");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
@@ -17,9 +19,9 @@ async function testInclusion(tree, key, circuit) {
assert(res.found); assert(res.found);
let siblings = res.siblings; let siblings = res.siblings;
while (siblings.length<10) siblings.push(Fr.e(0)); while (siblings.length<10) siblings.push(bigInt(0));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
enabled: 1, enabled: 1,
fnc: 0, fnc: 0,
root: tree.root, root: tree.root,
@@ -29,10 +31,9 @@ async function testInclusion(tree, key, circuit) {
isOld0: 0, isOld0: 0,
key: key, key: key,
value: res.foundValue value: res.foundValue
}, true); });
await circuit.checkConstraints(w);
assert(circuit.checkWitness(w));
} }
async function testExclusion(tree, key, circuit) { async function testExclusion(tree, key, circuit) {
@@ -40,9 +41,9 @@ async function testExclusion(tree, key, circuit) {
assert(!res.found); assert(!res.found);
let siblings = res.siblings; let siblings = res.siblings;
while (siblings.length<10) siblings.push(Fr.e(0)); while (siblings.length<10) siblings.push(bigInt(0));
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
enabled: 1, enabled: 1,
fnc: 1, fnc: 1,
root: tree.root, root: tree.root,
@@ -54,18 +55,21 @@ async function testExclusion(tree, key, circuit) {
value: 0 value: 0
}); });
await circuit.checkConstraints(w); assert(circuit.checkWitness(w));
} }
describe("SMT Verifier test", function () { describe("SMT test", function () {
let circuit; let circuit;
let tree; let tree;
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
circuit = await tester(path.join(__dirname, "circuits", "smtverifier10_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "smtverifier10_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains SMTVerifier: " + circuit.nConstraints);
tree = await smt.newMemEmptyTrie(); tree = await smt.newMemEmptyTrie();
await tree.insert(7,77); await tree.insert(7,77);
@@ -93,7 +97,7 @@ describe("SMT Verifier test", function () {
let siblings = []; let siblings = [];
for (let i=0; i<10; i++) siblings.push(i); for (let i=0; i<10; i++) siblings.push(i);
const w = await circuit.calculateWitness({ const w = circuit.calculateWitness({
enabled: 0, enabled: 0,
fnc: 0, fnc: 0,
root: 1, root: 1,
@@ -104,32 +108,7 @@ describe("SMT Verifier test", function () {
key: 44, key: 44,
value: 0 value: 0
}); });
assert(circuit.checkWitness(w));
await circuit.checkConstraints(w);
});
it("Check inclussion Adria case", async () => {
const e1_hi= Fr.e("17124152697573569611556136390143205198134245887034837071647643529178599000839");
const e1_hv= Fr.e("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const e2ok_hi= Fr.e("16498254692537945203721083102154618658340563351558973077349594629411025251262");
const e2ok_hv= Fr.e("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const e2fail_hi= Fr.e("17195092312975762537892237130737365903429674363577646686847513978084990105579");
const e2fail_hv= Fr.e("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const tree1 = await smt.newMemEmptyTrie();
await tree1.insert(e1_hi,e1_hv);
await tree1.insert(e2ok_hi,e2ok_hv);
await testInclusion(tree1, e2ok_hi, circuit);
const tree2 = await smt.newMemEmptyTrie();
await tree2.insert(e1_hi,e1_hv);
await tree2.insert(e2fail_hi,e2fail_hv);
await testInclusion(tree2, e2fail_hi, circuit);
}); });