Compare commits

..

89 Commits

Author SHA1 Message Date
14314b6bbb Bump version & use snarkjs dependency from self-hosted tornado git registry 2023-09-12 01:22:49 -07:00
Alexey
3b492f9801 poseidon contract now accepts both selectors: for uint256[n] and bytes32[n] 2020-10-27 21:31:39 +03:00
poma
afb4eff954
use 35 rounds for poseidon hash, update poseidon constants from sage script for 35 rounds 2020-10-27 13:23:41 +03:00
Alexey Pertsev
47f33f2275
Merge pull request #2 from tornadocash/poseidon-fixed-array
pass fixes size array arg in solidity poseidon implementation
2020-10-26 16:32:04 +03:00
Alexey
118238ea62 pass fixes size array arg in solidity poseidon implementation 2020-10-26 16:30:10 +03:00
poma
c4496aecc8
fix poseidon contract bug 2020-10-26 16:08:57 +03:00
poma
5beb6aee94
fix dependency 2020-08-19 01:31:49 +03:00
poma
6282474dc0
fix tests 2020-08-10 13:42:52 +03:00
poma
436cf45a04
poseidon contract 2020-08-10 13:19:52 +03:00
poma
528b292da5
Update references to Poseidon hash in the project 2020-08-10 13:18:02 +03:00
poma
82c2f606cc
Rewrite Poseidon hash implementation to be compatible with reference implementation 2020-08-10 13:13:45 +03:00
poma
48efcf02ce
update web3 2020-07-31 23:24:02 +03:00
Alexey
c372f14d32 pin snarkjs version 2020-04-06 13:00:11 +03:00
Pertsev Alexey
ce5dbe8e1a
Merge pull request #1 from tornadocash/feat/audit_fixes
Feat/audit fixes
2020-04-06 12:55:59 +03:00
Kobi Gurkan
3478226049 Merge remote-tracking branch 'iden3/master' into feat/audit_fixes 2019-12-11 18:33:31 +02:00
Jordi Baylina
3c2b566e68
0.0.20 2019-12-04 21:57:32 +01:00
Jordi Baylina
15eadfe50c
Merge branch 'master' of github.com:iden3/circomlib 2019-12-04 21:57:08 +01:00
Jordi Baylina
a1d4d1dca7
Convert constant components to functions 2019-12-04 21:57:02 +01:00
Kobi Gurkan
eeecd07cae Merge remote-tracking branch 'iden3/master' into feat/audit_fixes 2019-12-03 20:26:43 +02:00
Jordi Baylina
d6e6a3b3f4
Fix assigning to signal 2019-12-03 19:16:19 +01:00
Kobi Gurkan
b928421c58 adds comment about baby pbk public key extraction 2019-12-01 15:38:38 +02:00
Kobi Gurkan
8445381431 escalarmulfix uses segments of 246 and adds comments on limits 2019-11-23 22:00:11 +02:00
Kobi Gurkan
42e96c2e1f makes S value in eddsa signatures be 251 bit, uses alias checks with enabled flag and adds eddsamimcsponge test 2019-11-23 21:36:06 +02:00
Kobi Gurkan
5ec0744303 adds alias check for babyjubjub 2019-11-23 21:19:47 +02:00
Kobi Gurkan
451fb51a0d adds comments to binsum 2019-11-23 19:24:02 +02:00
Kobi Gurkan
ba656fefbe mimcsponge: makes the contract hash-only 2019-11-14 17:31:00 +02:00
Kobi Gurkan
5d626852ae Merge remote-tracking branch 'iden3/master' into feat/mimc_constant 2019-11-14 16:25:12 +02:00
Kobi Gurkan
de9c7dda46 mimcsponge: makes rounds constant 2019-11-14 16:24:29 +02:00
arnau
e3eb834322
Merge pull request #23 from kobigurk/fix/mimcsponge_round_constants
MiMCSponge: makes first and last round constants always zero
2019-10-12 14:03:37 +02:00
Kobi Gurkan
01a5530213 MiMCSponge: makes first and last round constants always zero 2019-10-04 17:39:53 +03:00
Jordi Baylina
50a725c174
0.0.19 2019-10-02 09:35:06 +02:00
Jordi Baylina
c4ce4cd946
multiget 2019-10-02 09:34:49 +02:00
Jordi Baylina
5bf52cda57
Merge pull request #20 from bellesmarta/master
Updated README files
2019-09-23 14:58:24 +02:00
Jordi Baylina
95abdd06d5
0.0.18 2019-09-17 07:57:45 +02:00
Jordi Baylina
9f69fab7c6
Merge pull request #22 from kobigurk/fix/mimcsponge_unconstrained
mimcsponge: fixes assignment to outs[0]
2019-09-17 08:55:22 +03:00
Kobi Gurkan
109cdf4056 mimcsponge: fixes assignment to outs[0] 2019-09-17 08:53:02 +03:00
Jordi Baylina
79d30349b4
0.0.17 2019-09-15 10:52:50 +02:00
Jordi Baylina
e3cd0e5aa7
Dependencies and publish smt 2019-09-15 10:52:18 +02:00
Jordi Baylina
86e970b888
0.0.16 2019-09-07 20:23:18 +02:00
Jordi Baylina
29e162383d
Allow full poseidnon fix handle enable in the sigposeidon 2019-09-07 20:22:44 +02:00
Marta Belles
97b870b725 Updated README files 2019-09-06 17:14:45 +02:00
Jordi Baylina
f9e0484663
0.0.15 2019-09-05 17:12:56 +02:00
Jordi Baylina
7bdb254f4f
deps snarkjs 2019-09-05 17:12:47 +02:00
Jordi Baylina
024188b638
Support mutiply by point 0 in scalarmulany 2019-09-05 17:10:20 +02:00
Jordi Baylina
ebbeaebc73
Merge branch 'arnaucube-master' 2019-09-05 16:51:29 +02:00
Jordi Baylina
25f392c8ae
sha256 with number of bits as a paramter 2019-09-05 16:41:58 +02:00
Jordi Baylina
52a1fb895d
0.0.14 2019-08-30 10:38:19 +02:00
Jordi Baylina
1621483d3b
deps 2019-08-30 10:38:04 +02:00
arnaucube
ae362ec61b add tests for babyjub eddsa poseidon sign & verify 2019-08-29 17:44:44 +02:00
Jordi Baylina
425f50a9ed
0.0.13 2019-08-24 19:53:41 +02:00
Jordi Baylina
173c17dedc
Change to a standard generator for Baby Jub 2019-08-03 12:46:21 +02:00
Jordi Baylina
23616427cd
0.0.12 2019-07-30 20:16:38 +02:00
Jordi Baylina
7c743659db
Fix escalarfix 2019-07-30 20:16:06 +02:00
Jordi Baylina
f04a318800
0.0.11 2019-07-30 19:35:35 +02:00
Jordi Baylina
b15c7c8089
FIX: escalarmul fix 2019-07-30 19:35:19 +02:00
Jordi Baylina
9282ffe8c3
0.0.10 2019-07-08 17:43:05 +02:00
Jordi Baylina
d5f02256f9
Merge branch 'feature/jstests' 2019-07-08 17:41:24 +02:00
Jordi Baylina
88acd49c0b
Merge branch 'master' into feature/jstests 2019-07-08 17:30:53 +02:00
Jordi Baylina
59f6e971cf
Merge branch 'arnaucube-master' 2019-07-08 17:28:11 +02:00
Jordi Baylina
da1cceed85
Merge branch 'master' of https://github.com/arnaucube/circomlib into arnaucube-master 2019-07-08 17:19:42 +02:00
Jordi Baylina
61c9703fb2
0.0.9 2019-07-08 14:42:56 +02:00
Jordi Baylina
c84f6da970
Merge branch 'kobigurk-feature/mimcsponge' 2019-07-08 14:34:15 +02:00
Jordi Baylina
42ff01fb3b
Some format and fixes from the last version 2019-07-08 14:33:37 +02:00
Jordi Baylina
861a75e0cb
Merge branch 'feature/mimcsponge' of https://github.com/kobigurk/circomlib into kobigurk-feature/mimcsponge 2019-07-08 14:21:43 +02:00
Jordi Baylina
7cce66b4d8
Merge branch 'master' of github.com:iden3/circomlib 2019-07-08 14:08:13 +02:00
Jordi Baylina
a9227b7b58
Update web3 2019-07-08 14:08:04 +02:00
Jordi Baylina
f91ed9793c
Merge pull request #15 from kobigurk/feature/expose_pedersen
Exposes Pedersen hashes
2019-07-08 13:09:00 +02:00
Kobi Gurkan
b0861bfe66 feat: exposes pedersen hash 2019-07-08 13:56:04 +03:00
Kobi Gurkan
1483abaa2f feat: makes mimcsponge contract act like the circuit version 2019-07-08 13:55:01 +03:00
Kobi Gurkan
324b8bf8cc fix: makes mimcsponge act like the paper description
* last constant is 0
* no swap at the last round
2019-07-08 13:54:46 +03:00
arnaucube
3bc864f110 update poseidon with blake2b 2019-06-28 10:50:49 +02:00
Kobi Gurkan
9e078dc299 fix: makes mimcsponge usable 2019-06-26 22:41:07 +03:00
Kobi Gurkan
17cb959364 Adds a sponge hash function based on MiMC2n-n 2019-06-26 22:41:07 +03:00
Jordi Baylina
d689f737d8
0.0.8 2019-06-04 17:55:28 +02:00
Jordi Baylina
154a9bcbae
Merge branch 'master' of github.com:iden3/circomlib 2019-06-04 17:36:54 +02:00
Jordi Baylina
c4490b2ce9
Poseidon in SMT 2019-06-04 17:32:28 +02:00
Jordi Baylina
590d62a07c
Poseidon 2019-06-04 13:40:15 +02:00
Eduard S
0aabe6447d Add babyjub and EdDSA js tests
Add tests with vectors for javascript implementation of babyjub and EdDSA.
2019-05-16 13:16:59 +02:00
Jordi Baylina
d91afa804a
Merge pull request #5 from udibr/multiplexer
fixed Multiplexer name and usage of old syntax
2019-05-11 21:04:17 +02:00
Jordi Baylina
1da1f5886f
Merge pull request #6 from udibr/circuits-readme
readme for circuits:
2019-05-11 21:00:43 +02:00
Jordi Baylina
fdce2a96e3
Merge pull request #7 from iden3/feature/babypbk
Add babyjub pvk->pbk circuit
2019-05-11 21:00:09 +02:00
Jordi Baylina
e7c4a979a0
Merge pull request #10 from kobigurk/fix_babyjubjub
fixes babyjubjub addition to use generic bigint interfaces
2019-05-11 20:45:27 +02:00
Jordi Baylina
efc77065e7
0.0.7 2019-05-08 19:09:28 +02:00
Jordi Baylina
58f758d5ad
Adapt the way to connect mimcs 2019-04-28 12:03:15 +01:00
Kobi Gurkan
0503ec9de9 fixes babyjubjub addition to use generic bigint interfaces 2019-04-22 17:19:39 +03:00
adriamb
d9d6e43143 added pvk->pbk circuit 2019-03-17 10:38:36 +01:00
adriamb
8cb7b46603 fix missing deps 2019-03-17 10:36:14 +01:00
Ehud Ben-Reuven
39bb716785 fixed Multiplexer name and usage of old syntax 2019-02-23 20:16:06 -05:00
Ehud Ben-Reuven
b14eef4d90 readme for circuits: 2019-02-23 14:25:43 -05:00
114 changed files with 7548 additions and 8007 deletions

1
.npmrc Normal file
View File

@ -0,0 +1 @@
@tornado:registry=https://git.tornado.ws/api/packages/tornado-packages/npm/

View File

@ -1,4 +1,17 @@
# cirpedersen # CircomLib
Pedersen Hash and Exponentiation circuits using Baby Jub Curve in circom language ## Description
- 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).
## Organisation
This respository contains 5 folders:
- `circuits`: it contains the implementation of different cryptographic primitives in circom language.
- `calcpedersenbases`: set of functions in JavaScript used to find a set of points in [Baby Jubjub](https://github.com/barryWhiteHat/baby_jubjub) elliptic curve that serve as basis for the [Pedersen Hash](https://github.com/zcash/zcash/issues/2234).
- `doc`: it contains some circuit schemes in ASCII (must be opened with Monodraw, an ASCII art editor for Mac).
- `src`: it contains similar implementation of circuits in JavaScript.
- `test`: tests.
A description of the specific circuit templates for the `circuit` folder will be soon updated.

View File

@ -1,5 +1,5 @@
const bn128 = require("snarkjs").bn128; const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("snarkjs").bigInt; const bigInt = require("@tornado/snarkjs").bigInt;
const createBlakeHash = require("blake-hash"); const createBlakeHash = require("blake-hash");
const babyJub = require("../src/babyjub"); const babyJub = require("../src/babyjub");
@ -8,17 +8,17 @@ function getPoint(S) {
const h = createBlakeHash("blake256").update(S).digest(); const h = createBlakeHash("blake256").update(S).digest();
if (h.length != 32) { if (h.length != 32) {
throw new Error("Invalid length") throw new Error("Invalid length");
} }
let sign = false; let sign = false;
if (h[31] & 0x80) { if (h[31] & 0x80) {
h[31] = h[31] & 0x7F; h[31] = h[31] & 0x7f;
sign = true; sign = true;
} }
let y = bigInt(0); let y = bigInt(0);
for (let i=0; i<32; i++) { for (let i = 0; i < 32; i++) {
y = y.shl(8); y = y.shl(8);
y = y.add(bigInt(h[i])); y = y.add(bigInt(h[i]));
} }
@ -28,9 +28,7 @@ function getPoint(S) {
const y2 = F.square(y); const y2 = F.square(y);
let x = F.sqrt(F.div( let x = F.sqrt(F.div(F.sub(F.one, y2), F.sub(a, F.mul(d, y2))));
F.sub(F.one, y2),
F.sub(a, F.mul(d, y2))));
if (x == null) return null; if (x == null) return null;
@ -43,41 +41,34 @@ function getPoint(S) {
return p8; return p8;
} }
function generatePoint(S) { function generatePoint(S) {
let p= null; let p = null;
let idx = 0; let idx = 0;
while (p==null) { while (p == null) {
let sidx = "" + idx; let sidx = "" + idx;
while (sidx.length<16) sidx = "0"+sidx; while (sidx.length < 16) sidx = "0" + sidx;
p = getPoint(S+"_"+sidx); p = getPoint(S + "_" + sidx);
idx++; idx++;
} }
if (!babyJub.inCurve(p)){ if (!babyJub.inCurve(p)) {
throw new Error("Point not in curve"); throw new Error("Point not in curve");
} }
return p; return p;
} }
const g = [ const g = [
bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")]; bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
// Sanity check // Sanity check
if (!babyJub.inCurve(g)) { if (!babyJub.inCurve(g)) {
throw new Error("Generator not In curve -> Some thing goes wrong..."); throw new Error("Generator not In curve -> Some thing goes wrong...");
} }
for (let i=0; i<25; i++) { for (let i = 0; i < 25; i++) {
let S = "" +i; let S = "" + i;
while (S.length<16) S = "0"+S; while (S.length < 16) S = "0" + S;
const P = generatePoint("Iden3_PedersenGenerator_"+S); const P = generatePoint("Iden3_PedersenGenerator_" + S);
console.log(`[${P[0].toString()}, ${P[1].toString()}]`); console.log(`[${P[0].toString()}, ${P[1].toString()}]`);
} }

830
circuits/README.md Normal file
View File

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

View File

@ -21,7 +21,6 @@ include "compconstant.circom";
template AliasCheck() { template AliasCheck() {
signal input in[254]; signal input in[254];
component compConstant = CompConstant(-1); component compConstant = CompConstant(-1);
@ -30,3 +29,15 @@ 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

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

View File

@ -50,6 +50,7 @@ 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;
@ -61,6 +62,7 @@ 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];

View File

@ -21,6 +21,7 @@ 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];
@ -76,6 +77,7 @@ 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

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

View File

@ -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 "compconstant.circom"; include "aliascheck.circom";
include "pointbits.circom"; include "pointbits.circom";
include "pedersen.circom"; include "pedersen.circom";
include "escalarmulany.circom"; include "escalarmulany.circom";
@ -40,12 +40,15 @@ template EdDSAVerifier(n) {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040); component aliasCheck = AliasCheckBabyJub();
aliasCheck.enabled <== 1;
for (i=0; i<254; i++) { for (i=0; i<251; i++) {
S[i] ==> compConstant.in[i]; S[i] ==> aliasCheck.in[i];
} }
compConstant.out === 0; S[251] === 0;
S[252] === 0;
S[253] === 0;
S[254] === 0; S[254] === 0;
S[255] === 0; S[255] === 0;
@ -123,8 +126,8 @@ template EdDSAVerifier(n) {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8 = [ var BASE8 = [
17777552123799933955779906779655732241715742912184938656739573121738514868268, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
2626589144620713026669568689430873010625803728049924121243784502389097019475 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(256, BASE8); component mulFix = EscalarMulFix(256, BASE8);
for (i=0; i<256; i++) { for (i=0; i<256; 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 "compconstant.circom"; include "aliascheck.circom";
include "pointbits.circom"; include "pointbits.circom";
include "mimc.circom"; include "mimc.circom";
include "bitify.circom"; include "bitify.circom";
@ -39,16 +39,15 @@ template EdDSAMiMCVerifier() {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component snum2bits = Num2Bits(253); component snum2bits = Num2Bits(251);
snum2bits.in <== S; snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040); component aliasCheck = AliasCheckBabyJub();
aliasCheck.enabled <== 1;
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
snum2bits.out[i] ==> compConstant.in[i]; snum2bits.out[i] ==> aliasCheck.in[i];
} }
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
@ -58,6 +57,7 @@ template EdDSAMiMCVerifier() {
hash.in[2] <== Ax; hash.in[2] <== Ax;
hash.in[3] <== Ay; hash.in[3] <== Ay;
hash.in[4] <== M; hash.in[4] <== M;
hash.k <== 0;
component h2bits = Num2Bits_strict(); component h2bits = Num2Bits_strict();
h2bits.in <== hash.out; h2bits.in <== hash.out;
@ -100,11 +100,11 @@ template EdDSAMiMCVerifier() {
// Calculate left side of equation left = S*B8 // Calculate left side of equation left = S*B8
var BASE8 = [ var BASE8 = [
17777552123799933955779906779655732241715742912184938656739573121738514868268, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
2626589144620713026669568689430873010625803728049924121243784502389097019475 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(253, BASE8); component mulFix = EscalarMulFix(251, BASE8);
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
mulFix.e[i] <== snum2bits.out[i]; mulFix.e[i] <== snum2bits.out[i];
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -137,18 +137,19 @@ template MiMC7(nrounds) {
template MultiMiMC7(nInputs, nRounds) { template MultiMiMC7(nInputs, nRounds) {
signal input in[nInputs]; signal input in[nInputs];
signal input k;
signal output out; signal output out;
signal r[nInputs +1];
component mims[nInputs]; component mims[nInputs];
r[0] <== k;
for (var i=0; i<nInputs; i++) { for (var i=0; i<nInputs; i++) {
mims[i] = MiMC7(nRounds); mims[i] = MiMC7(nRounds);
if (i==0) { mims[i].x_in <== in[i];
mims[i].x_in <== 15021630795539610737508582392395901278341266317943626182700664337106830745361; mims[i].k <== r[i];
} else { r[i+1] <== r[i] + in[i] + mims[i].out;
mims[i].x_in <== mims[i-1].out;
}
mims[i].k <== in[i];
} }
out <== mims[nInputs-1].out; out <== r[nInputs];
} }

290
circuits/mimcsponge.circom Normal file
View File

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

View File

@ -85,6 +85,7 @@ 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

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

47
circuits/mux1.circom Normal file
View File

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

62
circuits/mux2.circom Normal file
View File

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

View File

@ -108,6 +108,7 @@ 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];

97
circuits/poseidon.circom Normal file
View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

@ -29,19 +29,12 @@ template SMTHash1() {
signal input value; signal input value;
signal output out; signal output out;
component h1 = MiMC7(91); // Constant component h = MultiMiMC7(2, 91); // Constant
h1.x_in <== 15021630795539610737508582392395901278341266317943626182700664337106830745361; h.in[0] <== key;
h1.k <== 1; h.in[1] <== value;
h.k <== 1;
component h2 = MiMC7(91); out <== h.out;
h2.x_in <== h1.out;
h2.k <== key;
component h3 = MiMC7(91);
h3.x_in <== h2.out;
h3.k <== value;
out <== h3.out;
} }
/* /*
@ -55,13 +48,10 @@ template SMTHash2() {
signal input R; signal input R;
signal output out; signal output out;
component h1 = MiMC7(91); component h = MultiMiMC7(2, 91); // Constant
h1.x_in <== 15021630795539610737508582392395901278341266317943626182700664337106830745361; h.in[0] <== L;
h1.k <== L; h.in[1] <== R;
h.k <== 0;
component h2 = MiMC7(91); out <== h.out;
h2.x_in <== h1.out;
h2.k <== R;
out <== h2.out;
} }

View File

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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

View File

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

8814
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,39 @@
{ {
"name": "circomlib", "name": "@tornado/circomlib",
"version": "0.0.6", "version": "0.0.21",
"description": "Basic circuits library for Circom", "description": "Basic circuits library for Circom",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
"test": "test" "test": "test"
}, },
"scripts": { "scripts": {
"test": "mocha --max-old-space-size=4000" "test": "mocha --max-old-space-size=4000"
}, },
"keywords": [ "keywords": [
"pedersen", "pedersen",
"hash", "hash",
"ethereum", "ethereum",
"circuit", "circuit",
"circom", "circom",
"zksnark" "zksnark"
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/iden3/circomlib.git" "url": "https://git.tornado.ws/tornado-packages/circomlib.git"
}, },
"author": "0Kims", "author": "0Kims",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"blake-hash": "^1.1.0", "blake-hash": "^1.1.0",
"snarkjs": "0.1.11", "blake2b": "^2.1.3",
"web3": "^1.0.0-beta.36" "@tornado/snarkjs": "0.1.20",
}, "typedarray-to-buffer": "^3.1.5",
"devDependencies": { "web3": "^1.2.11"
"circom": "0.0.24", },
"eslint-plugin-mocha": "^5.2.0", "devDependencies": {
"ganache-cli": "^6.2.3", "circom": "0.0.35",
"mocha": "^5.2.0" "eslint-plugin-mocha": "^5.2.0",
} "ganache-cli": "^6.4.4",
"mocha": "^5.2.0"
}
} }

View File

@ -1,5 +1,5 @@
const bn128 = require("snarkjs").bn128; const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("snarkjs").bigInt; const bigInt = require("@tornado/snarkjs").bigInt;
exports.addPoint = addPoint; exports.addPoint = addPoint;
exports.mulPointEscalar = mulPointEscalar; exports.mulPointEscalar = mulPointEscalar;
@ -7,32 +7,51 @@ exports.inCurve = inCurve;
exports.inSubgroup = inSubgroup; exports.inSubgroup = inSubgroup;
exports.packPoint = packPoint; exports.packPoint = packPoint;
exports.unpackPoint = unpackPoint; exports.unpackPoint = unpackPoint;
exports.Generator = [
bigInt("995203441582195749578291179787384436505546430278305826713579947235728471134"),
bigInt("5472060717959818805561601436314318772137091100104008585924551046643952123905"),
];
exports.Base8 = [ exports.Base8 = [
bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475") bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
]; ];
exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328"); exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328");
exports.subOrder = exports.order.shr(3); exports.subOrder = exports.order.shr(3);
exports.p = bn128.r; exports.p = bn128.r;
exports.A = bigInt("168700");
exports.D = bigInt("168696");
function addPoint(a, b) {
function addPoint(a,b) {
const q = bn128.r; const q = bn128.r;
const cta = bigInt("168700");
const d = bigInt("168696");
const res = []; const res = [];
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
/* does the equivalent of:
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q); res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
*/
res[0] = bigInt(
bigInt(a[0])
.mul(b[1])
.add(bigInt(b[0]).mul(a[1]))
.mul(bigInt(bigInt("1").add(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))
).affine(q);
res[1] = bigInt(
bigInt(a[1])
.mul(b[1])
.sub(exports.A.mul(a[0]).mul(b[0]))
.mul(bigInt(bigInt("1").sub(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))
).affine(q);
return res; return res;
} }
function mulPointEscalar(base, e) { function mulPointEscalar(base, e) {
let res = [bigInt("0"),bigInt("1")]; let res = [bigInt("0"), bigInt("1")];
let rem = bigInt(e); let rem = bigInt(e);
let exp = base; let exp = base;
while (! rem.isZero()) { while (!rem.isZero()) {
if (rem.isOdd()) { if (rem.isOdd()) {
res = addPoint(res, exp); res = addPoint(res, exp);
} }
@ -45,22 +64,17 @@ 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 res[0].equals(bigInt(0)) && res[1].equals(bigInt(1));
} }
function inCurve(P) { function inCurve(P) {
const F = bn128.Fr; const F = bn128.Fr;
const a = bigInt("168700");
const d = bigInt("168696");
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( 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;
F.add(F.mul(a, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), d)))) return false;
return true; return true;
} }
@ -81,19 +95,14 @@ function unpackPoint(_buff) {
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] = bigInt.leBuff2int(buff);
if (P[1].greaterOrEquals(exports.p)) return null; if (P[1].greaterOrEquals(exports.p)) return null;
const a = bigInt("168700");
const d = bigInt("168696");
const y2 = F.square(P[1]); const y2 = F.square(P[1]);
let x = F.sqrt(F.div( let x = F.sqrt(F.div(F.sub(F.one, y2), F.sub(exports.A, F.mul(exports.D, y2))));
F.sub(F.one, y2),
F.sub(a, F.mul(d, y2))));
if (x == null) return null; if (x == null) return null;

View File

@ -1,29 +1,34 @@
const createBlakeHash = require("blake-hash"); const createBlakeHash = require("blake-hash");
const bigInt = require("snarkjs").bigInt; const bigInt = require("@tornado/snarkjs").bigInt;
const babyJub = require("./babyjub"); const babyJub = require("./babyjub");
const pedersenHash = require("./pedersenHash").hash; const pedersenHash = require("./pedersenHash").hash;
const mimc7 = require("./mimc7"); const mimc7 = require("./mimc7");
const poseidon = require("./poseidon.js");
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.signMiMCSponge = signMiMCSponge;
exports.verify = verify; exports.verify = verify;
exports.verifyMiMC = verifyMiMC; exports.verifyMiMC = verifyMiMC;
exports.verifyPoseidon = verifyPoseidon;
exports.verifyMiMCSponge = verifyMiMCSponge;
exports.packSignature = packSignature; 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 = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
return A; return A;
@ -31,11 +36,13 @@ function prv2pub(prv) {
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 = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest(); const rBuff = createBlakeHash("blake512")
.update(Buffer.concat([h1.slice(32, 64), msg]))
.digest();
let r = bigInt.leBuff2int(rBuff); let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder); r = r.mod(babyJub.subOrder);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r); const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
@ -46,18 +53,20 @@ function sign(prv, msg) {
const S = r.add(hm.mul(s)).mod(babyJub.subOrder); const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
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 = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3)); const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = bigInt.leInt2Buff(msg, 32); const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest(); const rBuff = createBlakeHash("blake512")
.update(Buffer.concat([h1.slice(32, 64), msgBuff]))
.digest();
let r = bigInt.leBuff2int(rBuff); let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder); r = r.mod(babyJub.subOrder);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r); const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
@ -65,7 +74,49 @@ function signMiMC(prv, msg) {
const S = r.add(hm.mul(s)).mod(babyJub.subOrder); const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return { return {
R8: R8, R8: R8,
S: S S: S,
};
}
function signMiMCSponge(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0, 32));
const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512")
.update(Buffer.concat([h1.slice(32, 64), msgBuff]))
.digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return {
R8: R8,
S: S,
};
}
function signPoseidon(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0, 32));
const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512")
.update(Buffer.concat([h1.slice(32, 64), msgBuff]))
.digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = poseidon([R8[0], R8[1], A[0], A[1], msg]);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return {
R8: R8,
S: S,
}; };
} }
@ -73,12 +124,12 @@ 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);
@ -98,12 +149,12 @@ 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]);
@ -116,6 +167,50 @@ function verifyMiMC(msg, sig, A) {
return true; return true;
} }
function verifyPoseidon(msg, sig, A) {
// Check parameters
if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length != 2) return false;
if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false;
if (A.length != 2) return false;
if (!babyJub.inCurve(A)) return false;
if (sig.S >= babyJub.subOrder) return false;
const hm = poseidon([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false;
return true;
}
function verifyMiMCSponge(msg, sig, A) {
// Check parameters
if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length != 2) return false;
if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false;
if (A.length != 2) return false;
if (!babyJub.inCurve(A)) return false;
if (sig.S >= babyJub.subOrder) return false;
const hm = mimcsponge.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false;
return true;
}
function packSignature(sig) { function packSignature(sig) {
const R8p = babyJub.packPoint(sig.R8); const R8p = babyJub.packPoint(sig.R8);
const Sp = bigInt.leInt2Buff(sig.S, 32); const Sp = bigInt.leInt2Buff(sig.S, 32);
@ -124,9 +219,7 @@ function packSignature(sig) {
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: bigInt.leBuff2int(sigBuff.slice(32, 64)),
}; };
} }

View File

@ -127,12 +127,16 @@ class Contract {
jmp(label) { jmp(label) {
this._pushLabel(label); if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x56); this.code.push(0x56);
} }
jmpi(label) { jmpi(label) {
this._pushLabel(label); if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x57); this.code.push(0x57);
} }
@ -150,6 +154,17 @@ class Contract {
} }
push(data) { push(data) {
if (typeof data === "number") {
let isNeg;
if (data<0) {
isNeg = true;
data = -data;
}
data = data.toString(16);
if (data.length % 2 == 1) data = "0" + data;
data = "0x" + data;
if (isNeg) data = "-"+data;
}
const d = Web3Utils.hexToBytes(Web3Utils.toHex(data)); const d = Web3Utils.hexToBytes(Web3Utils.toHex(data));
if (d.length == 0 || d.length > 32) { if (d.length == 0 || d.length > 32) {
throw new Error("Assertion failed"); throw new Error("Assertion failed");

572
src/g2_gencontract.js Normal file
View File

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

View File

@ -1,5 +1,5 @@
const bn128 = require("snarkjs").bn128; const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("snarkjs").bigInt; const bigInt = require("@tornado/snarkjs").bigInt;
const Web3Utils = require("web3-utils"); const Web3Utils = require("web3-utils");
const F = bn128.Fr; const F = bn128.Fr;
@ -8,7 +8,7 @@ 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 = bigInt(Web3Utils.toBN(c).toString());
const iv = cn.mod(F.q); const iv = cn.mod(F.q);
return iv; return iv;
@ -19,7 +19,7 @@ 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.q.toString()));
@ -32,22 +32,27 @@ exports.getConstants = (seed, nRounds) => {
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 = bigInt(_x_in);
const k = bigInt(_k); const k = bigInt(_k);
let r; let r;
for (let i=0; i<NROUNDS; i++) { for (let i = 0; i < NROUNDS; i++) {
const c = cts[i]; const c = cts[i];
const t = (i==0) ? F.add(x_in, k) : F.add(F.add(r, k), c); const t = i == 0 ? F.add(x_in, k) : F.add(F.add(r, k), c);
r = F.exp(t, 7); r = F.exp(t, 7);
} }
return F.affine(F.add(r, k)); return F.affine(F.add(r, k));
}; };
exports.multiHash = (arr) => { exports.multiHash = (arr, key) => {
let r = exports.getIV(); let r;
for (let i=0; i<arr.length; i++) { if (typeof key === "undefined") {
r = exports.hash(r, bigInt(arr[i])); r = F.zero;
} else {
r = key;
} }
return r; for (let i = 0; i < arr.length; i++) {
r = F.add(F.add(r, arr[i]), exports.hash(bigInt(arr[i]), r));
}
return F.affine(r);
}; };

86
src/mimcsponge.js Normal file
View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
const bn128 = require("snarkjs").bn128; const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("snarkjs").bigInt; const bigInt = require("@tornado/snarkjs").bigInt;
const babyJub = require("./babyjub"); const babyJub = require("./babyjub");
const createBlakeHash = require("blake-hash"); const createBlakeHash = require("blake-hash");
@ -11,39 +11,39 @@ exports.hash = pedersenHash;
exports.getBasePoint = getBasePoint; exports.getBasePoint = getBasePoint;
function pedersenHash(msg) { function pedersenHash(msg) {
const bitsPerSegment = windowSize*nWindowsPerSegment; const bitsPerSegment = windowSize * nWindowsPerSegment;
const bits = buffer2bits(msg); const bits = buffer2bits(msg);
const nSegments = Math.floor((bits.length - 1)/(windowSize*nWindowsPerSegment)) +1; const nSegments = Math.floor((bits.length - 1) / (windowSize * nWindowsPerSegment)) + 1;
let accP = [bigInt.zero,bigInt.one]; let accP = [bigInt.zero, bigInt.one];
for (let s=0; s<nSegments; s++) { for (let s = 0; s < nSegments; s++) {
let nWindows; let nWindows;
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 = bigInt.zero;
let exp = bigInt.one; let exp = bigInt.one;
for (let w=0; w<nWindows; w++) { for (let w = 0; w < nWindows; w++) {
let o = s*bitsPerSegment + w*windowSize; let o = s * bitsPerSegment + w * windowSize;
let acc = bigInt.one; let acc = bigInt.one;
for (let b=0; ((b<windowSize-1)&&(o<bits.length)) ; b++) { for (let b = 0; b < windowSize - 1 && o < bits.length; b++) {
if (bits[o]) { if (bits[o]) {
acc = acc.add( bigInt.one.shl(b) ); acc = acc.add(bigInt.one.shl(b));
} }
o++; o++;
} }
if (o<bits.length) { if (o < bits.length) {
if (bits[o]) { if (bits[o]) {
acc = acc.neg(); acc = acc.neg();
} }
o++; o++;
} }
escalar = escalar.add(acc.mul(exp)); escalar = escalar.add(acc.mul(exp));
exp = exp.shl(windowSize+1); exp = exp.shl(windowSize + 1);
} }
if (escalar.lesser(bigInt.zero)) { if (escalar.lesser(bigInt.zero)) {
@ -59,13 +59,13 @@ function pedersenHash(msg) {
let bases = []; let bases = [];
function getBasePoint(pointIdx) { function getBasePoint(pointIdx) {
if (pointIdx<bases.length) return bases[pointIdx]; if (pointIdx < bases.length) return bases[pointIdx];
let p= null; let p = null;
let tryIdx = 0; let tryIdx = 0;
while (p==null) { while (p == null) {
const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32); const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32);
const h = createBlakeHash("blake256").update(S).digest(); const h = createBlakeHash("blake256").update(S).digest();
h[31] = h[31] & 0xBF; // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1) h[31] = h[31] & 0xbf; // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1)
p = babyJub.unpackPoint(h); p = babyJub.unpackPoint(h);
tryIdx++; tryIdx++;
} }
@ -82,7 +82,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,21 +91,17 @@ 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;
} }

48
src/poseidon.js Normal file
View File

@ -0,0 +1,48 @@
const assert = require("assert");
const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("@tornado/snarkjs").bigInt;
const F = bn128.Fr;
const { unstringifyBigInts } = require("@tornado/snarkjs");
// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
// 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
// Used like so: sage generate_parameters_grain.sage 1 0 254 2 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
const { C, M } = unstringifyBigInts(require("./poseidon_constants.json"));
// Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8)
// Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py
// And rounded up to nearest integer that divides by t
const N_ROUNDS_F = 8;
const N_ROUNDS_P = 35;
const pow5 = (a) => F.mul(a, F.square(F.square(a, a)));
function poseidon(inputs) {
assert(inputs.length > 0);
assert(inputs.length < 5);
const t = inputs.length + 1;
const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P;
let state = [...inputs.map((a) => bigInt(a)), F.zero];
for (let r = 0; r < nRoundsF + nRoundsP; r++) {
state = state.map((a, i) => F.add(a, bigInt(C[t - 2][r * t + i])));
if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
state = state.map((a) => pow5(a));
} else {
state[0] = pow5(state[0]);
}
// no matrix multiplication in the last round
if (r < nRoundsF + nRoundsP - 1) {
state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(bigInt(M[t - 2][j][i]), a)), F.zero));
}
}
return F.affine(state[0]);
}
module.exports = poseidon;

706
src/poseidon_constants.json Normal file
View File

@ -0,0 +1,706 @@
{
"C": [
[
"0x1083c3a16f6c55c7956a5ce08fb39df23957cc6381c217985d9ba0ae29771100",
"0x1dd8990173e411a3a4dff6710e8c3df9ef8e07216efd610a63b3ce10ab57b8ae",
"0x1f3ff523faa41dab28fd27c47286a6b93fe44a9e993ea1ab3723d17aba78b3de",
"0x2662d2995574e11e58f4ce13e282b6b57c2d7df1681bfef79a0261dc300573fc",
"0x20b3c06fa2b82434f725af0c37efb847324312d182d127fdb2054cfa0da9a8be",
"0x18ff92e6daa7639fc832d97928e4098d84efa47d7ef5c1929e54232960ae32b1",
"0x2c175450b8686e4958e698cf1af0b54e0e912ea93f35be8e8e1c3daebbc034be",
"0x00596181885c32674b20103a1a153744c302cf1fa86ee39e14e2ff9a5f9efcba",
"0x0e21b4330dd8a9563e60ef4ffdbb26b85ae766e867633e58c20932365d273a53",
"0x16eb0a124adc927e3fdae149e1aef43d5ee08693f7dac9aa20b46bb31ae12d1f",
"0x0ba1d75274999eb448de5751b5bd165582205d564c636e8340d2a3fe09e4e01c",
"0x04d615bf7a10c566ae2b198a40bef494bc43e7bbd40baa908bf2ce989d39cb16",
"0x10f7d989ce23d2ec2dc7cb425b603ef0fb09efb7f620a25b4e0187fafaeb364e",
"0x091562ecab7c0dffec5f874d385c6a7f06e10c0ba2d43a6e4958a47b9d369438",
"0x214c48e2dd8005914ef1c20e4e2e73933abc7dde8bf2f87ffee4bacb52110931",
"0x29418d43249c5f094ff06f9bc1b80e21dffbaac1874539e42b40f8dc49facb42",
"0x017c1908a9f8359c1280d6ac4edfdcec6ae060d0d520bf64b183191397999203",
"0x1a01b85c3b8e81a862a90fd72d5989f75683d9573d4865d79228eb8c5a105e93",
"0x261b40b148e35d05c9a231b70f46bd67e973c7e3cb33648e1904cc257d52a4d5",
"0x036eb758e5135f0137fc7ef59c37454e2b86f0fd90932f0e382ae7c97e3b2e35",
"0x2de1f93fc74bfa9f08fae8bb730f8d266d3726892b97db237f703ed3a8817ac2",
"0x2be0f288c7cb40cf6b063559e689775aa6e0837ff4a3a5d3d62f9f14d688c925",
"0x202410f3233bc5ccf8621873ab2827da7a365ffbd5c55d62bed934a2bf441256",
"0x2f4aa966c6aaa0f96b1a2d8c7c6090ac81a390252e2c2eca95b2d9d4f6f60118",
"0x1c8b2beb3bbc01ec6a6f31261215c3d3aa4193322317b2a8f0816369fbd8db0d",
"0x09166d1877b85ed30781d55bd800917958abc8eb14be7acdf7c74dca69b9f293",
"0x054974baac27bad68c2928ad06d711cb424e77509102145b9e5a1b911dc2342c",
"0x08759d0b984c16c5ba432900cf2bd92c4919cdd7e99a10c29cd343f69b460f74",
"0x2a65153ca0dbc6487497126a6ec8a8d014bcb3d1818914865a504404a4ad03a0",
"0x2b1c5d81263028bcf7996584eede3c315789d1f3e205919585145e023cefd30e",
"0x1927d650073030417589aa9047f9b62ee876cca63cde015e24d0bf4894b2978f",
"0x2d76a732e12f3deafda7b22085efef22772cd3de8f7e001bc99088cb81c9b734",
"0x04063f088d29d7e91e72cdbc50afe1835c4b11ed14f769522c86760cbf526d50",
"0x03e3a3a1c937f3c05882148070e9dac6b5915751fbca27c212bf7582441819eb",
"0x0d416931f39d66d2c94f070c54cae280da1c12605fd2256a129696e98f11ccf6",
"0x2bc7ec8d56eaf3c8e0d7695f84cbf898f0155c3ebaf24583af09b0e7154bec1a",
"0x0367eff17e1bddbee7eed78ec874a9a01e6a9a38406108f487662dc60614010b",
"0x08dd17e110dc0768f10866e8ccf53efb5290468cd8afd07430def10ec9a586fd",
"0x218efb40100662ed34129a8246a90398a806f52f5f76e104299092860a7a8888",
"0x1ac99c81cc6f26be5143ea1daccd4eacaa31e3b223f0a6c4dec96633410f197d",
"0x12cd3c8d2ac7f084684109522fb7be0b7531e2acf8d9e7b686e177ea7a0f05d6",
"0x17e4773a46b9bb17843f36f6db850bace2c86aa3376abf06614f62bded94a7b1",
"0x29d767ca1255c6c1b1bce1d68ecfbd596aa77657dfbe4a604235e60449a9ff14",
"0x242b7392dec412813184d8dca1a25147c092f3d7dfd3c0c58174eb4268452cb8",
"0x0ea9a0a62f1db4cf40e5e2db0286e48312eee96e72305cf4f98c5f7d6c2df9e5",
"0x13b3fe8f9d94f4d1bcbbaa26018c2c54fcaf122015c5cb9bfbe7a6694ca718bc",
"0x2208e0ced2039b4140bd1fdc4cdff8568f92ea662ab6588a16c42fd95adc8f39",
"0x1e8616716cf3255c36bdb7b62fe0f9b41c3877aa2df998ab54e8974e017a3537",
"0x038c19e5b3c8c3a6e812190a39e6313b181dc71e065ada3b823547451b8288eb",
"0x2518ab4d82a14c358e67509c46fd78ef736049c9498592e9390fce0e8b42a314",
"0x2c2b623bc30fbc269b3ef27e6a7fd25c2968a321382218ab2548e18ff6ea4b3c",
"0x25fa075323cdc87b1db37b7d42fccf1fd9a7ad6a598085e68e57dd145032c15c",
"0x2f5f009c35bb13a3027067b3bf5881d8c533b67fcb390d162fc406c989575905",
"0x0b8e0cd5cab0e99ca405d6bd1597a9dee6cd3c0dd4e0f6929a1d4d88b42605a3",
"0x104069c2b60c8e4b01890e6992cc841e269636e3c5ab6905a8f4045711c19665",
"0x25d04aa8cab6c80cce8005e027f4bc3b82e91fe2f1ca6e2b652defed5b0af05c",
"0x2cc7d8d1f3deb41e50665cb11ad9e821464a382dd17d2e71fe9d1c52c167427d",
"0x1b176ebf76e8d0d4dd54afe65596621b9af71273e5006cc60cad9819e2a0b87c",
"0x128db0ff4dade1354d6ad7567e59b4aee9341ecf906f2988aaa53f6eff912aa1",
"0x19b85e448cd2bd1cd640922cc2c7ba93441f0bafdb8a38818a5d5a666c0eb921",
"0x0498634a814e0850c5063b301461fff914fb9debe1aa76673bc0dd089e8898a9",
"0x1e0081d167ae36dc04c5359042be8c26af96b4ecd92c398d36a12aa863f23bcc",
"0x26f2231aee75807dbbd2a46279b38e94514b1945517909b93e482feceaab0ac7",
"0x2b81566447dccb12959315088de6e42cabf4a0798110a8c2339e0c6fa35952f7",
"0x106920fdae1cfe63ce0199599d45c4343ae36a016cab57dee1a1bda89788a1d5",
"0x2d1b3979803f4f5ad56b9cfcb41d62c4a30b5f01251dbc845fc0004ffdf9aaee",
"0x0492886098bc8d5601930dd4bc7fabaded741f1acb5e6dceb523a7dfa70958eb",
"0x1b2f4d14a2c0d5908c6176e46d241af50de7927f0bc02d12ca61f4590c040823",
"0x1e792cdeb85952cdeddfc38534e2321f4a566798aa7b7caa7c655404f4aeec44",
"0x29d050fabbb2ec05984df81ed8be2838f94b6cf3819a68a42ffbb66dd4c90641",
"0x222805d8ae12b43cbe30e5be4dba67ff2353b06f4bde6af8a3e7f8860016a047",
"0x20eb248ee0196d8b59886a343afd2fa88960f208ebec71901da094128cbc4725",
"0x22058b95c5f9776d8d3dd8d0c7a922602606ac72d7ac0c3ce353ee0c798c54a1",
"0x22afd288266fa099adeaf954fe2a94b0c05445272ac8b50655677be97b130bee",
"0x25c343fe28997a29309a518d42c63b72c281bc44fcd4bc76d2cb1ad34a3fb59f",
"0x26c9e1c8f49e22d6ac88c7a362513a449e682ab324b5e792eced3c0cf5a41f4a",
"0x2b666c9f3ed397d5bb857215fce16a5de70d844ec6ad0b8e53a70287ee939668",
"0x0193818f6648e494b44941453f1163478525f5cbec6b7fbf7fbcd2f5f370052f",
"0x287663a600dd765c1439d38bb92544aeddcd9959c96868df261f70021f4643e1",
"0x044046628ffff9fb29c8c7d497ea02f9941fb149960b5f2ea48c800bcce85ac3",
"0x26677946fb04e67bf0603bccf418736f976fe326f2351e351a623a49f015950c",
"0x2a79f2df436cc4bf39b2ab08d989ea590d2d1fb85caac9bd8a526dd965b0ab6d",
"0x2177c32e659c0d78c6766c5633e9716e6a3e09b0f16e139985044f6d2d231bfd",
"0x2181f1fbf114eb1033d4727aa2b879e28d034d8197e460798b2d8be106695c25",
"0x1582e0e3ea89e6c7912c2b2ffd9b6de7f960a6a7ee9c27d2ec9d53aaed390656",
"0x2899f6acd826f205c140ac2599496b3a3448dd62e25b076be959cc24b12aa69a"
],
[
"0x211fa1419f2b7b630c9d42ac4dfff1d8201547e24651d10dd4b4988ac06216f6",
"0x18ac51e16e5865ee074806af313b040924f20a76c2a45a76b90aeb07ac438e03",
"0x2906c33d1c67bd9a2ba6ab37ef7aecf377eb3f324ce68be741441faa846133b6",
"0x0d6fdc1a5ff92bedc6919093d495de525266075a273eadea7287b1b4941cf427",
"0x2552b734c5a95e374c8286a1cf7c05975265132ec03487470a513366fb38c5fd",
"0x1a8e88f6d94394599224dba0906142559b388ba2cc168fe97b6af4a85aec2680",
"0x2573ce0ce1273b649d31dd96f1f03f2ec83cf4920b72db75e428707dc1e26db3",
"0x0ce0750d2b6bf2a1251c0c6b496f01f7217a58c4ae1e5bf17a1f884f9c430642",
"0x154735e5f8c0640c2c722fb3dac05c4d603c3e150dd2cd09475d5770159fdeef",
"0x1671d015b9090cd861a5a5ccbba2cbd7a51bf07febdefabeff7b69f4b219ff3f",
"0x2d2fbd76fcfbc5943b16d77456d974a7741165a49187f28efb5d64a7634a4260",
"0x040a119f75e867208bddfaeb55741ebf53a30c7a1affcb8b6cd267c66c054755",
"0x11a3eb9fe3312950bf5cafea6c2b97818825db4389b8ae9408f9c7cb4882665a",
"0x12c9a214894557df9260fee1fd68af4fe37e63234f4b1950fb6302ef5c7602e2",
"0x19fc5d4620dbaeaf5448897edf3bcbfeb3853a9126c7b3c3d5b77ebf5b7fbf21",
"0x257c925a34966aae22eb261d58f97b43f255ae75fd0864fc48e492de7e55becc",
"0x18115b83ed73527d8c1823f98ae53c499a375f99a82064b270a54d35ea9f0ba6",
"0x1002ae120de1a1f4ba32b976d7dd4f4579381ca75f00248c5afbdfd80fe521a3",
"0x24230056009f5af1b7f585fe11ab1af1f4e0529381455573c76094e9828c7cc1",
"0x2fefc9ed5c4feb1474dcdd8b11184afdfb5c4663cf077c81c8c2f118f101c583",
"0x121991b5b076111411145f18534359541107182407d3981d463a10a6c04f5f04",
"0x161a5dc3f5e215684236c228529d96b6cae2af12fce8c281ae7c5ae13251cf0d",
"0x1b7cde8e1bf7f5df08a8fc322f21af95a44f9d782a5d74de4b12b3cac52d3d18",
"0x1efcd1c5767a2ce97fa08064888beb441feb80d799f939d284790268313e0cb8",
"0x1516c91480500fb959576c060a50df5e5c13b86e39089be8fad5a3017c19fef1",
"0x1a5acefb238a038e8567c0f8a98840870c17b9e2841f6de8a75b4ec765fdc74e",
"0x26f743f547ba08bb0a3800e83d37a508063c10ab415fd1c6b71fc3e642e27804",
"0x0439c5460f9710db5ef74e5e4ecfbbab6c92d81e1bef048af2ba990af6a96412",
"0x0b1cdb26cef7f77835ba81f23832acbe2cc8ad11311982f0b39d89eaa4ff3d88",
"0x1a4cbeea3894f5692512f2e13ce9034239ef5c203682750d0ed7263c3dc4a05d",
"0x1be2d5efb6c55e9b31ade0b3ca179410702f09ab5c176fd719adb145642dd2fc",
"0x1771f3273703d9c276b6be221b24044ad33a4f04cfc871010b8d1d7b461a5034",
"0x21042bc294c0c181f4c512a6a7d94f3c2782bc28a774ce517efb5c567daa30ed",
"0x0d3ea1bd94a88d6d2a0aaece2f577ee98168284e59138411c47702aa6e9a9df7",
"0x1b2ec4de5e50bbf2c918dce28e1291e7620f28b0cdffec6db9a3afb857d48bec",
"0x052fe3c5b2091f4d9cd772fb788288430ab43c404a9f1afd28f9e8a9e2b539ba",
"0x1ad58f9fd03d9d21c74c08dce54dabdd724b25ce408fe990253740a1dac49186",
"0x11c044f3e07c21ff4a93fd1056d54567510c622ae24cc7c454af294b4d5a7371",
"0x14dc6b7bab9b24d83ab458d326ccb312335c3526cc9dee1802ccb7eb0cb8ee6b",
"0x137cf4c2a4afcc4bcb58a8eda56f5223750a12b2d4e41a66727d797138fbde86",
"0x07d9bc2c364231525ac35618fae08284af5127124da38777326b4ced6e87a0b8",
"0x0f7ead7cfeb697ad5d119032f9e8580cf8dc44c8268402d866ee3ec4f66e723b",
"0x0bb18ee7793d2bd5a3b32a6daf6bce111c1ba770a03c8cb19214cd9315e6b381",
"0x234650e3ac2fb30e34af2d36dc407c891d2093232f6e9d1a5c212bc998560d45",
"0x2eb1745785eb34354cbc25e4d7d20866e97bf688aba5aab3462aa9d53c753308",
"0x1695af57d2faab4077ac86998fa44f39c1b3a9a6e8e3da91293f254ce12fea86",
"0x1b9c5539bab55de67a1feff373539bf20d74b975f0271a77fa67c923529dafc7",
"0x1901b13ce9cbfd15e91fafb059ced8b7936dca44e3fb3a59b9858f80f7e79bb5",
"0x302d415567eda49ff0c3dc812dd4f2f90addb3161b7fc6f604b739a8988e9264",
"0x1ee445f02ed077fce7dcaae404c42c72ce5c73bb60c59ed03192398330f27e40",
"0x14577b4a2afc653d9193cf40100e439ed67b26be2a9c1dcc4c53f29fcce478ef",
"0x0f70ff1275eec4602dcbdd315329e51316e39bcf6ce618b8cf49b9d0b9cfaef8",
"0x2e26e4b699b1fabd0b7bb94ae902ce38f8e4be6b723b02918b59288fe36c6153",
"0x0596a8f8be07116754d6b2664f7759ca2a81dcc3f05f89977e04b0fa3e424aa1",
"0x050b34c574517ab6ac58b491774c7fa2572951c4c0c0cfdbd1ca46242da8b48d",
"0x17a32f1c2ed7875f416eb3c3bc5296085c0f95cf8fc91429a81010beff1aeda3",
"0x08c7b7dd56ffae4496dad107e585670dff7919514bf2dfa8572df8d019938cdc",
"0x1041cb8c6d4155e3f11ea4f4dcaac28874b20400d511c166108580f5b4e1ea5d",
"0x1b19cb3e41e9c29970a4123c4d0c834f19216a277a03caceb457463bf353ca1a",
"0x2e4680a4ac50cfc484bf0bc75f064e0cce85e5bf037908a1f4e54a66f1ae9a0c",
"0x114fc9070b4811217501ab969073e570d01ebf4b10b3ce9fa09007aed14d7b3b",
"0x12a97a6552f3cb4aed117f029d2fb8a26cc6142887d84579404893055fce6be0",
"0x1dda8d69266fd4f1ce596778727e55262f555f158ba453321bdb34e18d835dad",
"0x1aeeba0b8ee533f104ef753a049e0495ab8d2832d271580be677568dd54dbc8b",
"0x087d80c02cb866a6e48757dd0715ae16de850983a156e249e898c0a099feb2c2",
"0x210cd88db2e56f4197fd2e78fce4a33f955fadfb9db3f3442b864016e5ff30d6",
"0x132b7ca535bcb9e3c5b2c218a2a6ddf99900436d2d68bc7c5a155715db5bfc03",
"0x2c101ab309253551ba608b65def31b407a7d13b157818c1f1edfa96a8b3075bc",
"0x25a13366ee7d2cef6fc1365c349f2eab64dbb154f492885d950ab1494868125e",
"0x2f1a3b3695d525788fddb27219d3092eb8afbbec37d5e097bdfb1bcb1aa9bdf1",
"0x12eb5e560c681856fb6af9f6ea072fd7eb82aad57e88af7bfc7f0b075741efcd",
"0x11581e2e8eed45d13baa42e711b93639d3ae5247c69914272cc2ff6058d3acf3",
"0x0c0c34dae8f3bf7007564fabedd283cb025d64f4e8f88a47b4e37bd89b5c6fd1",
"0x05b47ec45a81568e0730df30770377053d5465341d3309a87fca8604fd1c35e4",
"0x09755b27f172ae86cffad94e78fab9d8b740d6891efe2cba55366e61c0c98206",
"0x0600a9f4ff5c9d8bccd4952029aae6f6e2004d7baaabd9040e3b4216e2cc4041",
"0x2864302ac98fdbe4a29cc57c83ee1b60e0a7ef59519bf20a556d7b77a0bdbf38",
"0x14a0943541647294c4d0442506d1896c909ac78166985ffc45a933b4c5a47f39",
"0x14f026e852ce5c5fd9a55741e4e33d0a6d8d45ea190894530871cf9803101b20",
"0x0b7ffc49fc5601a646564e4327ecf8061ff6f4982d5d6dd85699e6a589f59861",
"0x11ecc2afb666b89fa519954da8f1e775a16657786839dd15ce4e18b6114a17af",
"0x0266048d728717bb6736cec6bb53a48d53c34866376fdeb1368616540dd57b38",
"0x05d0653ece676b876c63c85abc06d14e4b4fd5bb959f24ff226aac3ef33c0604",
"0x04888bfa7c5cd40a493a9089b36341207c2302edfd283e723633e335ed4839d3",
"0x0c5df4b6cf3b9215e3d6342ffa2df33ede670db50dc2477a03d6d3063e64fdd1",
"0x2cdb43576702ed93262567dc50237ce620a628d4c3e4eba9eb863485db2a9a4f",
"0x1da473b175874ba5f44bb5ef6136b6a4e817140aa5d5fb30d7a7e4f05af44e5d",
"0x17c4bddb0c8bf05980c312557057790f8e9aa1345d0b2b24f652a72785199f16",
"0x156ff7be6a05828d933945b04155dd3cd1070d810843b334083850a8de293d73",
"0x0d37d0e3108d1f3f1b1677dd4174acc0afc962f54215fee14e32bceb8337aa2e",
"0x11ddb1a440a4d076942d52f68bf0ef70800aec60ef150216d242abdfa84b5c97",
"0x163bea67b48bc43fd3d96705cbef764c4db1b61041f02510abb546cb6dc4806a",
"0x22aa414c469933375bf3b583210ec1742b997ca4f121f62df210056624ecf304",
"0x2d7f90267ae5b326c3d007fac1f761190f1a2d2213c8a1915057705b888b3b42",
"0x103fba0819fa863fe82f18070149ed5b059825ca663e57ffc8e025f5f954ba9b",
"0x043ff968ce318a4219dc8b1b3e9b1d0b5770696dde2e8b6e4f5ede0cc630a4f9",
"0x0b3ac488943b0685151bda44aa6adb5b645fdf95d63c25bfa118729900b69551",
"0x1151bf21881610c2a1fccc5f25a8d24aadd5bab7620a456f542d2a27fb9d8333",
"0x0bfd02387911be559bbddb6072937662c15b2a5e2c190a5364f26ccf51d04def",
"0x1e23be22f022d1cd8a90938d552875a52efdccb8d51bfcd9993bae65f19f437a",
"0x2d64657d2392bab3d55a6f03f876da7325eaa8b26d4627623ee323280150d5c4",
"0x28398c2867f3e75c79a3d183ebc74757b0dbd5976375d5de3c4643d4696f9bba",
"0x2fe98cb56d56da5166550e3d62da69427818797fd678eb85548b3955bd9a8dde",
"0x15f2acb43b89e025ad031c3331b0cfe815ecdd34ce38c164d4ec65c1097fc152",
"0x1dc5214afb325fc97ec49b140c7362e48f916b5fefff40d1d4357a6e8a64afb1",
"0x0bf98e88782e75a8ce25deb8208bebd3dcde4a4d8c0d7c95b320f98ae37bde87",
"0x1c8e78dbdc499fe504d6637fb592695048f80d471e413f50cd13beb6008a8391",
"0x23445d2bc07a0705a84ad107f5ffef149f3deb0dc8993dff9ac7cb5d307cd0e0",
"0x165455fb86eb06686440c8c2289c446541e676341d95bf85105d08e994a2c9d0",
"0x177bd958941329e30138b30781b1686c1531212a075f0166494b226bd667fdda",
"0x1d9cac387b77178d0118f881ac7ca94f79cb8052a59235a42cf869b9290da2f8",
"0x294c0bc45d475a1175b9d7977763d26b155f39c6043ea67c7c528bd0ed4e7bb5",
"0x2338a930f2cae293c3dbd1386d74b5b7d88b8ad739bd54ae5d720fb697e0b5e5",
"0x1fb1f893d955103c39e9f5cba64bc7ff4a078f73f386d9c070179cc279881f51",
"0x04e7ce1c09295df1f4c16216867451d9424f33ade5e0274bda0cb417a729a7f6",
"0x12f5ceb80784cbc5631e1ca115f5b55dba3c4315cfbc4f3488eebc776194a3dc",
"0x0f6f9f33c1f40f141caea00e1b2acf51f41fe58ae14aa03ccd7d926bbe02148f",
"0x1be83122d94ce0deed510a78f30acd81764a4ea1b13acb7ad4ea3d481d4df954",
"0x0d80a6a155fb12ca328331a46dc758011bab2e4007a5e9a79b5d615131d3444a",
"0x194acfa387c01b063aa4a33551ed7cb9a5a217d4ffd0ed1639140db2b742470e",
"0x0b33f09047bc972a94494173ac41f3d7df5aa1fdd42d7217474d531e8ef6af68",
"0x0df147663bc28d9b200afd361dc6189a18b74ff6e4ec99c31d7f47db967a41e9",
"0x2a4338b94beca683c00f47c48bcafcbfe66babdaa51b27ffb32d17378aa78597",
"0x03afe0efd0394501f0fc763b3f1019182e62c0255e34d82a76719a5c6dcfcd06",
"0x1e1d4dcf35b59905dc2275f3a37f84b6dae9650988eea92180aee8f45fefba5b",
"0x2a4ae8053cb5aa44efa7af3f76957e572de37def354c04ae6eb0e17dc9f38012",
"0x26b6da57dd2d67f63611cf269d31b28080a92b00567894e3d56b6df783e02ec0",
"0x1d0b3ca820d67c20f0a83efd9a9c50a5ef2183813dc4d658329fe39435ce5710",
"0x1505b4c73b4b6b7d0d0e84d1cef6b86bc62c0d6eb3c745570ab1beb0669de635"
],
[
"0x0769209ddbe93ac17371b60ada48a8b0baf8c2df826d0c60791701122abb3647",
"0x08ef53e225e568f8c2957adf5e2418106f57809c8370793fb3ccac0eb9c4ef12",
"0x0f67730966f094a9ae0ece540cf1ed527cc31c5f161107ce2146ff11f6b6dcdf",
"0x2a2c892eca22e361229c79ac5dc2d9aab2ae508ed5f70b9832f0557ec40aabc3",
"0x039c7ef7c29f809073e30f2591c4ff9858f8d498e233f3883dacd7d6e7570be6",
"0x26ad7dce66a9a95a2b92d1633da3f33587a46117f4c26bc642c808b86b925a50",
"0x294402ea191b6b02d558c2f860e6e11898efc5cac4214d6eaf78bf046b424da7",
"0x200cc1d8d4d6f4a22934248446129b2082ebcac73dc9477599f5efcd8f092b7f",
"0x031b696ba36be3334afaa13168f5a212cb222a5a43dceb67ef2f90def1f2a3ac",
"0x22405ea030cbd6aea6efbc202372454f3cb7315bb24ec7d273569499cf602072",
"0x0e892bb94be4ddb0e13900727efbe6545a7cdaf7837d2e8aa91c085416f4a08b",
"0x2884ab441638fd7622aedc70b5a338450962e57e801975a887c28608a3f6f3d8",
"0x2ea66506abc2e2a5536857d8a372510a5dfd44005813a53d13a83eb3e30caff5",
"0x0fe3e93c274dfb0164a3479d77be40f51fbd808a27068da1e6d633566f5ad4b4",
"0x1b64728c657615de184eabf173ebd624e2eeba23e04c4a818be2e7ceef50d2b2",
"0x2c5d33d430dfddb329dab768eacff9d0be4dc9d638d171a835b72f2630fc07a3",
"0x00775ecd42283f8a4782a1a8e101c59df926ecaf123c83a569872cc8c1e3e955",
"0x2dd915162db8286e7863f207e5116c30539aa05753fa157dd2f3b07b6dfe11d0",
"0x1452f77a0c98817d3834aa29d6dceb1fd078b8873a02b33e650d3d9a463f4d7d",
"0x2bc056180a81b77fcbbf620aa8453ca644931dd432030390162525a596bc380b",
"0x0b3c1e2cb0607e12103406681be5635236551aa286f2261ec88f27a7ff16a7a9",
"0x1e7032ee33c3d1fa6d8d24f1307f53cb33461822f2717913ca654c0e3a13ab04",
"0x0bd2dd98fc4a8af526799f197c315857d71b0740f9a5274c4e3c4e269af0718c",
"0x142e9259f139ab5b18345dba3b11d4ea7ba6483cf28163b603674527073cdc2f",
"0x28bc36ae9e257061fcab76ad2114d96f29bdc78dc36bc65bc94328213e5ec615",
"0x274dedce47e3d3ad192b0d48e25c1e83c68d78318d2538d787b3a79b143cfaa5",
"0x172ee8a327ff74dd9910f098513499eace293d9276dd4ad9b01bed9a5fdd499b",
"0x27e7c5263cf192368bac114666c8adb002a01def45fbf084e3fb1781d37fa17a",
"0x2bda40b3cb61f7868ea66a588423000121bd08ac139e5bb92717fd427e15bbc6",
"0x26fac827cf9e87cd9f46a055ca32db3055c68f8e7097f1907b27e78197f6c4dd",
"0x271e74c38c0bc0b5f904e1459fafe0032ae2b3a27679fb8bdf8fcfd9294ff1f5",
"0x25da79c356d14b424f40e8052b8168c7dc4d938d181c2caaca27619f12d210ee",
"0x1e699abd2c6508eae9bd6a9a282e5513c003dd642dd262d2e17f79f09bdf6bd9",
"0x1ee81815c3be0406b2a9cff25d6f668d9ff89d3f795ca260c7187547cf09e79e",
"0x21c26c8c318b88a969c93cd35c7d227fcf0d69867238695726f90dffcf938279",
"0x14013837d5e3e65ea5155e016e3bddcd575fd584e4e61bbbf295f88fafd8fafa",
"0x154198f9c749177ed41262a5906028d7fe7ac4c6c808865a85816ef44824de23",
"0x1e59f9ee9c83ee78c55c6bec8201f28966beb0c5c11b54ffa01c6451f7a57210",
"0x2558c2e976422214f0dc5a2d2ff180de2628f1a18645da52f02b5e6f846f9504",
"0x0043de4604c7bd1ced85922717d06992924c23f4149f844be9bf6dd9c60f3388",
"0x282947ab201839e628460e16d3d31fad868bec724f263969b3d0c69e9e8bada6",
"0x0a1ada5b5b5018481015fbe3c43c38b44c7b67804f50bbe4952812372603c935",
"0x12d7c76e2833a9f8f57a17e7118ff6666581503026cc1c7a7655ccbb514e516e",
"0x24576880cf40f29a0fc19df8ed0239cfcc150e11b800aa880f6289bebd89a013",
"0x1c7590758c8996f2119af7cef10df7c1cf9d8c1dc388975e830b50680b09d7c4",
"0x2c9096f0f659ee66751cf179cdfe5af5470c6845335de41a3ade2111d9330152",
"0x0ce33a79644c079faa54139a5074943790985a7c6936aa2d3ea97fcadb8d64eb",
"0x0ffba00c11bbb7e6070153b817c9ab5acaeef3306cb05bb8feb5d54fe89ff8be",
"0x15a15cc692ed7bf420df399c9d14e5ff9758a6c7db3c5c097063217b4c6c4f1f",
"0x2214373b87f53cb1d4e91aa21d2e607e83c7ba2a61de8d32c54db7050e9fc17a",
"0x1f0ba195d267de887b51cbdc77e6c77a5c055a625e76c5a22ccbb8cc9bb15539",
"0x2f3b29c072d8cd7c1a673c6759fd58e34dbc2075dae7fd5ebde784113d61755a",
"0x23df997a7ef29ad9a5fc7cc21937c9977a73247434821ff60b31ef0170ed17a4",
"0x1928275de0e4fb64134721b14ab3d99f94b1c268368c1167b2b39ab30e308972",
"0x2bdfec339abdfc11fd5a9f48dceef79a463be5074df37bf00893c83f4b20cc0b",
"0x266134d4d26103883f7f429ed07fbed19bb0e17904cf03eda9da117f8c0f4e1a",
"0x0471a32e2cb225ba86c91cb136309cb462d49c9045a4d4d61e00de27e6ae3ea4",
"0x2c56d2388857121e91cea207347f0e5449b8f7d4bfcdd0c8d71872a5b223ba58",
"0x2acc967f4e0cda77f4f3578b2e463848895b31e7607dbe33e8a1f92a17ff1f2e",
"0x1a891c55471f9da7f6d6125219a3b47eef6560c0fd64dca3177e1efc9b681267",
"0x01f6674fb43a263d7e6bc9b5c02264b61fe779d65e28b68c2b4db7cb39cc94df",
"0x07bd8e87fd3c9d91bc1341cf7edde51781bc51834aa0e3b6a57a830a7e93b83b",
"0x17d9fa87ca04d5451aede41b787ed0313aeb5f1a5f4effb914820aeacf0af8cc",
"0x0793d4a71e22db2909586a0caeb15bb2edfa0eb1237ae62fa90033d45c9921b6",
"0x2e36dff4ef06152e28de7355e3c5e25f10c0da1dd9c639c7aea03e6d8c2e27a9",
"0x11ac31fa48899db062624788cfda7840b346854f90dd5a45be2496bf304e6131",
"0x2655ee18d2a0ff7ea24b51fc3d465eed4b5b579f0d7c8c1ee1c0e385f53ccfa8",
"0x01dfa376e1f3fa01a5efb6d4c79ec70fbc7a07a7ee7458f879da75e64d75ee5b",
"0x274eed37c69fb44ab5c9da14719d85bdde627967d14d460c7d44f7f32000d1e4",
"0x04fae3f7994206170e657f4064b91fd43f7f0a5542e333dbabaa60e2470fbc60",
"0x3045e0d8b192fd61f35a9b5369bbff3ae2cd4708ffe02e8f919230e428c5761a",
"0x14c7c2e746ce0b0f805ac85a3ac01207c9930368f4e8729c4248b433e845c794",
"0x095e5bc71d416d2301417d3693ed6cd5685af11569e2883f80756e683ca609fd",
"0x29c47dd05c547c0f3c194d5bb37ad7e1ba31a6ca4949da0224bc516986b61c78",
"0x221da684f92fd8f01d335437a5d5594849cdb4c0d3e350b2ab9a29e6e6ef93a4",
"0x20ec5172b4edcddeeb1a493cbe2e5561762f2c1d4b41b438bf04bfdfc0402f69",
"0x1b9bcb2aefaebc677c70fd0a4f38c87dc9a739d39bfef6b23b855b1a2e9724cd",
"0x098af3612282c3b93c2c3d782d4731b5cb5241cde22dc665230afd82ff5aa72b",
"0x056bf5e4248f55f2e4c5a800dc1086d82ca98cfd2c4be973e7d4685f612050e9",
"0x2eca3301b4fef07d2e51ae33d6e98033141a34ea1f9821529e73de6a8d67560e",
"0x0ee44ca475a08ce1d7579734cc1ac2ccab00dc92828df9a0a16b17bf0d040f40",
"0x061f484c4e6fbf65812ba4a08dd042b7be0148a35b79c0baab82dbd129e349f2",
"0x270a8d9040ee78734474a3f1c03258cdde4eb2774909520ac95056c48b471d86",
"0x24e8ea7fb0806e1f548e34b85f61fc93f6a33106e1c2837f26900261defeff5a",
"0x17e6f76d7f71216caa967230ba0d20b91991131c31fc03a77a0e4346fac0cc47",
"0x218e63ae07ab39824838ad7423b262f9231446669bd64596a21692938f5fdbd1",
"0x04cec38dafd7be3a0aad26b24b100e25977ad1d6ad471922e39211e54b5b9d78",
"0x14496b72f8518bbf22ae5764f4197df7eb2d4cce04eb2caedf606f1ea4183ab9",
"0x0b15601fc061a468459830764b59a565feeffd1bf6a536f420a7a3e0b7d6ef86",
"0x01955c37d5e6e42ab82c2a57ba398d10f90446acf0d1a98910db6fc7d56524dd",
"0x1bd6de8dc821a746020210e1e5f3dd6dbb41ceddbd73f7d73410181a8cc74d09",
"0x05280c6d461eb9d7967ac91f4af334607802b8db12e141b33a0e30217b693c44",
"0x159b199ca401c0c9b8248631bf39d7d35083b5c2bbbd0d871d3d0d4f3cecc368",
"0x248e2210ed2a826c83fbd6c235dcbbb3d24a7badce71702fcaf08f66b785777b",
"0x0c43b7f0265074447850c22cd3a81726f053f490b261dddc1712ca38a3ebd1b6",
"0x1ae8d611514f4d9e3750f4e66e8c2566e4842b6505e19c45f3eb051a7b6d8bb3",
"0x18eaf3e459dc8ba7d98d3cb2c274f8e902594d4bafebc0757dce1eed8332e8d8",
"0x0c7f13454b2f73791edea658be8d87c6dd72c3c7d26d91182d9c8cc87182edfa",
"0x16e398c145af7ac01167cf56440dc93eaa837cff3cc468de6029f5613270f964",
"0x0a7736c58b3771a259cc813f727d9c7fff087354542175eebf7d44e127c30aad",
"0x13684f6a837c01e824cbd026b6d8c4e61b98df6aeb62d1142df389894788b5ee",
"0x0c4b1c8e9801649077a17bb8eb2d995b3989780c3af7f651004fa2d3f1b8865f",
"0x173602d42c0a38489130960549542bef693e5681947c48657dfceb41b0a6606d",
"0x2389dddac6b2890c7e30504b0fc875ebf8629325206958b69c55c9cb6303edb4",
"0x06c9ca19714c42cc7189005cdb51ef7b2f07484cbe0c151d48c46d47b77a93f2",
"0x167b108ec7a36c0e1bcf9c69e8ecc5a189528813f1737e80209ac99c462159a1",
"0x1871a5f48a8e6bcf2319360dc7885cb1aabc505a3b53a44494e2fc400a62d370",
"0x2e59f862747c1ff8fb961836ce770a2aca5f3b4e0e83e338cd599f9c4e35c1c8",
"0x198c87cac3cc736412bf0d8d2f3a4672e3ecf503b4d7d2e40258e8e64e3eb72e",
"0x2b36f6f2c7130341b2c699532d06d98da2be8ad3b8556dc1bf35375f2dc2cc01",
"0x05ad47418ed404da00ae2493c6c532f783dfd5adc7c4a0f2fa1d60c0e7f4b82f",
"0x2c07656ed2a56f41ae7d387cc0213f440e102742360c44679a6aad8c8263315c",
"0x28fc3ed801e80b8f745f860d2f57447700d4470e31c1ecf0b1f19240085d3218",
"0x2315de5587a5ab1b774763401f71ac6e796055ad5633300abd2e63446bb87563",
"0x2f1f3fdf187e2a6e34a48ec9dc8838b188053dad8e6008c01f627388c8ebfd96",
"0x0c72edc09bff0911637af2314b12f04aa1ab2a8936a0d0932f129bf1e666e1fb",
"0x2061a56cde9b94de146617e1c2d7550a8f1272154eea488149faabcc614ecfb6",
"0x24efce7c9f9dc595ee0286527b581cdf659e5721bd7707e06580f5cf8b0cc513",
"0x2fbb45e2d316c9e9b974c081fda1418bf8de14ccae39daa6532e5e2473ad9b95",
"0x0db1fe4767ca51a7f940cc68ddd576211627ae28319f868ac47cf81163856da5",
"0x07d7947f75ca7eadc86debc9d876cb2421307bbb5518bf82c0e27b2206afdd83",
"0x301687b7aad786b2c3721f665fdf74b8170ab8650d287f842500224e93146169",
"0x0231c466db088e9f696b9aa566fdac7207155e19d5fdbed6524f2c1aec5020c7",
"0x29c11de1b503f5da4bd8b3c3db5fe7d37b3877ca51ad0dcad95152ba819fbfae",
"0x0101217cfe53dc6325a81eb7e920b198a1560cb9c7e5976443860a143f8445e2",
"0x29972ac040a02f55d8d0fd383d0ba147375dd71132b1a91f197292bbe424a41d",
"0x1a7bd39d6d6bec6cf5ddaeebd174bc8eb5b98d0cd36ecdd28e1319e745ba18c4",
"0x0c59b48dfe53bd9fea14943ccc317baab6476d230d29b69f1f6fdc8a7a4e0b80",
"0x16310faca95189f36bcf9855861205fe1af9940667db087684c76da61c759a11",
"0x2a3ca21c40d5bd4edacd339e5ac480354abfa781e43ab96e04c36fbfc9b96991",
"0x03856e1b9ea7eed963383320a289f8e4434ad11184075ec48441b07a6a996cf2",
"0x14bb06da170069f2075e2e98779980f8c25c9afa09b6d9200473b0b4be1dfd0e",
"0x021f6235693e64c3e04019d980f130a8e9e0463a06f20f7b48d70d4e2767df40",
"0x248a11d422e2ba3824f403b12bf91f7c3e1f4cd7df0c8d926f4db7ca088e88c4",
"0x27c83f0074d7f09f5c653402f14e6c237ffe6dc88517708d1a6f22f8fcc5eaa4",
"0x29d69c60e82302690ee548e134e3472c4fdfc0de1980b05a3b16f4bf90b75df3",
"0x16263dd56b3a5d8e1adf78537a59edebe9279a666be8376c0f857dbdf619b3b0",
"0x2faf509e27d009d539ded46f4205be2a4d07990c6c3adaec2774d29f211c333c",
"0x00636fcd12c4cea57010606a3032ec57759c1ef7857908bae6f478f2ce6b1116",
"0x1ae54440ec1448a756b6d17eca423496fc01981d625130f0a34b16406169c628",
"0x087f48ba394023dc06e837328fe9c5c360e8051f7331008f55e6efe703a6e670",
"0x259f66390c6850db70bd9baa0a9af2544f5038fef029dca5859c498359efcdde",
"0x1a320b174924a92e7e1799f926b1a4a8613469713df982d4feb17c469c6b3132",
"0x2cda975460540e7dab62116c6681d9687de10a80135949380a986da2d3b6a93b",
"0x2904eabcec7a95c537f59bf4ec25cb5f61050bc4b385af6a7ed8dc787844e00b",
"0x27ea9cb045a66580707da6934884df14aacf6f77e4196f940e022d3c02962f4b",
"0x2afd7329aa726b450e0687fa7661fcbccd1b4d00f5c63ff56cf71f6e0782b351",
"0x1f70cb2a4b5c22e7597556b55dc9ab3c289b63abb49109e64b3731c4cc899d02",
"0x09d2c500e798e9bd5c97a43a905fd18880ec3ab776c34ae975cd5820b5be6a71",
"0x187868870b76c4af4533bcfef9cfd3a26e89326389e87f79b23f986ef6546b36",
"0x20cf61235eb8a2faf09f62dee581d48e756b7f6f6b0e108abec7d1cb4c340523",
"0x06431aee16b0fbb9a402325fe3e1c78d03b49cf7211b78e122607f24906f74e1",
"0x0ea64a8557885b201149fed02d32539d2270ab155012f543419d66e584f70980",
"0x2f989e96ac7353934bd8333aaffd25900f6d4b78ed5b50d832e35915f20e3c9c",
"0x1f2357fea7a406b651ea80a7ae83f97248b2713a15b689d6b694f4a04464ac3e",
"0x091eadfd9e583cbf346d83b894982a75f827c89bbbfd6473dba601cedbb13dd5",
"0x0c14fd42428144b7b77b93340103fe047998e9c50993da3ddbe328b8bd804f9e",
"0x252da7206be17596eb2ef5bfa94f142b39eb9fdc7f7dc3bda16825e7ccfdd8c1",
"0x2ace67f28e90ecf05b00aca160ad0e5444d3397ef40640081864803a63747e1c",
"0x207aef533b735e20998f6b54574293f8b0e5479e32eff2dc6ea3fd10414db107",
"0x09b3080dbe8fa12b8eec5edc0d55d87fa3425ed591daaf8396f70421b1a0c35a",
"0x1003dc28c13b5737df9ce84ad23480f3393de6024b095ba842d9c8c3d7168a8e",
"0x23618fdc2960f9fa296e65a926573ae39e2c442f819c2ccd2387c1493a1ee57e",
"0x1b12fa3a918da62249968385c65552489c76f8a808f5b28e5a3b1a76a25a8ee6",
"0x087a632fe1f540ecf61722f036f3f6863ae9e5a093da6d4f57156e2e8c6f5f9d",
"0x2b460380d8151ee73eb997fcb89f9b0d63a210ea8cb9f23ae4e0c75346d89a0d",
"0x302e06a0b308b3004b980eece40bc80cdbfd863a284e643ccdb22c359af19241",
"0x13dc02643f54245a7ec529481d59e849f7e82e4328a4f1b0d916308aec44f20e",
"0x01f9ea46bd55b9f52acec310f44a71a389a5ecb20933baddbe29699a70adb6ba",
"0x15c2f7ff0464ec096a3c89e8a6563afc7d290bd50620c57fe0c3f8e2667ce224",
"0x2bb074ae7bd782f9a3aad78192c58d12535da87bb865936065a1c2d8bec0cb03",
"0x1afb2feafdd6b4b18bf120c1bd40a0661d675cb6cdea4ffb935550db66613f66"
],
[
"0x2f519d236ff3908aeed8bc12b6e3204820c18780cda2aa9bf32a675722a943e7",
"0x0d463eca09295bbf17ecbd6c0f1a2ae22e9e971abf332b50f6dc652948130ac9",
"0x04f7b92e174673f12ad94305e211dbc74505cea331c8270bbc0436cfd3f9203d",
"0x0b9ce1d7a1d5702d9cce533fed0eb4efa2d3d5adeb056a0bcfaa8df560e39d65",
"0x05fd9a940ebf8c4f6365146a71cc4d60792afcfe5edfb289ef3a5e0ee7171df5",
"0x0b5644601dcb7f359904a3be22a6726d88c91c83462e2a96eefcb2e0d3aac3b2",
"0x05270c934663d155aa71e7bb2c9bcc6d8dc181ae02c779a1bde958eda5b61398",
"0x1ca3acc7430ca47799891a4c459af74a965256eba9d6940381c1d0bf0a9739a5",
"0x03db72aade768b78c7a6a9ecda0f0f2c6733a0651cf2212e174ea97c01a59c70",
"0x1ad0aa205be150c5621b3fea98b78db2e4b20fecf80034c52e9ae558950dc780",
"0x041dddc69336c714ee7cb998b68d94c5232d4e8d1deeca05ce83b0ed0834cd3f",
"0x2b3e015174c3a6939f08df076b3ba73bbd4f2452100c1821492321175d162b1f",
"0x238e6389e5fb2584c06ed2f534d4d9e2d5d62bb99dfe8add413d809fbdc754d3",
"0x15f4f175fe2ef1101a4f0a34fb73acf4397c3379b1c2924dd94b1dd4d2c6b27a",
"0x04fa37d0ac02626ecd1f192e28acc2ad80f3de4354aa8ebe87471757dbabc9e7",
"0x24deab96a4e96719adf665e11c38a3334d9b47643171a7d814b9dc6fe7382d02",
"0x0a2c7eb8738a61719ce05c72547cfdce9f6ac8770cd64e6556a06c7ae86610c0",
"0x199482b63e5fdf185628c3046f0bf2f7be5d0f256ecd035bc212fc01eea8ffa6",
"0x296cfc7f739a3cf4e9b75994056e2568c6aa52b8333520627bd6b28cf484de9d",
"0x06fdb5a0e6f4e2c7e546bad6b1669db01d9d4e3bff4ee772507563da1ed92dca",
"0x1216f1b2f749f561078eeaf1fc60590a71e33157d0227ac8e796a4042e945ba8",
"0x193fa4aa12acc79be80e6a2424afeb3f4d249566e8a0908c908761758437929e",
"0x12ad33b11810144865ae5391c8f266adc3fa0adb622b90c2ada406253e09eb2b",
"0x1a90d5e1c0578c066529c54f8f37e23109de9159e298cb6c9102c6ccf581a07d",
"0x15af9b019146d04fd7db3dcc25ce29d163fb604f5ce11b8fd507089a8660095b",
"0x124aa9d20b2a15ec73fc6b6eb84b544edc13e9a72309ab080e362563881eb8ff",
"0x183cf3432c6354e3bef6170a32fd653b560748e59b65052512125db3b542ca7a",
"0x263159492b9a836f8d477e6ccf6f2dad9d4bc43eea7241f224314cd356fb07eb",
"0x2ef6717639f7e6a2a0c60da01ce73721b83f6f9fca63ad632a27c5e0d561dc26",
"0x1b85e4a891411168c803d411048f946a167f45edd0b98aea0e96fcf9796a5415",
"0x1712b6d3ab45b45a1a43bbb23ac830235f8fa4c6c057be35b84e77ef366fd89b",
"0x2e97c862eb257de5ef4f71b56bab12b449b3186cb3f4c44ff32c931bd9c3108a",
"0x0500ca19f7690358b983978382d969729008b41a902b03c8254e8a4b863ebe2d",
"0x25ecf7468c3d34ab9aced95fd7f966c7e7fe7ed74ac02c2f33cbf59d182c169a",
"0x061493f05adc4813cb62ea6269e2672c241b4ce0e3658542e4bedc660cb832c8",
"0x077d4ee2b3292e73eb891b51f63b0fc897ddf1095208c65a291f470391eccc8a",
"0x2a1ddaac93b561971f9174611a06273671f80dcf4eb355636577a623f2267239",
"0x28c9d37bc63119f5b846f969452d93c78743ed7c769590d1e2eaff2f7d51b636",
"0x1c12d6672a7c9c525e1ad06e91be238291b6a452298c3f0907b3bbeeee33a75b",
"0x295813176a99d708f66de0dd6a79790c1049113c1a9589f58e29aef2431dc3d0",
"0x11cf1b0b429cdde5235a2fa4044a75fa29d464d422bcec4cd5a77b2a70996952",
"0x26cd23abd3084eb97652a0bdfa0675107c27d021a797ffd85c3935035e82c708",
"0x0c98e951acef5ecdf322fd11adf84e1237fd7a2856f5d611185677e064e59a7c",
"0x0f65e0d787c7a80daffa6fcec8e4333baf1b7e536dc26da1617bf8d33fd571ea",
"0x0a6af46169c405b7aefa2369aea2437e83a5f936e21b2c5bdd40c4c229691035",
"0x2c5d17722f1e857bc53fb954a1c617be89f79f666e7d42e5cd289bd1f6c2c253",
"0x05ed375b0a7340fdd67b5a6e02e9d7f8cee95207cc1f021a98c9f026b6b8263a",
"0x05c43b6a0449ae8aba7f7ef495f81f9b1172e2e33d6b45641c85ac438f867072",
"0x0632e9aaccb645ff09e9a71c0bdc98bb8525d16dc0808089288084dc6a37239d",
"0x020115cdd5958aee185af3281eb02700cb22c680fea57e0e24ddcfea04e4ce44",
"0x130ed2b41ae4fa1bcb39907d9213b816fb5be6f78c8b33f81037c6c82351ad6e",
"0x198b2b80ff15fe2af3c414b89c4fab453017cadce1b42986a9064069b91e9d1a",
"0x26a02e2e22afd030083fac312c3ea5ef2b8261a789a3cdb14e0f59344710c7d6",
"0x1e972689e841a22940b918fb25a4fd47bc016bb627359e0f8efb982516900250",
"0x1719a91dcbaa2591741e3c6e8c813071dbb249caed013b1a49a09c6337588388",
"0x07ae0bd9a15c6093e83d203cee422cabaac2b1480b199a5a01f3b6bae8943c22",
"0x0335138c841a80c3374731753ec839f6240bd2a965d10971c20a5573c6700a61",
"0x0bccc625cafac996fc66d3d723e2efcbc7291c5c2ee94ec4308719f0f682bae9",
"0x1aca016e7c2b5f0fa4a3c8466822be48e461a2f96daa05a7e6bd65447ceedc20",
"0x228ca2efdfb5fc0371bef36dae53fb3e6743f7f5ac32773eb9daa1fff9ad5280",
"0x0abd2713ba22c5a0284319c09fdb52831253c15a3dd8bec25ef562dfd902ffb3",
"0x0c20a2af2b35bffc6c6b267df78c0ea1e9382f9508fa665f8fdc0836a4d5da0a",
"0x0da1ed20c40a98057ee6df9f8e55d6e0936ec8b1ded7ae68ee97c9329310c346",
"0x2b662b17eae86aef2137d9f669f08960d262f221708c49fe793884326c92aae8",
"0x00892d01420c44d4b5266e98d3963b613ee8b005a2b1c9cd20082a3d49f595ff",
"0x1e7068ac5f13d9a2e8b46d99b5d5f35f2d3de6de8bd81c8e78668ef467f05160",
"0x04c946cb36ed8b5935362ac33029dedd33cd3d62f638eb74f1834b1fb83060a2",
"0x0bfaea8cdbcbab42a9e8bf92141c329651a604055f555663fe983c1b0646d051",
"0x0ed5e5e518343fbbc0fb70386a6df1945679b165d1a65afc6c825315775694fb",
"0x266d7fa0ddc680255cb75a0cbaf4d586f8edee107e2d3d5ad5ce90b142b9812d",
"0x038632d442ca8a88fb33a37ffde668cc8c499b6eadc40af5b3f237f2ab62da06",
"0x18e36f3104718c8e25493c8d0410aec2779af54c23014de0feb6f96f34ee52bc",
"0x231745182598bb764367a8490e1d61c3d3db1699a7a54212144ffafddd37712e",
"0x298d6012d765ff5ca0e313106417ffe9a7f08185d7623b37abacf91ab0aebfb9",
"0x19f2674561197e8fe58d8547d3926ba2702999f9f5147fe77445ad75c336d683",
"0x2b15c22e56345b557175c1eca4279b909af4e965d941cc1b5352fe2d3229ab0a",
"0x289ad5b36e4dd22b2c92a95b1e3ef574601e8117ffd22ac0a0389b478f80572f",
"0x214626bdeae25c53e26eb6f7f65fa6bb4c83469735f03166061c245d00ca86d5",
"0x24f3525dabc6b7f53d021138eb9dc49133d046b851d4781ebbc94b05dec248d7",
"0x2791a40b5946f478a90d4e5efb36d8bba14f53e401f87056af2d55a6b7df5cf8",
"0x09318d2f819b522b0a847e5038118e65718f361f8947580cfa8b8b361ce5e8ee",
"0x219d8daacb4cef1375b06392f9220f1d204f0e88499c108c961de46fdb5d8fe5",
"0x268a3e49958e2d7a588b7276b41a2c7f18989d599e80dc85e39c7308d5e92f69",
"0x10d8226869f3e198f804bc9d51901e5bd24d824e03458fc549a6a16e5c62125d",
"0x0660a3ff70a9db2da72081518d7a9b473b054a2508b047a5c363f97931dfea83",
"0x031271a704e1a00bc2b860da159913bcaad3c8acf27c1fa3b28ce2c33841ffab",
"0x07eddfe02b81044a908a5f7d73f6f461aad59a29f1b55b41a2dfadb7968b4a07",
"0x1f93630d8bedc406368b348a7006ec4806b4dbadef3e7a022ac8e51f779f2828",
"0x085a2c147a95c4414b1b67df4fd75753f44d02cc54148ddbd6d771d3084f4cd9",
"0x02b256807b01a9aa040f02c771397590bad8d20df2520d6ff24401663a3d5f8d",
"0x1dc83ce1042b12070a2998b52f2d88a4fc2a7d324d6d00664a3bd617bbb4ae85",
"0x18233d96215c73f726760194809c1a4dd405a32ebe67620ae85f2f2b96862eaa",
"0x0c7add4ec9ce9e2fea0dbba3833f9e1260249cc855df6a2a1557740b9c477cd9",
"0x0eb7a2b2438ca0b3459f24bf4bfa719f08272a6f27c747cc151a482ad8fb3be0",
"0x0167e7ef87785ac6c577e395e475209462b7cfa832cebf6c2add446ecec58878",
"0x1e52ca68bd85803046e5036b236a6886aaf8fdfeb2bf41ab82c1e0eedf045a81",
"0x0875d6ad908a0e1b77b24422a99aba983c8eaee3a2ed63fe5d476d58890bf06b",
"0x1bd4fdd412c233e4ad6558382c336ce03b154baf81846aeb4977c1213c8d5618",
"0x13ad247e3e1eefb651b3ec25c7dc4aa9df5448c73adb7b683d96a6d66bfa3aa6",
"0x02bdda4b91162dfd2c210bae56f9252170f555fe3bb6b21a177cfd04eb660803",
"0x00e8b60d2341985c55753fb8e4ccbfa8b99692463b4e0a11a1b475b688480c4f",
"0x19cf84ff8a5184368bb6a6f20b3fe1380600b45758ad3cf7b88bfdee2ec61b49",
"0x25abb85753668de0457dfe38099de2bd1c47978b344ca58f7c2c0c02201997e5",
"0x24710d523c762410a2d4924464743478feb594b14f12851a541cd3d3ba75b247",
"0x29ffbe3a4a3087d01b5acb88009abde722a89296b420c9f52449128bc9fdc34c",
"0x0ec3577cf043961d009493d183d50720d25e49fbc8f9adf62ba72aecd781dc1a",
"0x26c113117e795ef7b8d7773f81912c80aabc19116464aa8fb12241ceb5dcc2ee",
"0x07d5f46533b2a2e88682c6fda0bc7cf8a0c70b160a83a967618c65b59c9001a1",
"0x23d54f9c4c3e67d924d26da36276acbfe02cb4f9ced76f4fe12e0a73ba803343",
"0x10cd6323749cc45b68d78b9d749dc4a3faf38bc329b4b29e4f80eb3dfe3e039f",
"0x29f2a6f05e471ef11fc76dfaf7732a9b03a69ebe58720dc54d95e8d66aac9601",
"0x188cf3ecdef093b77624ab20d47ae582fd0d9dae59987f7fd4c173900d50196e",
"0x27a03aefe417b4f88a4a811b2ef281b1b8eddd2ac9ea62560a86af54eb5f5f31",
"0x0990e3d736045f5fc126258b0bae3710d70a9a7fdd4a03834d6ba3e1c41645e1",
"0x01d0c03377b6c3e03a1cadb8f00aa6b3e856a5b12e9ffacd829a2e17eb1e57ff",
"0x0b3551f6faa579f6fec4b813a862f196a14f15357371499f98eeb9cfd9970acb",
"0x0f9444b6c7eafdb309da46679dcbab14a65268c58757e5ca9f76143205985949",
"0x14db8cfa9979850abc02c0b49b33e22dc4ba8d4557c37a4bbce9a2645a553934",
"0x08d995c609e1701dbc84e53f3bf3889beca275d0bf20de975ab7bd11f29168c1",
"0x22ee92f4ec09f2174537985f561d785c4942a28cefe4b1a6f2d736579b4306d5",
"0x0deac3e417c3e702add7e11e9a9076d2b12d6cd4c432b7bf199c492feaac78cf",
"0x215d0c99a7fb3227054ecbb04b39dd2e85a33be4b2a78455322b9a8209a7839a",
"0x144dfd27491018d95745bfa263ab11b6f6865c050700c8bc38ef6196973d4e82",
"0x2e4c9e84e7b07e659bfc709a3de211b454d028e4a74120b07f130f461210548b",
"0x260666b80f1d865b7ad6d98dca26cf2c1a5bcbd87d9d9d19673ca4db486652a3",
"0x21c2ef3ae808bc3b0c1ba5eb6fc594b6e383c1bcb05006b64fad6c3483aaa96f",
"0x1ea451ecce4adee6b1682153f4038d177e50944ae9cb55b4e0535c24f6911b55",
"0x0f8df7e95aeaaf0fd8f61c50a0b282c6df25fc884d707ab96936be3d87f75de2",
"0x2d9abc0ebc4284989c7cc7f6dac8b356c0ed4e6839d8a43d5783dd8dfb57acfb",
"0x1e851335f8cfaa72342db1d1cd9575d2190c671423fd5cde851051c0dd5746f7",
"0x189dd6ddeb39ca53540ecd57bfbdebc075f7abf25b1ce4f9ede0f093bee3e6cb",
"0x1e8e34d095df1eb92444afc3f89b848905b8c2ac63d3805af088e67ff695d5c8",
"0x187eb13c7f95499b8ebaa0c5100fbacb1184a61e62ca9be6601c3af34c0d0804",
"0x269000bab546cb9f4e54adc5adb3b08f6f45bb19114977cced6e5035b605e4cc",
"0x1a4273c2ff4b80a91443e25d1f0ad568ba4586cdb8bd9e412be1fa40ef2f10a2",
"0x0b2c26399060c182a27682869690bd61c9395795349b873b16ceceed98ccdb0f",
"0x187370c642e5fd783fba4b7cc7bf03341f6b8efd23fe8c82cf7b627f91bedeb2",
"0x1162e4855ebcea47475ef6016b2129f42c06dd2262eee9f43e5bdb024cb3e3ab",
"0x1cb4e22d4b8bfd114320b70e2edc8ec4d077820dc7caaaf3983e0791f77c5afd",
"0x0b9246a297596e5b285d111c1da4dec37a96a56fe1f3532d45b51cd06da11582",
"0x06b14752752ad07b43a8daa7963c3c0d9a522671c61f49e7aaa77373839a3ca3",
"0x21fb7f7798350e11d807e4bac95162f8cbba7f5528f030f22682de559952b444",
"0x26eaf07e3bb2ad298141174e39808d12d3e8359624d57dcd4bd40d517c889f41",
"0x1bc988e5a7e158d7367f959b6d877986fb0696e1e9c1f1a59462086d1b4a4a9d",
"0x1665b29cab9b55ffc5bf2376609265ed9a8f6b8b607636df26ce4f2bc3a6ae56",
"0x27b2623f1a2a2d769759232e2cff279d0916efd69efb8c8392a402192e4469a5",
"0x0b11a77df9412a21a871a117cb027da0f8af823131f60add22ed9c4a2928f332",
"0x1ce9f86e393b0e2d0ddf1270803c496284ded0b35f69972031a5ceaa360c5af4",
"0x2c97533771428606f2bb3d8cc740ee47c66018fe54fecc8b567483befaa3d898",
"0x1a257215c9ffb1465ec62562d98025bf33a23fcbb683f89d53a118d060c11cf8",
"0x25fd8cfe274fe98e6e3ae98aaaab03ade4d1c56cef810df237e42d324184d86d",
"0x286cea2aeabf040c9bf2160ce8ca90ac489f0098982d790fb42ab33345cfcfe7",
"0x124c35aa339e0ee2c2046b2f5f0367ce4eedfeb8e3c6c94b7f6460dee9e51099",
"0x1665dee3f142dbe8f44d85e4d93b39fbf1c86e7a797a8d55932d81a3efa516a4",
"0x12cc10508db3a8b2f2c53afe91252ddf4bbcf5e4e2738fa8e699edb9fa3df62c",
"0x1ef850e8b97b2c0560843986acfff158d75aa9210acc6420e9650b56dd9b3c4b",
"0x2afe8e7f5b4525a1c015f8ace5dd35e62cf89e2232b90eb3eb011d082a114a37",
"0x2e9c398649994f32c3cd610bc6546bc05aab563fbba41d3124e255ff45e1c940",
"0x03b21b85b77588506db2fc108bd0cf2c03f6c0653020f46d939d8194ea1e716b",
"0x2e43508dd63e40681c9122d482d7900ebad01b9392e6c1611019e43cbc5455b8",
"0x113febd0e87001dda480a8c347f8a368c00740a25ee2d8d36c0608500bec6f2f",
"0x23cfec0d834aadca55bfe515af80e59183c1b24ea600cf7cde863df02fc859fc",
"0x1cbb1f36a1e7bc45c29ed8922599374d57010887420c91ecfa8727ad51df9b21",
"0x1c2a24adf0e0c5254eb4c834e252a04758e84181cfd1a163dc7089337c4eba52",
"0x2b7a7d74ea33c98f3b45bae98a2498ad5d316a43cfd40e8be9e1c5fd901f5bd8",
"0x1edb94d38964f284b41136812bd52c7679b1e1a3ce3b3a1354b1417b9012ec4b",
"0x2c2bad47394f3068c8b996c4859a22dd65460292fef9c250a5a9da8e0628d534",
"0x0b140b193aab84f6235a88b862ce4275746d5cac940fc494aef23d2279e8a353",
"0x15673d3dd92656dd60513676f7814459619a09681ee4ab63dd8ff3407a547846",
"0x2180ff0b613f8cce937068fa4a77a0f97865c4aed76483cb1fe09227517ba888",
"0x1048b70290f52d668ee6b98950b3e904fee8c844428919300a8945c0fe3e7280",
"0x0326df120ad22e946c41f475b7702dae0dd42a4387a8702c8e954aca640b2c79",
"0x2fc77a73fdbaaa22e2fc521f72f9ce5cef4857f58001409898d52c5e5b1723db",
"0x14938b2b6259f02791cccd157d789c2de68cdad27dc55aa08b9b90ec13dbfd79",
"0x0493187bf26d38b13ca04c712b42778f8618e6f7d9f9dd52bd4da96e085c7a78",
"0x1d40769876c58db37289e371fef2ffa559c95630dee045cde6e18370d2ceb561",
"0x03e7e9b8084366995f7a2f5732349b1139726536b378d78772eabb302705d204",
"0x06147e6e152d7d58f4cf01e05ae0f024607b8b7c3770bd5b7f3a54e048c30a17",
"0x2e49300214c5a0a7a6ebbbc8c48cc323be26d42e98e5bbbb0e2a10ecf4fe40fe",
"0x051c8240e8907e776279e7c66cdbdf39c9516f39ae61883185fac1ef5c64bbba",
"0x2c737904e8f8e845bf132de2b3be5d638993a9987d0e8003022f08bf6633a5bd",
"0x07825bfc67f5658bb5a3b1a26c8ad00f657b54a4a1a679ee37df11bed2ba219d",
"0x1c0e4d8b013541963f8e04667f13e6a60fafebb9bceca823d4054a7a63f8b569",
"0x1083d7cd5a11e3d3dba85745de17ea4abec8a2790003f39f1b1262521380d4b6",
"0x0e14bed1525102ddc1d3c17478ab0c2d4cdbfa67f5ef1a568642984665b4dad2",
"0x1d0c3a89fcc0171b7977f8f20bad9cfae37507a2038d3165d764632461745760",
"0x03162758d9df43281331905c161ed977e240f4a0c9cdd3f3f18a3b0592c3e67e",
"0x0fe5ec0343e9832d8a4c7c1bee1d73decc0661a27c527bec309561fda95a529a",
"0x0ddd28a35af3aced48f61c6558c5c4a72690975c2fc948feec51e1a53a6be5e7",
"0x2318c886ea334e72e9833e3b0bc9868e51843b8b63e0fa3d814540ad7f5d0359",
"0x0d5786dec1685237e3d171eb298a36a475c83c0651a450227d261d78260bab70",
"0x152282540da509e8ab8abcf010d3bd8f29d1c2c60454ffda67ca732db024f3ec",
"0x1b7f4ec7b4c7a593efd5f53ef204e642bb16fb9298a6ffbd1767183170822ad2",
"0x19e02df6f343636868908d644e9a2f767bb9fa9c13756669cb1d805898d949c0",
"0x115d3fa50f1ea1f76b4641586e954be25d7428ad21f5fea76b5889a3f4923ab6",
"0x059db78b0146183e8e6e0829bad801fcb4a0c4e6a8872cb3a5a497118dd29f2c",
"0x0e6441f0174ebe123449b9072472442e03c2f72a29c474d514e4dbb72c23bce1",
"0x2c5302069d7b3b9638a3ea52e5530059155d706af30df469ab929fa1c954efa6",
"0x181a99f989f2f853ae7db14bef800710a05ddc26ed65cd5e1588150864565829",
"0x248a2275485f8946848f0d9433ee1cf6501bbfa8f9404341ef81a9c4b128db3a",
"0x081fa1eb11e0e5198e7135c533688ad0b4e438773b9d99a610ece3dd414845ad",
"0x17b1a8626b79093deb27cfa548da7bf8499e71928d9433a7243037d493c08b53",
"0x0af8f7fc8f0ba49245ae28cfbb7b86bdf3f38b4229981b42ad8ba4af993ae5d8",
"0x19da094b62046661682693af49d35d72a055555b0b2f1a717ef61a0fbdc90169",
"0x287b1755734c8e691d9651ff53f3bae296bc16d33713bf32457869e3650dbc9e",
"0x26501a99afdb95154415e3de32b0d4790ff228ee94577537608d30d85a3349d0",
"0x0c7ca2af6c86f460df0b20ccb30b2a3395f2dabaf7f970f1e1955a1166e0460b",
"0x141cffa13da7885f34ff295561b5d2da8c5b785932ebcd7039752c0dd1cc08a5",
"0x188f478690e359cc0b468d095b37f314c53a5873054cbdb5eb4cde9b97d8c837",
"0x2daafa58220bc8ab507118fb29b65e48e6d8d3ad20d6fa24d57b8a90e21530d6",
"0x1c8eaf137b6310715fc0881b8a080e9391a0217e8e3980ccc3fbc6423ae10f1b",
"0x018864151eb108a9115379b3d3ec902aa961f1b846490266855ab48077487948",
"0x16a426c1847543857385ef8ed03325a50d5cbeff1ac61ef3b710099ab8be88ae",
"0x13d7ed015205feee9d09307b193811ea89b22bf4ecb3e8dcb951ff1e86ea1dbb",
"0x2b35afa98d5c3da62ae05e0e3ec587eacbd195fa3405260ce2b910cb198acf5f"
]
],
"M": [
[
[
"0x028540ffcb050250186bb64a9b6e6d0eaf493d2c72701392fa8de7dbd371fad4",
"0x1afa3a02008d8eab18725ff780b7f310156ddef81579367ae944478644e6367e"
],
[
"0x00b0cad1d2259f1f6dd07b4e5674057f531b5ce316f741437137b7615caf9fb0",
"0x1378798a617a99c07cd850cb3daab0a1b20cb2fe9125133ae092132a071eeffe"
]
],
[
[
"0x142d76a5176d04542cc86c20ad276af0f1c4b85a08f5c7fb7076c37bee91b0b0",
"0x1f020db9ae14abc9448d91922ce7e8a4b751468b692082ac74d4db30f9a20cbd",
"0x02f57e7420298b689cc5932b434d659054d7e9e1a28ce342a357d28d3d0e7ce6"
],
[
"0x0cc8c6aa7aa0f7a0191f236aad3b994b4e6d2671ef5cddef7395a663f18a82b6",
"0x132d968e1372659c4b77528bec8b46830564bbb1ef44e828966a07578b52db1e",
"0x2e7a166a1b7e646c9f9e04f451e541b3eb516fbad05901b4f37e7dd402a501de"
],
[
"0x0411c26273e6ac2f2b7ef6da84499413605b6099bda4254a31ab3bac526a1581",
"0x1e9d5cd096fd315de38e6e2490b8e9c406f954ba63a8be9f11756780af6315f1",
"0x198dfceb06c35ab9162320e55b68a7d160ac9caf74ff1098d62b4cd86823e74c"
]
],
[
[
"0x055042fce3759fd347470105116d64130f5cb362e345d7651c377a63f1c73f81",
"0x2ce35792e15aa0836ab5089a71903eb626bfe7fd6a460cb2f9d93f338b1c93a8",
"0x123324a5430d1e324553566a662bab9bd5b78bc183829124d3407352f3399a44",
"0x014b3af716655fd79b921fb8aba95bf4033d91eefddba964c6813b194ec2e92b"
],
[
"0x00f7a1e3ee734053ac96e44087e97819d5289c2e002339ed649d14df4416c664",
"0x158586db6e410642a1e221f5d80a482cc6ba3cfbe51a38502987db8c42d53bea",
"0x1607fd8dcba9cecf99fa9f882b7bf67c9bdf121aef9843d5d47301d812d23406",
"0x02afb3d945a884974edcf2b2ea59422bfbfb98ba0ea6ae232a2fbf2a98fce73c"
],
[
"0x1303c19d840c01975ac5f417c7d797c84e32937e82c3267a8a5abf86c2adc2dc",
"0x0dfbb78b621ce3f17ea1fca649c7fdf8936872b335d86c5f3ac83072f2b0804e",
"0x0c6d9cca76d73644645d39f6da45e32a5784eb278da4ba346226e3503767c559",
"0x271868e3480e8509ee5b7d057e0e85677220d4751c1475c8a07c578584dba071"
],
[
"0x1ce85b8925fef3258cf52dd26ea5dbe2616118a051fad03b174c55e6bf25c193",
"0x10a902db55c0d71628c51efcb7f01c28e3e60833c254e68d38833c0b577e7bf8",
"0x24afc938e9d8abe5f4cc11f1388ab83460681a00dced6ccd170860e03508ca5c",
"0x297a43fb5e3fefcf3ccabaacf30e9171e4fb359ab66c6ebc8bd6654bd387ab1b"
]
],
[
[
"0x098df2176f14c72d9ef76d268c6526704b2dce0d2ab0bf0d0b6506c598a12e39",
"0x1ee4a90d3dc9864851e9cefb41c3e19218f7ec9b97283b8781d74a9260a9b182",
"0x090becc1ca85079c519e9519456d0613c4dea08dc17ce3d3ac24c51780bbe653",
"0x24510d25f0893ebc56cb6d302b08ebc1fe23a842483a1cf105efccdb8f6623be",
"0x1836f551337cc92e446cda258313ddb9a1291f822c2120d3765f5bb29bccd044"
],
[
"0x235a03a1f31060c62a1bb1b6cbce38317dcf3501e3f0b3d92b4b01a070ee58b2",
"0x1b0481c924c00fd4b7809ff4a9f9daa7f12efea4821078b869159d34e7c9caca",
"0x2f1ced49ea067ad0f3a22b51ad12da2d7b0280f3f50977f9b09d4bea92e6b34e",
"0x28f301e64ff54c671bb7a9fc672a420e3af0382c71af2aec84d1b26d19bd01ee",
"0x05c29dff5d6ae85f7bc09637a86134c63a8052d1905a8057449cc7d92658f24d"
],
[
"0x2885788b4255180581aac93d5313e7489efc386deceaf13050ebcb8cdddff5fa",
"0x2a7f03d4b0954a37f9a33ebd9117e2c4cfaa3978e5f221a30db56a7403572a3c",
"0x291093f3d5182756f267566140d2d8f5356be8408b40ead3748484267f1e90cb",
"0x29ecfb524f4135deb55d9d9eb02839dedda189c17726aeef96019b205c8aab53",
"0x1650d221980ec72736322d9fa404a0fe6bea3d8530b71c9522096e455be52379"
],
[
"0x10d08ba1c37b79a36c9d3c9a3d8fd2ff41f2445e7d71dd5ede6f45987e5e1044",
"0x1eaa7441754632ffae99c9e2f2264c1bc89551e7bbf2c889d92af30bef70e817",
"0x062101fedd4ecff781f529f57f45e8b479b03d86a11acf549c6555a1293c70b3",
"0x1c1ec7db63405475e844b5cb6215d9e2919e903a7387721db150c9977a1818b5",
"0x0b5ca51ebe8fd98da6e8f4a4465e19dd210bf59e0841f50fcf0f06e43d83ce1f"
],
[
"0x0143b223ed92a0b426f8f2886cda3d8fdb565eb6acb4841897489e14cbc943a8",
"0x017f82dcfdf078265df4cfa1d9d79aeec0fee433eebc489a875785b99dc8832a",
"0x0013ae98ed23af18461bcde9ff99728edeec173e63c5467a209c2a34b503dc72",
"0x0e120df26061ea797bba1f6153995de0090ddb744ad23bfcdf1ecc28a9b18338",
"0x0233c1411c8cb5ff0d33e20a65bfd9c0347deb9a12a50e55fb01a40248ccc366"
]
]
]
}

213
src/poseidon_gencontract.js Normal file
View File

@ -0,0 +1,213 @@
// Copyright (c) 2018 Jordi Baylina
// License: LGPL-3.0+
//
const Contract = require("./evmasm");
const { unstringifyBigInts } = require("@tornado/snarkjs");
const Web3Utils = require("web3-utils");
const { C: K, M } = unstringifyBigInts(require("./poseidon_constants.json"));
const N_ROUNDS_F = 8;
const N_ROUNDS_P = 35;
function toHex256(a) {
if (typeof a === "string" && a.startsWith("0x")) {
return a;
}
let S = a.toString(16);
while (S.length < 64) S = "0" + S;
return "0x" + S;
}
function createCode(nInputs) {
if (nInputs < 1 || nInputs > 4) throw new Error("Invalid number of inputs. Must be 1<=nInputs<=8");
const t = nInputs + 1;
const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P;
const C = new Contract();
function saveM() {
for (let i = 0; i < t; i++) {
for (let j = 0; j < t; j++) {
C.push(toHex256(M[t - 2][j][i]));
C.push((1 + i * t + j) * 32);
C.mstore();
}
}
}
function ark(r) {
// st, q
for (let i = 0; i < t; i++) {
C.dup(t); // q, st, q
C.push(toHex256(K[t - 2][r * t + i])); // K, q, st, q
C.dup(2 + i); // st[i], K, q, st, q
C.addmod(); // newSt[i], st, q
C.swap(1 + i); // xx, st, q
C.pop();
}
}
function sigma(p) {
// sq, q
C.dup(t); // q, st, q
C.dup(1 + p); // st[p] , q , st, q
C.dup(1); // q, st[p] , q , st, q
C.dup(0); // q, q, st[p] , q , st, q
C.dup(2); // st[p] , q, q, st[p] , q , st, q
C.dup(0); // st[p] , st[p] , q, q, st[p] , q , st, q
C.mulmod(); // st2[p], q, st[p] , q , st, q
C.dup(0); // st2[p], st2[p], q, st[p] , q , st, q
C.mulmod(); // st4[p], st[p] , q , st, q
C.mulmod(); // st5[p], st, q
C.swap(1 + p);
C.pop(); // newst, q
}
function mix() {
C.label("mix");
for (let i = 0; i < t; i++) {
for (let j = 0; j < t; j++) {
if (j == 0) {
C.dup(i + t); // q, newSt, oldSt, q
C.push((1 + i * t + j) * 32);
C.mload(); // M, q, newSt, oldSt, q
C.dup(2 + i + j); // oldSt[j], M, q, newSt, oldSt, q
C.mulmod(); // acc, newSt, oldSt, q
} else {
C.dup(1 + i + t); // q, acc, newSt, oldSt, q
C.push((1 + i * t + j) * 32);
C.mload(); // M, q, acc, newSt, oldSt, q
C.dup(3 + i + j); // oldSt[j], M, q, acc, newSt, oldSt, q
C.mulmod(); // aux, acc, newSt, oldSt, q
C.dup(2 + i + t); // q, aux, acc, newSt, oldSt, q
C.swap(2); // acc, aux, q, newSt, oldSt, q
C.addmod(); // acc, newSt, oldSt, q
}
}
}
for (let i = 0; i < t; i++) {
C.swap(t - i + (t - i - 1));
C.pop();
}
C.push(0);
C.mload();
C.jmp();
}
// Check selector
C.push("0x0100000000000000000000000000000000000000000000000000000000");
C.push(0);
C.calldataload();
C.div();
C.dup(0);
C.push(Web3Utils.keccak256(`poseidon(uint256[${nInputs}])`).slice(0, 10)); // poseidon(uint256[n])
C.eq();
C.swap(1);
C.push(Web3Utils.keccak256(`poseidon(bytes32[${nInputs}])`).slice(0, 10)); // poseidon(bytes32[n])
C.eq();
C.or();
C.jmpi("start");
C.invalid();
C.label("start");
saveM();
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
// Load t values from the call data.
// The function has a single array param param
// [Selector (4)] [item1 (32)] [item2 (32)] ....
// Stack positions 0-nInputs.
for (let i = 0; i < t; i++) {
C.push(0x04 + 0x20 * (nInputs - i));
C.calldataload();
}
for (let i = 0; i < nRoundsF + nRoundsP - 1; i++) {
ark(i);
if (i < nRoundsF / 2 || i >= nRoundsP + nRoundsF / 2) {
for (let j = 0; j < t; j++) {
sigma(j);
}
} else {
sigma(0);
}
const strLabel = "aferMix" + i;
C._pushLabel(strLabel);
C.push(0);
C.mstore();
C.jmp("mix");
C.label(strLabel);
}
C.push(toHex256(K[t - 2][(nRoundsF + nRoundsP - 1) * t])); // K, st, q
C.dup(t + 1); // q, K, st, q
C.swap(2); // st[0], K, q, st\st[0]
C.addmod(); // st q
sigma(0);
C.push("0x00");
C.mstore(); // Save it to pos 0;
C.push("0x20");
C.push("0x00");
C.return();
mix();
return C.createTxData();
}
function generateABI(nInputs) {
return [
{
constant: true,
inputs: [
{
internalType: `bytes32[${nInputs}]`,
name: "input",
type: `bytes32[${nInputs}]`,
},
],
name: "poseidon",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
payable: false,
stateMutability: "pure",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: `uint256[${nInputs}]`,
name: "input",
type: `uint256[${nInputs}]`,
},
],
name: "poseidon",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
payable: false,
stateMutability: "pure",
type: "function",
},
];
}
module.exports.generateABI = generateABI;
module.exports.createCode = createCode;

View File

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

View File

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

View File

@ -1,17 +1,15 @@
const bigInt = require("snarkjs").bigInt; const bigInt = require("@tornado/snarkjs").bigInt;
const SMTMemDB = require("./smt_memdb"); const SMTMemDB = require("./smt_memdb");
const mimc7 = require("./mimc7"); const { hash0, hash1 } = 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); let k = bigInt(_key);
const res = []; const res = [];
@ -24,7 +22,7 @@ class SMT {
k = k.shr(1); k = k.shr(1);
} }
while (res.length<256) res.push(false); while (res.length < 256) res.push(false);
return res; return res;
} }
@ -33,7 +31,6 @@ class SMT {
const key = bigInt(_key); const key = bigInt(_key);
const newValue = bigInt(_newValue); const newValue = bigInt(_newValue);
const resFind = await this.find(key); const resFind = await this.find(key);
const res = {}; const res = {};
res.oldRoot = this.root; res.oldRoot = this.root;
@ -46,24 +43,24 @@ class SMT {
const ins = []; const ins = [];
const dels = []; const dels = [];
let rtOld = mimc7.multiHash([1, key, resFind.foundValue]); let rtOld = hash1(key, resFind.foundValue);
let rtNew = mimc7.multiHash([1, 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]) {
oldNode = [sibling, rtOld]; oldNode = [sibling, rtOld];
newNode = [sibling, rtNew]; newNode = [sibling, rtNew];
} else { } else {
oldNode = [rtOld, sibling, ]; oldNode = [rtOld, sibling];
newNode = [rtNew, sibling, ]; newNode = [rtNew, sibling];
} }
rtOld = mimc7.multiHash(oldNode); rtOld = hash0(oldNode[0], oldNode[1]);
rtNew = mimc7.multiHash(newNode); rtNew = hash0(newNode[0], newNode[1]);
dels.push(rtOld); dels.push(rtOld);
ins.push([rtNew, newNode]); ins.push([rtNew, newNode]);
} }
@ -87,19 +84,19 @@ class SMT {
const res = { const res = {
siblings: [], siblings: [],
delKey: key, delKey: key,
delValue: resFind.foundValue delValue: resFind.foundValue,
}; };
const dels = []; const dels = [];
const ins = []; const ins = [];
let rtOld = mimc7.multiHash([1, key, resFind.foundValue]); let rtOld = hash1(key, resFind.foundValue);
let rtNew; let rtNew;
dels.push(rtOld); dels.push(rtOld);
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 && record[0].equals(bigInt.one)) {
mixed = false; mixed = false;
res.oldKey = record[1]; res.oldKey = record[1];
res.oldValue = record[2]; res.oldValue = record[2];
@ -123,16 +120,16 @@ class SMT {
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 = bigInt.zero;
} }
const oldSibling = resFind.siblings[level]; const oldSibling = resFind.siblings[level];
if (keyBits[level]) { if (keyBits[level]) {
rtOld = mimc7.multiHash([oldSibling, rtOld]); rtOld = hash0(oldSibling, rtOld);
} else { } else {
rtOld = mimc7.multiHash([rtOld, oldSibling]); rtOld = hash0(rtOld, oldSibling);
} }
dels.push(rtOld); dels.push(rtOld);
if (!newSibling.isZero()) { if (!newSibling.isZero()) {
@ -147,7 +144,7 @@ class SMT {
} else { } else {
newNode = [rtNew, newSibling]; newNode = [rtNew, newSibling];
} }
rtNew = mimc7.multiHash(newNode); rtNew = hash0(newNode[0], newNode[1]);
ins.push([rtNew, newNode]); ins.push([rtNew, newNode]);
} }
} }
@ -182,14 +179,14 @@ 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(bigInt.zero);
} }
rtOld = mimc7.multiHash([1, 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 = bigInt.zero;
} }
@ -197,37 +194,36 @@ class SMT {
const inserts = []; const inserts = [];
const dels = []; const dels = [];
let rt = mimc7.multiHash([1, 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 && !res.siblings[i].isZero()) {
mixed = true; mixed = true;
} }
if (mixed) { if (mixed) {
const oldSibling = resFind.siblings[i]; const oldSibling = resFind.siblings[i];
if (newKeyBits[i]) { if (newKeyBits[i]) {
rtOld = mimc7.multiHash([oldSibling, rtOld]); rtOld = hash0(oldSibling, rtOld);
} else { } else {
rtOld = mimc7.multiHash([rtOld, oldSibling]); rtOld = hash0(rtOld, oldSibling);
} }
dels.push(rtOld); dels.push(rtOld);
} }
let newRt; let newRt;
if (newKeyBits[i]) { if (newKeyBits[i]) {
newRt = mimc7.multiHash([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 = mimc7.multiHash([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 && res.siblings[res.siblings.length - 1].isZero()) {
res.siblings.pop(); res.siblings.pop();
} }
res.oldKey = resFind.notFoundKey; res.oldKey = resFind.notFoundKey;
@ -235,7 +231,6 @@ 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;
@ -259,20 +254,20 @@ class SMT {
siblings: [], siblings: [],
notFoundKey: key, notFoundKey: key,
notFoundValue: bigInt.zero, notFoundValue: bigInt.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 && record[0].equals(bigInt.one)) {
if (record[1].equals(key)) { if (record[1].equals(key)) {
res = { res = {
found: true, found: true,
siblings: [], siblings: [],
foundValue: record[2], foundValue: record[2],
isOld0: false isOld0: false,
}; };
} else { } else {
res = { res = {
@ -280,15 +275,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]);
} }
} }
@ -296,9 +291,7 @@ class SMT {
} }
} }
async function loadFromFile(fileName) { async function loadFromFile(fileName) {}
}
async function newMemEmptyTrie() { async function newMemEmptyTrie() {
const db = new SMTMemDB(); const db = new SMTMemDB();
@ -309,3 +302,5 @@ async function newMemEmptyTrie() {
module.exports.loadFromFile = loadFromFile; module.exports.loadFromFile = loadFromFile;
module.exports.newMemEmptyTrie = newMemEmptyTrie; module.exports.newMemEmptyTrie = newMemEmptyTrie;
module.exports.SMT = SMT;
module.exports.SMTMemDB = SMTMemDB;

10
src/smt_hashes_mimc.js Normal file
View File

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

View File

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

View File

@ -1,4 +1,4 @@
const bigInt = require("snarkjs").bigInt; const bigInt = require("@tornado/snarkjs").bigInt;
class SMTMemDb { class SMTMemDb {
constructor() { constructor() {
@ -17,7 +17,7 @@ class SMTMemDb {
} }
_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] = bigInt(n[i]);
} }
} }
@ -27,12 +27,20 @@ class SMTMemDb {
return this.nodes[keyS]; return this.nodes[keyS];
} }
async multiGet(keys) {
const promises = [];
for (let i = 0; i < keys.length; i++) {
promises.push(this.get(keys[i]));
}
return await Promise.all(promises);
}
async setRoot(rt) { async setRoot(rt) {
this.root = rt; this.root = rt;
} }
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];
@ -40,7 +48,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,6 +1,6 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const assert = chai.assert; const assert = chai.assert;
@ -13,7 +13,7 @@ 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 (v.shr(i).isOdd()) {
res.push(bigInt.one); res.push(bigInt.one);
} else { } else {
@ -27,7 +27,7 @@ const q = bigInt("21888242871839275222246405745257275088548364400416034343698204
describe("Aliascheck test", () => { describe("Aliascheck test", () => {
let circuit; let circuit;
before( async() => { before(async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "aliascheck_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "aliascheck_test.circom"));
circuit = new snarkjs.Circuit(cirDef); circuit = new snarkjs.Circuit(cirDef);
@ -37,38 +37,38 @@ describe("Aliascheck test", () => {
it("Satisfy the aliastest 0", async () => { it("Satisfy the aliastest 0", async () => {
const inp = getBits(bigInt.zero, 254); const inp = getBits(bigInt.zero, 254);
circuit.calculateWitness({in: inp}); circuit.calculateWitness({ in: inp });
}); });
it("Satisfy the aliastest 3", async () => { it("Satisfy the aliastest 3", async () => {
const inp = getBits(bigInt(3), 254); const inp = getBits(bigInt(3), 254);
circuit.calculateWitness({in: inp}); circuit.calculateWitness({ in: inp });
}); });
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(q.sub(bigInt.one), 254);
circuit.calculateWitness({in: inp}); circuit.calculateWitness({ in: inp });
}); });
it("Nhot not satisfy an input of q", async () => { it("Nhot not satisfy an input of q", async () => {
const inp = getBits(q, 254); const inp = getBits(q, 254);
try { try {
circuit.calculateWitness({in: inp}); circuit.calculateWitness({ in: inp });
assert(false); assert(false);
} catch(err) { } catch (err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); 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("Nhot not satisfy all ones", async () => {
const inp = getBits(bigInt(1).shl(254).sub(bigInt(1)), 254); const inp = getBits(bigInt(1).shl(254).sub(bigInt(1)), 254);
try { try {
circuit.calculateWitness({in: inp}); circuit.calculateWitness({ in: inp });
assert(false); assert(false);
} catch(err) { } catch (err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message));
assert(err.message.indexOf("1 != 0") >= 0);
} }
}); });
}); });

74
test/aliascheckbabyjub.js Normal file
View File

@ -0,0 +1,74 @@
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,12 +1,14 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const createBlakeHash = require("blake-hash");
const eddsa = require("../src/eddsa.js");
const assert = chai.assert; const assert = chai.assert;
const bigInt = require("big-integer"); const bigInt = require("@tornado/snarkjs").bigInt;
describe("Baby Jub test", function () { describe("Baby Jub test", function () {
let circuitAdd; let circuitAdd;
@ -14,7 +16,7 @@ describe("Baby Jub test", function () {
this.timeout(100000); this.timeout(100000);
before( async() => { before(async () => {
const cirDefAdd = await compiler(path.join(__dirname, "circuits", "babyadd_tester.circom")); const cirDefAdd = await compiler(path.join(__dirname, "circuits", "babyadd_tester.circom"));
circuitAdd = new snarkjs.Circuit(cirDefAdd); circuitAdd = new snarkjs.Circuit(cirDefAdd);
console.log("NConstrains BabyAdd: " + circuitAdd.nConstraints); console.log("NConstrains BabyAdd: " + circuitAdd.nConstraints);
@ -22,15 +24,18 @@ describe("Baby Jub test", function () {
const cirDefTest = await compiler(path.join(__dirname, "circuits", "babycheck_test.circom")); const cirDefTest = await compiler(path.join(__dirname, "circuits", "babycheck_test.circom"));
circuitTest = new snarkjs.Circuit(cirDefTest); circuitTest = new snarkjs.Circuit(cirDefTest);
console.log("NConstrains BabyTest: " + circuitTest.nConstraints); console.log("NConstrains BabyTest: " + circuitTest.nConstraints);
const cirDefPbk = await compiler(path.join(__dirname, "circuits", "babypbk_test.circom"));
circuitPbk = new snarkjs.Circuit(cirDefPbk);
console.log("NConstrains BabyPbk: " + circuitPbk.nConstraints);
}); });
it("Should add point (0,1) and (0,1)", async () => { it("Should add point (0,1) and (0,1)", async () => {
const input = {
const input={
x1: snarkjs.bigInt(0), x1: snarkjs.bigInt(0),
y1: snarkjs.bigInt(1), y1: snarkjs.bigInt(1),
x2: snarkjs.bigInt(0), x2: snarkjs.bigInt(0),
y2: snarkjs.bigInt(1) y2: snarkjs.bigInt(1),
}; };
const w = circuitAdd.calculateWitness(input); const w = circuitAdd.calculateWitness(input);
@ -43,12 +48,11 @@ describe("Baby Jub test", function () {
}); });
it("Should add 2 same numbers", async () => { it("Should add 2 same numbers", async () => {
const input = {
const input={
x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
x2: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), x2: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
y2: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475") y2: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
}; };
const w = circuitAdd.calculateWitness(input); const w = circuitAdd.calculateWitness(input);
@ -61,12 +65,11 @@ describe("Baby Jub test", function () {
}); });
it("Should add 2 different numbers", async () => { it("Should add 2 different numbers", async () => {
const input = {
const input={
x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), x1: snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), y1: snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"),
x2: snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"), x2: snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"),
y2: snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311") y2: snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"),
}; };
const w = circuitAdd.calculateWitness(input); const w = circuitAdd.calculateWitness(input);
@ -83,18 +86,35 @@ describe("Baby Jub test", function () {
assert(yout.equals(snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499"))); assert(yout.equals(snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499")));
}); });
it("Should check 0 is a valid poiny", async() => { it("Should check 0 is a valid poiny", async () => {
const w = circuitTest.calculateWitness({x: 0, y:1}); const w = circuitTest.calculateWitness({ x: 0, y: 1 });
assert(circuitTest.checkWitness(w)); assert(circuitTest.checkWitness(w));
}); });
it("Should check 0 is an invalid poiny", async() => { it("Should check 0 is an invalid poiny", async () => {
try { try {
circuitTest.calculateWitness({x: 1, y: 0}); circuitTest.calculateWitness({ x: 1, y: 0 });
assert(false, "Should be a valid point"); assert(false, "Should be a valid point");
} catch(err) { } catch (err) {
assert.equal(err.message, "Constraint doesn't match: 168700 != 1"); 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 () => {
const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex");
const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0, 32));
const S = bigInt.leBuff2int(pvk).shr(3);
const A = eddsa.prv2pub(rawpvk);
const input = {
in: S,
Ax: A[0],
Ay: A[1],
};
const w = circuitPbk.calculateWitness(input);
assert(circuitPbk.checkWitness(w));
});
}); });

162
test/babyjub_js.js Normal file
View File

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

View File

@ -1,6 +1,6 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const assert = chai.assert; const assert = chai.assert;
@ -11,21 +11,21 @@ function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
function checkSub(_a,_b, circuit) { function checkSub(_a, _b, circuit) {
let a=bigInt(_a); let a = bigInt(_a);
let b=bigInt(_b); let b = bigInt(_b);
if (a.lesser(bigInt.zero)) a = a.add(bigInt.one.shl(16)); if (a.lesser(bigInt.zero)) a = a.add(bigInt.one.shl(16));
if (b.lesser(bigInt.zero)) b = b.add(bigInt.one.shl(16)); if (b.lesser(bigInt.zero)) b = b.add(bigInt.one.shl(16));
const w = circuit.calculateWitness({a: a, b: b}); const w = circuit.calculateWitness({ a: a, b: b });
let res = a.sub(b); let res = a.sub(b);
if (res.lesser(bigInt.zero)) res = res.add(bigInt.one.shl(16)); if (res.lesser(bigInt.zero)) res = res.add(bigInt.one.shl(16));
assert( w[circuit.getSignalIdx("main.out")].equals(bigInt(res)) ); assert(w[circuit.getSignalIdx("main.out")].equals(bigInt(res)));
} }
describe("BinSub test", () => { describe("BinSub test", () => {
let circuit; let circuit;
before( async() => { before(async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "binsub_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "binsub_test.circom"));
circuit = new snarkjs.Circuit(cirDef); circuit = new snarkjs.Circuit(cirDef);
@ -34,23 +34,21 @@ describe("BinSub test", () => {
}); });
it("Should check variuos ege cases", async () => { it("Should check variuos ege cases", async () => {
checkSub(0,0, circuit); checkSub(0, 0, circuit);
checkSub(1,0, circuit); checkSub(1, 0, circuit);
checkSub(-1,0, circuit); checkSub(-1, 0, circuit);
checkSub(2,1, circuit); checkSub(2, 1, circuit);
checkSub(2,2, circuit); checkSub(2, 2, circuit);
checkSub(2,3, circuit); checkSub(2, 3, circuit);
checkSub(2,-1, circuit); checkSub(2, -1, circuit);
checkSub(2,-2, circuit); checkSub(2, -2, circuit);
checkSub(2,-3, circuit); checkSub(2, -3, circuit);
checkSub(-2,-3, circuit); checkSub(-2, -3, circuit);
checkSub(-2,-2, circuit); checkSub(-2, -2, circuit);
checkSub(-2,-1, circuit); checkSub(-2, -1, circuit);
checkSub(-2,0, circuit); checkSub(-2, 0, circuit);
checkSub(-2,1, circuit); checkSub(-2, 1, circuit);
checkSub(-2,2, circuit); checkSub(-2, 2, circuit);
checkSub(-2,3, circuit); checkSub(-2, 3, circuit);
}); });
}); });

View File

@ -1,6 +1,6 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const crypto = require("crypto"); const crypto = require("crypto");
const compiler = require("circom"); const compiler = require("circom");
@ -9,25 +9,23 @@ const assert = chai.assert;
describe("Sum test", () => { describe("Sum test", () => {
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 cirDef = await compiler(path.join(__dirname, "circuits", "constants_test.circom"));
assert.equal(cirDef.nVars, 2); assert.equal(cirDef.nVars, 2);
const circuit = new snarkjs.Circuit(cirDef); const circuit = new snarkjs.Circuit(cirDef);
const witness = circuit.calculateWitness({ "in": "0xd807aa98" }); const witness = circuit.calculateWitness({ in: "0xd807aa98" });
assert(witness[0].equals(snarkjs.bigInt(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt("0xd807aa98"))); assert(witness[1].equals(snarkjs.bigInt("0xd807aa98")));
}); });
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 cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom"));
assert.equal(cirDef.nVars, 101); assert.equal(cirDef.nVars, 97); // 32 (in1) + 32(in2) + 32(out) + 1 (carry)
const circuit = new snarkjs.Circuit(cirDef); const circuit = new snarkjs.Circuit(cirDef);
const witness = circuit.calculateWitness({ "a": "111", "b": "222" }); const witness = circuit.calculateWitness({ a: "111", b: "222" });
assert(witness[0].equals(snarkjs.bigInt(1))); assert(witness[0].equals(snarkjs.bigInt(1)));
assert(witness[1].equals(snarkjs.bigInt("333"))); assert(witness[1].equals(snarkjs.bigInt("333")));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
// const crypto = require("crypto"); // const crypto = require("crypto");
@ -17,9 +17,9 @@ function print(circuit, w, 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(bigInt.one);
} else { } else {
res.push(bigInt.zero); res.push(bigInt.zero);
@ -29,13 +29,12 @@ function buffer2bits(buff) {
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")); const cirDef = await compiler(path.join(__dirname, "circuits", "eddsa_test.circom"));
circuit = new snarkjs.Circuit(cirDef); circuit = new snarkjs.Circuit(cirDef);
@ -46,7 +45,7 @@ describe("EdDSA test", function () {
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");
@ -66,9 +65,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 = circuit.calculateWitness({ A: aBits, R8: r8Bits, S: sBits, msg: msgBits });
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
}); });
}); });

75
test/eddsa_js.js Normal file
View File

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

View File

@ -1,6 +1,6 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const eddsa = require("../src/eddsa.js"); const eddsa = require("../src/eddsa.js");
@ -9,17 +9,17 @@ const assert = chai.assert;
const bigInt = snarkjs.bigInt; const bigInt = snarkjs.bigInt;
describe("EdDSA 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")); const cirDef = await compiler(path.join(__dirname, "circuits", "eddsamimc_test.circom"));
circuit = new snarkjs.Circuit(cirDef); circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains EdDSA: " + circuit.nConstraints); console.log("NConstrains EdDSA MiMC: " + circuit.nConstraints);
}); });
it("Sign a single number", async () => { it("Sign a single number", async () => {
@ -40,7 +40,8 @@ describe("EdDSA test", function () {
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)); assert(circuit.checkWitness(w));
}); });
@ -52,7 +53,6 @@ describe("EdDSA test", function () {
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));
@ -64,14 +64,14 @@ describe("EdDSA test", function () {
R8x: signature.R8[0].add(bigInt(1)), R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg}); M: msg,
});
assert(false); assert(false);
} catch(err) { } catch (err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); 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 = bigInt(1234);
@ -79,7 +79,6 @@ describe("EdDSA test", function () {
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));
@ -91,7 +90,8 @@ describe("EdDSA test", function () {
R8x: signature.R8[0].add(bigInt(1)), R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1], R8y: signature.R8[1],
S: signature.S, S: signature.S,
M: msg}); M: msg,
});
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
}); });

99
test/eddsamimcsponge.js Normal file
View File

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

98
test/eddsaposeidon.js Normal file
View File

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

View File

@ -1,21 +1,20 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt; const bigInt = snarkjs.bigInt;
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const q=bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); function addPoint(a, b) {
function addPoint(a,b) {
const cta = bigInt("168700"); const cta = bigInt("168700");
const d = bigInt("168696"); const d = bigInt("168696");
const res = []; 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[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); 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; return res;
} }
@ -25,136 +24,140 @@ function print(circuit, w, s) {
describe("Exponentioation test", () => { describe("Exponentioation test", () => {
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")); const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulw4table_test.circom"));
// console.log(JSON.stringify(cirDef, null, 1)); // console.log(JSON.stringify(cirDef, null, 1));
// assert.equal(cirDef.nVars, 2); // assert.equal(cirDef.nVars, 2);
const circuit = new snarkjs.Circuit(cirDef); const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints); console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({}); const w = circuit.calculateWitness({ in: 1 });
let g = [bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")]
dbl= [bigInt("0"), snarkjs.bigInt("1")];
for (let i=0; i<16; i++) {
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
/*
console.log(xout1.toString());
console.log(yout1.toString());
console.log(dbl[0]);
console.log(dbl[1]);
*/
assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1]));
dbl = addPoint([xout1, yout1],g);
}
});
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));
// assert.equal(cirDef.nVars, 2);
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({});
let g = [snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")]
for (let i=0; i<12;i++) {
g = addPoint(g,g);
}
dbl= [snarkjs.bigInt("0"), snarkjs.bigInt("1")];
for (let i=0; i<16; i++) {
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
/*
console.log(xout1.toString());
console.log(yout1.toString());
console.log(dbl[0]);
console.log(dbl[1]);
*/
assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1]));
dbl = addPoint([xout1, yout1],g);
}
});
it("Should exponentiate g^31", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmul_test.circom"));
// console.log(JSON.stringify(cirDef, null, 1));
// assert.equal(cirDef.nVars, 2);
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({"in": 31});
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
let g = [snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), let g = [
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")] bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
dbl = [bigInt("0"), snarkjs.bigInt("1")];
for (let i = 0; i < 16; i++) {
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
// console.log(xout1.toString());
// console.log(yout1.toString());
// console.log(dbl[0]);
// console.log(dbl[1]);
assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1]));
dbl = addPoint([xout1, yout1], g);
}
});
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));
// assert.equal(cirDef.nVars, 2);
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({ in: 1 });
assert(circuit.checkWitness(w));
let g = [
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
for (let i = 0; i < 12; i++) {
g = addPoint(g, g);
}
dbl = [snarkjs.bigInt("0"), snarkjs.bigInt("1")];
for (let i = 0; i < 16; i++) {
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
// console.log(xout1.toString());
// console.log(yout1.toString());
// console.log(dbl[0]);
// console.log(dbl[1]);
assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1]));
dbl = addPoint([xout1, yout1], g);
}
});
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));
// assert.equal(cirDef.nVars, 2);
const circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
const w = circuit.calculateWitness({ in: 31 });
assert(circuit.checkWitness(w));
let g = [
snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
let c = [0n, 1n]; let c = [0n, 1n];
for (let i=0; i<31;i++) { for (let i = 0; i < 31; i++) {
c = addPoint(c,g); c = addPoint(c, g);
} }
const xout = w[circuit.getSignalIdx(`main.out[0]`)]; const xout = w[circuit.getSignalIdx(`main.out[0]`)];
const yout = w[circuit.getSignalIdx(`main.out[1]`)]; const yout = w[circuit.getSignalIdx(`main.out[1]`)];
/* /*
console.log(xout.toString()); console.log(xout.toString());
console.log(yout.toString()); console.log(yout.toString());
*/ */
assert(xout.equals(c[0])); assert(xout.equals(c[0]));
assert(yout.equals(c[1])); assert(yout.equals(c[1]));
console.log("-------") console.log("-------");
const w2 = circuit.calculateWitness({"in": (1n<<252n)+1n}); const w2 = circuit.calculateWitness({ in: (1n << 252n) + 1n });
const xout2 = w2[circuit.getSignalIdx(`main.out[0]`)]; const xout2 = w2[circuit.getSignalIdx(`main.out[0]`)];
const yout2 = w2[circuit.getSignalIdx(`main.out[1]`)]; 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 = addPoint(c, c);
} }
c = addPoint(c,g); c = addPoint(c, g);
/*
console.log(xout2.toString()); // console.log(xout2.toString());
console.log(yout2.toString()); // console.log(yout2.toString());
console.log(c[0].toString()); // console.log(c[0].toString());
console.log(c[1].toString()); // console.log(c[1].toString());
*/
assert(xout2.equals(c[0])); assert(xout2.equals(c[0]));
assert(yout2.equals(c[1])); 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 () => {
@ -164,5 +167,4 @@ describe("Exponentioation test", () => {
console.log("NConstrains: " + circuit.nConstraints); console.log("NConstrains: " + circuit.nConstraints);
}).timeout(10000000); }).timeout(10000000);
}); });

View File

@ -1,13 +1,12 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const assert = chai.assert; const assert = chai.assert;
const bigInt = snarkjs.bigInt; const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
@ -18,19 +17,18 @@ describe("Escalarmul test", function () {
this.timeout(100000); this.timeout(100000);
let g = [ let g = [
snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475") snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
]; ];
before( async() => { before(async () => {
const cirDefEMulAny = await compiler(path.join(__dirname, "circuits", "escalarmulany_test.circom")); const cirDefEMulAny = await compiler(path.join(__dirname, "circuits", "escalarmulany_test.circom"));
circuitEMulAny = new snarkjs.Circuit(cirDefEMulAny); circuitEMulAny = new snarkjs.Circuit(cirDefEMulAny);
console.log("NConstrains Escalarmul any: " + circuitEMulAny.nConstraints); 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 });
const w = circuitEMulAny.calculateWitness({"e": 1, "p": g});
assert(circuitEMulAny.checkWitness(w)); assert(circuitEMulAny.checkWitness(w));
@ -42,9 +40,8 @@ describe("Escalarmul test", function () {
}); });
it("If multiply by order should return 0", async () => { it("If multiply by order should return 0", async () => {
const r = bigInt("2736030358979909402780800718157159386076813972158567259200215660948447373041"); const r = bigInt("2736030358979909402780800718157159386076813972158567259200215660948447373041");
const w = circuitEMulAny.calculateWitness({"e": r, "p": g}); const w = circuitEMulAny.calculateWitness({ e: r, p: g });
assert(circuitEMulAny.checkWitness(w)); assert(circuitEMulAny.checkWitness(w));
@ -54,6 +51,4 @@ describe("Escalarmul test", function () {
assert(xout.equals(bigInt.zero)); assert(xout.equals(bigInt.zero));
assert(yout.equals(bigInt.one)); assert(yout.equals(bigInt.one));
}); });
}); });

View File

@ -1,6 +1,6 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const babyjub = require("../src/babyjub"); const babyjub = require("../src/babyjub");
@ -8,7 +8,6 @@ const assert = chai.assert;
const bigInt = snarkjs.bigInt; const bigInt = snarkjs.bigInt;
function print(circuit, w, s) { function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]); console.log(s + ": " + w[circuit.getSignalIdx(s)]);
} }
@ -18,15 +17,14 @@ 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")); const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmulfix_test.circom"));
circuit = new snarkjs.Circuit(cirDef); circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains Escalarmul fix: " + circuit.nConstraints); 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 });
const w = circuit.calculateWitness({"e": 0});
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
@ -38,8 +36,7 @@ describe("Escalarmul test", function () {
}); });
it("Should generate Same escalar mul", async () => { it("Should generate Same escalar mul", async () => {
const w = circuit.calculateWitness({ e: 1 });
const w = circuit.calculateWitness({"e": 1});
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
@ -50,9 +47,51 @@ describe("Escalarmul test", function () {
assert(yout.equals(babyjub.Base8[1])); assert(yout.equals(babyjub.Base8[1]));
}); });
it("If multiply by order should return 0", async () => { it("Should generate scalar mul of a specific constant", async () => {
const s = bigInt("2351960337287830298912035165133676222414898052661454064215017316447594616519");
const base8 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
const w = circuit.calculateWitness({"e": babyjub.subOrder }); const w = circuit.calculateWitness({ e: s });
assert(circuit.checkWitness(w));
const xout = w[circuit.getSignalIdx("main.out[0]")];
const yout = w[circuit.getSignalIdx("main.out[1]")];
const expectedRes = babyjub.mulPointEscalar(base8, s);
assert(xout.equals(expectedRes[0]));
assert(yout.equals(expectedRes[1]));
});
it("Should generate scalar mul of the firsts 50 elements", async () => {
const base8 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
for (let i = 0; i < 50; i++) {
const s = bigInt(i);
const w = circuit.calculateWitness({ e: s });
assert(circuit.checkWitness(w));
const xout = w[circuit.getSignalIdx("main.out[0]")];
const yout = w[circuit.getSignalIdx("main.out[1]")];
const expectedRes = babyjub.mulPointEscalar(base8, s);
assert(xout.equals(expectedRes[0]));
assert(yout.equals(expectedRes[1]));
}
});
it("If multiply by order should return 0", async () => {
const w = circuit.calculateWitness({ e: babyjub.subOrder });
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
@ -62,6 +101,4 @@ describe("Escalarmul test", function () {
assert(xout.equals(bigInt.zero)); assert(xout.equals(bigInt.zero));
assert(yout.equals(bigInt.one)); assert(yout.equals(bigInt.one));
}); });
}); });

View File

@ -1,13 +1,12 @@
const snarkjs = require("@tornado/snarkjs");
const snarkjs = require("snarkjs");
const bigInt = snarkjs.bigInt; const bigInt = snarkjs.bigInt;
module.exports = function hexBits(cir, witness, sig, nBits) { module.exports = function hexBits(cir, witness, sig, nBits) {
let v = bigInt(0); let v = bigInt(0);
for (let i=nBits-1; i>=0; i--) { for (let i = nBits - 1; i >= 0; i--) {
v = v.shiftLeft(1); v = v.shiftLeft(1);
const name = sig+"["+i+"]"; const name = sig + "[" + i + "]";
const idx = cir.getSignalIdx(name); const idx = cir.getSignalIdx(name);
const vbit = bigInt(witness[idx].toString()); const vbit = bigInt(witness[idx].toString());
if (vbit.equals(bigInt(1))) { if (vbit.equals(bigInt(1))) {
@ -15,7 +14,7 @@ module.exports = function hexBits(cir, witness, sig, nBits) {
} else if (vbit.equals(bigInt(0))) { } else if (vbit.equals(bigInt(0))) {
v; v;
} else { } else {
console.log("Not Binary: "+name); console.log("Not Binary: " + name);
} }
} }
return v.toString(16); return v.toString(16);

View File

@ -1,6 +1,6 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const compiler = require("circom"); const compiler = require("circom");
const mimcjs = require("../src/mimc7.js"); const mimcjs = require("../src/mimc7.js");
@ -12,7 +12,7 @@ describe("MiMC Circuit test", function () {
this.timeout(100000); this.timeout(100000);
before( async () => { before(async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "mimc_test.circom"));
circuit = new snarkjs.Circuit(cirDef); circuit = new snarkjs.Circuit(cirDef);
@ -21,15 +21,14 @@ describe("MiMC Circuit test", function () {
}); });
it("Should check constrain", async () => { it("Should check constrain", async () => {
const w = circuit.calculateWitness({x_in: 1, k: 2}); const w = circuit.calculateWitness({ x_in: 1, k: 2 });
const res = w[circuit.getSignalIdx("main.out")]; const res = w[circuit.getSignalIdx("main.out")];
const res2 = mimcjs.hash(1,2,91); const res2 = mimcjs.hash(1, 2, 91);
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
}); });
}); });

View File

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

56
test/mimcspongecircuit.js Normal file
View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More