Compare commits

..

56 Commits

Author SHA1 Message Date
7b7a057160 updated package-lock.json metadata for good 2024-07-31 14:13:42 -04:00
ea3dc38335 updated npm, links 2024-07-30 22:25:47 -04:00
fdcb762030 Use self-hosted snarkjs dependency 2023-09-11 21:43:48 -07:00
e9256fbf85 Change repository info 2023-09-11 21:11:57 -07:00
d20d53411d
use 35 rounds for poseidon hash, update poseidon constants from sage script for 35 rounds
(cherry picked from commit afb4eff954)
2021-02-02 15:18:23 +03:00
Jordi Baylina
f4e209728e
0.4.1 2020-12-26 20:13:30 +01:00
Jordi Baylina
c90b18e93b
0.4.0 2020-12-26 20:12:33 +01:00
Jordi Baylina
5935ac69df
0.3.0 2020-11-26 07:38:39 +01:00
Jordi Baylina
45f190b445
Merge pull request #51 from tornadocash/upstream
pass fixes size array arg in solidity poseidon implementation
2020-11-26 07:35:17 +01:00
Jordi Baylina
8423282b8c
Improve performance sha256compressor 2020-11-26 07:29:48 +01:00
Alexey
1e04fc0325 poseidon contract now accepts both selectors: for uint256[n] and bytes32[n] 2020-10-27 21:23:32 +03:00
Alexey
1f9d0bd37f pass fixes size array arg in solidity poseidon implementation 2020-10-26 16:47:07 +03:00
Marta Bellés
411a7d7576
Update README.md 2020-10-05 10:18:06 +02:00
Jordi Baylina
6bcbf3370e
0.2.4 2020-08-31 18:30:11 +02:00
Jordi Baylina
9d876a1b32
deps 2020-08-31 18:30:04 +02:00
Jordi Baylina
d422471b5b
Merge pull request #49 from krlosMata/feature/fix-smt-update
fix smt update
2020-08-31 17:14:45 +02:00
Jordi Baylina
01da5f90db
Merge pull request #50 from tornadocash/poseidon-pr-2
add poseidon comments and refactorings
2020-08-28 04:29:49 +02:00
fabc586fea
add poseidon comments and refactorings 2020-08-27 16:46:49 +03:00
krlosMata
7e93b3fcf8 fix smt update 2020-08-25 13:08:53 +02:00
Jordi Baylina
3f4734d4dd
Merge pull request #48 from kobigurk/kobigurk/fix_and_assert_less_than
fix: improve LessThan and adds assert
2020-08-24 11:12:11 +02:00
Kobi Gurkan
1cd3d203c5 fix LessThan and adds assert 2020-08-24 10:46:37 +03:00
Jordi Baylina
01e3f0d680
Poseidon genContract nInputs as parameters 2020-08-09 17:19:53 +02:00
Jordi Baylina
86c6a2a6f5
New Version of Poseidon 2020-08-09 17:13:04 +02:00
Jordi Baylina
5269afee0a
0.2.3 2020-04-20 11:01:20 +02:00
Jordi Baylina
48c721c8af
smtdb key string 2020-04-20 11:01:11 +02:00
Jordi Baylina
0efecf16fa
0.2.2 2020-04-19 18:46:11 +02:00
Jordi Baylina
7705fe8339
deps 2020-04-19 18:45:43 +02:00
Jordi Baylina
401c9e0728
0.2.1 2020-04-19 12:24:04 +02:00
Jordi Baylina
d5ed1c3ce4
Go back to blake 2020-04-19 12:23:55 +02:00
Jordi Baylina
6a1efe4820
0.2.0 2020-04-18 22:34:09 +02:00
Jordi Baylina
b2ac4daaa7
Blake to Blake2b and use of native big num 2020-04-18 22:33:59 +02:00
Jordi Baylina
6df6e9cb1c
0.1.2 2020-03-31 15:38:46 +02:00
Jordi Baylina
9c68d4a363
Exporting buffer to int 2020-03-31 15:38:37 +02:00
Jordi Baylina
57be559c44
0.1.1 2020-03-26 22:49:49 +01:00
Jordi Baylina
7bf8325662
deps 2020-03-26 22:49:31 +01:00
Jordi Baylina
899d15f0c2
0.1.0 2020-03-26 19:58:53 +01:00
Jordi Baylina
0bf26ea5ec
Merge branch 'c_build' 2020-03-26 19:52:34 +01:00
Jordi Baylina
e240605642
pre 0.5 all working 2020-03-26 19:24:20 +01:00
Jordi Baylina
273ab79665
Negative numbers and fix in comparator 2020-03-16 20:41:11 +01:00
Jordi Baylina
a851d08a46
0.0.21 2020-02-25 05:42:31 -08:00
Jordi Baylina
19bbada388
Poseidon for t=3 2020-02-25 05:41:51 -08:00
Jordi Baylina
cf6d1f0bb1
Test name changed on comparators 2020-02-04 19:19:11 +01:00
Jordi Baylina
2f28fc7002
remove pows and shifts for optimization 2020-01-23 07:23:17 +07:00
Jordi Baylina
4f11565ca4
Adapted circuits to the construction fase refactorization 2019-12-23 19:36:26 +01:00
Jordi Baylina
756f1f51e5
Multithread 2019-12-20 21:59:58 +01:00
Jordi Baylina
bc0fb60f89
SMT test title better explained 2019-12-17 17:12:29 +01:00
Jordi Baylina
7a6b0eda6e
All testst finished with c_build 2019-12-16 21:35:52 +01:00
Jordi Baylina
e32460efe1
All tests working 2019-12-14 20:32:45 +01:00
Jordi Baylina
a8107abbe9
pedersen2 adapted 2019-12-13 19:05:20 +01:00
Jordi Baylina
4117ebc64a
pedersen working 2019-12-13 18:35:29 +01:00
Jordi Baylina
b4cd3889b6
babyjub.js adapted 2019-12-12 19:46:07 +01:00
Jordi Baylina
30c6cf55b9
Alias Check and Babyjub adapted 2019-12-12 16:49:58 +01:00
Jordi Baylina
d5bca9feb6
sha256 tests updated to c 2019-12-12 13:04:02 +01:00
Jordi Baylina
bdfb0fb928
clean sha256 tests 2019-12-11 21:55:51 +01:00
Jordi Baylina
8bd0fac913
sha256 testing 2019-12-11 21:41:15 +01:00
Jordi Baylina
9941aac2f2
Fix sha256 last 448 test 2019-12-11 06:55:23 +01:00
97 changed files with 17454 additions and 6402 deletions

View File

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

View File

@ -4,6 +4,7 @@
- This repository contains a library of circuit templates. - 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). - 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 ## Organisation
@ -14,4 +15,4 @@ This respository contains 5 folders:
- `src`: it contains similar implementation of circuits in JavaScript. - `src`: it contains similar implementation of circuits in JavaScript.
- `test`: tests. - `test`: tests.
A description of the specific circuit templates for the `circuit` folder will be soon updated. A description of the specific circuit templates for the `circuit` folder will be soon updated.

View File

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

View File

@ -21,6 +21,7 @@ include "compconstant.circom";
template AliasCheck() { template AliasCheck() {
signal input in[254]; signal input in[254];
component compConstant = CompConstant(-1); component compConstant = CompConstant(-1);
@ -29,15 +30,3 @@ template AliasCheck() {
compConstant.out === 0; compConstant.out === 0;
} }
template AliasCheckBabyJub() {
signal input in[251];
signal input enabled;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
for (var i=0; i<251; i++) in[i] ==> compConstant.in[i];
for (var i=0; i<3; i++) 0 ==> compConstant.in[251+i];
compConstant.out*enabled === 0;
}

View File

@ -81,13 +81,13 @@ template BabyCheck() {
a*x2 + y2 === 1 + d*x2*y2; a*x2 + y2 === 1 + d*x2*y2;
} }
// Extracts the public key from private key, as mentioned in https://tools.ietf.org/html/rfc8032 // Extracts the public key from private key
template BabyPbk() { template BabyPbk() {
signal private input in; signal private input in;
signal output Ax; signal output Ax;
signal output Ay; signal output Ay;
var BASE8 = [ var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];

View File

@ -48,12 +48,14 @@ template BinSub(n) {
var lin = 2**n; var lin = 2**n;
var lout = 0; var lout = 0;
for (var i=0; i<n; i++) { var 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 (var i=0; i<n; i++) { for (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

@ -50,7 +50,6 @@ To waranty binary outputs:
This function calculates the number of extra bits in the output to do the full sum. This function calculates the number of extra bits in the output to do the full sum.
*/ */
/* a must be < Nq/2, where Nq is the number of elements in the scalar field */
function nbits(a) { function nbits(a) {
var n = 1; var n = 1;
var r = 0; var r = 0;
@ -62,7 +61,6 @@ function nbits(a) {
} }
/* n must be such that (2**(n+1) -2) < Nq/ops, where Nq is the number of bits in the scalar field */
template BinSum(n, ops) { template BinSum(n, ops) {
var nout = nbits((2**n -1)*ops); var nout = nbits((2**n -1)*ops);
signal input in[ops][n]; signal input in[ops][n];
@ -74,19 +72,26 @@ 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] * 2**k; lin += in[j][k] * e2;
} }
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] * 2**k; lout += out[k] * e2;
e2 = e2+e2;
} }
// Ensure the sum; // Ensure the sum;

View File

@ -21,16 +21,17 @@ include "comparators.circom";
include "aliascheck.circom"; include "aliascheck.circom";
/* This doesn't check aliasing, so for n > 253 there are multiple bit strings for each number */
template Num2Bits(n) { template Num2Bits(n) {
signal input in; signal input in;
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] * 2**i; lc1 += out[i] * e2;
e2 = e2+e2;
} }
lc1 === in; lc1 === in;
@ -55,8 +56,10 @@ 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] * 2**i; lc1 += in[i] * e2;
e2 = e2 + e2;
} }
lc1 ==> out; lc1 ==> out;
@ -77,7 +80,6 @@ template Bits2Num_strict() {
b2n.out ==> out; b2n.out ==> out;
} }
/* n must not exceed 253 */
template Num2BitsNeg(n) { template Num2BitsNeg(n) {
signal input in; signal input in;
signal output out[n]; signal output out[n];

View File

@ -86,10 +86,11 @@ 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*2+1); component n2b = Num2Bits(n+1);
n2b.in <== in[0]+ (1<<n) - in[1]; n2b.in <== in[0]+ (1<<n) - in[1];

View File

@ -46,12 +46,11 @@ 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

@ -17,7 +17,7 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
include "aliascheck.circom"; include "compconstant.circom";
include "pointbits.circom"; include "pointbits.circom";
include "pedersen.circom"; include "pedersen.circom";
include "escalarmulany.circom"; include "escalarmulany.circom";
@ -40,15 +40,12 @@ template EdDSAVerifier(n) {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component aliasCheck = AliasCheckBabyJub(); component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
aliasCheck.enabled <== 1;
for (i=0; i<251; i++) { for (i=0; i<254; i++) {
S[i] ==> aliasCheck.in[i]; S[i] ==> compConstant.in[i];
} }
S[251] === 0; compConstant.out === 0;
S[252] === 0;
S[253] === 0;
S[254] === 0; S[254] === 0;
S[255] === 0; S[255] === 0;
@ -125,7 +122,7 @@ template EdDSAVerifier(n) {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8 = [ var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];

View File

@ -17,7 +17,7 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
include "aliascheck.circom"; include "compconstant.circom";
include "pointbits.circom"; include "pointbits.circom";
include "mimc.circom"; include "mimc.circom";
include "bitify.circom"; include "bitify.circom";
@ -39,15 +39,16 @@ template EdDSAMiMCVerifier() {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component snum2bits = Num2Bits(251); component snum2bits = Num2Bits(253);
snum2bits.in <== S; snum2bits.in <== S;
component aliasCheck = AliasCheckBabyJub(); component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
aliasCheck.enabled <== 1;
for (i=0; i<251; i++) { for (i=0; i<253; i++) {
snum2bits.out[i] ==> aliasCheck.in[i]; snum2bits.out[i] ==> compConstant.in[i];
} }
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
@ -99,12 +100,12 @@ template EdDSAMiMCVerifier() {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8 = [ var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(251, BASE8); component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<251; i++) { for (i=0; i<253; i++) {
mulFix.e[i] <== snum2bits.out[i]; mulFix.e[i] <== snum2bits.out[i];
} }

View File

@ -17,7 +17,7 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
include "aliascheck.circom"; include "compconstant.circom";
include "pointbits.circom"; include "pointbits.circom";
include "mimcsponge.circom"; include "mimcsponge.circom";
include "bitify.circom"; include "bitify.circom";
@ -39,19 +39,20 @@ template EdDSAMiMCSpongeVerifier() {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component snum2bits = Num2Bits(251); component snum2bits = Num2Bits(253);
snum2bits.in <== S; snum2bits.in <== S;
component aliasCheck = AliasCheckBabyJub(); component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
aliasCheck.enabled <== 1;
for (i=0; i<251; i++) { for (i=0; i<253; i++) {
snum2bits.out[i] ==> aliasCheck.in[i]; snum2bits.out[i] ==> compConstant.in[i];
} }
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
component hash = MiMCSponge(5, 1); component hash = MiMCSponge(5, 220, 1);
hash.ins[0] <== R8x; hash.ins[0] <== R8x;
hash.ins[1] <== R8y; hash.ins[1] <== R8y;
hash.ins[2] <== Ax; hash.ins[2] <== Ax;
@ -99,12 +100,12 @@ template EdDSAMiMCSpongeVerifier() {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8 = [ var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(251, BASE8); component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<251; i++) { for (i=0; i<253; i++) {
mulFix.e[i] <== snum2bits.out[i]; mulFix.e[i] <== snum2bits.out[i];
} }

View File

@ -38,15 +38,16 @@ template EdDSAPoseidonVerifier() {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component snum2bits = Num2Bits(251); component snum2bits = Num2Bits(253);
snum2bits.in <== S; snum2bits.in <== S;
component aliasCheck = AliasCheckBabyJub(); component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
aliasCheck.enabled <== enabled;
for (i=0; i<251; i++) { for (i=0; i<253; i++) {
snum2bits.out[i] ==> aliasCheck.in[i]; snum2bits.out[i] ==> compConstant.in[i];
} }
compConstant.in[253] <== 0;
compConstant.out*enabled === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
@ -98,12 +99,12 @@ template EdDSAPoseidonVerifier() {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8 = [ var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(251, BASE8); component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<251; i++) { for (i=0; i<253; i++) {
mulFix.e[i] <== snum2bits.out[i]; mulFix.e[i] <== snum2bits.out[i];
} }

View File

@ -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; var table[16][2];
component mux; component mux;
component adder; component adder;

View File

@ -44,7 +44,6 @@ include "babyjub.circom";
A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
is the output of the windows that it's going to be <= 2^246*B is the output of the windows that it's going to be <= 2^246*B
*/ */
/* base must not be the neutral element nor points of small order */
template WindowMulFix() { template WindowMulFix() {
signal input in[3]; signal input in[3];
signal input base[2]; signal input base[2];
@ -134,12 +133,11 @@ template WindowMulFix() {
/* /*
This component does a multiplication of a escalar times a fix base This component does a multiplication of a escalar times a fix base
nWindows must not exceed 82
Signals: Signals:
e: The scalar in bits e: The scalar in bits
base: the base point in edwards format base: the base point in edwards format
out: The result out: The result
dbl: Point in Montgomery to be linked to the next segment. dbl: Point in Edwards to be linked to the next segment.
*/ */
template SegmentMulFix(nWindows) { template SegmentMulFix(nWindows) {
@ -178,6 +176,9 @@ 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];
@ -187,9 +188,6 @@ 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++) {
@ -238,7 +236,7 @@ template EscalarMulFix(n, BASE) {
signal output out[2]; // Point (Twisted format) signal output out[2]; // Point (Twisted format)
var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246 var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
var nlastsegment = n - (nsegments-1)*246; var nlastsegment = n - (nsegments-1)*249;
component segments[nsegments]; component segments[nsegments];
@ -252,13 +250,13 @@ template EscalarMulFix(n, BASE) {
for (s=0; s<nsegments; s++) { for (s=0; s<nsegments; s++) {
nseg = (s < nsegments-1) ? 246 : nlastsegment; nseg = (s < nsegments-1) ? 249 : nlastsegment;
nWindows = ((nseg - 1)\3)+1; nWindows = ((nseg - 1)\3)+1;
segments[s] = SegmentMulFix(nWindows); segments[s] = SegmentMulFix(nWindows);
for (i=0; i<nseg; i++) { for (i=0; i<nseg; i++) {
segments[s].e[i] <== e[s*246+i]; segments[s].e[i] <== e[s*249+i];
} }
for (i = nseg; i<nWindows*3; i++) { for (i = nseg; i<nWindows*3; i++) {

View File

@ -33,7 +33,7 @@ function EscalarMulW4Table(base, k) {
var i; var i;
var p[2]; var p[2];
var dbl = base; var dbl[2] = 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]);

View File

@ -67,6 +67,7 @@ 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) {
@ -81,8 +82,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 (var i=0; i<n1; i++) ands[0].in[i] <== in[i]; for (i=0; i<n1; i++) ands[0].in[i] <== in[i];
for (var i=0; i<n2; i++) ands[1].in[i] <== in[n1+i]; for (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 = [ var c[91] = [
0, 0,
20888961410941983456478427210666206549300505294776164667214940546594746570981, 20888961410941983456478427210666206549300505294776164667214940546594746570981,
15265126113435022738560151911929040668591755459209400716467504685752745317193, 15265126113435022738560151911929040668591755459209400716467504685752745317193,

View File

@ -1,17 +1,17 @@
// implements MiMC-2n/n as hash using a sponge construction. // implements MiMC-2n/n as hash using a sponge construction.
// log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110 // log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110
// => nRounds should be 220 // => nRounds should be 220
template MiMCSponge(nInputs, nOutputs) { template MiMCSponge(nInputs, nRounds, nOutputs) {
signal input ins[nInputs]; signal input ins[nInputs];
signal input k; signal input k;
signal output outs[nOutputs]; signal output outs[nOutputs];
var nRounds = 220; var i;
// S = R||C // S = R||C
component S[nInputs + nOutputs - 1]; component S[nInputs + nOutputs - 1];
for (var i = 0; i < nInputs; i++) { for (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) {
@ -25,7 +25,7 @@ template MiMCSponge(nInputs, nOutputs) {
outs[0] <== S[nInputs - 1].xL_out; outs[0] <== S[nInputs - 1].xL_out;
for (var i = 0; i < nOutputs - 1; i++) { for (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;
@ -42,7 +42,7 @@ template MiMCFeistel(nrounds) {
signal output xR_out; signal output xR_out;
// doesn't contain the first and last round constants, which are always zero // doesn't contain the first and last round constants, which are always zero
var c_partial = [ var c_partial[218] = [
7120861356467848435263064379192047478074060781135320967663101236819528304084, 7120861356467848435263064379192047478074060781135320967663101236819528304084,
5024705281721889198577876690145313457398658950011302225525409148828000436681, 5024705281721889198577876690145313457398658950011302225525409148828000436681,
17980351014018068290387269214713820287804403312720763401943303895585469787384, 17980351014018068290387269214713820287804403312720763401943303895585469787384,

View File

@ -85,7 +85,6 @@ template Montgomery2Edwards() {
*/ */
/* in1 must be != in2 */
template MontgomeryAdd() { template MontgomeryAdd() {
signal input in1[2]; signal input in1[2];
signal input in2[2]; signal input in2[2];

View File

@ -108,7 +108,6 @@ template Window4() {
} }
/* nWindows must not exceed 50 */
template Segment(nWindows) { template Segment(nWindows) {
signal input in[nWindows*4]; signal input in[nWindows*4];
signal input base[2]; signal input base[2];
@ -129,6 +128,9 @@ 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];
@ -154,9 +156,6 @@ 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();
@ -177,7 +176,7 @@ template Pedersen(n) {
signal input in[n]; signal input in[n];
signal output out[2]; signal output out[2];
var BASE = [ var BASE[10][2] = [
[10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317], [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094], [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896], [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
@ -188,7 +187,8 @@ 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 = [ var PBASE[10][2] = [
[10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317], [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094], [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896], [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
@ -39,6 +39,7 @@ 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 > ((-1) >> 1)) { if (r < 0 ) {
r = -r; r = -r;
} }

View File

@ -40,9 +40,9 @@ template Poseidon(nInputs) {
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) // Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8)
// Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py // Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py
// And rounded up to nearest integer that divides by t // And rounded up to nearest integer that divides by t
var t = nInputs + 1; var t = nInputs + 1;
var nRoundsF = 8; var nRoundsF = 8;
var nRoundsP = 35; var nRoundsP = 35;

View File

@ -19,7 +19,7 @@
template H(x) { template H(x) {
signal output out[32]; signal output out[32];
var c = [0x6a09e667, var c[8] = [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 = [ var c[64] = [
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,6 +22,8 @@ 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];
@ -37,7 +39,11 @@ 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();
@ -74,6 +80,9 @@ 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];
} }
} }
@ -144,13 +153,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

@ -0,0 +1,112 @@
// 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,22 +24,26 @@ 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 (var k=0; k<32; k++) { for (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];
} }
} }
@ -47,22 +51,26 @@ 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,20 +26,24 @@ 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 sum = BinSum(32, 4);
component sigma1 = SmallSigma(17,19,10); component sigma1 = SmallSigma(17,19,10);
component sigma0 = SmallSigma(7, 18, 3); component sigma0 = SmallSigma(7, 18, 3);
for (k=0; k<32; k++) {
for (var k=0; k<32; k++) {
sigma1.in[k] <== in2[k]; sigma1.in[k] <== in2[k];
sigma0.in[k] <== in15[k]; sigma0.in[k] <== in15[k];
}
component sum = BinSum(32, 4);
for (k=0; k<32; 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,23 +30,28 @@ template T1() {
signal input w[32]; signal input w[32];
signal output out[32]; signal output out[32];
component sum = BinSum(32, 5); var ki;
component ch = Ch(32);
component ch = Ch(32);
component bigsigma1 = BigSigma(6, 11, 25); component bigsigma1 = BigSigma(6, 11, 25);
for (var ki=0; ki<32; ki++) { for (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,22 +26,25 @@ 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

@ -79,9 +79,11 @@ 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 (var i=0; i<nLevels; i++) { for (i=0; i<nLevels; i++) {
isZero[i] = IsZero(); isZero[i] = IsZero();
isZero[i].in <== siblings[i]; isZero[i].in <== siblings[i];
} }
@ -91,7 +93,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 (var i=nLevels-2; i>0; i--) { for (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,6 +150,8 @@ 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();
@ -167,18 +169,18 @@ template SMTProcessor(nLevels) {
n2bNew.in <== newKey; n2bNew.in <== newKey;
component smtLevIns = SMTLevIns(nLevels); component smtLevIns = SMTLevIns(nLevels);
for (var i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i]; for (i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
smtLevIns.enabled <== enabled; smtLevIns.enabled <== enabled;
component xors[nLevels]; component xors[nLevels];
for (var i=0; i<nLevels; i++) { for (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 (var i=0; i<nLevels; i++) { for (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;
@ -204,7 +206,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 (var i=nLevels-1; i != -1; i--) { for (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,6 +48,8 @@ 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;
@ -63,11 +65,11 @@ template SMTVerifier(nLevels) {
n2bNew.in <== key; n2bNew.in <== key;
component smtLevIns = SMTLevIns(nLevels); component smtLevIns = SMTLevIns(nLevels);
for (var i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i]; for (i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
smtLevIns.enabled <== enabled; smtLevIns.enabled <== enabled;
component sm[nLevels]; component sm[nLevels];
for (var i=0; i<nLevels; i++) { for (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;
@ -89,7 +91,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 (var i=nLevels-1; i != -1; i--) { for (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

@ -7,3 +7,6 @@ exports.pedersenHash = require("./src/pedersenHash");
exports.SMT = require("./src/smt").SMT; exports.SMT = require("./src/smt").SMT;
exports.SMTMemDB = require("./src/smt_memdb"); exports.SMTMemDB = require("./src/smt_memdb");
exports.poseidon = require("./src/poseidon"); exports.poseidon = require("./src/poseidon");

19882
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@tornado/circomlib", "name": "@tornado/circomlib",
"version": "0.0.21", "version": "0.4.1",
"description": "Basic circuits library for Circom", "description": "Basic circuits library for Circom",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@ -24,16 +24,16 @@
"author": "0Kims", "author": "0Kims",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@tornado/snarkjs": "0.1.20",
"blake-hash": "^1.1.0", "blake-hash": "^1.1.0",
"blake2b": "^2.1.3", "blake2b": "^2.1.3",
"@tornado/snarkjs": "0.1.20", "circom": "0.5.33",
"typedarray-to-buffer": "^3.1.5", "ffjavascript": "0.1.0"
"web3": "^1.2.11"
}, },
"devDependencies": { "devDependencies": {
"circom": "0.0.35", "eslint": "^6.8.0",
"eslint-plugin-mocha": "^5.2.0", "ganache-cli": "^6.12.1",
"ganache-cli": "^6.4.4", "mocha": "^7.1.1",
"mocha": "^5.2.0" "web3": "^1.3.0"
} }
} }

View File

@ -1,5 +1,6 @@
const bn128 = require("@tornado/snarkjs").bn128; const F1Field = require("ffjavascript").F1Field;
const bigInt = require("@tornado/snarkjs").bigInt; const Scalar = require("ffjavascript").Scalar;
const utils = require("ffjavascript").utils;
exports.addPoint = addPoint; exports.addPoint = addPoint;
exports.mulPointEscalar = mulPointEscalar; exports.mulPointEscalar = mulPointEscalar;
@ -7,22 +8,27 @@ 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 = [
bigInt("995203441582195749578291179787384436505546430278305826713579947235728471134"), F.e("995203441582195749578291179787384436505546430278305826713579947235728471134"),
bigInt("5472060717959818805561601436314318772137091100104008585924551046643952123905"), F.e("5472060717959818805561601436314318772137091100104008585924551046643952123905")
]; ];
exports.Base8 = [ exports.Base8 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), F.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), F.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328"); exports.order = Scalar.fromString("21888242871839275222246405745257275088614511777268538073601725287587578984328");
exports.subOrder = exports.order.shr(3); exports.subOrder = Scalar.shiftRight(exports.order, 3);
exports.p = bn128.r; exports.A = F.e("168700");
exports.A = bigInt("168700"); exports.D = F.e("168696");
exports.D = bigInt("168696");
function addPoint(a, b) {
const q = bn128.r; function addPoint(a,b) {
const res = []; const res = [];
@ -30,33 +36,40 @@ 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]) const beta = F.mul(a[0],b[1]);
.mul(b[1]) const gamma = F.mul(a[1],b[0]);
.add(bigInt(b[0]).mul(a[1])) const delta = F.mul(
.mul(bigInt(bigInt("1").add(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q)) F.sub(a[1], F.mul(exports.A, a[0])),
).affine(q); F.add(b[0], b[1])
res[1] = bigInt( );
bigInt(a[1]) const tau = F.mul(beta, gamma);
.mul(b[1]) const dtau = F.mul(exports.D, tau);
.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)) res[0] = F.div(
).affine(q); 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 = [bigInt("0"), bigInt("1")]; let res = [F.e("0"),F.e("1")];
let rem = bigInt(e); let rem = e;
let exp = base; let exp = base;
while (!rem.isZero()) { while (! Scalar.isZero(rem)) {
if (rem.isOdd()) { if (Scalar.isOdd(rem)) {
res = addPoint(res, exp); res = addPoint(res, exp);
} }
exp = addPoint(exp, exp); exp = addPoint(exp, exp);
rem = rem.shr(1); rem = Scalar.shiftRight(rem, 1);
} }
return res; return res;
@ -64,51 +77,52 @@ 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 res[0].equals(bigInt(0)) && res[1].equals(bigInt(1)); return (F.isZero(res[0]) && F.eq(res[1], F.one));
} }
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.equals(F.add(F.mul(exports.A, x2), y2), F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false; if (!F.eq(
F.add(F.mul(exports.A, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false;
return true; return true;
} }
function packPoint(P) { function packPoint(P) {
const buff = bigInt.leInt2Buff(P[1], 32); const buff = utils.leInt2Buff(P[1], 32);
if (P[0].greater(exports.p.shr(1))) { if (F.lt(P[0], F.zero)) {
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);
if (buff[31] & 0x80) { if (buff[31] & 0x80) {
sign = true; sign = true;
buff[31] = buff[31] & 0x7f; buff[31] = buff[31] & 0x7F;
} }
P[1] = bigInt.leBuff2int(buff); P[1] = utils.leBuff2int(buff);
if (P[1].greaterOrEquals(exports.p)) return null; if (Scalar.gt(P[1], exports.p)) return null;
const y2 = F.square(P[1]); const y2 = F.square(P[1]);
let x = F.sqrt(F.div(F.sub(F.one, y2), F.sub(exports.A, F.mul(exports.D, y2)))); let x = F.sqrt(F.div(
F.sub(F.one, y2),
F.sub(exports.A, F.mul(exports.D, y2))));
if (x == null) return null; if (x == null) return null;
if (sign) x = F.neg(x); if (sign) x = F.neg(x);
P[0] = F.affine(x); P[0] = x;
return P; return P;
} }

View File

@ -1,12 +1,15 @@
const createBlakeHash = require("blake-hash"); const createBlakeHash = require("blake-hash");
const bigInt = require("@tornado/snarkjs").bigInt; const Scalar = require("ffjavascript").Scalar;
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;
exports.signPoseidon = signPoseidon; exports.signPoseidon = signPoseidon;
@ -19,104 +22,101 @@ exports.packSignature = packSignature;
exports.unpackSignature = unpackSignature; exports.unpackSignature = unpackSignature;
exports.pruneBuffer = pruneBuffer; exports.pruneBuffer = pruneBuffer;
function pruneBuffer(_buff) { function pruneBuffer(_buff) {
const buff = Buffer.from(_buff); const buff = Buffer.from(_buff);
buff[0] = buff[0] & 0xf8; buff[0] = buff[0] & 0xF8;
buff[31] = buff[31] & 0x7f; buff[31] = buff[31] & 0x7F;
buff[31] = buff[31] | 0x40; buff[31] = buff[31] | 0x40;
return buff; return 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 = bigInt.leBuff2int(sBuff); let s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s,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 = bigInt.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const rBuff = createBlakeHash("blake512") const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest();
.update(Buffer.concat([h1.slice(32, 64), msg])) let r = utils.leBuff2int(rBuff);
.digest(); const Fr = new F1Field(babyJub.subOrder);
let r = bigInt.leBuff2int(rBuff); r = Fr.e(r);
r = r.mod(babyJub.subOrder);
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 = bigInt.leBuff2int(hmBuff); const hm = utils.leBuff2int(hmBuff);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder); const S = Fr.add(r , Fr.mul(hm, s));
return { return {
R8: R8, R8: R8,
S: S, S: S
}; };
} }
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 = bigInt.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = bigInt.leInt2Buff(msg, 32); const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512") const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
.update(Buffer.concat([h1.slice(32, 64), msgBuff])) let r = utils.leBuff2int(rBuff);
.digest(); const Fr = new F1Field(babyJub.subOrder);
let r = bigInt.leBuff2int(rBuff); r = Fr.e(r);
r = r.mod(babyJub.subOrder);
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 = r.add(hm.mul(s)).mod(babyJub.subOrder); const S = Fr.add(r , Fr.mul(hm, s));
return { return {
R8: R8, R8: R8,
S: S, S: S
}; };
} }
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 = bigInt.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = bigInt.leInt2Buff(msg, 32); const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512") const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
.update(Buffer.concat([h1.slice(32, 64), msgBuff])) let r = utils.leBuff2int(rBuff);
.digest(); const Fr = new F1Field(babyJub.subOrder);
let r = bigInt.leBuff2int(rBuff); r = Fr.e(r);
r = r.mod(babyJub.subOrder);
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 = r.add(hm.mul(s)).mod(babyJub.subOrder); const S = Fr.add(r , Fr.mul(hm, s));
return { return {
R8: R8, R8: R8,
S: S, S: S
}; };
} }
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 = bigInt.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = bigInt.leInt2Buff(msg, 32); const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512") const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
.update(Buffer.concat([h1.slice(32, 64), msgBuff])) let r = utils.leBuff2int(rBuff);
.digest(); const Fr = new F1Field(babyJub.subOrder);
let r = bigInt.leBuff2int(rBuff); r = Fr.e(r);
r = r.mod(babyJub.subOrder);
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 hm = poseidon([R8[0], R8[1], A[0], A[1], msg]);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder); const S = Fr.add(r , Fr.mul(hm, s));
return { return {
R8: R8, R8: R8,
S: S, S: S
}; };
} }
@ -124,24 +124,24 @@ function verify(msg, sig, A) {
// Check parameters // Check parameters
if (typeof sig != "object") return false; if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false; if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length != 2) return false; if (sig.R8.length!= 2) return false;
if (!babyJub.inCurve(sig.R8)) return false; if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false; if (!Array.isArray(A)) return false;
if (A.length != 2) return false; if (A.length!= 2) return false;
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 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 = bigInt.leBuff2int(hmBuff); const hm = utils.leBuff2int(hmBuff);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S); const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8"))); let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm,8));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false; if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false; if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
return true; return true;
} }
@ -149,43 +149,44 @@ function verifyMiMC(msg, sig, A) {
// Check parameters // Check parameters
if (typeof sig != "object") return false; if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false; if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length != 2) return false; if (sig.R8.length!= 2) return false;
if (!babyJub.inCurve(sig.R8)) return false; if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false; if (!Array.isArray(A)) return false;
if (A.length != 2) return false; if (A.length!= 2) return false;
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 = 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, hm.mul(bigInt("8"))); let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false; if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false; if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
return true; return true;
} }
function verifyPoseidon(msg, sig, A) { function verifyPoseidon(msg, sig, A) {
// Check parameters // Check parameters
if (typeof sig != "object") return false; if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false; if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length != 2) return false; if (sig.R8.length!= 2) return false;
if (!babyJub.inCurve(sig.R8)) return false; if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false; if (!Array.isArray(A)) return false;
if (A.length != 2) return false; if (A.length!= 2) return false;
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 hm = poseidon([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S); const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8"))); let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false; if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false; if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
return true; return true;
} }
@ -193,33 +194,35 @@ function verifyMiMCSponge(msg, sig, A) {
// Check parameters // Check parameters
if (typeof sig != "object") return false; if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false; if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length != 2) return false; if (sig.R8.length!= 2) return false;
if (!babyJub.inCurve(sig.R8)) return false; if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false; if (!Array.isArray(A)) return false;
if (A.length != 2) return false; if (A.length!= 2) return false;
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 = 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.mul(bigInt("8"))); let Pright = babyJub.mulPointEscalar(A, hm.times(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright); Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false; if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false; if (!babyJub.F.eq(Pleft[1],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 = bigInt.leInt2Buff(sig.S, 32); const Sp = utils.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: bigInt.leBuff2int(sigBuff.slice(32, 64)), S: utils.leBuff2int(sigBuff.slice(32,64))
}; };
} }

View File

@ -4,7 +4,6 @@
const Contract = require("./evmasm"); const Contract = require("./evmasm");
const G2 = require("@tornado/snarkjs").bn128.G2; const G2 = require("@tornado/snarkjs").bn128.G2;
const bigInt = require("@tornado/snarkjs").bigInt;
function toHex256(a) { function toHex256(a) {
let S = a.toString(16); let S = a.toString(16);
@ -529,7 +528,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, bigInt(i))); const MP = G2.affine(G2.mulScalar(P, 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,16 +1,18 @@
const bn128 = require("@tornado/snarkjs").bn128; const Scalar = require("ffjavascript").Scalar;
const bigInt = require("@tornado/snarkjs").bigInt; const ZqField = require("ffjavascript").ZqField;
const Web3Utils = require("web3-utils"); const Web3Utils = require("web3-utils");
const F = bn128.Fr; const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
exports.F = F;
const SEED = "mimc"; const SEED = "mimc";
const NROUNDS = 91; 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 = bigInt(Web3Utils.toBN(c).toString()); const cn = Scalar.FromString(Web3Utils.toBN(c).toString());
const iv = cn.mod(F.q); const iv = cn.mod(F.p);
return iv; return iv;
}; };
@ -19,40 +21,46 @@ exports.getConstants = (seed, nRounds) => {
if (typeof nRounds === "undefined") nRounds = NROUNDS; if (typeof nRounds === "undefined") nRounds = NROUNDS;
const cts = new Array(nRounds); const cts = new Array(nRounds);
let c = Web3Utils.keccak256(SEED); let c = Web3Utils.keccak256(SEED);
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.q.toString())); const n1 = Web3Utils.toBN(c).mod(Web3Utils.toBN(F.p.toString()));
const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64); const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64);
cts[i] = bigInt(Web3Utils.toBN(c2).toString()); cts[i] = Scalar.fromString(Web3Utils.toBN(c2).toString());
} }
cts[0] = bigInt(0); cts[0] = F.e(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 = bigInt(_x_in); const x_in = F.e(_x_in);
const k = bigInt(_k); const k = F.e(_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.exp(t, 7); r = F.pow(t, 7);
} }
return F.affine(F.add(r, k)); return F.add(r, k);
}; };
exports.multiHash = (arr, key) => { exports.multiHash = (arr, key) => {
let r; let r;
if (typeof key === "undefined") { if (typeof(key) === "undefined") {
r = F.zero; r = F.zero;
} else { } else {
r = key; r = key;
} }
for (let i = 0; i < arr.length; i++) { for (let i=0; i<arr.length; i++) {
r = F.add(F.add(r, arr[i]), exports.hash(bigInt(arr[i]), r)); r = F.add(
F.add(
r,
arr[i]
),
exports.hash(F.e(arr[i]), r)
);
} }
return F.affine(r); return r;
}; };

View File

@ -1,16 +1,16 @@
const bn128 = require("@tornado/snarkjs").bn128; const Scalar = require("ffjavascript").Scalar
const bigInt = require("@tornado/snarkjs").bigInt;
const Web3Utils = require("web3-utils"); const Web3Utils = require("web3-utils");
const F = bn128.Fr; const ZqField = require("ffjavascript").ZqField;
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
const SEED = "mimcsponge"; const SEED = "mimcsponge";
const NROUNDS = 220; 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 = bigInt(Web3Utils.toBN(c).toString()); const cn = Scalar.fromString(Web3Utils.toBN(c).toString());
const iv = cn.mod(F.q); const iv = cn.mod(F.p);
return iv; return iv;
}; };
@ -19,68 +19,68 @@ exports.getConstants = (seed, nRounds) => {
if (typeof nRounds === "undefined") nRounds = NROUNDS; if (typeof nRounds === "undefined") nRounds = NROUNDS;
const cts = new Array(nRounds); const cts = new Array(nRounds);
let c = Web3Utils.keccak256(SEED); let c = Web3Utils.keccak256(SEED);
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.q.toString())); const n1 = Web3Utils.toBN(c).mod(Web3Utils.toBN(F.p.toString()));
const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64); const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64);
cts[i] = bigInt(Web3Utils.toBN(c2).toString()); cts[i] = F.e(Web3Utils.toBN(c2).toString());
} }
cts[0] = bigInt(0); cts[0] = F.e(0);
cts[cts.length - 1] = bigInt(0); cts[cts.length - 1] = F.e(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 = bigInt(_xL_in); let xL = F.e(_xL_in);
let xR = bigInt(_xR_in); let xR = F.e(_xR_in);
const k = bigInt(_k); const k = F.e(_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 = bigInt(xR); const xR_tmp = F.e(xR);
if (i < NROUNDS - 1) { if (i < (NROUNDS - 1)) {
xR = xL; xR = xL;
xL = F.add(xR_tmp, F.exp(t, 5)); xL = F.add(xR_tmp, F.pow(t, 5));
} else { } else {
xR = F.add(xR_tmp, F.exp(t, 5)); xR = F.add(xR_tmp, F.pow(t, 5));
} }
} }
return { return {
xL: F.affine(xL), xL: F.normalize(xL),
xR: F.affine(xR), xR: F.normalize(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;
} }
let R = F.zero; let R = F.zero;
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, bigInt(arr[i])); R = F.add(R, F.e(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.affine(outputs[0]); return F.normalize(outputs[0]);
} else { } else {
return outputs.map((x) => F.affine(x)); return outputs.map(x => F.normalize(x));
} }
}; };

View File

@ -20,29 +20,34 @@ function createCode(seed, n) {
C.push("0x00"); C.push("0x00");
C.mload(); C.mload();
C.div(); C.div();
C.push("0xf47d33b5"); // MiMCSponge(uint256,uint256) C.push("0x3f1a1187"); // MiMCSponge(uint256,uint256,uint256)
C.eq(); C.eq();
C.jmpi("start"); C.jmpi("start");
C.invalid(); C.invalid();
C.label("start"); C.label("start");
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
C.push("0x44");
C.mload(); // k q
C.push("0x04"); C.push("0x04");
C.mload(); // xL q C.mload(); // xL k q
C.dup(1); // q xL q C.dup(2); // q xL k q
C.push("0x24"); C.push("0x24");
C.mload(); // xR q xL q C.mload(); // xR q xL k q
C.dup(1); // q xR q xL q C.dup(1); // q xR q xL k q
C.dup(3); // xL q xR q xL q C.dup(0); // q q xR q xL k q
C.dup(1); // q xL q xR q xL q C.dup(4); // xL q q xR q xL k q
C.dup(0); // q q xL q xR q xL q C.dup(6); // k xL q q xR q xL k q
C.dup(2); // xL q q xL q xR q xL q C.addmod(); // t=k+xL q xR q xL k q
C.dup(0); // xL xL q q xL q xR q xL q C.dup(1); // q t q xR q xL k q
C.mulmod(); // b=xL^2 q xL q xR q xL q C.dup(0); // q q t q xR q xL k q
C.dup(0); // b b q xL q xR q xL q C.dup(2); // t q q t q xR q xL k q
C.mulmod(); // c=xL^4 xL q xR q xL q C.dup(0); // t t q q t q xR q xL k q
C.mulmod(); // d=xL^5 xR q xL q C.mulmod(); // b=t^2 q t q xR q xL k q
C.addmod(); // e=xL^5+xR xL q (for next round: xL xR q) C.dup(0); // b b q t q xR q xL k q
C.mulmod(); // c=t^4 t q xR q xL k q
C.mulmod(); // d=t^5 xR q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
for (let i=0; i<n-1; i++) { for (let i=0; i<n-1; i++) {
if (i < n-2) { if (i < n-2) {
@ -50,24 +55,27 @@ function createCode(seed, n) {
} else { } else {
ci = "0x00"; ci = "0x00";
} }
C.swap(1); // xR xL q C.swap(1); // xR xL k q
C.dup(2); // q xR xL q C.dup(3); // q xR xL k q
C.dup(2); // xL q xR xL q C.dup(3); // k q xR xL k q
C.push(ci); // ci xL q xR xL q C.dup(1); // q k q xR xL k q
C.addmod(); // a=ci+xL xR xL q C.dup(4); // xL q k q xR xL k q
C.dup(3); // q a xR xL q C.push(ci); // ci xL q k q xR xL k q
C.swap(1); // a q xR xL q C.addmod(); // a=ci+xL k q xR xL k q
C.dup(1); // q a q xR xL q C.addmod(); // t=a+k xR xL k q
C.dup(0); // q q a q xR xL q C.dup(4); // q t xR xL k q
C.dup(2); // a q q a q xR xL q C.swap(1); // t q xR xL k q
C.dup(0); // a a q q a q xR xL q C.dup(1); // q t q xR xL k q
C.mulmod(); // b=a^2 q a q xR xL q C.dup(0); // q q t q xR xL k q
C.dup(0); // b b q a q xR xL q C.dup(2); // t q q t q xR xL k q
C.mulmod(); // c=a^4 a q xR xL q C.dup(0); // t t q q t q xR xL k q
C.mulmod(); // d=a^5 xR xL q C.mulmod(); // b=t^2 q t q xR xL k q
C.dup(3); // q d xR xL q C.dup(0); // b b q t q xR xL k q
C.swap(2); // xR d q xL q C.mulmod(); // c=t^4 t q xR xL k q
C.addmod(); // e=a^5+xR xL q (for next round: xL xR q) C.mulmod(); // d=t^5 xR xL k q
C.dup(4); // q d xR xL k q
C.swap(2); // xR d q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
} }
C.push("0x20"); C.push("0x20");
@ -92,6 +100,10 @@ module.exports.abi = [
{ {
"name": "xR_in", "name": "xR_in",
"type": "uint256" "type": "uint256"
},
{
"name": "k",
"type": "uint256"
} }
], ],
"name": "MiMCSponge", "name": "MiMCSponge",

View File

@ -1,7 +1,7 @@
const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("@tornado/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,47 +10,57 @@ const nWindowsPerSegment = 50;
exports.hash = pedersenHash; exports.hash = pedersenHash;
exports.getBasePoint = getBasePoint; exports.getBasePoint = getBasePoint;
function pedersenHash(msg) { function baseHash(type, S) {
const bitsPerSegment = windowSize * nWindowsPerSegment; 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 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 = [bigInt.zero, bigInt.one]; let accP = [babyJub.F.zero,babyJub.F.one];
for (let s = 0; s < nSegments; s++) { for (let s=0; s<nSegments; s++) {
let nWindows; let nWindows;
if (s == nSegments - 1) { if (s == nSegments-1) {
nWindows = Math.floor((bits.length - (nSegments - 1) * bitsPerSegment - 1) / windowSize) + 1; nWindows = Math.floor(((bits.length - (nSegments - 1)*bitsPerSegment) - 1) / windowSize) +1;
} else { } else {
nWindows = nWindowsPerSegment; nWindows = nWindowsPerSegment;
} }
let escalar = bigInt.zero; let escalar = Scalar.e(0);
let exp = bigInt.one; let exp = Scalar.e(1);
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 = bigInt.one; let acc = Scalar.e(1);
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 = acc.add(bigInt.one.shl(b)); acc = Scalar.add(acc, Scalar.shl(Scalar.e(1), b) );
} }
o++; o++;
} }
if (o < bits.length) { if (o<bits.length) {
if (bits[o]) { if (bits[o]) {
acc = acc.neg(); acc = Scalar.neg(acc);
} }
o++; o++;
} }
escalar = escalar.add(acc.mul(exp)); escalar = Scalar.add(escalar, Scalar.mul(acc, exp));
exp = exp.shl(windowSize + 1); exp = Scalar.shl(exp, windowSize+1);
} }
if (escalar.lesser(bigInt.zero)) { if (Scalar.lt(escalar, 0)) {
escalar = babyJub.subOrder.add(escalar); escalar = Scalar.add( escalar, babyJub.subOrder);
} }
accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(s), escalar)); accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(options.baseHash, s), escalar));
} }
return babyJub.packPoint(accP); return babyJub.packPoint(accP);
@ -58,14 +68,14 @@ function pedersenHash(msg) {
let bases = []; let bases = [];
function getBasePoint(pointIdx) { function getBasePoint(baseHashType, 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 = createBlakeHash("blake256").update(S).digest(); const h = baseHash(baseHashType, S);
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++;
} }
@ -82,7 +92,7 @@ function getBasePoint(pointIdx) {
function padLeftZeros(idx, n) { function padLeftZeros(idx, n) {
let sidx = "" + idx; let sidx = "" + idx;
while (sidx.length < n) sidx = "0" + sidx; while (sidx.length<n) sidx = "0"+sidx;
return sidx; return sidx;
} }
@ -91,17 +101,21 @@ Input a buffer
Returns an array of booleans. 0 is LSB of first byte and so on. Returns an array of booleans. 0 is LSB of first byte and so on.
*/ */
function buffer2bits(buff) { function buffer2bits(buff) {
const res = new Array(buff.length * 8); const res = new Array(buff.length*8);
for (let i = 0; i < buff.length; i++) { for (let i=0; i<buff.length; i++) {
const b = buff[i]; const b = buff[i];
res[i * 8] = b & 0x01; res[i*8] = b & 0x01;
res[i * 8 + 1] = b & 0x02; res[i*8+1] = b & 0x02;
res[i * 8 + 2] = b & 0x04; res[i*8+2] = b & 0x04;
res[i * 8 + 3] = b & 0x08; res[i*8+3] = b & 0x08;
res[i * 8 + 4] = b & 0x10; res[i*8+4] = b & 0x10;
res[i * 8 + 5] = b & 0x20; res[i*8+5] = b & 0x20;
res[i * 8 + 6] = b & 0x40; res[i*8+6] = b & 0x40;
res[i * 8 + 7] = b & 0x80; res[i*8+7] = b & 0x80;
} }
return res; return res;
} }

View File

@ -7,7 +7,15 @@ 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(i); const p = pedersenHash.getBasePoint(baseHash, i);
console.log(`[${p[0]},${p[1]}]`); console.log(`[${p[0]},${p[1]}]`);
} }

View File

@ -1,11 +1,10 @@
const assert = require("assert"); const assert = require("assert");
const bn128 = require("@tornado/snarkjs").bn128; const Scalar = require("ffjavascript").Scalar;
const bigInt = require("@tornado/snarkjs").bigInt; const ZqField = require("ffjavascript").ZqField;
const F = bn128.Fr; const { unstringifyBigInts } = require("ffjavascript").utils;
const { unstringifyBigInts } = require("@tornado/snarkjs");
// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 // Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
// const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617")); const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
// Parameters are generated by a reference script https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/generate_parameters_grain.sage // Parameters are generated by a reference script https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/generate_parameters_grain.sage
// Used like so: sage generate_parameters_grain.sage 1 0 254 2 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 // Used like so: sage generate_parameters_grain.sage 1 0 254 2 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
@ -17,7 +16,7 @@ const { C, M } = unstringifyBigInts(require("./poseidon_constants.json"));
const N_ROUNDS_F = 8; const N_ROUNDS_F = 8;
const N_ROUNDS_P = 35; const N_ROUNDS_P = 35;
const pow5 = (a) => F.mul(a, F.square(F.square(a, a))); const pow5 = a => F.mul(a, F.square(F.square(a, a)));
function poseidon(inputs) { function poseidon(inputs) {
assert(inputs.length > 0); assert(inputs.length > 0);
@ -27,22 +26,23 @@ function poseidon(inputs) {
const nRoundsF = N_ROUNDS_F; const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P; const nRoundsP = N_ROUNDS_P;
let state = [...inputs.map((a) => bigInt(a)), F.zero]; let state = [...inputs.map(a => F.e(a)), F.zero];
for (let r = 0; r < nRoundsF + nRoundsP; r++) { for (let r = 0; r < nRoundsF + nRoundsP; r++) {
state = state.map((a, i) => F.add(a, bigInt(C[t - 2][r * t + i]))); state = state.map((a, i) => F.add(a, BigInt(C[t - 2][r * t + i])));
if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) { if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
state = state.map((a) => pow5(a)); state = state.map(a => pow5(a));
} else { } else {
state[0] = pow5(state[0]); state[0] = pow5(state[0]);
} }
// no matrix multiplication in the last round // no matrix multiplication in the last round
if (r < nRoundsF + nRoundsP - 1) { if (r < nRoundsF + nRoundsP - 1) {
state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(bigInt(M[t - 2][j][i]), a)), F.zero)); state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(BigInt(M[t - 2][j][i]), a)), F.zero)
);
} }
} }
return F.affine(state[0]); return F.normalize(state[0]);
} }
module.exports = poseidon; module.exports = poseidon;

View File

@ -3,10 +3,10 @@
// //
const Contract = require("./evmasm"); const Contract = require("./evmasm");
const { unstringifyBigInts } = require("@tornado/snarkjs"); const { unstringifyBigInts } = require("ffjavascript").utils;
const Web3Utils = require("web3-utils"); const Web3Utils = require("web3-utils");
const { C: K, M } = unstringifyBigInts(require("./poseidon_constants.json")); const { C:K, M } = unstringifyBigInts(require("./poseidon_constants.json"));
const N_ROUNDS_F = 8; const N_ROUNDS_F = 8;
const N_ROUNDS_P = 35; const N_ROUNDS_P = 35;
@ -16,12 +16,13 @@ function toHex256(a) {
return a; return a;
} }
let S = a.toString(16); let S = a.toString(16);
while (S.length < 64) S = "0" + S; while (S.length < 64) S="0"+S;
return "0x" + S; return "0x" + S;
} }
function createCode(nInputs) { function createCode(nInputs) {
if (nInputs < 1 || nInputs > 4) throw new Error("Invalid number of inputs. Must be 1<=nInputs<=8");
if (( nInputs<1) || (nInputs>4)) throw new Error("Invalid number of inputs. Must be 1<=nInputs<=8");
const t = nInputs + 1; const t = nInputs + 1;
const nRoundsF = N_ROUNDS_F; const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P; const nRoundsP = N_ROUNDS_P;
@ -29,21 +30,20 @@ function createCode(nInputs) {
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][j][i])); C.push(toHex256(M[t-2][j][i]));
C.push((1 + i * t + j) * 32); C.push((1+i*t+j)*32);
C.mstore(); C.mstore();
} }
} }
} }
function ark(r) { function ark(r) { // st, q
// st, q for (let i=0; i<t; i++) {
for (let i = 0; i < t; i++) {
C.dup(t); // q, st, q C.dup(t); // q, st, q
C.push(toHex256(K[t - 2][r * t + i])); // K, q, st, q C.push(toHex256(K[t-2][r*t+i])); // K, q, st, q
C.dup(2 + i); // st[i], K, q, st, q C.dup(2+i); // st[i], K, q, st, q
C.addmod(); // newSt[i], st, q C.addmod(); // newSt[i], st, q
C.swap(1 + i); // xx, st, q C.swap(1 + i); // xx, st, q
C.pop(); C.pop();
@ -52,44 +52,44 @@ function createCode(nInputs) {
function sigma(p) { function sigma(p) {
// sq, q // sq, q
C.dup(t); // q, st, q C.dup(t); // q, st, q
C.dup(1 + p); // st[p] , q , st, q C.dup(1+p); // st[p] , q , st, q
C.dup(1); // q, st[p] , q , st, q C.dup(1); // q, st[p] , q , st, q
C.dup(0); // q, q, st[p] , q , st, q C.dup(0); // q, q, st[p] , q , st, q
C.dup(2); // st[p] , q, q, st[p] , q , st, q C.dup(2); // st[p] , q, q, st[p] , q , st, q
C.dup(0); // st[p] , st[p] , q, q, st[p] , q , st, q C.dup(0); // st[p] , st[p] , q, q, st[p] , q , st, q
C.mulmod(); // st2[p], q, st[p] , q , st, q C.mulmod(); // st2[p], q, st[p] , q , st, q
C.dup(0); // st2[p], st2[p], q, st[p] , q , st, q C.dup(0); // st2[p], st2[p], q, st[p] , q , st, q
C.mulmod(); // st4[p], st[p] , q , st, q C.mulmod(); // st4[p], st[p] , q , st, q
C.mulmod(); // st5[p], st, q C.mulmod(); // st5[p], st, q
C.swap(1 + p); C.swap(1+p);
C.pop(); // newst, q C.pop(); // newst, q
} }
function mix() { function mix() {
C.label("mix"); C.label("mix");
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++) {
if (j == 0) { if (j==0) {
C.dup(i + t); // q, newSt, oldSt, q C.dup(i+t); // q, newSt, oldSt, q
C.push((1 + i * t + j) * 32); C.push((1+i*t+j)*32);
C.mload(); // M, q, newSt, oldSt, q C.mload(); // M, q, newSt, oldSt, q
C.dup(2 + i + j); // oldSt[j], M, q, newSt, oldSt, q C.dup(2+i+j); // oldSt[j], M, q, newSt, oldSt, q
C.mulmod(); // acc, newSt, oldSt, q C.mulmod(); // acc, newSt, oldSt, q
} else { } else {
C.dup(1 + i + t); // q, acc, newSt, oldSt, q C.dup(1+i+t); // q, acc, newSt, oldSt, q
C.push((1 + i * t + j) * 32); C.push((1+i*t+j)*32);
C.mload(); // M, q, acc, newSt, oldSt, q C.mload(); // M, q, acc, newSt, oldSt, q
C.dup(3 + i + j); // oldSt[j], M, q, acc, newSt, oldSt, q C.dup(3+i+j); // oldSt[j], M, q, acc, newSt, oldSt, q
C.mulmod(); // aux, acc, newSt, oldSt, q C.mulmod(); // aux, acc, newSt, oldSt, q
C.dup(2 + i + t); // q, aux, acc, newSt, oldSt, q C.dup(2+i+t); // q, aux, acc, newSt, oldSt, q
C.swap(2); // acc, aux, q, newSt, oldSt, q C.swap(2); // acc, aux, q, newSt, oldSt, q
C.addmod(); // acc, newSt, oldSt, q C.addmod(); // acc, newSt, oldSt, q
} }
} }
} }
for (let i = 0; i < t; i++) { for (let i=0; i<t; i++) {
C.swap(t - i + (t - i - 1)); C.swap((t -i) + (t -i-1));
C.pop(); C.pop();
} }
C.push(0); C.push(0);
@ -97,6 +97,7 @@ function createCode(nInputs) {
C.jmp(); C.jmp();
} }
// Check selector // Check selector
C.push("0x0100000000000000000000000000000000000000000000000000000000"); C.push("0x0100000000000000000000000000000000000000000000000000000000");
C.push(0); C.push(0);
@ -116,27 +117,27 @@ function createCode(nInputs) {
saveM(); saveM();
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
// Load t values from the call data. // Load t values from the call data.
// The function has a single array param param // The function has a single array param param
// [Selector (4)] [item1 (32)] [item2 (32)] .... // [Selector (4)] [item1 (32)] [item2 (32)] ....
// Stack positions 0-nInputs. // Stack positions 0-nInputs.
for (let i = 0; i < t; i++) { for (let i=0; i<t; i++) {
C.push(0x04 + 0x20 * (nInputs - i)); C.push(0x04+(0x20*(nInputs-i)));
C.calldataload(); C.calldataload();
} }
for (let i = 0; i < nRoundsF + nRoundsP - 1; i++) { for (let i=0; i<nRoundsF+nRoundsP-1; i++) {
ark(i); ark(i);
if (i < nRoundsF / 2 || i >= nRoundsP + nRoundsF / 2) { if ((i<nRoundsF/2) || (i>=nRoundsP+nRoundsF/2)) {
for (let j = 0; j < t; j++) { for (let j=0; j<t; j++) {
sigma(j); sigma(j);
} }
} else { } else {
sigma(0); sigma(0);
} }
const strLabel = "aferMix" + i; const strLabel = "aferMix"+i;
C._pushLabel(strLabel); C._pushLabel(strLabel);
C.push(0); C.push(0);
C.mstore(); C.mstore();
@ -144,15 +145,15 @@ function createCode(nInputs) {
C.label(strLabel); C.label(strLabel);
} }
C.push(toHex256(K[t - 2][(nRoundsF + nRoundsP - 1) * t])); // K, st, q C.push(toHex256(K[t-2][(nRoundsF+nRoundsP-1)*t])); // K, st, q
C.dup(t + 1); // q, K, st, q C.dup(t+1); // q, K, st, q
C.swap(2); // st[0], K, q, st\st[0] C.swap(2); // st[0], K, q, st\st[0]
C.addmod(); // st q C.addmod(); // st q
sigma(0); 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");
C.push("0x00"); C.push("0x00");
C.return(); C.return();
@ -165,49 +166,51 @@ function createCode(nInputs) {
function generateABI(nInputs) { function generateABI(nInputs) {
return [ return [
{ {
constant: true, "constant": true,
inputs: [ "inputs": [
{ {
internalType: `bytes32[${nInputs}]`, "internalType": `bytes32[${nInputs}]`,
name: "input", "name": "input",
type: `bytes32[${nInputs}]`, "type": `bytes32[${nInputs}]`
}, }
], ],
name: "poseidon", "name": "poseidon",
outputs: [ "outputs": [
{ {
internalType: "bytes32", "internalType": "bytes32",
name: "", "name": "",
type: "bytes32", "type": "bytes32"
}, }
], ],
payable: false, "payable": false,
stateMutability: "pure", "stateMutability": "pure",
type: "function", "type": "function"
}, },
{ {
constant: true, "constant": true,
inputs: [ "inputs": [
{ {
internalType: `uint256[${nInputs}]`, "internalType": `uint256[${nInputs}]`,
name: "input", "name": "input",
type: `uint256[${nInputs}]`, "type": `uint256[${nInputs}]`
}, }
], ],
name: "poseidon", "name": "poseidon",
outputs: [ "outputs": [
{ {
internalType: "uint256", "internalType": "uint256",
name: "", "name": "",
type: "uint256", "type": "uint256"
}, }
], ],
payable: false, "payable": false,
stateMutability: "pure", "stateMutability": "pure",
type: "function", "type": "function"
}, }
]; ];
} }
module.exports.generateABI = generateABI; module.exports.generateABI = generateABI;
module.exports.createCode = createCode; module.exports.createCode = createCode;

View File

@ -1,35 +1,26 @@
const bigInt = require("@tornado/snarkjs").bigInt; const Scalar = require("ffjavascript").Scalar;
const SMTMemDB = require("./smt_memdb"); const SMTMemDB = require("./smt_memdb");
const { hash0, hash1 } = require("./smt_hashes_poseidon"); const {hash0, hash1, F} = require("./smt_hashes_poseidon");
class SMT { class SMT {
constructor(db, root) { constructor(db, root) {
this.db = db; this.db = db;
this.root = root; this.root = root;
} }
_splitBits(_key) { _splitBits(_key) {
let k = bigInt(_key); const res = Scalar.bits(_key);
const res = [];
while (!k.isZero()) { while (res.length<256) res.push(false);
if (k.isOdd()) {
res.push(true);
} else {
res.push(false);
}
k = k.shr(1);
}
while (res.length < 256) res.push(false);
return res; return res;
} }
async update(_key, _newValue) { async update(_key, _newValue) {
const key = bigInt(_key); const key = Scalar.e(_key);
const newValue = bigInt(_newValue); const newValue = F.e(_newValue);
const resFind = await this.find(key); const resFind = await this.find(key);
const res = {}; const res = {};
@ -45,11 +36,11 @@ class SMT {
let rtOld = hash1(key, resFind.foundValue); let rtOld = hash1(key, resFind.foundValue);
let rtNew = hash1(key, newValue); let rtNew = hash1(key, newValue);
ins.push([rtNew, [1, key, newValue]]); ins.push([rtNew, [1, key, newValue ]]);
dels.push(rtOld); dels.push(rtOld);
const keyBits = this._splitBits(key); const keyBits = this._splitBits(key);
for (let level = resFind.siblings.length - 1; level >= 0; level--) { for (let level = resFind.siblings.length-1; level >=0; level--) {
let oldNode, newNode; let oldNode, newNode;
const sibling = resFind.siblings[level]; const sibling = resFind.siblings[level];
if (keyBits[level]) { if (keyBits[level]) {
@ -67,16 +58,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 = bigInt(_key); const key = Scalar.e(_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");
@ -84,7 +75,7 @@ class SMT {
const res = { const res = {
siblings: [], siblings: [],
delKey: key, delKey: key,
delValue: resFind.foundValue, delValue: resFind.foundValue
}; };
const dels = []; const dels = [];
@ -96,7 +87,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 && record[0].equals(bigInt.one)) { if ((record.length == 3)&&(F.eq(record[0], F.one))) {
mixed = false; mixed = false;
res.oldKey = record[1]; res.oldKey = record[1];
res.oldValue = record[2]; res.oldValue = record[2];
@ -105,25 +96,25 @@ class SMT {
} else if (record.length == 2) { } else if (record.length == 2) {
mixed = true; mixed = true;
res.oldKey = key; res.oldKey = key;
res.oldValue = bigInt(0); res.oldValue = F.zero;
res.isOld0 = true; res.isOld0 = true;
rtNew = bigInt.zero; rtNew = F.zero;
} else { } else {
throw new Error("Invalid node. Database corrupted"); throw new Error("Invalid node. Database corrupted");
} }
} else { } else {
rtNew = bigInt.zero; rtNew = F.zero;
res.oldKey = key; res.oldKey = key;
res.oldValue = bigInt(0); res.oldValue = F.zero;
res.isOld0 = true; res.isOld0 = true;
} }
const keyBits = this._splitBits(key); const keyBits = this._splitBits(key);
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 = bigInt.zero; newSibling = F.zero;
} }
const oldSibling = resFind.siblings[level]; const oldSibling = resFind.siblings[level];
if (keyBits[level]) { if (keyBits[level]) {
@ -132,7 +123,7 @@ class SMT {
rtOld = hash0(rtOld, oldSibling); rtOld = hash0(rtOld, oldSibling);
} }
dels.push(rtOld); dels.push(rtOld);
if (!newSibling.isZero()) { if (!F.isZero(newSibling)) {
mixed = true; mixed = true;
} }
@ -161,8 +152,8 @@ class SMT {
} }
async insert(_key, _value) { async insert(_key, _value) {
const key = bigInt(_key); const key = Scalar.e(_key);
const value = bigInt(_value); const value = F.e(_value);
let addedOne = false; let addedOne = false;
const res = {}; const res = {};
res.oldRoot = this.root; res.oldRoot = this.root;
@ -179,26 +170,26 @@ 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(bigInt.zero); res.siblings.push(F.zero);
} }
rtOld = hash1(resFind.notFoundKey, resFind.notFoundValue); rtOld = hash1(resFind.notFoundKey, resFind.notFoundValue);
res.siblings.push(rtOld); res.siblings.push(rtOld);
addedOne = true; addedOne = true;
mixed = false; mixed = false;
} else if (res.siblings.length > 0) { } else if (res.siblings.length >0) {
mixed = true; mixed = true;
rtOld = bigInt.zero; rtOld = F.zero;
} }
const inserts = []; const inserts = [];
const dels = []; const dels = [];
let rt = hash1(key, value); let rt = hash1(key, value);
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 && !res.siblings[i].isZero()) { if ((i<res.siblings.length-1)&&(!F.isZero(res.siblings[i]))) {
mixed = true; mixed = true;
} }
if (mixed) { if (mixed) {
@ -211,19 +202,20 @@ class SMT {
dels.push(rtOld); dels.push(rtOld);
} }
let newRt; let newRt;
if (newKeyBits[i]) { if (newKeyBits[i]) {
newRt = hash0(res.siblings[i], rt); newRt = hash0(res.siblings[i], rt);
inserts.push([newRt, [res.siblings[i], rt]]); inserts.push([newRt,[res.siblings[i], rt]] );
} else { } else {
newRt = hash0(rt, res.siblings[i]); newRt = hash0(rt, res.siblings[i]);
inserts.push([newRt, [rt, res.siblings[i]]]); inserts.push([newRt,[rt, res.siblings[i]]] );
} }
rt = newRt; rt = newRt;
} }
if (addedOne) res.siblings.pop(); if (addedOne) res.siblings.pop();
while (res.siblings.length > 0 && res.siblings[res.siblings.length - 1].isZero()) { while ((res.siblings.length>0) && (F.isZero(res.siblings[res.siblings.length-1]))) {
res.siblings.pop(); res.siblings.pop();
} }
res.oldKey = resFind.notFoundKey; res.oldKey = resFind.notFoundKey;
@ -231,6 +223,7 @@ class SMT {
res.newRoot = rt; res.newRoot = rt;
res.isOld0 = resFind.isOld0; res.isOld0 = resFind.isOld0;
await this.db.multiIns(inserts); await this.db.multiIns(inserts);
await this.db.setRoot(rt); await this.db.setRoot(rt);
this.root = rt; this.root = rt;
@ -248,26 +241,26 @@ class SMT {
if (typeof root === "undefined") root = this.root; if (typeof root === "undefined") root = this.root;
let res; let res;
if (root.isZero()) { if (F.isZero(root)) {
res = { res = {
found: false, found: false,
siblings: [], siblings: [],
notFoundKey: key, notFoundKey: key,
notFoundValue: bigInt.zero, notFoundValue: F.zero,
isOld0: true, isOld0: true
}; };
return res; return res;
} }
const record = await this.db.get(root); const record = await this.db.get(root);
if (record.length == 3 && record[0].equals(bigInt.one)) { if ((record.length==3)&&(F.eq(record[0],F.one))) {
if (record[1].equals(key)) { if (F.eq(record[1],key)) {
res = { res = {
found: true, found: true,
siblings: [], siblings: [],
foundValue: record[2], foundValue: record[2],
isOld0: false, isOld0: false
}; };
} else { } else {
res = { res = {
@ -275,15 +268,15 @@ class SMT {
siblings: [], siblings: [],
notFoundKey: record[1], notFoundKey: record[1],
notFoundValue: record[2], notFoundValue: record[2],
isOld0: false, isOld0: false
}; };
} }
} else { } else {
if (keyBits[level] == 0) { if (keyBits[level] == 0) {
res = await this._find(key, keyBits, record[0], level + 1); res = await this._find(key, keyBits, record[0], level+1);
res.siblings.unshift(record[1]); res.siblings.unshift(record[1]);
} else { } else {
res = await this._find(key, keyBits, record[1], level + 1); res = await this._find(key, keyBits, record[1], level+1);
res.siblings.unshift(record[0]); res.siblings.unshift(record[0]);
} }
} }
@ -291,7 +284,9 @@ class SMT {
} }
} }
async function loadFromFile(fileName) {} async function loadFromFile(fileName) {
}
async function newMemEmptyTrie() { async function newMemEmptyTrie() {
const db = new SMTMemDB(); const db = new SMTMemDB();

View File

@ -1,10 +1,12 @@
const mimc7 = require("./mimc7"); const mimc7 = require("./mimc7");
const bigInt = require("@tornado/snarkjs").bigInt; const bigInt = require("big-integer");
exports.hash0 = function (left, right) { exports.hash0 = function (left, right) {
return mimc7.multiHash(left, right); return mimc7.multiHash(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,10 +1,18 @@
const ZqField = require("ffjavascript").ZqField;
const Scalar = require("ffjavascript").Scalar;
const poseidon = require("./poseidon"); const poseidon = require("./poseidon");
const bigInt = require("@tornado/snarkjs").bigInt;
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
exports.hash0 = function (left, right) { exports.hash0 = function (left, right) {
return poseidon([left, right]); return poseidon([left, right]);
}; };
exports.hash1 = function (key, value) { exports.hash1 = function(key, value) {
return poseidon([key, value, bigInt.one]); return poseidon([key, value, F.one]);
}; };
exports.F = F;

View File

@ -1,9 +1,14 @@
const bigInt = require("@tornado/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 = bigInt(0); this.root = F.zero;
} }
async getRoot() { async getRoot() {
@ -12,13 +17,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 = bigInt(k).toString(); const keyS = 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] = bigInt(n[i]); n[i] = F.e(n[i]);
} }
} }
@ -29,7 +34,7 @@ class SMTMemDb {
async multiGet(keys) { async multiGet(keys) {
const promises = []; const promises = [];
for (let i = 0; i < keys.length; i++) { for (let i=0; i<keys.length; i++) {
promises.push(this.get(keys[i])); promises.push(this.get(keys[i]));
} }
return await Promise.all(promises); return await Promise.all(promises);
@ -40,7 +45,7 @@ class SMTMemDb {
} }
async multiIns(inserts) { async multiIns(inserts) {
for (let i = 0; i < inserts.length; i++) { for (let i=0; i<inserts.length; i++) {
const keyS = this._key2str(inserts[i][0]); const keyS = this._key2str(inserts[i][0]);
this._normalize(inserts[i][1]); this._normalize(inserts[i][1]);
this.nodes[keyS] = inserts[i][1]; this.nodes[keyS] = inserts[i][1];
@ -48,7 +53,7 @@ class SMTMemDb {
} }
async multiDel(dels) { async multiDel(dels) {
for (let i = 0; i < dels.length; i++) { for (let i=0; i<dels.length; i++) {
const keyS = this._key2str(dels[i]); const keyS = this._key2str(dels[i]);
delete this.nodes[keyS]; delete this.nodes[keyS];
} }

View File

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

View File

@ -1,74 +0,0 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]);
}
function getBits(v, n) {
const res = [];
for (let i = 0; i < n; i++) {
if (v.shr(i).isOdd()) {
res.push(bigInt.one);
} else {
res.push(bigInt.zero);
}
}
return res;
}
const r = bigInt("2736030358979909402780800718157159386076813972158567259200215660948447373041");
describe("Aliascheck test", () => {
let circuit;
before(async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "aliascheckbabyjub_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
});
it("Satisfy the aliastest 0", async () => {
const inp = getBits(bigInt.zero, 251);
circuit.calculateWitness({ in: inp });
});
it("Satisfy the aliastest 3", async () => {
const inp = getBits(bigInt(3), 251);
circuit.calculateWitness({ in: inp });
});
it("Satisfy the aliastest r-1", async () => {
const inp = getBits(r.sub(bigInt.one), 251);
circuit.calculateWitness({ in: inp });
});
it("Nhot not satisfy an input of r", async () => {
const inp = getBits(r, 251);
try {
circuit.calculateWitness({ in: inp });
assert(false);
} catch (err) {
assert(err.message.indexOf("Constraint doesn't match") >= 0);
assert(err.message.indexOf("1 != 0") >= 0);
}
});
it("Nhot not satisfy all ones", async () => {
const inp = getBits(bigInt(1).shl(251).sub(bigInt(1)), 251);
try {
circuit.calculateWitness({ in: inp });
assert(false);
} catch (err) {
assert(err.message.indexOf("Constraint doesn't match") >= 0);
assert(err.message.indexOf("1 != 0") >= 0);
}
});
});

View File

@ -1,120 +1,113 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/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 bigInt = require("@tornado/snarkjs").bigInt; const tester = require("circom").tester;
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() => {
const cirDefAdd = await compiler(path.join(__dirname, "circuits", "babyadd_tester.circom")); circuitAdd = await tester(path.join(__dirname, "circuits", "babyadd_tester.circom"));
circuitAdd = new snarkjs.Circuit(cirDefAdd);
console.log("NConstrains BabyAdd: " + circuitAdd.nConstraints);
const cirDefTest = await compiler(path.join(__dirname, "circuits", "babycheck_test.circom")); circuitTest = await tester(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 = await tester(path.join(__dirname, "circuits", "babypbk_test.circom"));
circuitPbk = new snarkjs.Circuit(cirDefPbk);
console.log("NConstrains BabyPbk: " + circuitPbk.nConstraints);
}); });
it("Should add point (0,1) and (0,1)", async () => { it("Should add point (0,1) and (0,1)", async () => {
const input = {
x1: snarkjs.bigInt(0), const input={
y1: snarkjs.bigInt(1), x1: F.e(0),
x2: snarkjs.bigInt(0), y1: F.e(1),
y2: snarkjs.bigInt(1), x2: F.e(0),
y2: F.e(1)
}; };
const w = circuitAdd.calculateWitness(input); const w = await circuitAdd.calculateWitness(input, true);
const xout = w[circuitAdd.getSignalIdx("main.xout")]; await circuitAdd.assertOut(w, {xout: F.e(0), yout: F.e(1)});
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 = {
x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), const input={
y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), x1: F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
x2: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), y1: F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
y2: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), x2: F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
y2: F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475")
}; };
const w = circuitAdd.calculateWitness(input); const w = await circuitAdd.calculateWitness(input, true);
const xout = w[circuitAdd.getSignalIdx("main.xout")]; await circuitAdd.assertOut(w, {
const yout = w[circuitAdd.getSignalIdx("main.yout")]; xout: F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
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 = {
x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), const input={
y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), x1: F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
x2: snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"), y1: F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
y2: snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"), x2: F.e("16540640123574156134436876038791482806971768689494387082833631921987005038935"),
y2: F.e("20819045374670962167435360035096875258406992893633759881276124905556507972311")
}; };
const w = circuitAdd.calculateWitness(input); const w = await circuitAdd.calculateWitness(input, true);
const xout = w[circuitAdd.getSignalIdx("main.xout")]; await circuitAdd.assertOut(w, {
const yout = w[circuitAdd.getSignalIdx("main.yout")]; xout: F.e("7916061937171219682591368294088513039687205273691143098332585753343424131937"),
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 is a valid poiny", async () => { it("Should check (0,1) is a valid point", async() => {
const w = circuitTest.calculateWitness({ x: 0, y: 1 }); const w = await circuitTest.calculateWitness({x: 0, y:1}, true);
assert(circuitTest.checkWitness(w));
await circuitTest.checkConstraints(w);
}); });
it("Should check 0 is an invalid poiny", async () => { it("Should check (1,0) is an invalid point", async() => {
try { try {
circuitTest.calculateWitness({ x: 1, y: 0 }); await circuitTest.calculateWitness({x: 1, y: 0}, true);
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(/Constraint\sdoesn't\smatch(.*)168700\s!=\s1/.test(err.message) );
assert(err.message.indexOf("168700 != 1") >= 0);
} }
}); });
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 pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0, 32));
const S = bigInt.leBuff2int(pvk).shr(3);
const A = eddsa.prv2pub(rawpvk); const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex");
const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0,32));
const S = Scalar.shr(utils.leBuff2int(pvk), 3);
const A = eddsa.prv2pub(rawpvk);
const input = { const input = {
in: S, in : S
Ax: A[0],
Ay: A[1],
}; };
const w = circuitPbk.calculateWitness(input); const w = await circuitPbk.calculateWitness(input, true);
assert(circuitPbk.checkWitness(w));
await circuitPbk.assertOut(w, {Ax : A[0], Ay: A[1]});
await circuitPbk.checkConstraints(w);
}); });
}); });

View File

@ -1,23 +1,29 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path");
const snarkjs = require("@tornado/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;
// const bigInt = require("big-integer"); // const bigInt = require("big-integer");
describe("Baby Jub js test", function () { describe("Baby Jub js test", function () {
this.timeout(100000); this.timeout(100000);
it("Should add point (0,1) and (0,1)", () => { it("Should add point (0,1) and (0,1)", () => {
const p1 = [snarkjs.bigInt(0), snarkjs.bigInt(1)];
const p2 = [snarkjs.bigInt(0), snarkjs.bigInt(1)]; const p1 = [
babyjub.F.e(0),
babyjub.F.e(1)];
const p2 = [
babyjub.F.e(0),
babyjub.F.e(1)
];
const out = babyjub.addPoint(p1, p2); const out = babyjub.addPoint(p1, p2);
assert(out[0].equals(0)); assert(babyjub.F.eq(out[0], babyjub.F.zero));
assert(out[1].equals(1)); assert(babyjub.F.eq(out[1], babyjub.F.one));
}); });
it("Should base be 8*generator", () => { it("Should base be 8*generator", () => {
@ -26,48 +32,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(res[0].equals(babyjub.Base8[0])); assert(babyjub.F.eq(res[0], babyjub.Base8[0]));
assert(res[1].equals(babyjub.Base8[1])); assert(babyjub.F.eq(res[1], babyjub.Base8[1]));
}); });
it("Should add 2 same numbers", () => { it("Should add 2 same numbers", () => {
const p1 = [ const p1 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const p2 = [ const p2 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const out = babyjub.addPoint(p1, p2); const out = babyjub.addPoint(p1, p2);
assert(out[0].equals(snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"))); assert(babyjub.F.eq(out[0], babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365")));
assert(out[1].equals(snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"))); assert(babyjub.F.eq(out[1], babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889")));
}); });
it("Should add 2 different numbers", () => { it("Should add 2 different numbers", () => {
const p1 = [ const p1 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const p2 = [ const p2 = [
snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"), babyjub.F.e("16540640123574156134436876038791482806971768689494387082833631921987005038935"),
snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"), babyjub.F.e("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 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("3")); const r = babyjub.mulPointEscalar(p, 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());
@ -78,68 +86,62 @@ describe("Baby Jub js test", function () {
it("should mulPointEscalar 1", () => { it("should mulPointEscalar 1", () => {
const p = [ const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const r = babyjub.mulPointEscalar( const r = babyjub.mulPointEscalar(p, Scalar.fromString("14035240266687799601661095864649209771790948434046947201833777492504781204499"));
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 = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
const r = babyjub.mulPointEscalar( const r = babyjub.mulPointEscalar(p, Scalar.fromString("20819045374670962167435360035096875258406992893633759881276124905556507972311"));
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 = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
assert(babyjub.inCurve(p)); assert(babyjub.inCurve(p));
}); });
it("should inCurve 2", () => { it("should inCurve 2", () => {
const p = [ const p = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
assert(babyjub.inCurve(p)); assert(babyjub.inCurve(p));
}); });
it("should inSubgroup 1", () => { it("should inSubgroup 1", () => {
const p = [ const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
assert(babyjub.inSubgroup(p)); assert(babyjub.inSubgroup(p));
}); });
it("should inSubgroup 2", () => { it("should inSubgroup 2", () => {
const p = [ const p = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
assert(babyjub.inSubgroup(p)); assert(babyjub.inSubgroup(p));
}); });
it("should packPoint - unpackPoint 1", () => { it("should packPoint - unpackPoint 1", () => {
const p = [ const p = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), babyjub.F.e("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), babyjub.F.e("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
]; ];
const buf = babyjub.packPoint(p); const buf = babyjub.packPoint(p);
assert.equal(buf.toString("hex"), "53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85"); assert.equal(buf.toString("hex"), "53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85");
@ -150,8 +152,8 @@ describe("Baby Jub js test", function () {
it("should packPoint - unpackPoint 2", () => { it("should packPoint - unpackPoint 2", () => {
const p = [ const p = [
snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), babyjub.F.e("6890855772600357754907169075114257697580319025794532037257385534741338397365"),
snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), babyjub.F.e("4338620300185947561074059802482547481416142213883829469920100239455078257889"),
]; ];
const buf = babyjub.packPoint(p); const buf = babyjub.packPoint(p);
assert.equal(buf.toString("hex"), "e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709"); assert.equal(buf.toString("hex"), "e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709");

View File

@ -1,54 +1,53 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom");
const assert = chai.assert; const Fr = require("ffjavascript").bn128.Fr;
const Scalar = require("ffjavascript").Scalar;
const bigInt = snarkjs.bigInt; 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)]);
} }
function checkSub(_a, _b, circuit) { async function checkSub(_a,_b, circuit) {
let a = bigInt(_a); let a=Scalar.e(_a);
let b = bigInt(_b); let b=Scalar.e(_b);
if (a.lesser(bigInt.zero)) a = a.add(bigInt.one.shl(16)); if (Scalar.lt(a, 0)) a = Scalar.add(a, Scalar.shl(1, 16));
if (b.lesser(bigInt.zero)) b = b.add(bigInt.one.shl(16)); if (Scalar.lt(b, 0)) b = Scalar.add(b, Scalar.shl(1, 16));
const w = circuit.calculateWitness({ a: a, b: b }); const w = await circuit.calculateWitness({a: a, b: b}, true);
let res = a.sub(b); let res = Scalar.sub(a, b);
if (res.lesser(bigInt.zero)) res = res.add(bigInt.one.shl(16)); if (Scalar.lt(res, 0)) res = Scalar.add(res, Scalar.shl(1, 16));
assert(w[circuit.getSignalIdx("main.out")].equals(bigInt(res)));
await circuit.assertOut(w, {out: res});
} }
describe("BinSub test", () => { describe("BinSub test", function () {
this.timeout(100000);
let circuit; let circuit;
before(async () => { before( async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "binsub_test.circom")); circuit = await tester(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 () => {
checkSub(0, 0, circuit); await checkSub(0,0, circuit);
checkSub(1, 0, circuit); await checkSub(1,0, circuit);
checkSub(-1, 0, circuit); await checkSub(-1,0, circuit);
checkSub(2, 1, circuit); await checkSub(2,1, circuit);
checkSub(2, 2, circuit); await checkSub(2,2, circuit);
checkSub(2, 3, circuit); await checkSub(2,3, circuit);
checkSub(2, -1, circuit); await checkSub(2,-1, circuit);
checkSub(2, -2, circuit); await checkSub(2,-2, circuit);
checkSub(2, -3, circuit); await checkSub(2,-3, circuit);
checkSub(-2, -3, circuit); await checkSub(-2,-3, circuit);
checkSub(-2, -2, circuit); await checkSub(-2,-2, circuit);
checkSub(-2, -1, circuit); await checkSub(-2,-1, circuit);
checkSub(-2, 0, circuit); await checkSub(-2,0, circuit);
checkSub(-2, 1, circuit); await checkSub(-2,1, circuit);
checkSub(-2, 2, circuit); await checkSub(-2,2, circuit);
checkSub(-2, 3, circuit); await checkSub(-2,3, circuit);
}); });
}); });

View File

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

View File

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

View File

@ -6,6 +6,8 @@ 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);
@ -14,9 +16,12 @@ template A() {
n2ba.in <== a; n2ba.in <== a;
n2bb.in <== b; n2bb.in <== b;
for (var i=0; i<16; i++) { for (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

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

View File

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

View File

@ -7,8 +7,8 @@ template Main() {
var i; var i;
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553, var base[2] = [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 = [5299619240641551281634865583518297030282874472190772894086521144482721001553, var base[2] = [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 = [5299619240641551281634865583518297030282874472190772894086521144482721001553, var base[2] = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203] 16950150798460657717958625567821834550301663161624707787222815936182638968203]
component main = EscalarMulW4Table(base, 0); component main = EscalarMulW4Table(base, 0);

View File

@ -4,10 +4,10 @@ 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 = [5299619240641551281634865583518297030282874472190772894086521144482721001553, var base[2] = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]; 16950150798460657717958625567821834550301663161624707787222815936182638968203];
var escalarMul = EscalarMulW4Table(base, 0); var escalarMul[16][2] = 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[i][0]*in;
out[i][1] <== escalarMul[i][1]*in; out[i][1] <== escalarMul[i][1]*in;

View File

@ -4,10 +4,10 @@ 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 = [5299619240641551281634865583518297030282874472190772894086521144482721001553, var base[2] = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]; 16950150798460657717958625567821834550301663161624707787222815936182638968203];
var escalarMul = EscalarMulW4Table(base, 3); var escalarMul[16][2] = 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[i][0]*in;
out[i][1] <== escalarMul[i][1]*in; out[i][1] <== escalarMul[i][1]*in;

View File

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

View File

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

View File

@ -6,6 +6,8 @@ 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);
@ -14,9 +16,12 @@ template A() {
n2ba.in <== a; n2ba.in <== a;
n2bb.in <== b; n2bb.in <== b;
for (var i=0; i<32; i++) { for (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,193 +1,185 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs");
const crypto = require("crypto");
const compiler = require("circom"); const tester = require("circom").tester;
const Fr = require("ffjavascript").bn128.Fr;
const assert = chai.assert; const assert = chai.assert;
describe("Sum test", () => { describe("Comparators test", function () {
it("Should create a iszero circuit", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "iszero.circom"));
const circuit = new snarkjs.Circuit(cirDef); this.timeout(100000);
it("Should create a iszero circuit", async() => {
const circuit = await tester(path.join(__dirname, "circuits", "iszero.circom"));
let witness; let witness;
witness = circuit.calculateWitness({ in: 111 }); witness = await circuit.calculateWitness({ "in": 111}, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ in: 0 }); witness = await circuit.calculateWitness({ "in": 0 }, 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 isequal circuit", async () => { it("Should create a isequal circuit", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "isequal.circom")); const circuit = await tester(path.join(__dirname, "circuits", "isequal.circom"));
const circuit = new snarkjs.Circuit(cirDef);
let witness; let witness;
witness = circuit.calculateWitness({ "in[0]": "111", "in[1]": "222" }); witness = await circuit.calculateWitness({ "in": [111,222] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "444", "in[1]": "444" });
assert(witness[0].equals(snarkjs.bigInt(1))); witness = await circuit.calculateWitness({ "in": [444,444] }, true);
assert(witness[1].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(Fr.eq(witness[1], Fr.e(1)));
}); });
it("Should create a comparison lessthan", async () => { it("Should create a comparison lessthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "lessthan.circom")); const circuit = await tester(path.join(__dirname, "circuits", "lessthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
let witness; let witness;
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [333,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)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in":[1,1] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" }); witness = await circuit.calculateWitness({ "in": [661, 660] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in": [0, 1] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [0, 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)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [1, 0] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [555, 0] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [0, 0] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(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 = new snarkjs.Circuit(cirDef); const circuit = await tester(path.join(__dirname, "circuits", "lesseqthan.circom"));
let witness; let witness;
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [333,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)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in":[1,1] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" }); witness = await circuit.calculateWitness({ "in": [661, 660] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in": [0, 1] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [0, 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)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [1, 0] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [555, 0] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [0, 0] }, 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 greaterthan", async () => { it("Should create a comparison greaterthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "greaterthan.circom"));
const circuit = new snarkjs.Circuit(cirDef); const circuit = await tester(path.join(__dirname, "circuits", "greaterthan.circom"));
let witness; let witness;
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [333,444] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in":[1,1] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" }); witness = await circuit.calculateWitness({ "in": [661, 660] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in": [0, 1] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [0, 444] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [1, 0] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [555, 0] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [0, 0] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
}); });
it("Should create a comparison greatereqthan", async () => { it("Should create a comparison greatereqthan", async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "greatereqthan.circom")); const circuit = await tester(path.join(__dirname, "circuits", "greatereqthan.circom"));
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstraints BalancesUpdater: " + circuit.nConstraints);
let witness; let witness;
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [333,444] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in":[1,1] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" }); witness = await circuit.calculateWitness({ "in": [661, 660] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" }); witness = await circuit.calculateWitness({ "in": [0, 1] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" }); witness = await circuit.calculateWitness({ "in": [0, 444] }, true);
assert(witness[0].equals(snarkjs.bigInt(1))); assert(Fr.eq(witness[0], Fr.e(1)));
assert(witness[1].equals(snarkjs.bigInt(0))); assert(Fr.eq(witness[1], Fr.e(0)));
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [1, 0] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [555, 0] }, 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)));
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" }); witness = await circuit.calculateWitness({ "in": [0, 0] }, 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)));
}); });
}); });

View File

@ -1,51 +1,46 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const tester = require("circom").tester;
// const crypto = require("crypto"); const Fr = require("ffjavascript").bn128.Fr;
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)]);
} }
function buffer2bits(buff) { function buffer2bits(buff) {
const res = []; const res = [];
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(bigInt.one); res.push(Fr.one);
} else { } else {
res.push(bigInt.zero); res.push(Fr.zero);
} }
} }
} }
return res; return res;
} }
describe("EdDSA test", function () { describe("EdDSA test", function () {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before(async () => { before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "eddsa_test.circom")); circuit = await tester(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 () => {
const msg = Buffer.from("00010203040506070809", "hex"); const msg = Buffer.from("00010203040506070809", "hex");
// const prvKey = crypto.randomBytes(32); // const prvKey = crypto.randomBytes(32);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@ -65,8 +60,8 @@ 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 = circuit.calculateWitness({ A: aBits, R8: r8Bits, S: sBits, msg: msgBits }); const w = await circuit.calculateWitness({A: aBits, R8: r8Bits, S: sBits, msg: msgBits}, true);
assert(circuit.checkWitness(w)); await circuit.checkConstraints(w);
}); });
}); });

View File

@ -1,19 +1,19 @@
const chai = require("chai"); const chai = require("chai");
const snarkjs = require("@tornado/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 bigInt = snarkjs.bigInt; const utils = require("ffjavascript").utils;
describe("EdDSA js test", function () { describe("EdDSA js test", function () {
this.timeout(100000); this.timeout(100000);
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 = bigInt.leBuff2int(msgBuf); const msg = utils.leBuff2int(msgBuf);
// const prvKey = crypto.randomBytes(32); // const prvKey = crypto.randomBytes(32);
@ -21,55 +21,61 @@ describe("EdDSA js test", function () {
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
assert.equal(pubKey[0].toString(), "13277427435165878497778222415993513565335242147425444199013288855685581939618"); assert.equal(pubKey[0].toString(),
assert.equal(pubKey[1].toString(), "13622229784656158136036771217484571176836296686641868549125388198837476602820"); "13277427435165878497778222415993513565335242147425444199013288855685581939618");
assert.equal(pubKey[1].toString(),
"13622229784656158136036771217484571176836296686641868549125388198837476602820");
const pPubKey = babyJub.packPoint(pubKey); const pPubKey = babyJub.packPoint(pubKey);
const signature = eddsa.signMiMC(prvKey, msg); const signature = eddsa.signMiMC(prvKey, msg);
assert.equal(signature.R8[0].toString(), "11384336176656855268977457483345535180380036354188103142384839473266348197733"); assert.equal(signature.R8[0].toString(),
assert.equal(signature.R8[1].toString(), "15383486972088797283337779941324724402501462225528836549661220478783371668959"); "11384336176656855268977457483345535180380036354188103142384839473266348197733");
assert.equal(signature.S.toString(), "2523202440825208709475937830811065542425109372212752003460238913256192595070"); assert.equal(signature.R8[1].toString(),
"15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(),
"2523202440825208709475937830811065542425109372212752003460238913256192595070");
const pSignature = eddsa.packSignature(signature); const pSignature = eddsa.packSignature(signature);
assert.equal( assert.equal(pSignature.toString("hex"), ""+
pSignature.toString("hex"), "dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"" + "7ed40dab29bf993c928e789d007387998901a24913d44fddb64b1f21fc149405");
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2" +
"7ed40dab29bf993c928e789d007387998901a24913d44fddb64b1f21fc149405"
);
const uSignature = eddsa.unpackSignature(pSignature); const uSignature = eddsa.unpackSignature(pSignature);
assert(eddsa.verifyMiMC(msg, uSignature, pubKey)); assert(eddsa.verifyMiMC(msg, uSignature, pubKey));
}); });
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 = bigInt.leBuff2int(msgBuf); const msg = utils.leBuff2int(msgBuf);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
assert.equal(pubKey[0].toString(), "13277427435165878497778222415993513565335242147425444199013288855685581939618"); assert.equal(pubKey[0].toString(),
assert.equal(pubKey[1].toString(), "13622229784656158136036771217484571176836296686641868549125388198837476602820"); "13277427435165878497778222415993513565335242147425444199013288855685581939618");
assert.equal(pubKey[1].toString(),
"13622229784656158136036771217484571176836296686641868549125388198837476602820");
const pPubKey = babyJub.packPoint(pubKey); const pPubKey = babyJub.packPoint(pubKey);
const signature = eddsa.signPoseidon(prvKey, msg); const signature = eddsa.signPoseidon(prvKey, msg);
assert.equal(signature.R8[0].toString(), "11384336176656855268977457483345535180380036354188103142384839473266348197733"); assert.equal(signature.R8[0].toString(),
assert.equal(signature.R8[1].toString(), "15383486972088797283337779941324724402501462225528836549661220478783371668959"); "11384336176656855268977457483345535180380036354188103142384839473266348197733");
assert.equal(signature.S.toString(), "1398758333392199195742243841591064350253744445503462896781493968760929513778"); assert.equal(signature.R8[1].toString(),
"15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(),
"1398758333392199195742243841591064350253744445503462896781493968760929513778");
const pSignature = eddsa.packSignature(signature); const pSignature = eddsa.packSignature(signature);
assert.equal( assert.equal(pSignature.toString("hex"), ""+
pSignature.toString("hex"), "dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"" + "32f16b0f2f4c4e1169aa59685637e1429b6581a9531d058d65f4ab224eab1703");
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2" +
"32f16b0f2f4c4e1169aa59685637e1429b6581a9531d058d65f4ab224eab1703"
);
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,29 +1,25 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
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 = new snarkjs.Circuit(cirDef); circuit = await tester(path.join(__dirname, "circuits", "eddsamimc_test.circom"));
console.log("NConstrains EdDSA MiMC: " + circuit.nConstraints);
}); });
it("Sign a single number", async () => { it("Sign a single number", async () => {
const msg = bigInt(1234); const msg = Fr.e(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@ -33,66 +29,69 @@ describe("EdDSA MiMC test", function () {
assert(eddsa.verifyMiMC(msg, signature, pubKey)); assert(eddsa.verifyMiMC(msg, signature, pubKey));
const w = circuit.calculateWitness({ const w = await 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}, true);
});
await circuit.checkConstraints(w);
assert(circuit.checkWitness(w));
}); });
it("Detect Invalid signature", async () => { it("Detect Invalid signature", async () => {
const msg = bigInt(1234); const msg = Fr.e(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signMiMC(prvKey, msg); const signature = eddsa.signMiMC(prvKey, msg);
assert(eddsa.verifyMiMC(msg, signature, pubKey)); assert(eddsa.verifyMiMC(msg, signature, pubKey));
try { try {
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
enabled: 1, enabled: 1,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)), R8x: Fr.add(signature.R8[0], Fr.e(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg, M: msg}, true);
});
assert(false); assert(false);
} catch (err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message)); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
} }
}); });
it("Test a dissabled circuit with a bad signature", async () => { it("Test a dissabled circuit with a bad signature", async () => {
const msg = bigInt(1234); const msg = Fr.e(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signMiMC(prvKey, msg); const signature = eddsa.signMiMC(prvKey, msg);
assert(eddsa.verifyMiMC(msg, signature, pubKey)); assert(eddsa.verifyMiMC(msg, signature, pubKey));
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
enabled: 0, enabled: 0,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)), R8x: Fr.add(signature.R8[0], Fr.e(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg, M: msg}, true);
});
await circuit.checkConstraints(w);
assert(circuit.checkWitness(w));
}); });
}); });

View File

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

View File

@ -1,29 +1,25 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
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 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 = new snarkjs.Circuit(cirDef); circuit = await tester(path.join(__dirname, "circuits", "eddsaposeidon_test.circom"));
console.log("NConstrains EdDSA Poseidon: " + circuit.nConstraints);
}); });
it("Sign a single number", async () => { it("Sign a single number", async () => {
const msg = bigInt(1234); const msg = Fr.e(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
@ -33,66 +29,71 @@ describe("EdDSA Poseidon test", function () {
assert(eddsa.verifyPoseidon(msg, signature, pubKey)); assert(eddsa.verifyPoseidon(msg, signature, pubKey));
const w = circuit.calculateWitness({ const input = {
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
}); };
assert(circuit.checkWitness(w)); // console.log(JSON.stringify(utils.stringifyBigInts(input)));
const w = await circuit.calculateWitness(input, true);
await circuit.checkConstraints(w);
}); });
it("Detect Invalid signature", async () => { it("Detect Invalid signature", async () => {
const msg = bigInt(1234); const msg = Fr.e(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signPoseidon(prvKey, msg); const signature = eddsa.signPoseidon(prvKey, msg);
assert(eddsa.verifyPoseidon(msg, signature, pubKey)); assert(eddsa.verifyPoseidon(msg, signature, pubKey));
try { try {
circuit.calculateWitness({ await circuit.calculateWitness({
enabled: 1, enabled: 1,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)), R8x: Fr.add(signature.R8[0], Fr.e(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg, M: msg}, true);
});
assert(false); assert(false);
} catch (err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message)); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
} }
}); });
it("Test a dissabled circuit with a bad signature", async () => { it("Test a dissabled circuit with a bad signature", async () => {
const msg = bigInt(1234); const msg = Fr.e(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signPoseidon(prvKey, msg); const signature = eddsa.signPoseidon(prvKey, msg);
assert(eddsa.verifyPoseidon(msg, signature, pubKey)); assert(eddsa.verifyPoseidon(msg, signature, pubKey));
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
enabled: 0, enabled: 0,
Ax: pubKey[0], Ax: pubKey[0],
Ay: pubKey[1], Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)), R8x: Fr.add(signature.R8[0], Fr.e(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg, M: msg}, true);
});
assert(circuit.checkWitness(w)); await circuit.checkConstraints(w);
}); });
}); });

View File

@ -1,170 +1,115 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
const compiler = require("circom"); const babyJub = require("../src/babyjub.js");
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", () => { describe("Exponentioation test", function () {
this.timeout(100000);
it("Should generate the Exponentiation table in k=0", async () => { it("Should generate the Exponentiation table in k=0", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulw4table_test.circom"));
// console.log(JSON.stringify(cirDef, null, 1)); const circuit = await tester(path.join(__dirname, "circuits", "escalarmulw4table_test.circom"));
// assert.equal(cirDef.nVars, 2); const w = await circuit.calculateWitness({in: 1});
const circuit = new snarkjs.Circuit(cirDef); await circuit.checkConstraints(w);
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({ in: 1 });
assert(circuit.checkWitness(w));
let g = [ let g = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
dbl = [bigInt("0"), snarkjs.bigInt("1")]; let dbl= [Fr.e("0"), Fr.e("1")];
for (let i = 0; i < 16; i++) { const expectedOut = [];
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
// console.log(xout1.toString()); for (let i=0; i<16; i++) {
// console.log(yout1.toString());
// console.log(dbl[0]);
// console.log(dbl[1]);
assert(xout1.equals(dbl[0])); expectedOut.push(dbl);
assert(yout1.equals(dbl[1])); dbl = babyJub.addPoint(dbl,g);
dbl = addPoint([xout1, yout1], 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 cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulw4table_test3.circom"));
// console.log(JSON.stringify(cirDef, null, 1)); const circuit = await tester(path.join(__dirname, "circuits", "escalarmulw4table_test3.circom"));
// assert.equal(cirDef.nVars, 2); const w = await circuit.calculateWitness({in: 1});
const circuit = new snarkjs.Circuit(cirDef); await circuit.checkConstraints(w);
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({ in: 1 });
assert(circuit.checkWitness(w));
let g = [ let g = [
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
for (let i = 0; i < 12; i++) { for (let i=0; i<12;i++) {
g = addPoint(g, g); g = babyJub.addPoint(g,g);
} }
dbl = [snarkjs.bigInt("0"), snarkjs.bigInt("1")]; let dbl= [Fr.e("0"), Fr.e("1")];
for (let i = 0; i < 16; i++) { const expectedOut = [];
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
// console.log(xout1.toString()); for (let i=0; i<16; i++) {
// console.log(yout1.toString()); expectedOut.push(dbl);
// console.log(dbl[0]);
// console.log(dbl[1]);
assert(xout1.equals(dbl[0])); dbl = babyJub.addPoint(dbl,g);
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"), { reduceConstraints: true });
// console.log(JSON.stringify(cirDef, null, 1)); const circuit = await tester(path.join(__dirname, "circuits", "escalarmul_test.circom"));
// assert.equal(cirDef.nVars, 2); const w = await circuit.calculateWitness({"in": 31});
const circuit = new snarkjs.Circuit(cirDef); await circuit.checkConstraints(w);
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({ in: 31 });
assert(circuit.checkWitness(w));
let g = [ let g = [
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
let c = [0n, 1n]; let c = [Fr.e(0), Fr.e(1)];
for (let i = 0; i < 31; i++) { for (let i=0; i<31;i++) {
c = addPoint(c, g); c = babyJub.addPoint(c,g);
} }
const xout = w[circuit.getSignalIdx(`main.out[0]`)]; await circuit.assertOut(w, {out: c});
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 = addPoint(c, c); c = babyJub.addPoint(c,c);
} }
c = addPoint(c, g); c = babyJub.addPoint(c,g);
// console.log(xout2.toString()); await circuit.assertOut(w2, {out: c});
// 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 = new snarkjs.Circuit(cirDef); const circuit = await tester(path.join(__dirname, "circuits", "escalarmul_test_min.circom"));
console.log("NConstrains: " + circuit.nConstraints);
}).timeout(10000000); }).timeout(10000000);
}); });

View File

@ -1,11 +1,8 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
const compiler = require("circom"); const Fr = require("ffjavascript").bn128.Fr;
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,38 +14,34 @@ describe("Escalarmul test", function () {
this.timeout(100000); this.timeout(100000);
let g = [ let g = [
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
before(async () => { before( async() => {
const cirDefEMulAny = await compiler(path.join(__dirname, "circuits", "escalarmulany_test.circom")); circuitEMulAny = await tester(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 = circuitEMulAny.calculateWitness({ e: 1, p: g });
assert(circuitEMulAny.checkWitness(w)); const w = await circuitEMulAny.calculateWitness({"e": 1, "p": g});
const xout = w[circuitEMulAny.getSignalIdx("main.out[0]")]; await circuitEMulAny.checkConstraints(w);
const yout = w[circuitEMulAny.getSignalIdx("main.out[1]")];
await circuitEMulAny.assertOut(w, {out: g}, true);
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 = bigInt("2736030358979909402780800718157159386076813972158567259200215660948447373041");
const w = circuitEMulAny.calculateWitness({ e: r, p: g });
assert(circuitEMulAny.checkWitness(w)); const r = Fr.e("2736030358979909402780800718157159386076813972158567259200215660948447373041");
const w = await circuitEMulAny.calculateWitness({"e": r, "p": g});
const xout = w[circuitEMulAny.getSignalIdx("main.out[0]")]; await circuitEMulAny.checkConstraints(w);
const yout = w[circuitEMulAny.getSignalIdx("main.out[1]")];
await circuitEMulAny.assertOut(w, {out: [0,1]}, true);
assert(xout.equals(bigInt.zero));
assert(yout.equals(bigInt.one));
}); });
}); });

View File

@ -1,13 +1,11 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
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)]);
} }
@ -17,88 +15,76 @@ describe("Escalarmul test", function () {
this.timeout(100000); this.timeout(100000);
before(async () => { before( async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulfix_test.circom")); circuit = await tester(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 = circuit.calculateWitness({ e: 0 });
assert(circuit.checkWitness(w)); const w = await circuit.calculateWitness({"e": 0});
const xout = w[circuit.getSignalIdx("main.out[0]")]; await circuit.checkConstraints(w);
const yout = w[circuit.getSignalIdx("main.out[1]")];
await circuit.assertOut(w, {out: [0,1]}, true);
assert(xout.equals(0));
assert(yout.equals(1));
}); });
it("Should generate Same escalar mul", async () => { it("Should generate Same escalar mul", async () => {
const w = circuit.calculateWitness({ e: 1 });
assert(circuit.checkWitness(w)); const w = await circuit.calculateWitness({"e": 1}, true);
const xout = w[circuit.getSignalIdx("main.out[0]")]; await circuit.checkConstraints(w);
const yout = w[circuit.getSignalIdx("main.out[1]")];
await circuit.assertOut(w, {out: babyjub.Base8});
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 = bigInt("2351960337287830298912035165133676222414898052661454064215017316447594616519");
const s = Fr.e("2351960337287830298912035165133676222414898052661454064215017316447594616519");
const base8 = [ const base8 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
const w = circuit.calculateWitness({ e: s }); const w = await circuit.calculateWitness({"e": s}, true);
assert(circuit.checkWitness(w)); await circuit.checkConstraints(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);
assert(xout.equals(expectedRes[0])); await circuit.assertOut(w, {out: expectedRes});
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 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
for (let i = 0; i < 50; i++) { for (let i=0; i<50; i++) {
const s = bigInt(i); const s = Fr.e(i);
const w = circuit.calculateWitness({ e: s }); const w = await circuit.calculateWitness({"e": s}, true);
assert(circuit.checkWitness(w)); await circuit.checkConstraints(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);
assert(xout.equals(expectedRes[0])); await circuit.assertOut(w, {out: expectedRes});
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 = circuit.calculateWitness({ e: babyjub.subOrder });
assert(circuit.checkWitness(w)); const w = await circuit.calculateWitness({"e": babyjub.subOrder }, true);
const xout = w[circuit.getSignalIdx("main.out[0]")]; await circuit.checkConstraints(w);
const yout = w[circuit.getSignalIdx("main.out[1]")];
assert(xout.equals(bigInt.zero)); await circuit.assertOut(w, {out: [0,1]});
assert(yout.equals(bigInt.one));
}); });
}); });

View File

@ -1,34 +1,25 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
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 () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_test.circom")); circuit = await tester(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 = circuit.calculateWitness({ x_in: 1, k: 2 }); const w = await circuit.calculateWitness({x_in: 1, k: 2}, true);
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()); await circuit.checkConstraints(w);
assert(circuit.checkWitness(w));
}); });
}); });

View File

@ -1,11 +1,8 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
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;
@ -13,44 +10,28 @@ 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 = new snarkjs.Circuit(cirDef); circuit = await tester(path.join(__dirname, "circuits", "mimc_sponge_test.circom"));
console.log("MiMC Feistel constraints: " + circuit.nConstraints); const w = await circuit.calculateWitness({xL_in: 1, xR_in: 2, k: 3});
const w = circuit.calculateWitness({ xL_in: 1, xR_in: 2, k: 3 }); const out2 = mimcjs.hash(1,2,3);
const xLout = w[circuit.getSignalIdx("main.xL_out")]; await circuit.assertOut(w, {xL_out: out2.xL, xR_out: out2.xR});
const xRout = w[circuit.getSignalIdx("main.xR_out")];
const out2 = mimcjs.hash(1, 2, 3); await circuit.checkConstraints(w);
assert.equal(xLout.toString(), out2.xL.toString());
assert.equal(xRout.toString(), out2.xR.toString());
assert(circuit.checkWitness(w));
}); });
it("Should check hash", async () => { it("Should check hash", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_sponge_hash_test.circom")); circuit = await tester(path.join(__dirname, "circuits", "mimc_sponge_hash_test.circom"));
circuit = new snarkjs.Circuit(cirDef); const w = await circuit.calculateWitness({ins: [1, 2], k: 0});
console.log("MiMC Sponge constraints: " + circuit.nConstraints); const out2 = mimcjs.multiHash([1,2], 0, 3);
const w = circuit.calculateWitness({ ins: [1, 2], k: 0 }); await circuit.assertOut(w, {outs: out2});
const o1 = w[circuit.getSignalIdx("main.outs[0]")]; await circuit.checkConstraints(w);
const o2 = w[circuit.getSignalIdx("main.outs[1]")];
const o3 = w[circuit.getSignalIdx("main.outs[2]")];
const out2 = mimcjs.multiHash([1, 2], 0, 3);
assert.equal(o1.toString(), out2[0].toString());
assert.equal(o2.toString(), out2[1].toString());
assert.equal(o3.toString(), out2[2].toString());
assert(circuit.checkWitness(w));
}); });
}); });

View File

@ -33,8 +33,8 @@ describe("MiMC Sponge Smart contract test", () => {
}); });
it("Shold calculate the mimc correctly", async () => { it("Shold calculate the mimc correctly", async () => {
const res = await mimc.methods.MiMCSponge(1,2).call(); const res = await mimc.methods.MiMCSponge(1,2,3).call();
const res2 = await mimcjs.hash(1,2, 0); const res2 = await mimcjs.hash(1,2,3);
assert.equal(res.xL.toString(), res2.xL.toString()); assert.equal(res.xL.toString(), res2.xL.toString());
assert.equal(res.xR.toString(), res2.xR.toString()); assert.equal(res.xR.toString(), res2.xR.toString());

View File

@ -1,13 +1,11 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
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;
@ -15,86 +13,80 @@ describe("Montgomery test", function () {
let circuitMDouble; let circuitMDouble;
let g = [ let g = [
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), Fr.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"), Fr.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
]; ];
let mg, mg2, g2, g3, mg3; let mg, mg2, g2, g3, mg3;
this.timeout(100000); this.timeout(100000);
before(async () => { before( async() => {
const cirDefE2M = await compiler(path.join(__dirname, "circuits", "edwards2montgomery.circom")); circuitE2M = await tester(path.join(__dirname, "circuits", "edwards2montgomery.circom"));
circuitE2M = new snarkjs.Circuit(cirDefE2M); await circuitE2M.loadSymbols();
console.log("NConstrains Edwards -> Montgomery: " + circuitE2M.nConstraints); circuitM2E = await tester(path.join(__dirname, "circuits", "montgomery2edwards.circom"));
await circuitM2E.loadSymbols();
const cirDefM2E = await compiler(path.join(__dirname, "circuits", "montgomery2edwards.circom")); circuitMAdd = await tester(path.join(__dirname, "circuits", "montgomeryadd.circom"));
circuitM2E = new snarkjs.Circuit(cirDefM2E); await circuitMAdd.loadSymbols();
console.log("NConstrains Montgomery -> Edwards: " + circuitM2E.nConstraints); circuitMDouble = await tester(path.join(__dirname, "circuits", "montgomerydouble.circom"));
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 = circuitE2M.calculateWitness({ in: g }); w = await circuitE2M.calculateWitness({ in: g}, true);
xout = w[circuitE2M.getSignalIdx("main.out[0]")]; xout = w[circuitE2M.symbols["main.out[0]"].varIdx];
yout = w[circuitE2M.getSignalIdx("main.out[1]")]; yout = w[circuitE2M.symbols["main.out[1]"].varIdx];
mg = [xout, yout]; mg = [xout, yout];
w = circuitM2E.calculateWitness({ in: [xout, yout] }); w = await circuitM2E.calculateWitness({ in: [xout, yout]}, true);
xout = w[circuitM2E.getSignalIdx("main.out[0]")]; xout = w[circuitM2E.symbols["main.out[0]"].varIdx];
yout = w[circuitM2E.getSignalIdx("main.out[1]")]; yout = w[circuitM2E.symbols["main.out[1]"].varIdx];
assert(xout.equals(g[0])); assert(Fr.eq(xout, g[0]));
assert(yout.equals(g[1])); assert(Fr.eq(yout, 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 = circuitMDouble.calculateWitness({ in: mg }); w = await circuitMDouble.calculateWitness({ in: mg}, true);
xout = w[circuitE2M.getSignalIdx("main.out[0]")]; xout = w[circuitE2M.symbols["main.out[0]"].varIdx];
yout = w[circuitE2M.getSignalIdx("main.out[1]")]; yout = w[circuitE2M.symbols["main.out[1]"].varIdx];
mg2 = [xout, yout]; mg2 = [xout, yout];
w = circuitM2E.calculateWitness({ in: mg2 }); w = await circuitM2E.calculateWitness({ in: mg2}, true);
xout = w[circuitM2E.getSignalIdx("main.out[0]")]; xout = w[circuitM2E.symbols["main.out[0]"].varIdx];
yout = w[circuitM2E.getSignalIdx("main.out[1]")]; yout = w[circuitM2E.symbols["main.out[1]"].varIdx];
assert(xout.equals(g2[0]));
assert(yout.equals(g2[1])); assert(Fr.eq(xout, g2[0]));
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 = circuitMAdd.calculateWitness({ in1: mg, in2: mg2 }); w = await circuitMAdd.calculateWitness({ in1: mg, in2: mg2}, true);
xout = w[circuitMAdd.getSignalIdx("main.out[0]")]; xout = w[circuitMAdd.symbols["main.out[0]"].varIdx];
yout = w[circuitMAdd.getSignalIdx("main.out[1]")]; yout = w[circuitMAdd.symbols["main.out[1]"].varIdx];
mg3 = [xout, yout]; mg3 = [xout, yout];
w = circuitM2E.calculateWitness({ in: mg3 }); w = await circuitM2E.calculateWitness({ in: mg3}, true);
xout = w[circuitM2E.getSignalIdx("main.out[0]")]; xout = w[circuitM2E.symbols["main.out[0]"].varIdx];
yout = w[circuitM2E.getSignalIdx("main.out[1]")]; yout = w[circuitM2E.symbols["main.out[1]"].varIdx];
assert(xout.equals(g3[0])); assert(Fr.eq(xout, g3[0]));
assert(yout.equals(g3[1])); assert(Fr.eq(yout, g3[1]));
}); });
}); });

View File

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

View File

@ -1,104 +1,77 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom");
const assert = chai.assert; const Fr = require("ffjavascript").bn128.Fr;
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 =
[ [
bigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), [Fr.e("10457101036533406547632367118273992217979173478358440826365724437999023779287"),Fr.e("19824078218392094440610104313265183977899662750282163392862422243483260492317")],
bigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), [Fr.e("2671756056509184035029146175565761955751135805354291559563293617232983272177"),Fr.e("2663205510731142763556352975002641716101654201788071096152948830924149045094")],
], [Fr.e("5802099305472655231388284418920769829666717045250560929368476121199858275951"),Fr.e("5980429700218124965372158798884772646841287887664001482443826541541529227896")],
[ [Fr.e("7107336197374528537877327281242680114152313102022415488494307685842428166594"),Fr.e("2857869773864086953506483169737724679646433914307247183624878062391496185654")],
bigInt("2671756056509184035029146175565761955751135805354291559563293617232983272177"), [Fr.e("20265828622013100949498132415626198973119240347465898028410217039057588424236"),Fr.e("1160461593266035632937973507065134938065359936056410650153315956301179689506")]
bigInt("2663205510731142763556352975002641716101654201788071096152948830924149045094"), ];
],
[
bigInt("5802099305472655231388284418920769829666717045250560929368476121199858275951"),
bigInt("5980429700218124965372158798884772646841287887664001482443826541541529227896"),
],
[
bigInt("7107336197374528537877327281242680114152313102022415488494307685842428166594"),
bigInt("2857869773864086953506483169737724679646433914307247183624878062391496185654"),
],
[
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 = new snarkjs.Circuit(cirDef); circuit = await tester(path.join(__dirname, "circuits", "pedersen_test.circom"));
console.log("NConstrains: " + circuit.nConstraints);
}); });
it("Should pedersen at zero", async () => { it("Should pedersen at zero", async () => {
let w, xout, yout;
w = circuit.calculateWitness({ in: ["0", "0"] }); let w;
xout = w[circuit.getSignalIdx("main.out[0]")]; w = await circuit.calculateWitness({ in: ["0", "0"]}, true);
yout = w[circuit.getSignalIdx("main.out[1]")];
await circuit.assertOut(w, {out: [0,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, xout, yout; let w;
w = circuit.calculateWitness({ in: ["1", "0"] }); w = await circuit.calculateWitness({ in: ["1", "0"]}, true);
xout = bigInt(w[circuit.getSignalIdx("main.out[0]")]); await circuit.assertOut(w, {out: PBASE[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, xout, yout; let w;
w = circuit.calculateWitness({ in: ["0", "1"] }); w = await circuit.calculateWitness({ in: ["0", "1"]}, true);
xout = w[circuit.getSignalIdx("main.out[0]")]; await circuit.assertOut(w, {out: PBASE[1]});
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, xout, yout; let w;
w = circuit.calculateWitness({ in: ["3", "7"] }); w = await circuit.calculateWitness({ in: ["3", "7"]}, true);
xout = w[circuit.getSignalIdx("main.out[0]")]; const r = babyJub.addPoint(
yout = w[circuit.getSignalIdx("main.out[1]")]; babyJub.mulPointEscalar(PBASE[0], 3),
babyJub.mulPointEscalar(PBASE[1], 7)
);
const r = babyJub.addPoint(babyJub.mulPointEscalar(PBASE[0], 3), 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, xout, yout; let w;
const allOnes = bigInt("1").shl(250).sub(bigInt("1")); const allOnes = Fr.sub(Fr.shl(Fr.e("1"), Fr.e(250)), Fr.e("1"));
w = circuit.calculateWitness({ in: [allOnes, allOnes] }); w = await circuit.calculateWitness({ in: [allOnes, allOnes]}, true);
xout = w[circuit.getSignalIdx("main.out[0]")];
yout = w[circuit.getSignalIdx("main.out[1]")];
const r2 = babyJub.addPoint(babyJub.mulPointEscalar(PBASE[0], allOnes), babyJub.mulPointEscalar(PBASE[1], allOnes)); const r2 = babyJub.addPoint(
babyJub.mulPointEscalar(PBASE[0], allOnes),
babyJub.mulPointEscalar(PBASE[1], allOnes)
);
assert(xout.equals(r2[0])); await circuit.assertOut(w, {out: r2});
assert(yout.equals(r2[1]));
}); });
}); });

View File

@ -1,70 +1,49 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom");
const assert = chai.assert; const Fr = require("ffjavascript").bn128.Fr;
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");
describe("Pedersen test", function () {
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 = new snarkjs.Circuit(cirDef); circuit = await tester(path.join(__dirname, "circuits", "pedersen2_test.circom"));
console.log("NConstrains Pedersen2: " + circuit.nConstraints);
}); });
it("Should pedersen at zero", async () => { it("Should pedersen at zero", async () => {
let w, xout, yout;
w = circuit.calculateWitness({ in: 0 }); let w;
xout = w[circuit.getSignalIdx("main.out[0]")]; w = await circuit.calculateWitness({ in: 0}, true);
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, xout, yout;
const n = bigInt.one.shl(253).sub(bigInt.one); let w;
console.log(n.toString(16));
w = circuit.calculateWitness({ in: n }); const n = Fr.sub(Fr.shl(Fr.one, Fr.e(253)), Fr.one);
xout = w[circuit.getSignalIdx("main.out[0]")]; w = await circuit.calculateWitness({ in: n}, true);
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,32 +1,23 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
const compiler = require("circom");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
const babyJub = require("../src/babyjub.js"); const babyJub = require("../src/babyjub.js");
describe("Point 2 bits test", function () {
describe("Point 2 bits test", function() {
let circuit; let circuit;
this.timeout(100000); this.timeout(100000);
before(async () => { before( async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "pointbits_loopback.circom")); circuit = await tester(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 = circuit.calculateWitness({ in: babyJub.Base8 }); const w = await circuit.calculateWitness({ in: babyJub.Base8}, true);
assert(circuit.checkWitness(w)); await circuit.checkConstraints(w);
}); });
it("Should do the both convertions for Zero point", async () => { it("Should do the both convertions for Zero point", async () => {
const w = circuit.calculateWitness({ in: [0, 1] }); const w = await circuit.calculateWitness({ in: [0, 1]}, true);
assert(circuit.checkWitness(w)); await circuit.checkConstraints(w);
}); });
}); });

View File

@ -1,59 +1,57 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
const compiler = require("circom");
const poseidon = require("../src/poseidon.js"); const poseidon = require("../src/poseidon.js");
const assert = chai.assert; const assert = chai.assert;
describe("Poseidon Circuit test", function () { describe("Poseidon Circuit test", function () {
let circuit2; let circuit6;
let circuit4; let circuit3;
this.timeout(100000); this.timeout(100000);
before(async () => { before( async () => {
const cirDef2 = await compiler(path.join(__dirname, "circuits", "poseidon2_test.circom")); circuit6 = await tester(path.join(__dirname, "circuits", "poseidon6_test.circom"));
const cirDef4 = await compiler(path.join(__dirname, "circuits", "poseidon4_test.circom")); circuit3 = await tester(path.join(__dirname, "circuits", "poseidon3_test.circom"));
circuit2 = new snarkjs.Circuit(cirDef2);
circuit4 = new snarkjs.Circuit(cirDef4);
}); });
it("Should check constrain of hash([1, 2])", async () => { it("Should check constrain of hash([1, 2]) t=6", async () => {
const hash = poseidon([1, 2]); const w = await circuit6.calculateWitness({inputs: [1, 2, 0,0,0]}, true);
assert.equal("0x11ad302b36a2d7e09653c8e90618f00c06cd0a7348e52cdf2ccced3c3abec679", "0x" + hash.toString(16));
const w = await circuit2.calculateWitness({ inputs: [1, 2] }, true); const res2 = poseidon([1,2,0,0,0]);
const res = w[circuit2.getSignalIdx("main.out")]; assert.equal("3975478831357328722254985704342968745327876719981393787143845259590563829094", res2.toString());
assert.equal(res.toString(), hash.toString()); await circuit6.assertOut(w, {out : res2});
await circuit2.checkWitness(w); await circuit6.checkConstraints(w);
}); });
it("Should check constrain of hash([3, 4])", async () => { it("Should check constrain of hash([3, 4]) t=6", async () => {
const hash = poseidon([3, 4]); const w = await circuit6.calculateWitness({inputs: [3, 4,5,10,23]});
assert.equal("0x23939f0972e764d6e252060279aabaca8ec650ab30b17d2c13551bec2a66bcef", "0x" + hash.toString(16));
const w = await circuit2.calculateWitness({ inputs: [3, 4] }); const res2 = poseidon([3, 4,5,10,23]);
const res = w[circuit2.getSignalIdx("main.out")];
assert.equal(res.toString(), hash.toString()); assert.equal("18540626624821144952552691894137986276337186174352554475896834101336254024067", res2.toString());
await circuit2.checkWitness(w); await circuit6.assertOut(w, {out : res2});
await circuit6.checkConstraints(w);
}); });
it("Should check constrain of hash([1, 2, 3, 4])", async () => {
const hash = poseidon([1, 2, 3, 4]); it("Should check constrain of hash([1, 2]) t=3", async () => {
assert.equal("0x2e4fb80ce74868b0d33f4acb22071d8d8f8da7d30ebf972e6e4f72a64bb0633f", "0x" + hash.toString(16)); const w = await circuit3.calculateWitness({inputs: [1, 2]});
const w = await circuit4.calculateWitness({ inputs: [1, 2, 3, 4] });
const res = w[circuit4.getSignalIdx("main.out")]; const res2 = poseidon([1,2]);
assert.equal(res.toString(), hash.toString()); assert.equal("17117985411748610629288516079940078114952304104811071254131751175361957805920", res2.toString());
await circuit4.checkWitness(w); await circuit3.assertOut(w, {out : res2});
await circuit3.checkConstraints(w);
}); });
it("Should check constrain of hash([5, 6, 7, 8])", async () => { it("Should check constrain of hash([3, 4]) t=3", async () => {
const hash = poseidon([5, 6, 7, 8]); const w = await circuit3.calculateWitness({inputs: [3, 4]});
assert.equal("0x2a3fc67aa97766917ee06e927f35fd70f4655ad6c1f2e7bcd5c5c85aa3a8a974", "0x" + hash.toString(16));
const w = await circuit4.calculateWitness({ inputs: [5, 6, 7, 8] }); const res2 = poseidon([3, 4]);
const res = w[circuit4.getSignalIdx("main.out")]; assert.equal("21867347236198497199818917118739170715216974132230970409806500217655788551452", res2.toString());
assert.equal(res.toString(), hash.toString()); await circuit3.assertOut(w, {out : res2});
await circuit4.checkWitness(w); await circuit3.checkConstraints(w);
}); });
}); });

View File

@ -10,12 +10,10 @@ const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); };
describe("Poseidon Smart contract test", function () { describe("Poseidon Smart contract test", function () {
let testrpc; let testrpc;
let web3; let web3;
let poseidon2; let poseidon6;
let poseidon4; let poseidon3;
let accounts; let accounts;
this.timeout(100000); this.timeout(100000);
let C2;
let C4;
before(async () => { before(async () => {
web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 }); web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 });
@ -23,41 +21,41 @@ 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));
C2 = new web3.eth.Contract(poseidonGenContract.generateABI(2)); const C3 = new web3.eth.Contract(poseidonGenContract.generateABI(2));
poseidon2 = await C2.deploy({
poseidon6 = await C6.deploy({
data: poseidonGenContract.createCode(5)
}).send({
gas: 5000000,
from: accounts[0]
});
poseidon3 = await C3.deploy({
data: poseidonGenContract.createCode(2) data: poseidonGenContract.createCode(2)
}).send({ }).send({
gas: 5000000, gas: 5000000,
from: accounts[0] from: accounts[0]
}); });
C4 = new web3.eth.Contract(poseidonGenContract.generateABI(4));
poseidon4 = await C4.deploy({
data: poseidonGenContract.createCode(4)
}).send({
gas: 5000000,
from: accounts[0]
});
}); });
it("Should calculate the poseidon correctly for 2 inputs", async () => { it("Should calculate the poseidon correctly t=6", async () => {
const res = await poseidon2.methods.poseidon([1, 2]).call();
const res = await poseidon6.methods.poseidon([1,2, 0, 0, 0]).call();
// console.log("Cir: " + bigInt(res.toString(16)).toString(16)); // console.log("Cir: " + bigInt(res.toString(16)).toString(16));
const res2 = poseidon([1, 2]); const res2 = poseidon([1,2, 0, 0, 0]);
// console.log("Ref: " + bigInt(res2).toString(16)); // console.log("Ref: " + bigInt(res2).toString(16));
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());
}); });
it("Should calculate the poseidon correctly for 4 inputs", async () => { it("Should calculate the poseidon correctly t=3", async () => {
const res = await poseidon4.methods.poseidon([1, 2, 3, 4]).call(); const res = await poseidon3.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, 3, 4]); const res2 = poseidon([1,2]);
// console.log("Ref: " + bigInt(res2).toString(16)); // console.log("Ref: " + bigInt(res2).toString(16));
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());

View File

@ -1,23 +0,0 @@
include "../circuits/smt/smtverifier.circom";
template SMT(nLevels) {
signal input root;
signal input mtp[nLevels];
signal input hi;
signal input hv;
component smtClaimExists = SMTVerifier(nLevels);
smtClaimExists.enabled <== 1;
smtClaimExists.fnc <== 0;
smtClaimExists.root <== root;
for (var i=0; i<nLevels; i++) {
smtClaimExists.siblings[i] <== mtp[i];
}
smtClaimExists.oldKey <== 0;
smtClaimExists.oldValue <== 0;
smtClaimExists.isOld0 <== 0;
smtClaimExists.key <== hi;
smtClaimExists.value <== hv;
}
component main = SMT(4);

View File

@ -1,122 +1,115 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/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");
function buffer2bitArray(b) { function buffer2bitArray(b) {
const res = []; const res = [];
for (let i = 0; i < b.length; i++) { for (let i=0; i<b.length; i++) {
for (let j = 0; j < 8; j++) { for (let j=0; j<8; j++) {
res.push((b[i] >> (7 - j)) & 1); res.push((b[i] >> (7-j) &1));
} }
} }
return res; return res;
} }
function bitArray2buffer(a) { function bitArray2buffer(a) {
const len = Math.floor((a.length - 1) / 8) + 1; const len = Math.floor((a.length -1 )/8)+1;
const b = new Buffer.alloc(len); const b = new Buffer.alloc(len);
for (let i = 0; i < a.length; i++) { for (let i=0; i<a.length; i++) {
const p = Math.floor(i / 8); const p = Math.floor(i/8);
b[p] = b[p] | (Number(a[i]) << (7 - (i % 8))); b[p] = b[p] | (Number(a[i]) << ( 7 - (i%8) ));
} }
return b; return b;
} }
describe("SHA256 test", () => {
describe("SHA256 test", function () {
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 () => {
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;
} }
const a = buffer2bitArray(b); const a = buffer2bitArray(b);
const b2 = bitArray2buffer(a); const b2 = bitArray2buffer(a);
assert.equal(b.toString("hex"), b2.toString("hex")); assert.equal(b.toString("hex"), b2.toString("hex"), true);
}); });
it("Should calculate a hash of 1 compressor", async () => { it("Should calculate a hash of 1 compressor", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_2_test.circom")); const cir = await tester(path.join(__dirname, "circuits", "sha256_2_test.circom"));
const circuit = new snarkjs.Circuit(cirDef);
console.log("Vars: " + circuit.nVars); const witness = await cir.calculateWitness({ "a": "1", "b": "2" }, true);
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;
b[53] = 2; b[53] = 2;
const hash = crypto.createHash("sha256").update(b).digest("hex"); const hash = crypto.createHash("sha256")
.update(b)
.digest("hex");
const r = "0x" + hash.slice(10); const r = "0x" + hash.slice(10);
const hash2 = sha256.hash(b.toString("hex"), { msgFormat: "hex-bytes" }); const hash2 = sha256.hash(b.toString("hex"), {msgFormat: "hex-bytes"});
assert.equal(hash, hash2); assert.equal(hash, hash2);
assert(witness[1].equals(snarkjs.bigInt(r))); assert(Fr.eq(witness[1], Fr.e(r)));
}).timeout(1000000); }).timeout(1000000);
it("Should calculate a hash of 2 compressor", async () => { it("Should calculate a hash of 2 compressor", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_test512.circom"), { reduceConstraints: false }); const cir = await tester(path.join(__dirname, "circuits", "sha256_test512.circom"));
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;
} }
const hash = crypto.createHash("sha256").update(b).digest("hex"); const hash = crypto.createHash("sha256")
.update(b)
.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); }).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_test448.circom"));
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").update(b).digest("hex"); const hash = crypto.createHash("sha256")
.update(b)
.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,11 +1,7 @@
const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const Fr = require("ffjavascript").bn128.Fr;
const compiler = require("circom"); const Scalar = require("ffjavascript").Scalar;
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)]);
@ -13,74 +9,72 @@ 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 (v.shr(i).isOdd()) { if (Scalar.isOdd(Scalar.shr(v, i))) {
res.push(bigInt.one); res.push(Fr.one);
} else { } else {
res.push(bigInt.zero); res.push(Fr.zero);
} }
} }
return res; return res;
} }
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const q = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
describe("Sign test", () => { describe("Sign test", function() {
let circuit; let circuit;
before(async () => { this.timeout(100000);
const cirDef = await compiler(path.join(__dirname, "circuits", "sign_test.circom"));
circuit = new snarkjs.Circuit(cirDef); before( async() => {
circuit = await tester(path.join(__dirname, "circuits", "sign_test.circom"));
console.log("NConstrains: " + circuit.nConstraints);
}); });
it("Sign of 0", async () => { it("Sign of 0", async () => {
const inp = getBits(bigInt.zero, 254); const inp = getBits(Scalar.e(0), 254);
const w = circuit.calculateWitness({ in: inp }); const w = await circuit.calculateWitness({in: inp}, true);
assert(w[circuit.getSignalIdx("main.sign")].equals(bigInt(0))); await circuit.assertOut(w, {sign: 0});
}); });
it("Sign of 3", async () => { it("Sign of 3", async () => {
const inp = getBits(bigInt(3), 254); const inp = getBits(Scalar.e(3), 254);
const w = circuit.calculateWitness({ in: inp }); const w = await circuit.calculateWitness({in: inp}, true);
assert(w[circuit.getSignalIdx("main.sign")].equals(bigInt(0))); await circuit.assertOut(w, {sign: 0});
}); });
it("Sign of q/2", async () => { it("Sign of q/2", async () => {
const inp = getBits(q.shr(bigInt.one), 254); const inp = getBits(Scalar.shr(q, 1), 254);
const w = circuit.calculateWitness({ in: inp }); const w = await circuit.calculateWitness({in: inp}, true);
assert(w[circuit.getSignalIdx("main.sign")].equals(bigInt(0))); await circuit.assertOut(w, {sign: 0});
}); });
it("Sign of q/2+1", async () => { it("Sign of q/2+1", async () => {
const inp = getBits(q.shr(bigInt.one).add(bigInt.one), 254); const inp = getBits(Scalar.add(Scalar.shr(q, 1), 1) , 254);
const w = circuit.calculateWitness({ in: inp }); const w = await circuit.calculateWitness({in: inp}, true);
assert(w[circuit.getSignalIdx("main.sign")].equals(bigInt(1))); await circuit.assertOut(w, {sign: 1});
}); });
it("Sign of q-1", async () => { it("Sign of q-1", async () => {
const inp = getBits(q.sub(bigInt.one), 254); const inp = getBits(Scalar.sub(q, 1), 254);
const w = circuit.calculateWitness({ in: inp }); const w = await circuit.calculateWitness({in: inp}, true);
assert(w[circuit.getSignalIdx("main.sign")].equals(bigInt(1))); await circuit.assertOut(w, {sign: 1});
}); });
it("Sign of q", async () => { it("Sign of q", async () => {
const inp = getBits(q, 254); const inp = getBits(q, 254);
const w = circuit.calculateWitness({ in: inp }); const w = await circuit.calculateWitness({in: inp}, true);
assert(w[circuit.getSignalIdx("main.sign")].equals(bigInt(1))); await circuit.assertOut(w, {sign: 1});
}); });
it("Sign of all ones", async () => { it("Sign of all ones", async () => {
const inp = getBits(bigInt(1).shl(254).sub(bigInt(1)), 254); const inp = getBits(Scalar.sub(Scalar.shl(1,254),1), 254);
const w = circuit.calculateWitness({ in: inp }); const w = await circuit.calculateWitness({in: inp}, true);
assert(w[circuit.getSignalIdx("main.sign")].equals(bigInt(1))); await circuit.assertOut(w, {sign: 1});
}); });
}); });

View File

@ -1,50 +1,34 @@
const chai = require("chai"); const chai = require("chai");
const snarkjs = require("@tornado/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 () => {
});
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 = bigInt(111); const key1 = Fr.e(111);
const value1 = bigInt(222); const value1 = Fr.e(222);
const key2 = bigInt(333); const key2 = Fr.e(333);
const value2 = bigInt(444); const value2 = Fr.e(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(tree.root.isZero()); assert(Fr.isZero(tree.root));
}); });
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 = [bigInt(8), bigInt(9), bigInt(32)]; const keys = [Fr.e(8), Fr.e(9), Fr.e(32)];
const values = [bigInt(88), bigInt(99), bigInt(3232)]; const values = [Fr.e(88), Fr.e(99), Fr.e(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();
@ -52,59 +36,59 @@ describe("SMT Javascript test", function () {
const tree5 = await smt.newMemEmptyTrie(); const tree5 = await smt.newMemEmptyTrie();
const tree6 = await smt.newMemEmptyTrie(); const tree6 = await smt.newMemEmptyTrie();
await tree1.insert(keys[0], values[0]); await tree1.insert(keys[0],values[0]);
await tree1.insert(keys[1], values[1]); await tree1.insert(keys[1],values[1]);
await tree1.insert(keys[2], values[2]); await tree1.insert(keys[2],values[2]);
await tree2.insert(keys[0], values[0]); await tree2.insert(keys[0],values[0]);
await tree2.insert(keys[2], values[2]); await tree2.insert(keys[2],values[2]);
await tree2.insert(keys[1], values[1]); await tree2.insert(keys[1],values[1]);
await tree3.insert(keys[1], values[1]); await tree3.insert(keys[1],values[1]);
await tree3.insert(keys[0], values[0]); await tree3.insert(keys[0],values[0]);
await tree3.insert(keys[2], values[2]); await tree3.insert(keys[2],values[2]);
await tree4.insert(keys[1], values[1]); await tree4.insert(keys[1],values[1]);
await tree4.insert(keys[2], values[2]); await tree4.insert(keys[2],values[2]);
await tree4.insert(keys[0], values[0]); await tree4.insert(keys[0],values[0]);
await tree5.insert(keys[2], values[2]); await tree5.insert(keys[2],values[2]);
await tree5.insert(keys[0], values[0]); await tree5.insert(keys[0],values[0]);
await tree5.insert(keys[1], values[1]); await tree5.insert(keys[1],values[1]);
await tree6.insert(keys[2], values[2]); await tree6.insert(keys[2],values[2]);
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(tree1.root.equals(tree2.root)); assert(Fr.eq(tree1.root, tree2.root));
assert(tree2.root.equals(tree3.root)); assert(Fr.eq(tree2.root, tree3.root));
assert(tree3.root.equals(tree4.root)); assert(Fr.eq(tree3.root, tree4.root));
assert(tree4.root.equals(tree5.root)); assert(Fr.eq(tree4.root, tree5.root));
assert(tree5.root.equals(tree6.root)); assert(Fr.eq(tree5.root, 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);
assert.equal(Object.keys(tree3.db.nodes).length, Object.keys(tree4.db.nodes).length); assert.equal(Object.keys(tree3.db.nodes).length, Object.keys(tree4.db.nodes).length);
assert.equal(Object.keys(tree4.db.nodes).length, Object.keys(tree5.db.nodes).length); assert.equal(Object.keys(tree4.db.nodes).length, Object.keys(tree5.db.nodes).length);
assert.equal(Object.keys(tree5.db.nodes).length, Object.keys(tree6.db.nodes).length); assert.equal(Object.keys(tree5.db.nodes).length, Object.keys(tree6.db.nodes).length);
await tree1.delete(keys[0]); await tree1.delete(keys[0]);
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(tree1.root.equals(tree2.root)); assert(Fr.eq(tree1.root, 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(tree3.root.equals(tree4.root)); assert(Fr.eq(tree3.root, 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(tree5.root.equals(tree6.root)); assert(Fr.eq(tree5.root, tree6.root));
await tree1.delete(keys[2]); await tree1.delete(keys[2]);
await tree2.delete(keys[2]); await tree2.delete(keys[2]);
@ -113,12 +97,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(tree1.root.isZero()); assert(Fr.isZero(tree1.root));
assert(tree2.root.isZero()); assert(Fr.isZero(tree2.root));
assert(tree3.root.isZero()); assert(Fr.isZero(tree3.root));
assert(tree4.root.isZero()); assert(Fr.isZero(tree4.root));
assert(tree5.root.isZero()); assert(Fr.isZero(tree5.root));
assert(tree6.root.isZero()); assert(Fr.isZero(tree6.root));
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);
@ -132,7 +116,7 @@ describe("SMT Javascript test", function () {
function perm(a) { function perm(a) {
const arr = a.slice(); const arr = a.slice();
const rArr = []; const rArr = [];
for (let i = 0; i < arr.length; i++) { for (let i=0; i<arr.length; i++) {
let rIdx = Math.floor(Math.random() * (arr.length - i)); let rIdx = Math.floor(Math.random() * (arr.length - i));
rArr.push(arr[rIdx]); rArr.push(arr[rIdx]);
arr[rIdx] = arr[arr.length - i - 1]; arr[rIdx] = arr[arr.length - i - 1];
@ -142,19 +126,19 @@ describe("SMT Javascript test", function () {
const tree = await smt.newMemEmptyTrie(); const tree = await smt.newMemEmptyTrie();
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(bigInt(i)); arr.push(Fr.e(i));
} }
const insArr = perm(arr); const insArr = perm(arr);
for (let i = 0; i < N; i++) { for (let i=0; i<N; i++) {
await tree.insert(insArr[i], i); await tree.insert(insArr[i], i);
} }
const delArr = perm(insArr); const delArr = perm(insArr);
for (let i = 0; i < N; i++) { for (let i=0; i<N; i++) {
await tree.delete(delArr[i]); await tree.delete(delArr[i]);
} }
assert(tree.root.isZero()); assert(Fr.isZero(tree.root));
assert.equal(Object.keys(tree.db.nodes).length, 0); assert.equal(Object.keys(tree.db.nodes).length, 0);
}); });
@ -162,18 +146,28 @@ describe("SMT Javascript test", function () {
const tree1 = await smt.newMemEmptyTrie(); const tree1 = await smt.newMemEmptyTrie();
const tree2 = await smt.newMemEmptyTrie(); const tree2 = await smt.newMemEmptyTrie();
await tree1.insert(8, 88); await tree1.insert(8,88);
await tree1.insert(9, 99); await tree1.insert(9,99,);
await tree1.insert(32, 3232); await tree1.insert(32,3232);
await tree2.insert(8, 888); await tree2.insert(8,888);
await tree2.insert(9, 999); await tree2.insert(9,999);
await tree2.insert(32, 323232); await tree2.insert(32,323232);
await tree1.update(8, 888); await tree1.update(8, 888);
await tree1.update(9, 999); await tree1.update(9, 999);
await tree1.update(32, 323232); await tree1.update(32, 323232);
assert(tree1.root.equals(tree2.root)); assert(Fr.eq(tree1.root, 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,112 +1,105 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const tester = require("circom").tester;
const compiler = require("circom"); 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 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, log) { async function testInsert(tree, key, value, circuit ) {
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(bigInt(0)); while (siblings.length<10) siblings.push(Fr.e(0));
const w = circuit.calculateWitness( const w = await circuit.calculateWitness({
{ fnc: [1,0],
fnc: [1, 0], oldRoot: res.oldRoot,
oldRoot: res.oldRoot, siblings: siblings,
siblings: siblings, oldKey: res.isOld0 ? 0 : res.oldKey,
oldKey: res.isOld0 ? 0 : res.oldKey, oldValue: res.isOld0 ? 0 : res.oldValue,
oldValue: res.isOld0 ? 0 : res.oldValue, 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(bigInt(0)); while (siblings.length<10) siblings.push(Fr.e(0));
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
fnc: [1, 1], fnc: [1,1],
oldRoot: res.oldRoot, oldRoot: res.oldRoot,
siblings: siblings, siblings: siblings,
oldKey: res.isOld0 ? 0 : res.oldKey, oldKey: res.isOld0 ? 0 : res.oldKey,
oldValue: res.isOld0 ? 0 : res.oldValue, oldValue: res.isOld0 ? 0 : res.oldValue,
isOld0: res.isOld0 ? 1 : 0, isOld0: res.isOld0 ? 1 : 0,
newKey: res.delKey, newKey: res.delKey,
newValue: res.delValue, newValue: res.delValue
}); }, true);
const root1 = w[circuit.getSignalIdx("main.newRoot")]; await circuit.checkConstraints(w);
assert(circuit.checkWitness(w)); await circuit.assertOut(w, {newRoot: res.newRoot});
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(bigInt(0)); while (siblings.length<10) siblings.push(Fr.e(0));
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
fnc: [0, 1], fnc: [0,1],
oldRoot: res.oldRoot, oldRoot: res.oldRoot,
siblings: siblings, siblings: siblings,
oldKey: res.oldKey, oldKey: res.oldKey,
oldValue: res.oldValue, oldValue: res.oldValue,
isOld0: 0, isOld0: 0,
newKey: res.newKey, newKey: res.newKey,
newValue: res.newValue, newValue: res.newValue
}); });
const root1 = w[circuit.getSignalIdx("main.newRoot")]; await circuit.checkConstraints(w);
assert(circuit.checkWitness(w)); await circuit.assertOut(w, {newRoot: res.newRoot});
assert(root1.equals(res.newRoot));
} }
describe("SMT test", function () {
describe("SMT Processor test", function () {
let circuit; let circuit;
let tree; let tree;
this.timeout(10000000); this.timeout(10000000);
before(async () => { before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "smtprocessor10_test.circom")); circuit = await tester(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 = bigInt(111); const key = Fr.e(111);
const value = bigInt(222); const value = Fr.e(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 = bigInt(333); const key = Fr.e(333);
const value = bigInt(444); const value = Fr.e(444);
await testInsert(tree, key, value, circuit); await testInsert(tree, key, value, circuit);
}); });
@ -117,8 +110,8 @@ describe("SMT test", function () {
}); });
it("Should test convination of adding and removing 3 elements", async () => { it("Should test convination of adding and removing 3 elements", async () => {
const keys = [bigInt(8), bigInt(9), bigInt(32)]; const keys = [Fr.e(8), Fr.e(9), Fr.e(32)];
const values = [bigInt(88), bigInt(99), bigInt(3232)]; const values = [Fr.e(88), Fr.e(99), Fr.e(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();
@ -126,29 +119,30 @@ describe("SMT test", function () {
const tree5 = await smt.newMemEmptyTrie(); const tree5 = await smt.newMemEmptyTrie();
const tree6 = await smt.newMemEmptyTrie(); const tree6 = await smt.newMemEmptyTrie();
await testInsert(tree1, keys[0], values[0], circuit); await testInsert(tree1,keys[0],values[0], circuit);
await testInsert(tree1, keys[1], values[1], circuit); await testInsert(tree1,keys[1],values[1], circuit);
await testInsert(tree1, keys[2], values[2], circuit); await testInsert(tree1,keys[2],values[2], circuit);
await testInsert(tree2, keys[0], values[0], circuit); await testInsert(tree2,keys[0],values[0], circuit);
await testInsert(tree2, keys[2], values[2], circuit); await testInsert(tree2,keys[2],values[2], circuit);
await testInsert(tree2, keys[1], values[1], circuit); await testInsert(tree2,keys[1],values[1], circuit);
await testInsert(tree3, keys[1], values[1], circuit); await testInsert(tree3,keys[1],values[1], circuit);
await testInsert(tree3, keys[0], values[0], circuit); await testInsert(tree3,keys[0],values[0], circuit);
await testInsert(tree3, keys[2], values[2], circuit); await testInsert(tree3,keys[2],values[2], circuit);
await testInsert(tree4, keys[1], values[1], circuit); await testInsert(tree4,keys[1],values[1], circuit);
await testInsert(tree4, keys[2], values[2], circuit); await testInsert(tree4,keys[2],values[2], circuit);
await testInsert(tree4, keys[0], values[0], circuit); await testInsert(tree4,keys[0],values[0], circuit);
await testInsert(tree5, keys[2], values[2], circuit); await testInsert(tree5,keys[2],values[2], circuit);
await testInsert(tree5, keys[0], values[0], circuit); await testInsert(tree5,keys[0],values[0], circuit);
await testInsert(tree5, keys[1], values[1], circuit); await testInsert(tree5,keys[1],values[1], circuit);
await testInsert(tree6,keys[2],values[2], circuit);
await testInsert(tree6,keys[1],values[1], circuit);
await testInsert(tree6,keys[0],values[0], circuit);
await testInsert(tree6, keys[2], values[2], circuit);
await testInsert(tree6, keys[1], values[1], circuit);
await testInsert(tree6, keys[0], values[0], circuit);
await testDelete(tree1, keys[0], circuit); await testDelete(tree1, keys[0], circuit);
await testDelete(tree1, keys[1], circuit); await testDelete(tree1, keys[1], circuit);
@ -160,6 +154,7 @@ describe("SMT test", function () {
await testDelete(tree4, keys[2], circuit); await testDelete(tree4, keys[2], circuit);
await testDelete(tree4, keys[0], circuit); await testDelete(tree4, keys[0], circuit);
await testDelete(tree5, keys[1], circuit); await testDelete(tree5, keys[1], circuit);
await testDelete(tree5, keys[2], circuit); await testDelete(tree5, keys[2], circuit);
await testDelete(tree6, keys[2], circuit); await testDelete(tree6, keys[2], circuit);
@ -175,35 +170,36 @@ describe("SMT 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(bigInt(88)); while (siblings.length<10) siblings.push(Fr.e(88));
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
fnc: [0, 0], fnc: [0,0],
oldRoot: 11, oldRoot: 11,
siblings: siblings, siblings: siblings,
oldKey: 33, oldKey: 33,
oldValue: 44, oldValue: 44,
isOld0: 55, isOld0: 55,
newKey: 66, newKey: 66,
newValue: 77, newValue: 77
}); });
const root1 = w[circuit.getSignalIdx("main.oldRoot")]; const root1 = w[circuit.symbols["main.oldRoot"].varIdx];
const root2 = w[circuit.getSignalIdx("main.newRoot")]; const root2 = w[circuit.symbols["main.newRoot"].varIdx];
assert(circuit.checkWitness(w)); await circuit.checkConstraints(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();
const tree2 = await smt.newMemEmptyTrie(); const tree2 = await smt.newMemEmptyTrie();
await testInsert(tree1, 8, 88, circuit); await testInsert(tree1,8,88, circuit);
await testInsert(tree1, 9, 99, circuit); await testInsert(tree1,9,99, circuit);
await testInsert(tree1, 32, 3232, circuit); await testInsert(tree1,32,3232, circuit);
await testInsert(tree2, 8, 888, circuit); await testInsert(tree2,8,888, circuit);
await testInsert(tree2, 9, 999, circuit); await testInsert(tree2,9,999, circuit);
await testInsert(tree2, 32, 323232, circuit); await testInsert(tree2,32,323232, circuit);
await testUpdate(tree1, 8, 888, circuit); await testUpdate(tree1, 8, 888, circuit);
await testUpdate(tree1, 9, 999, circuit); await testUpdate(tree1, 9, 999, circuit);

View File

@ -1,26 +1,25 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("@tornado/snarkjs"); const Fr = require("ffjavascript").bn128.Fr;
const compiler = require("circom"); const tester = require("circom").tester;
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 testInclusion(tree, key, circuit) { async function testInclusion(tree, key, circuit) {
const res = await tree.find(key); const res = await tree.find(key);
assert(res.found); assert(res.found);
let siblings = res.siblings; let siblings = res.siblings;
while (siblings.length < 10) siblings.push(bigInt(0)); while (siblings.length<10) siblings.push(Fr.e(0));
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
enabled: 1, enabled: 1,
fnc: 0, fnc: 0,
root: tree.root, root: tree.root,
@ -29,10 +28,11 @@ async function testInclusion(tree, key, circuit) {
oldValue: 0, oldValue: 0,
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 +40,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(bigInt(0)); while (siblings.length<10) siblings.push(Fr.e(0));
const w = circuit.calculateWitness({ const w = await circuit.calculateWitness({
enabled: 1, enabled: 1,
fnc: 1, fnc: 1,
root: tree.root, root: tree.root,
@ -51,29 +51,26 @@ async function testExclusion(tree, key, circuit) {
oldValue: res.isOld0 ? 0 : res.notFoundValue, oldValue: res.isOld0 ? 0 : res.notFoundValue,
isOld0: res.isOld0 ? 1 : 0, isOld0: res.isOld0 ? 1 : 0,
key: key, key: key,
value: 0, value: 0
}); });
assert(circuit.checkWitness(w)); await circuit.checkConstraints(w);
} }
describe("SMT test", function () { describe("SMT Verifier test", function () {
let circuit; let circuit;
let tree; let tree;
this.timeout(100000); this.timeout(100000);
before(async () => { before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "smtverifier10_test.circom")); circuit = await tester(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);
await tree.insert(8, 88); await tree.insert(8,88);
await tree.insert(32, 3232); await tree.insert(32,3232);
}); });
it("Check inclussion in a tree of 3", async () => { it("Check inclussion in a tree of 3", async () => {
@ -94,9 +91,9 @@ describe("SMT test", function () {
it("Check not enabled accepts any thing", async () => { it("Check not enabled accepts any thing", async () => {
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 = circuit.calculateWitness({ const w = await circuit.calculateWitness({
enabled: 0, enabled: 0,
fnc: 0, fnc: 0,
root: 1, root: 1,
@ -105,31 +102,35 @@ describe("SMT test", function () {
oldValue: 33, oldValue: 33,
isOld0: 0, isOld0: 0,
key: 44, key: 44,
value: 0, value: 0
}); });
assert(circuit.checkWitness(w));
await circuit.checkConstraints(w);
}); });
it("Check inclussion Adria case", async () => { it("Check inclussion Adria case", async () => {
const e1_hi = bigInt("17124152697573569611556136390143205198134245887034837071647643529178599000839"); const e1_hi= Fr.e("17124152697573569611556136390143205198134245887034837071647643529178599000839");
const e1_hv = bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179"); const e1_hv= Fr.e("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const e2ok_hi = bigInt("16498254692537945203721083102154618658340563351558973077349594629411025251262"); const e2ok_hi= Fr.e("16498254692537945203721083102154618658340563351558973077349594629411025251262");
const e2ok_hv = bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179"); const e2ok_hv= Fr.e("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const e2fail_hi = bigInt("17195092312975762537892237130737365903429674363577646686847513978084990105579"); const e2fail_hi= Fr.e("17195092312975762537892237130737365903429674363577646686847513978084990105579");
const e2fail_hv = bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179"); const e2fail_hv= Fr.e("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const tree1 = await smt.newMemEmptyTrie(); const tree1 = await smt.newMemEmptyTrie();
await tree1.insert(e1_hi, e1_hv); await tree1.insert(e1_hi,e1_hv);
await tree1.insert(e2ok_hi, e2ok_hv); await tree1.insert(e2ok_hi,e2ok_hv);
await testInclusion(tree1, e2ok_hi, circuit); await testInclusion(tree1, e2ok_hi, circuit);
const tree2 = await smt.newMemEmptyTrie(); const tree2 = await smt.newMemEmptyTrie();
await tree2.insert(e1_hi, e1_hv); await tree2.insert(e1_hi,e1_hv);
await tree2.insert(e2fail_hi, e2fail_hv); await tree2.insert(e2fail_hi,e2fail_hv);
await testInclusion(tree2, e2fail_hi, circuit); await testInclusion(tree2, e2fail_hi, circuit);
}); });
}); });

View File

@ -1,93 +0,0 @@
const path = require("path");
const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom");
const fs = require("fs");
const bigInt = snarkjs.bigInt;
const smt = require("../src/smt.js");
const circuitSource = `
include "../circuits/smt/smtverifier.circom";
template SMT(nLevels) {
signal input root;
signal input mtp[nLevels];
signal input hi;
signal input hv;
component smtClaimExists = SMTVerifier(nLevels);
smtClaimExists.enabled <== 1;
smtClaimExists.fnc <== 0;
smtClaimExists.root <== root;
for (var i=0; i<nLevels; i++) {
smtClaimExists.siblings[i] <== mtp[i];
}
smtClaimExists.oldKey <== 0;
smtClaimExists.oldValue <== 0;
smtClaimExists.isOld0 <== 0;
smtClaimExists.key <== hi;
smtClaimExists.value <== hv;
}
component main = SMT(4);
`;
describe("smt3test", function () {
this.timeout(200000);
let circuitFileName;
before(async () => {
circuitFileName = path.join(__dirname, ".", "rawsmt3.circom");
fs.writeFileSync(circuitFileName, circuitSource);
});
const levels = 4;
async function testsmt3(e1, e2) {
let tree = await smt.newMemEmptyTrie();
// insert e1, e2
await tree.insert(e1.hi, e1.hv);
await tree.insert(e2.hi, e2.hv);
// generate proof for e1
const findInfo = await tree.find(e1.hi);
const siblings = findInfo.siblings;
while (siblings.length < levels) siblings.push(bigInt(0));
const input = {
root: tree.root,
mtp: siblings,
hi: e1.hi,
hv: e1.hv,
};
const compiledCircuit = await compiler(circuitFileName, { reduceConstraints: false });
const circuit = new snarkjs.Circuit(compiledCircuit);
const witness = circuit.calculateWitness(input);
circuit.checkWitness(witness);
}
it("TestSmts", async () => {
const e1 = {
hi: bigInt("17124152697573569611556136390143205198134245887034837071647643529178599000839"),
hv: bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179"),
};
const e2ok = {
hi: bigInt("16498254692537945203721083102154618658340563351558973077349594629411025251262"),
hv: bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179"),
};
const e2fail = {
hi: bigInt("17195092312975762537892237130737365903429674363577646686847513978084990105579"),
hv: bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179"),
};
console.log("test e1, e2ok");
await testsmt3(e1, e2ok);
console.log("test e1, e2fail");
await testsmt3(e1, e2fail);
});
});