Compare commits

..

123 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
Jordi Baylina
7792887216
0.0.6 2019-02-15 09:41:11 +01:00
Jordi Baylina
7971f0150e
snarkjs version dep 2019-02-15 09:40:56 +01:00
Jordi Baylina
b3ff8b246d
Merge branch 'master' of github.com:iden3/circomlib 2019-02-15 09:39:43 +01:00
Jordi Baylina
951e51423d
rollupdoc 2019-02-15 09:39:38 +01:00
Jordi Baylina
9a5294dea1
Merge pull request #4 from ledfusion/master
Combined small fixes
2019-02-15 00:04:42 +01:00
Jordi
2635e8d3c9 Make code independent of NodeJS core modules 2019-02-12 12:21:44 +01:00
Jordi
138945bfdc Overcome undefined "Web3.utils" on web3@1.0.0-beta41 2019-02-12 12:19:17 +01:00
Jordi
2f9ad59c3a Exposing babyjub and pruneBuffer 2019-02-12 12:11:25 +01:00
Jordi Baylina
4a4a30b8b8
0.0.5 2018-12-23 00:02:50 +01:00
Jordi Baylina
084f5b593b
deps 2018-12-23 00:02:40 +01:00
Jordi Baylina
57da978ff5
0.0.4 2018-12-22 23:55:18 +01:00
Jordi Baylina
d1bde3ab55
version 2018-12-22 23:55:12 +01:00
Jordi Baylina
ed820fbc9b
0.0.2 2018-12-22 23:54:40 +01:00
Jordi Baylina
0639963bea
Small patches 2018-12-22 23:54:25 +01:00
Jordi Baylina
345f040b41
Package change name 2018-12-20 08:28:11 +01:00
Jordi Baylina
9cab539698
Substractor 2018-12-16 11:27:29 +01:00
Jordi Baylina
6ea1ea718a
BabyJub Optimization 2018-12-16 08:44:12 +01:00
Jordi Baylina
37edfc1834
Change bases and IV 2018-12-16 08:05:20 +01:00
Jordi Baylina
6d6558370f
Sparse Merkle tree working 2018-12-15 09:15:58 +01:00
Jordi Baylina
09f36d1e4d
Verification not working 2018-12-15 09:00:35 +01:00
Jordi Baylina
e02fd5edf8
SMT Update 2018-12-14 14:24:30 +01:00
Jordi Baylina
e636a4ac83
Simplify and working test 2018-12-13 21:04:37 +01:00
Jordi Baylina
ccaa7ff23b
working with some errors yet 2018-12-13 19:53:32 +01:00
Jordi Baylina
38fc4b7396
First Version SMT 2018-12-11 17:25:21 +01:00
Jordi Baylina
2d43178c8d
Merge other basic circuits here 2018-12-06 17:32:49 +01:00
Jordi Baylina
2cab572c66
Before merging in a single lib 2018-12-06 12:13:27 +01:00
Jordi Baylina
2ef25591b6
0.0.3 2018-11-28 10:29:19 +01:00
Jordi Baylina
91fe53118a
deps 2018-11-28 10:28:56 +01:00
Jordi Baylina
98a33d5700
eddsa done 2018-11-27 18:30:33 +01:00
Jordi Baylina
55e9a60c37
Pedersen2 and BitPoints MulFix and MulAny 2018-11-27 16:03:57 +01:00
Jordi Baylina
fcc61f9237
Change pedersen length to 251 2018-11-13 13:40:42 +01:00
Jordi Baylina
4b147eca7f
Pedersen Hash done with tests 2018-11-13 10:57:54 +01:00
Jordi Baylina
9513ee2ff2
Clarify the modules 2018-11-11 21:07:11 +01:00
Jordi Baylina
e4a5860117
Select points in subgroup and calculate x from y 2018-11-11 20:58:36 +01:00
183 changed files with 16128 additions and 1124 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,84 +1,74 @@
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 assert = require("assert"); const babyJub = require("../src/babyjub");
function getPoint(S) { function getPoint(S) {
const F = bn128.Fr; const F = bn128.Fr;
const h = createBlakeHash("blake256").update(S).digest(); const h = createBlakeHash("blake256").update(S).digest();
assert(h.length == 32); if (h.length != 32) {
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 x = bigInt(0); let y = bigInt(0);
for (let i=0; i<32; i++) { for (let i = 0; i < 32; i++) {
x = x.shl(8); y = y.shl(8);
x = x.add(bigInt(h[i])); y = y.add(bigInt(h[i]));
} }
const a = bigInt("168700"); const a = bigInt("168700");
const d = bigInt("168696"); const d = bigInt("168696");
const x2 = F.square(x); const y2 = F.square(y);
let y = 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, F.mul(a, x2)),
F.sub(F.one, F.mul(d, x2))));
if (y == null) return null; if (x == null) return null;
if (sign) y = F.neg(y); if (sign) x = F.neg(x);
return [bn128.Fr.affine(x), bn128.Fr.affine(y)]; const p = [bn128.Fr.affine(x), bn128.Fr.affine(y)];
const p8 = babyJub.mulPointEscalar(p, 8);
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++;
} }
assert(inCurve(p)); if (!babyJub.inCurve(p)) {
throw new Error("Point not in curve");
}
return p; return p;
} }
function inCurve(p) {
const F = bn128.Fr;
const a = bigInt("168700");
const d = bigInt("168696");
const x2 = F.square(p[0]);
const y2 = F.square(p[1]);
return F.equals(
F.add(F.mul(a, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), d)));
}
const g = [ const g = [
bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")]; bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
if (!inCurve(g)) { // Sanity check
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()}]`);
} }

View File

@ -1,298 +0,0 @@
{
"mainCode": "{\n {\n }\n ctx.setVar(\"base\", [], [\"17777552123799933955779906779655732241715742912184938656739573121738514868268\",\"2626589144620713026669568689430873010625803728049924121243784502389097019475\"]);\n}\n",
"signalName2Idx": {
"one": 0,
"main.out[0][0]": 1,
"main.out[0][1]": 2,
"main.out[1][0]": 3,
"main.out[1][1]": 4,
"main.out[2][0]": 5,
"main.out[2][1]": 6,
"main.out[3][0]": 7,
"main.out[3][1]": 8,
"main.out[4][0]": 9,
"main.out[4][1]": 10,
"main.out[5][0]": 11,
"main.out[5][1]": 12,
"main.out[6][0]": 13,
"main.out[6][1]": 14,
"main.out[7][0]": 15,
"main.out[7][1]": 16,
"main.out[8][0]": 17,
"main.out[8][1]": 18,
"main.out[9][0]": 19,
"main.out[9][1]": 20,
"main.out[10][0]": 21,
"main.out[10][1]": 22,
"main.out[11][0]": 23,
"main.out[11][1]": 24,
"main.out[12][0]": 25,
"main.out[12][1]": 26,
"main.out[13][0]": 27,
"main.out[13][1]": 28,
"main.out[14][0]": 29,
"main.out[14][1]": 30,
"main.out[15][0]": 31,
"main.out[15][1]": 32
},
"components": [
{
"name": "main",
"params": {
"base": [
{
"type": "NUMBER",
"value": "17777552123799933955779906779655732241715742912184938656739573121738514868268",
"first_line": 3,
"first_column": 12,
"last_line": 3,
"last_column": 89
},
{
"type": "NUMBER",
"value": "2626589144620713026669568689430873010625803728049924121243784502389097019475",
"first_line": 4,
"first_column": 12,
"last_line": 4,
"last_column": 88
}
],
"k": {
"type": "NUMBER",
"value": "0",
"first_line": 6,
"first_column": 41,
"last_line": 6,
"last_column": 42
}
},
"template": "EscalarMulW4Table",
"inputSignals": 0
}
],
"componentName2Idx": {
"main": 0
},
"signals": [
{
"names": [
"one"
],
"triggerComponents": []
},
{
"names": [
"main.out[0][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[0][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[1][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[1][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[2][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[2][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[3][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[3][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[4][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[4][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[5][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[5][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[6][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[6][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[7][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[7][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[8][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[8][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[9][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[9][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[10][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[10][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[11][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[11][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[12][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[12][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[13][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[13][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[14][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[14][1]"
],
"triggerComponents": []
},
{
"names": [
"main.out[15][0]"
],
"triggerComponents": []
},
{
"names": [
"main.out[15][1]"
],
"triggerComponents": []
}
],
"constraints": [],
"templates": {
"EscalarMulW4Table": "function(ctx) {\n ctx.setVar(\"dbl\", [], ctx.getVar(\"base\",[]));\n for (ctx.setVar(\"i\", [], \"0\");bigInt(ctx.getVar(\"i\",[])).lt(bigInt(bigInt(ctx.getVar(\"k\",[])).mul(bigInt(\"4\")).mod(__P__))) ? 1 : 0;(ctx.setVar(\"i\", [], bigInt(ctx.getVar(\"i\",[])).add(bigInt(\"1\")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__)) { \n {\n ctx.setVar(\"dbl\", [], ctx.callFunction(\"pointAdd\", [ctx.getVar(\"dbl\",[\"0\"]),ctx.getVar(\"dbl\",[\"1\"]),ctx.getVar(\"dbl\",[\"0\"]),ctx.getVar(\"dbl\",[\"1\"])]));\n }\n\n }\n ctx.setSignal(\"out\", [\"0\",\"0\"], \"0\");\n ctx.assert(ctx.getSignal(\"out\", [\"0\",\"0\"]), \"0\");\n ctx.setSignal(\"out\", [\"0\",\"1\"], \"1\");\n ctx.assert(ctx.getSignal(\"out\", [\"0\",\"1\"]), \"1\");\n for (ctx.setVar(\"i\", [], \"1\");bigInt(ctx.getVar(\"i\",[])).lt(bigInt(\"16\")) ? 1 : 0;(ctx.setVar(\"i\", [], bigInt(ctx.getVar(\"i\",[])).add(bigInt(\"1\")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__)) { \n {\n ctx.setVar(\"p\", [], ctx.callFunction(\"pointAdd\", [ctx.getSignal(\"out\", [bigInt(ctx.getVar(\"i\",[])).add(__P__).sub(bigInt(\"1\")).mod(__P__),\"0\"]),ctx.getSignal(\"out\", [bigInt(ctx.getVar(\"i\",[])).add(__P__).sub(bigInt(\"1\")).mod(__P__),\"1\"]),ctx.getVar(\"dbl\",[\"0\"]),ctx.getVar(\"dbl\",[\"1\"])]));\n ctx.setSignal(\"out\", [ctx.getVar(\"i\",[]),\"0\"], ctx.getVar(\"p\",[\"0\"]));\n ctx.assert(ctx.getSignal(\"out\", [ctx.getVar(\"i\",[]),\"0\"]), ctx.getVar(\"p\",[\"0\"]));\n ctx.setSignal(\"out\", [ctx.getVar(\"i\",[]),\"1\"], ctx.getVar(\"p\",[\"1\"]));\n ctx.assert(ctx.getSignal(\"out\", [ctx.getVar(\"i\",[]),\"1\"]), ctx.getVar(\"p\",[\"1\"]));\n }\n\n }\n}\n"
},
"functions": {
"pointAdd": {
"params": [
"x1",
"y1",
"x2",
"y2"
],
"func": "function(ctx) {\n ctx.setVar(\"a\", [], \"168700\");\n ctx.setVar(\"d\", [], \"168696\");\n ctx.setVar(\"res\", [\"0\"], bigInt(bigInt(bigInt(ctx.getVar(\"x1\",[])).mul(bigInt(ctx.getVar(\"y2\",[]))).mod(__P__)).add(bigInt(bigInt(ctx.getVar(\"y1\",[])).mul(bigInt(ctx.getVar(\"x2\",[]))).mod(__P__))).mod(__P__)).mul( bigInt(bigInt(\"1\").add(bigInt(bigInt(bigInt(bigInt(bigInt(ctx.getVar(\"d\",[])).mul(bigInt(ctx.getVar(\"x1\",[]))).mod(__P__)).mul(bigInt(ctx.getVar(\"x2\",[]))).mod(__P__)).mul(bigInt(ctx.getVar(\"y1\",[]))).mod(__P__)).mul(bigInt(ctx.getVar(\"y2\",[]))).mod(__P__))).mod(__P__)).inverse(__P__) ).mod(__P__));\n ctx.setVar(\"res\", [\"1\"], bigInt(bigInt(bigInt(ctx.getVar(\"y1\",[])).mul(bigInt(ctx.getVar(\"y2\",[]))).mod(__P__)).add(__P__).sub(bigInt(bigInt(bigInt(ctx.getVar(\"a\",[])).mul(bigInt(ctx.getVar(\"x1\",[]))).mod(__P__)).mul(bigInt(ctx.getVar(\"x2\",[]))).mod(__P__))).mod(__P__)).mul( bigInt(bigInt(\"1\").add(__P__).sub(bigInt(bigInt(bigInt(bigInt(bigInt(ctx.getVar(\"d\",[])).mul(bigInt(ctx.getVar(\"x1\",[]))).mod(__P__)).mul(bigInt(ctx.getVar(\"x2\",[]))).mod(__P__)).mul(bigInt(ctx.getVar(\"y1\",[]))).mod(__P__)).mul(bigInt(ctx.getVar(\"y2\",[]))).mod(__P__))).mod(__P__)).inverse(__P__) ).mod(__P__));\n return ctx.getVar(\"res\",[]);;\n}\n"
}
},
"nPrvInputs": 0,
"nPubInputs": 0,
"nInputs": 0,
"nOutputs": 0,
"nVars": 1,
"nConstants": 32,
"nSignals": 33
}

View File

@ -1,31 +0,0 @@
template BabyAdd() {
signal input x1;
signal input y1;
signal input x2;
signal input y2;
signal output xout;
signal output yout;
signal beta;
signal gamma;
signal delta;
signal epsilon;
signal tau;
var a = 168700;
var d = 168696;
beta <== x1*y2;
gamma <== y1*x2;
delta <== y1*y2;
epsilon <== x1*x2;
tau <== delta * epsilon;
xout <-- (beta + gamma) / (1+ d*tau);
(1+ d*tau) * xout === (beta + gamma);
yout <-- (delta - a * epsilon) / (1-d*tau);
(1-d*tau)*yout === (delta - a * epsilon);
}

View File

@ -1,22 +0,0 @@
templete Verfier() {
signal input hMsg[256];
signal input Ax;
signal input Ay;
signal input Rx;
signal input Ry;
signal input s[256];
componet exps = Exp();
component exph = Exp();
component adder = BabyAdd();
}

View File

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

View File

@ -1,47 +0,0 @@
include "escalarmul.circom";
component Pedersen(n) {
signal input in[n];
signal output out[2];
var nexps = ((n-1) \ 253) + 1;
var nlastbits = n - (nexps-1)*253;
component escalarMuls[nexps];
var PBASE = [
[17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475],
[17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475],
[17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475],
[17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475],
[17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475]
];
var i;
var j;
for (i=0; i<nexps; i++) {
var nexpbits = (i == nexps-1) ? nlastbits : 253;
escalarMuls[i] = EscalarMul(nexpbits, PBASE[i][0], PBAS[i][1]);
for (j=0; j<nexpbits; j++) {
escalarMuls[i].in[j] <== in[253*i + j];
}
if (i==0) {
escalarMuls[i].inp[0] <== 0;
escalarMuls[i].inp[1] <== 0;
} else {
escalarMuls[i].inp[0] <== escalarMuls[i-1].out[0];
escalarMuls[i].inp[1] <== escalarMuls[i-1].out[1];
}
}
escalarMuls[nexps-1].out[0] ==> out[0];
escalarMuls[nexps-1].out[1] ==> out[1];
}

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

@ -0,0 +1,43 @@
/*
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";
template AliasCheck() {
signal input in[254];
component compConstant = CompConstant(-1);
for (var i=0; i<254; i++) in[i] ==> compConstant.in[i];
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;
}

106
circuits/babyjub.circom Normal file
View File

@ -0,0 +1,106 @@
/*
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 "bitify.circom";
include "escalarmulfix.circom";
template BabyAdd() {
signal input x1;
signal input y1;
signal input x2;
signal input y2;
signal output xout;
signal output yout;
signal beta;
signal gamma;
signal delta;
signal tau;
var a = 168700;
var d = 168696;
beta <== x1*y2;
gamma <== y1*x2;
delta <== (-a*x1+y1)*(x2 + y2);
tau <== beta * gamma;
xout <-- (beta + gamma) / (1+ d*tau);
(1+ d*tau) * xout === (beta + gamma);
yout <-- (delta + a*beta - gamma) / (1-d*tau);
(1-d*tau)*yout === (delta + a*beta - gamma);
}
template BabyDbl() {
signal input x;
signal input y;
signal output xout;
signal output yout;
component adder = BabyAdd();
adder.x1 <== x;
adder.y1 <== y;
adder.x2 <== x;
adder.y2 <== y;
adder.xout ==> xout;
adder.yout ==> yout;
}
template BabyCheck() {
signal input x;
signal input y;
signal x2;
signal y2;
var a = 168700;
var d = 168696;
x2 <== x*x;
y2 <== y*y;
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];
}

71
circuits/binsub.circom Normal file
View File

@ -0,0 +1,71 @@
/*
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/>.
*/
/*
This component creates a binary substraction.
Main Constraint:
(in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1)) +
+ 2^n
- (in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1))
===
out[0] * 2^0 + out[1] * 2^1 + + out[n-1] *2^(n-1) + aux
out[0] * (out[0] - 1) === 0
out[1] * (out[0] - 1) === 0
.
.
.
out[n-1] * (out[n-1] - 1) === 0
aux * (aux-1) == 0
*/
template BinSub(n) {
signal input in[2][n];
signal output out[n];
signal aux;
var lin = 2**n;
var lout = 0;
for (var i=0; i<n; i++) {
lin = lin + in[0][i]*(2**i);
lin = lin - in[1][i]*(2**i);
}
for (var i=0; i<n; i++) {
out[i] <-- (lin >> i) & 1;
// Ensure out is binary
out[i] * (out[i] - 1) === 0;
lout = lout + out[i]*(2**i);
}
aux <-- (lin >> n) & 1;
aux*(aux-1) === 0;
lout = lout + aux*(2**n);
// Ensure the sum;
lin === lout;
}

95
circuits/binsum.circom Normal file
View File

@ -0,0 +1,95 @@
/*
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/>.
*/
/*
Binary Sum
==========
This component creates a binary sum componet of ops operands and n bits each operand.
e is Number of carries: Depends on the number of operands in the input.
Main Constraint:
in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1) +
+ in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1) +
+ ..
+ in[ops-1][0] * 2^0 + in[ops-1][1] * 2^1 + ..... + in[ops-1][n-1] * 2^(n-1) +
===
out[0] * 2^0 + out[1] * 2^1 + + out[n+e-1] *2(n+e-1)
To waranty binary outputs:
out[0] * (out[0] - 1) === 0
out[1] * (out[0] - 1) === 0
.
.
.
out[n+e-1] * (out[n+e-1] - 1) == 0
*/
/*
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) {
var n = 1;
var r = 0;
while (n-1<a) {
r++;
n *= 2;
}
return r;
}
/* 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) {
var nout = nbits((2**n -1)*ops);
signal input in[ops][n];
signal output out[nout];
var lin = 0;
var lout = 0;
var k;
var j;
for (k=0; k<n; k++) {
for (j=0; j<ops; j++) {
lin += in[j][k] * 2**k;
}
}
for (k=0; k<nout; k++) {
out[k] <-- (lin >> k) & 1;
// Ensure out is binary
out[k] * (out[k] - 1) === 0;
lout += out[k] * 2**k;
}
// Ensure the sum;
lin === lout;
}

103
circuits/bitify.circom Normal file
View File

@ -0,0 +1,103 @@
/*
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 "comparators.circom";
include "aliascheck.circom";
/* This doesn't check aliasing, so for n > 253 there are multiple bit strings for each number */
template Num2Bits(n) {
signal input in;
signal output out[n];
var lc1=0;
for (var i = 0; i<n; i++) {
out[i] <-- (in >> i) & 1;
out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * 2**i;
}
lc1 === in;
}
template Num2Bits_strict() {
signal input in;
signal output out[254];
component aliasCheck = AliasCheck();
component n2b = Num2Bits(254);
in ==> n2b.in;
for (var i=0; i<254; i++) {
n2b.out[i] ==> out[i];
n2b.out[i] ==> aliasCheck.in[i];
}
}
template Bits2Num(n) {
signal input in[n];
signal output out;
var lc1=0;
for (var i = 0; i<n; i++) {
lc1 += in[i] * 2**i;
}
lc1 ==> out;
}
template Bits2Num_strict() {
signal input in[n];
signal output out;
component aliasCheck = AliasCheck();
component b2n = Bits2Num(254);
for (var i=0; i<254; i++) {
in[i] ==> b2n.in[i];
in[i] ==> aliasCheck.in[i];
}
b2n.out ==> out;
}
/* n must not exceed 253 */
template Num2BitsNeg(n) {
signal input in;
signal output out[n];
var lc1=0;
component isZero;
isZero = IsZero();
var neg = n == 0 ? 0 : 2**n - in;
for (var i = 0; i<n; i++) {
out[i] <-- (neg >> i) & 1;
out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * 2**i;
}
in ==> isZero.in;
lc1 + isZero.out * 2**n === 2**n - in;
}

139
circuits/comparators.circom Normal file
View File

@ -0,0 +1,139 @@
/*
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 "bitify.circom";
include "binsum.circom";
template IsZero() {
signal input in;
signal output out;
signal inv;
inv <-- in!=0 ? 1/in : 0;
out <== -in*inv +1;
in*out === 0;
}
template IsEqual() {
signal input in[2];
signal output out;
component isz = IsZero();
in[1] - in[0] ==> isz.in;
isz.out ==> out;
}
template ForceEqualIfEnabled() {
signal input enabled;
signal input in[2];
component isz = IsZero();
in[1] - in[0] ==> isz.in;
(1 - isz.out)*enabled === 0;
}
/*
// N is the number of bits the input have.
// The MSF is the sign bit.
template LessThan(n) {
signal input in[2];
signal output out;
component num2Bits0;
component num2Bits1;
component adder;
adder = BinSum(n, 2);
num2Bits0 = Num2Bits(n);
num2Bits1 = Num2BitsNeg(n);
in[0] ==> num2Bits0.in;
in[1] ==> num2Bits1.in;
var i;
for (i=0;i<n;i++) {
num2Bits0.out[i] ==> adder.in[0][i];
num2Bits1.out[i] ==> adder.in[1][i];
}
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

@ -0,0 +1,74 @@
/*
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 "bitify.circom";
// Returns 1 if in (in binary) > ct
template CompConstant(ct) {
signal input in[254];
signal output out;
signal parts[127];
signal sout;
var clsb;
var cmsb;
var slsb;
var smsb;
var sum=0;
var b = (1 << 128) -1;
var a = 1;
var e = 1;
var i;
for (i=0;i<127; i++) {
clsb = (ct >> (i*2)) & 1;
cmsb = (ct >> (i*2+1)) & 1;
slsb = in[i*2];
smsb = in[i*2+1];
if ((cmsb==0)&(clsb==0)) {
parts[i] <== -b*smsb*slsb + b*smsb + b*slsb;
} else if ((cmsb==0)&(clsb==1)) {
parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a;
} else if ((cmsb==1)&(clsb==0)) {
parts[i] <== b*smsb*slsb - a*smsb + a;
} else {
parts[i] <== -a*smsb*slsb + a;
}
sum = sum + parts[i];
b = b -e;
a = a +e;
e = e*2;
}
sout <== sum;
component num2bits = Num2Bits(135);
num2bits.in <== sout;
out <== num2bits.out[127];
}

141
circuits/eddsa.circom Normal file
View File

@ -0,0 +1,141 @@
/*
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 "pedersen.circom";
include "escalarmulany.circom";
include "escalarmulfix.circom";
template EdDSAVerifier(n) {
signal input msg[n];
signal input A[256];
signal input R8[256];
signal input S[256];
signal Ax;
signal Ay;
signal R8x;
signal R8y;
var i;
// Ensure S<Subgroup Order
component aliasCheck = AliasCheckBabyJub();
aliasCheck.enabled <== 1;
for (i=0; i<251; i++) {
S[i] ==> aliasCheck.in[i];
}
S[251] === 0;
S[252] === 0;
S[253] === 0;
S[254] === 0;
S[255] === 0;
// Convert A to Field elements (And verify A)
component bits2pointA = Bits2Point_Strict();
for (i=0; i<256; i++) {
bits2pointA.in[i] <== A[i];
}
Ax <== bits2pointA.out[0];
Ay <== bits2pointA.out[1];
// Convert R8 to Field elements (And verify R8)
component bits2pointR8 = Bits2Point_Strict();
for (i=0; i<256; i++) {
bits2pointR8.in[i] <== R8[i];
}
R8x <== bits2pointR8.out[0];
R8y <== bits2pointR8.out[1];
// Calculate the h = H(R,A, msg)
component hash = Pedersen(512+n);
for (i=0; i<256; i++) {
hash.in[i] <== R8[i];
hash.in[256+i] <== A[i];
}
for (i=0; i<n; i++) {
hash.in[512+i] <== msg[i];
}
component point2bitsH = Point2Bits_Strict();
point2bitsH.in[0] <== hash.out[0];
point2bitsH.in[1] <== hash.out[1];
// 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(256);
for (i=0; i<256; i++) {
mulAny.e[i] <== point2bitsH.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(256, BASE8);
for (i=0; i<256; i++) {
mulFix.e[i] <== S[i];
}
// Do the comparation left == right
mulFix.out[0] === addRight.xout;
mulFix.out[1] === addRight.yout;
}

122
circuits/eddsamimc.circom Normal file
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 "mimc.circom";
include "bitify.circom";
include "escalarmulany.circom";
include "escalarmulfix.circom";
template EdDSAMiMCVerifier() {
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 = MultiMiMC7(5, 91);
hash.in[0] <== R8x;
hash.in[1] <== R8y;
hash.in[2] <== Ax;
hash.in[3] <== Ay;
hash.in[4] <== M;
hash.k <== 0;
component h2bits = Num2Bits_strict();
h2bits.in <== hash.out;
// Calculate second part of the right side: right2 = h*8*A
// Multiply by 8 by adding it 3 times. This also ensure that the result is in
// the subgroup.
component dbl1 = BabyDbl();
dbl1.x <== Ax;
dbl1.y <== Ay;
component dbl2 = BabyDbl();
dbl2.x <== dbl1.xout;
dbl2.y <== dbl1.yout;
component dbl3 = BabyDbl();
dbl3.x <== dbl2.xout;
dbl3.y <== dbl2.yout;
// We check that A is not zero.
component isZero = IsZero();
isZero.in <== dbl3.x;
isZero.out === 0;
component mulAny = EscalarMulAny(254);
for (i=0; i<254; i++) {
mulAny.e[i] <== h2bits.out[i];
}
mulAny.p[0] <== dbl3.xout;
mulAny.p[1] <== dbl3.yout;
// Compute the right side: right = R8 + right2
component addRight = BabyAdd();
addRight.x1 <== R8x;
addRight.y1 <== R8y;
addRight.x2 <== mulAny.out[0];
addRight.y2 <== mulAny.out[1];
// Calculate left side of equation left = S*B8
var BASE8 = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(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,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,3 +1,22 @@
/*
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/>.
*/
/* /*
┏━━━━━━━━━━━┓ ┏━━━━━━━━━━━┓
@ -52,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;
@ -67,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

@ -0,0 +1,196 @@
/*
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 "montgomery.circom";
include "babyjub.circom";
include "comparators.circom";
template Multiplexor2() {
signal input sel;
signal input in[2][2];
signal output out[2];
out[0] <== (in[1][0] - in[0][0])*sel + in[0][0];
out[1] <== (in[1][1] - in[0][1])*sel + in[0][1];
}
template BitElementMulAny() {
signal input sel;
signal input dblIn[2];
signal input addIn[2];
signal output dblOut[2];
signal output addOut[2];
component doubler = MontgomeryDouble();
component adder = MontgomeryAdd();
component selector = Multiplexor2();
sel ==> selector.sel;
dblIn[0] ==> doubler.in[0];
dblIn[1] ==> doubler.in[1];
doubler.out[0] ==> adder.in1[0];
doubler.out[1] ==> adder.in1[1];
addIn[0] ==> adder.in2[0];
addIn[1] ==> adder.in2[1];
addIn[0] ==> selector.in[0][0];
addIn[1] ==> selector.in[0][1];
adder.out[0] ==> selector.in[1][0];
adder.out[1] ==> selector.in[1][1];
doubler.out[0] ==> dblOut[0];
doubler.out[1] ==> dblOut[1];
selector.out[0] ==> addOut[0];
selector.out[1] ==> addOut[1];
}
// p is montgomery point
// n must be <= 248
// returns out in twisted edwards
// Double is in montgomery to be linked;
template SegmentMulAny(n) {
signal input e[n];
signal input p[2];
signal output out[2];
signal output dbl[2];
component bits[n-1];
component e2m = Edwards2Montgomery();
p[0] ==> e2m.in[0];
p[1] ==> e2m.in[1];
var i;
bits[0] = BitElementMulAny();
e2m.out[0] ==> bits[0].dblIn[0]
e2m.out[1] ==> bits[0].dblIn[1]
e2m.out[0] ==> bits[0].addIn[0]
e2m.out[1] ==> bits[0].addIn[1]
e[1] ==> bits[0].sel;
for (i=1; i<n-1; i++) {
bits[i] = BitElementMulAny();
bits[i-1].dblOut[0] ==> bits[i].dblIn[0]
bits[i-1].dblOut[1] ==> bits[i].dblIn[1]
bits[i-1].addOut[0] ==> bits[i].addIn[0]
bits[i-1].addOut[1] ==> bits[i].addIn[1]
e[i+1] ==> bits[i].sel;
}
bits[n-2].dblOut[0] ==> dbl[0];
bits[n-2].dblOut[1] ==> dbl[1];
component m2e = Montgomery2Edwards();
bits[n-2].addOut[0] ==> m2e.in[0];
bits[n-2].addOut[1] ==> m2e.in[1];
component eadder = BabyAdd();
m2e.out[0] ==> eadder.x1;
m2e.out[1] ==> eadder.y1;
-p[0] ==> eadder.x2;
p[1] ==> eadder.y2;
component lastSel = Multiplexor2();
e[0] ==> lastSel.sel;
eadder.xout ==> lastSel.in[0][0];
eadder.yout ==> lastSel.in[0][1];
m2e.out[0] ==> lastSel.in[1][0];
m2e.out[1] ==> lastSel.in[1][1];
lastSel.out[0] ==> out[0];
lastSel.out[1] ==> out[1];
}
// This function assumes that p is in the subgroup and it is different to 0
template EscalarMulAny(n) {
signal input e[n]; // Input in binary format
signal input p[2]; // Point (Twisted format)
signal output out[2]; // Point (Twisted format)
var nsegments = (n-1)\148 +1;
var nlastsegment = n - (nsegments-1)*148;
component segments[nsegments];
component doublers[nsegments-1];
component m2e[nsegments-1];
component adders[nsegments-1];
component zeropoint = IsZero();
zeropoint.in <== p[0];
var s;
var i;
var nseg;
for (s=0; s<nsegments; s++) {
nseg = (s < nsegments-1) ? 148 : nlastsegment;
segments[s] = SegmentMulAny(nseg);
for (i=0; i<nseg; i++) {
e[s*148+i] ==> segments[s].e[i];
}
if (s==0) {
// force G8 point if input point is zero
segments[s].p[0] <== p[0] + (5299619240641551281634865583518297030282874472190772894086521144482721001553 - p[0])*zeropoint.out;
segments[s].p[1] <== p[1] + (16950150798460657717958625567821834550301663161624707787222815936182638968203 - p[1])*zeropoint.out;
} else {
doublers[s-1] = MontgomeryDouble();
m2e[s-1] = Montgomery2Edwards();
adders[s-1] = BabyAdd();
segments[s-1].dbl[0] ==> doublers[s-1].in[0];
segments[s-1].dbl[1] ==> doublers[s-1].in[1];
doublers[s-1].out[0] ==> m2e[s-1].in[0];
doublers[s-1].out[1] ==> m2e[s-1].in[1];
m2e[s-1].out[0] ==> segments[s].p[0];
m2e[s-1].out[1] ==> segments[s].p[1];
if (s==1) {
segments[s-1].out[0] ==> adders[s-1].x1;
segments[s-1].out[1] ==> adders[s-1].y1;
} else {
adders[s-2].xout ==> adders[s-1].x1;
adders[s-2].yout ==> adders[s-1].y1;
}
segments[s].out[0] ==> adders[s-1].x2;
segments[s].out[1] ==> adders[s-1].y2;
}
}
if (nsegments == 1) {
segments[0].out[0]*(1-zeropoint.out) ==> out[0];
segments[0].out[1]+(1-segments[0].out[1])*zeropoint.out ==> out[1];
} else {
adders[nsegments-2].xout*(1-zeropoint.out) ==> out[0];
adders[nsegments-2].yout+(1-adders[nsegments-2].yout)*zeropoint.out ==> out[1];
}
}

View File

@ -0,0 +1,300 @@
/*
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 "mux3.circom";
include "montgomery.circom";
include "babyjub.circom";
/*
Window of 3 elements, it calculates
out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
out4 = 4*base
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() {
signal input in[3];
signal input base[2];
signal output out[2];
signal output out8[2]; // Returns 8*Base (To be linked)
component mux = MultiMux3(2);
mux.s[0] <== in[0];
mux.s[1] <== in[1];
mux.s[2] <== in[2];
component dbl2 = MontgomeryDouble();
component adr3 = MontgomeryAdd();
component adr4 = MontgomeryAdd();
component adr5 = MontgomeryAdd();
component adr6 = MontgomeryAdd();
component adr7 = MontgomeryAdd();
component adr8 = MontgomeryAdd();
// in[0] -> 1*BASE
mux.c[0][0] <== base[0];
mux.c[1][0] <== base[1];
// in[1] -> 2*BASE
dbl2.in[0] <== base[0];
dbl2.in[1] <== base[1];
mux.c[0][1] <== dbl2.out[0];
mux.c[1][1] <== dbl2.out[1];
// in[2] -> 3*BASE
adr3.in1[0] <== base[0];
adr3.in1[1] <== base[1];
adr3.in2[0] <== dbl2.out[0];
adr3.in2[1] <== dbl2.out[1];
mux.c[0][2] <== adr3.out[0];
mux.c[1][2] <== adr3.out[1];
// in[3] -> 4*BASE
adr4.in1[0] <== base[0];
adr4.in1[1] <== base[1];
adr4.in2[0] <== adr3.out[0];
adr4.in2[1] <== adr3.out[1];
mux.c[0][3] <== adr4.out[0];
mux.c[1][3] <== adr4.out[1];
// in[4] -> 5*BASE
adr5.in1[0] <== base[0];
adr5.in1[1] <== base[1];
adr5.in2[0] <== adr4.out[0];
adr5.in2[1] <== adr4.out[1];
mux.c[0][4] <== adr5.out[0];
mux.c[1][4] <== adr5.out[1];
// in[5] -> 6*BASE
adr6.in1[0] <== base[0];
adr6.in1[1] <== base[1];
adr6.in2[0] <== adr5.out[0];
adr6.in2[1] <== adr5.out[1];
mux.c[0][5] <== adr6.out[0];
mux.c[1][5] <== adr6.out[1];
// in[6] -> 7*BASE
adr7.in1[0] <== base[0];
adr7.in1[1] <== base[1];
adr7.in2[0] <== adr6.out[0];
adr7.in2[1] <== adr6.out[1];
mux.c[0][6] <== adr7.out[0];
mux.c[1][6] <== adr7.out[1];
// in[7] -> 8*BASE
adr8.in1[0] <== base[0];
adr8.in1[1] <== base[1];
adr8.in2[0] <== adr7.out[0];
adr8.in2[1] <== adr7.out[1];
mux.c[0][7] <== adr8.out[0];
mux.c[1][7] <== adr8.out[1];
out8[0] <== adr8.out[0];
out8[1] <== adr8.out[1];
out[0] <== mux.out[0];
out[1] <== mux.out[1];
}
/*
This component does a multiplication of a escalar times a fix base
nWindows must not exceed 82
Signals:
e: The scalar in bits
base: the base point in edwards format
out: The result
dbl: Point in Montgomery to be linked to the next segment.
*/
template SegmentMulFix(nWindows) {
signal input e[nWindows*3];
signal input base[2];
signal output out[2];
signal output dbl[2];
var i;
var j;
// Convert the base to montgomery
component e2m = Edwards2Montgomery();
e2m.in[0] <== base[0];
e2m.in[1] <== base[1];
component windows[nWindows];
component adders[nWindows];
component cadders[nWindows];
// In the last step we add an extra doubler so that numbers do not match.
component dblLast = MontgomeryDouble();
for (i=0; i<nWindows; i++) {
windows[i] = WindowMulFix();
cadders[i] = MontgomeryAdd();
if (i==0) {
windows[i].base[0] <== e2m.out[0];
windows[i].base[1] <== e2m.out[1];
cadders[i].in1[0] <== e2m.out[0];
cadders[i].in1[1] <== e2m.out[1];
} else {
windows[i].base[0] <== windows[i-1].out8[0];
windows[i].base[1] <== windows[i-1].out8[1];
cadders[i].in1[0] <== cadders[i-1].out[0];
cadders[i].in1[1] <== cadders[i-1].out[1];
}
if (i<nWindows-1) {
cadders[i].in2[0] <== windows[i].out8[0];
cadders[i].in2[1] <== windows[i].out8[1];
} else {
dblLast.in[0] <== windows[i].out8[0];
dblLast.in[1] <== windows[i].out8[1];
cadders[i].in2[0] <== dblLast.out[0];
cadders[i].in2[1] <== dblLast.out[1];
}
for (j=0; j<3; j++) {
windows[i].in[j] <== e[3*i+j];
}
}
for (i=0; i<nWindows; i++) {
adders[i] = MontgomeryAdd();
if (i==0) {
adders[i].in1[0] <== dblLast.out[0];
adders[i].in1[1] <== dblLast.out[1];
} else {
adders[i].in1[0] <== adders[i-1].out[0];
adders[i].in1[1] <== adders[i-1].out[1];
}
adders[i].in2[0] <== windows[i].out[0];
adders[i].in2[1] <== windows[i].out[1];
}
component m2e = Montgomery2Edwards();
component cm2e = Montgomery2Edwards();
m2e.in[0] <== adders[nWindows-1].out[0];
m2e.in[1] <== adders[nWindows-1].out[1];
cm2e.in[0] <== cadders[nWindows-1].out[0];
cm2e.in[1] <== cadders[nWindows-1].out[1];
component cAdd = BabyAdd();
cAdd.x1 <== m2e.out[0];
cAdd.y1 <== m2e.out[1];
cAdd.x2 <== -cm2e.out[0];
cAdd.y2 <== cm2e.out[1];
cAdd.xout ==> out[0];
cAdd.yout ==> out[1];
windows[nWindows-1].out8[0] ==> dbl[0];
windows[nWindows-1].out8[1] ==> dbl[1];
}
/*
This component multiplies a escalar times a fixed point BASE (twisted edwards format)
Signals
e: The escalar in binary format
out: The output point in twisted edwards
*/
template EscalarMulFix(n, BASE) {
signal input e[n]; // Input in binary format
signal output out[2]; // Point (Twisted format)
var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
var nlastsegment = n - (nsegments-1)*246;
component segments[nsegments];
component m2e[nsegments-1];
component adders[nsegments-1];
var s;
var i;
var nseg;
var nWindows;
for (s=0; s<nsegments; s++) {
nseg = (s < nsegments-1) ? 246 : nlastsegment;
nWindows = ((nseg - 1)\3)+1;
segments[s] = SegmentMulFix(nWindows);
for (i=0; i<nseg; i++) {
segments[s].e[i] <== e[s*246+i];
}
for (i = nseg; i<nWindows*3; i++) {
segments[s].e[i] <== 0;
}
if (s==0) {
segments[s].base[0] <== BASE[0];
segments[s].base[1] <== BASE[1];
} else {
m2e[s-1] = Montgomery2Edwards();
adders[s-1] = BabyAdd();
segments[s-1].dbl[0] ==> m2e[s-1].in[0];
segments[s-1].dbl[1] ==> m2e[s-1].in[1];
m2e[s-1].out[0] ==> segments[s].base[0];
m2e[s-1].out[1] ==> segments[s].base[1];
if (s==1) {
segments[s-1].out[0] ==> adders[s-1].x1;
segments[s-1].out[1] ==> adders[s-1].y1;
} else {
adders[s-2].xout ==> adders[s-1].x1;
adders[s-2].yout ==> adders[s-1].y1;
}
segments[s].out[0] ==> adders[s-1].x2;
segments[s].out[1] ==> adders[s-1].y2;
}
}
if (nsegments == 1) {
segments[0].out[0] ==> out[0];
segments[0].out[1] ==> out[1];
} else {
adders[nsegments-2].xout ==> out[0];
adders[nsegments-2].yout ==> out[1];
}
}

View File

@ -0,0 +1,51 @@
/*
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/>.
*/
function pointAdd(x1,y1,x2,y2) {
var a = 168700;
var d = 168696;
var res[2];
res[0] = (x1*y2 + y1*x2) / (1 + d*x1*x2*y1*y2);
res[1] = (y1*y2 - a*x1*x2) / (1 - d*x1*x2*y1*y2);
return res;
}
function EscalarMulW4Table(base, k) {
var out[16][2];
var i;
var p[2];
var dbl = base;
for (i=0; i<k*4; i++) {
dbl = pointAdd(dbl[0], dbl[1], dbl[0], dbl[1]);
}
out[0][0] = 0;
out[0][1] = 1;
for (i=1; i<16; i++) {
p = pointAdd(out[i-1][0], out[i-1][1], dbl[0], dbl[1]);
out[i][0] = p[0];
out[i][1] = p[1];
}
return out;
}

92
circuits/gates.circom Normal file
View File

@ -0,0 +1,92 @@
/*
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 XOR() {
signal input a;
signal input b;
signal output out;
out <== a + b - 2*a*b;
}
template AND() {
signal input a;
signal input b;
signal output out;
out <== a*b;
}
template OR() {
signal input a;
signal input b;
signal output out;
out <== a + b - a*b;
}
template NOT() {
signal input in;
signal output out;
out <== 1 + in - 2*in;
}
template NAND() {
signal input a;
signal input b;
signal output out;
out <== 1 - a*b;
}
template NOR() {
signal input a;
signal input b;
signal output out;
out <== a*b + 1 - a - b;
}
template MultiAND(n) {
signal input in[n];
signal output out;
if (n==1) {
out <== in[0];
} else if (n==2) {
component and1 = AND();
and1.a <== in[0];
and1.b <== in[1];
out <== and1.out;
} else {
component and2 = AND();
component ands[2];
var n1 = n\2;
var n2 = n-n\2;
ands[0] = MultiAND(n1);
ands[1] = MultiAND(n2);
for (var i=0; i<n1; i++) ands[0].in[i] <== in[i];
for (var i=0; i<n2; i++) ands[1].in[i] <== in[n1+i];
and2.a <== ands[0].out;
and2.b <== ands[1].out;
out <== and2.out;
}
}

155
circuits/mimc.circom Normal file
View File

@ -0,0 +1,155 @@
/*
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 MiMC7(nrounds) {
signal input x_in;
signal input k;
signal output out;
var c = [
0,
20888961410941983456478427210666206549300505294776164667214940546594746570981,
15265126113435022738560151911929040668591755459209400716467504685752745317193,
8334177627492981984476504167502758309043212251641796197711684499645635709656,
1374324219480165500871639364801692115397519265181803854177629327624133579404,
11442588683664344394633565859260176446561886575962616332903193988751292992472,
2558901189096558760448896669327086721003508630712968559048179091037845349145,
11189978595292752354820141775598510151189959177917284797737745690127318076389,
3262966573163560839685415914157855077211340576201936620532175028036746741754,
17029914891543225301403832095880481731551830725367286980611178737703889171730,
4614037031668406927330683909387957156531244689520944789503628527855167665518,
19647356996769918391113967168615123299113119185942498194367262335168397100658,
5040699236106090655289931820723926657076483236860546282406111821875672148900,
2632385916954580941368956176626336146806721642583847728103570779270161510514,
17691411851977575435597871505860208507285462834710151833948561098560743654671,
11482807709115676646560379017491661435505951727793345550942389701970904563183,
8360838254132998143349158726141014535383109403565779450210746881879715734773,
12663821244032248511491386323242575231591777785787269938928497649288048289525,
3067001377342968891237590775929219083706800062321980129409398033259904188058,
8536471869378957766675292398190944925664113548202769136103887479787957959589,
19825444354178182240559170937204690272111734703605805530888940813160705385792,
16703465144013840124940690347975638755097486902749048533167980887413919317592,
13061236261277650370863439564453267964462486225679643020432589226741411380501,
10864774797625152707517901967943775867717907803542223029967000416969007792571,
10035653564014594269791753415727486340557376923045841607746250017541686319774,
3446968588058668564420958894889124905706353937375068998436129414772610003289,
4653317306466493184743870159523234588955994456998076243468148492375236846006,
8486711143589723036499933521576871883500223198263343024003617825616410932026,
250710584458582618659378487568129931785810765264752039738223488321597070280,
2104159799604932521291371026105311735948154964200596636974609406977292675173,
16313562605837709339799839901240652934758303521543693857533755376563489378839,
6032365105133504724925793806318578936233045029919447519826248813478479197288,
14025118133847866722315446277964222215118620050302054655768867040006542798474,
7400123822125662712777833064081316757896757785777291653271747396958201309118,
1744432620323851751204287974553233986555641872755053103823939564833813704825,
8316378125659383262515151597439205374263247719876250938893842106722210729522,
6739722627047123650704294650168547689199576889424317598327664349670094847386,
21211457866117465531949733809706514799713333930924902519246949506964470524162,
13718112532745211817410303291774369209520657938741992779396229864894885156527,
5264534817993325015357427094323255342713527811596856940387954546330728068658,
18884137497114307927425084003812022333609937761793387700010402412840002189451,
5148596049900083984813839872929010525572543381981952060869301611018636120248,
19799686398774806587970184652860783461860993790013219899147141137827718662674,
19240878651604412704364448729659032944342952609050243268894572835672205984837,
10546185249390392695582524554167530669949955276893453512788278945742408153192,
5507959600969845538113649209272736011390582494851145043668969080335346810411,
18177751737739153338153217698774510185696788019377850245260475034576050820091,
19603444733183990109492724100282114612026332366576932662794133334264283907557,
10548274686824425401349248282213580046351514091431715597441736281987273193140,
1823201861560942974198127384034483127920205835821334101215923769688644479957,
11867589662193422187545516240823411225342068709600734253659804646934346124945,
18718569356736340558616379408444812528964066420519677106145092918482774343613,
10530777752259630125564678480897857853807637120039176813174150229243735996839,
20486583726592018813337145844457018474256372770211860618687961310422228379031,
12690713110714036569415168795200156516217175005650145422920562694422306200486,
17386427286863519095301372413760745749282643730629659997153085139065756667205,
2216432659854733047132347621569505613620980842043977268828076165669557467682,
6309765381643925252238633914530877025934201680691496500372265330505506717193,
20806323192073945401862788605803131761175139076694468214027227878952047793390,
4037040458505567977365391535756875199663510397600316887746139396052445718861,
19948974083684238245321361840704327952464170097132407924861169241740046562673,
845322671528508199439318170916419179535949348988022948153107378280175750024,
16222384601744433420585982239113457177459602187868460608565289920306145389382,
10232118865851112229330353999139005145127746617219324244541194256766741433339,
6699067738555349409504843460654299019000594109597429103342076743347235369120,
6220784880752427143725783746407285094967584864656399181815603544365010379208,
6129250029437675212264306655559561251995722990149771051304736001195288083309,
10773245783118750721454994239248013870822765715268323522295722350908043393604,
4490242021765793917495398271905043433053432245571325177153467194570741607167,
19596995117319480189066041930051006586888908165330319666010398892494684778526,
837850695495734270707668553360118467905109360511302468085569220634750561083,
11803922811376367215191737026157445294481406304781326649717082177394185903907,
10201298324909697255105265958780781450978049256931478989759448189112393506592,
13564695482314888817576351063608519127702411536552857463682060761575100923924,
9262808208636973454201420823766139682381973240743541030659775288508921362724,
173271062536305557219323722062711383294158572562695717740068656098441040230,
18120430890549410286417591505529104700901943324772175772035648111937818237369,
20484495168135072493552514219686101965206843697794133766912991150184337935627,
19155651295705203459475805213866664350848604323501251939850063308319753686505,
11971299749478202793661982361798418342615500543489781306376058267926437157297,
18285310723116790056148596536349375622245669010373674803854111592441823052978,
7069216248902547653615508023941692395371990416048967468982099270925308100727,
6465151453746412132599596984628739550147379072443683076388208843341824127379,
16143532858389170960690347742477978826830511669766530042104134302796355145785,
19362583304414853660976404410208489566967618125972377176980367224623492419647,
1702213613534733786921602839210290505213503664731919006932367875629005980493,
10781825404476535814285389902565833897646945212027592373510689209734812292327,
4212716923652881254737947578600828255798948993302968210248673545442808456151,
7594017890037021425366623750593200398174488805473151513558919864633711506220,
18979889247746272055963929241596362599320706910852082477600815822482192194401,
13602139229813231349386885113156901793661719180900395818909719758150455500533
];
var t;
signal t2[nrounds];
signal t4[nrounds];
signal t6[nrounds];
signal t7[nrounds-1];
for (var i=0; i<nrounds; i++) {
t = (i==0) ? k+x_in : k + t7[i-1] + c[i];
t2[i] <== t*t;
t4[i] <== t2[i]*t2[i];
t6[i] <== t4[i]*t2[i];
if (i<nrounds-1) {
t7[i] <== t6[i]*t;
} else {
out <== t6[i]*t + k;
}
}
}
template MultiMiMC7(nInputs, nRounds) {
signal input in[nInputs];
signal input k;
signal output out;
signal r[nInputs +1];
component mims[nInputs];
r[0] <== k;
for (var i=0; i<nInputs; i++) {
mims[i] = MiMC7(nRounds);
mims[i].x_in <== in[i];
mims[i].k <== r[i];
r[i+1] <== r[i] + in[i] + mims[i].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];
}
}
}

142
circuits/montgomery.circom Normal file
View File

@ -0,0 +1,142 @@
/*
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/>.
*/
/*
Source: https://en.wikipedia.org/wiki/Montgomery_curve
1 + y 1 + y
[u, v] = [ ------- , ---------- ]
1 - y (1 - y)x
*/
template Edwards2Montgomery() {
signal input in[2];
signal output out[2];
out[0] <-- (1 + in[1]) / (1 - in[1]);
out[1] <-- out[0] / in[0];
out[0] * (1-in[1]) === (1 + in[1]);
out[1] * in[0] === out[0];
}
/*
u u - 1
[x, y] = [ ---, ------- ]
v u + 1
*/
template Montgomery2Edwards() {
signal input in[2];
signal output out[2];
out[0] <-- in[0] / in[1];
out[1] <-- (in[0] - 1) / (in[0] + 1);
out[0] * in[1] === in[0];
out[1] * (in[0] + 1) === in[0] - 1;
}
/*
x2 - x1
lamda = ---------
y2 - y1
x3 + A + x1 + x2
x3 = B * lamda^2 - A - x1 -x2 => lamda^2 = ------------------
B
y3 = (2*x1 + x2 + A)*lamda - B*lamda^3 - y1 =>
=> y3 = lamda * ( 2*x1 + x2 + A - x3 - A - x1 - x2) - y1 =>
=> y3 = lamda * ( x1 - x3 ) - y1
----------
y2 - y1
lamda = ---------
x2 - x1
x3 = B * lamda^2 - A - x1 -x2
y3 = lamda * ( x1 - x3 ) - y1
*/
/* in1 must be != in2 */
template MontgomeryAdd() {
signal input in1[2];
signal input in2[2];
signal output out[2];
var a = 168700;
var d = 168696;
var A = (2 * (a + d)) / (a - d);
var B = 4 / (a - d);
signal lamda;
lamda <-- (in2[1] - in1[1]) / (in2[0] - in1[0]);
lamda * (in2[0] - in1[0]) === (in2[1] - in1[1]);
out[0] <== B*lamda*lamda - A - in1[0] -in2[0];
out[1] <== lamda * (in1[0] - out[0]) - in1[1];
}
/*
x1_2 = x1*x1
3*x1_2 + 2*A*x1 + 1
lamda = ---------------------
2*B*y1
x3 = B * lamda^2 - A - x1 -x1
y3 = lamda * ( x1 - x3 ) - y1
*/
template MontgomeryDouble() {
signal input in[2];
signal output out[2];
var a = 168700;
var d = 168696;
var A = (2 * (a + d)) / (a - d);
var B = 4 / (a - d);
signal lamda;
signal x1_2;
x1_2 <== in[0] * in[0];
lamda <-- (3*x1_2 + 2*A*in[0] + 1 ) / (2*B*in[1]);
lamda * (2*B*in[1]) === (3*x1_2 + 2*A*in[0] + 1 );
out[0] <== B*lamda*lamda - A - 2*in[0];
out[1] <== lamda * (in[0] - out[0]) - in[1];
}

113
circuits/multiplexer.circom Normal file
View File

@ -0,0 +1,113 @@
/*
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/>.
*/
/*
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/>.
*/
// --> Assignation without constraint
// <-- Assignation without constraint
// === Constraint
// <== Assignation with constraint
// ==> Assignation with constraint
// All variables are members of the field F[p]
// https://github.com/zcash-hackworks/sapling-crypto
// https://github.com/ebfull/bellman
/*
function log2(a) {
if (a==0) {
return 0;
}
let n = 1;
let r = 1;
while (n<a) {
r++;
n *= 2;
}
return r;
}
*/
template EscalarProduct(w) {
signal input in1[w];
signal input in2[w];
signal output out;
signal aux[w];
var lc = 0;
for (var i=0; i<w; i++) {
aux[i] <== in1[i]*in2[i];
lc = lc + aux[i];
}
out <== lc;
}
template Decoder(w) {
signal input inp;
signal output out[w];
signal output success;
var lc=0;
for (var i=0; i<w; i++) {
out[i] <-- (inp == i) ? 1 : 0;
out[i] * (inp-i) === 0;
lc = lc + out[i];
}
lc ==> success;
success * (success -1) === 0;
}
template Multiplexer(wIn, nIn) {
signal input inp[nIn][wIn];
signal input sel;
signal output out[wIn];
component dec = Decoder(nIn);
component ep[wIn];
for (var k=0; k<wIn; k++) {
ep[k] = EscalarProduct(nIn);
}
sel ==> dec.inp;
for (var j=0; j<wIn; j++) {
for (var k=0; k<nIn; k++) {
inp[k][j] ==> ep[j].in1[k];
dec.out[k] ==> ep[j].in2[k];
}
ep[j].out ==> out[j];
}
dec.success === 1;
}

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

74
circuits/mux3.circom Normal file
View File

@ -0,0 +1,74 @@
/*
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 MultiMux3(n) {
signal input c[n][8]; // Constants
signal input s[3]; // Selector
signal output out[n];
signal a210[n];
signal a21[n];
signal a20[n];
signal a2[n];
signal a10[n];
signal a1[n];
signal a0[n];
signal a[n];
// 4 constrains for the intermediary variables
signal s10;
s10 <== s[1] * s[0];
for (var i=0; i<n; i++) {
a210[i] <== ( c[i][ 7]-c[i][ 6]-c[i][ 5]+c[i][ 4] - c[i][ 3]+c[i][ 2]+c[i][ 1]-c[i][ 0] ) * s10;
a21[i] <== ( c[i][ 6]-c[i][ 4]-c[i][ 2]+c[i][ 0] ) * s[1];
a20[i] <== ( c[i][ 5]-c[i][ 4]-c[i][ 1]+c[i][ 0] ) * s[0];
a2[i] <== ( c[i][ 4]-c[i][ 0] );
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] <== ( a210[i] + a21[i] + a20[i] + a2[i] ) * s[2] +
( a10[i] + a1[i] + a0[i] + a[i] );
}
}
template Mux3() {
var i;
signal input c[8]; // Constants
signal input s[3]; // Selector
signal output out;
component mux = MultiMux3(1);
for (i=0; i<8; i++) {
mux.c[0][i] <== c[i];
}
for (i=0; i<3; i++) {
s[i] ==> mux.s[i];
}
mux.out[0] ==> out;
}

View File

@ -1,6 +1,21 @@
/*
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 MultiMux4(n) { template MultiMux4(n) {
signal input c[n][16]; // Constants signal input c[n][16]; // Constants

256
circuits/pedersen.circom Normal file
View File

@ -0,0 +1,256 @@
/*
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 "montgomery.circom";
include "mux3.circom";
include "babyjub.circom";
template Window4() {
signal input in[4];
signal input base[2];
signal output out[2];
signal output out8[2]; // Returns 8*Base (To be linked)
component mux = MultiMux3(2);
mux.s[0] <== in[0];
mux.s[1] <== in[1];
mux.s[2] <== in[2];
component dbl2 = MontgomeryDouble();
component adr3 = MontgomeryAdd();
component adr4 = MontgomeryAdd();
component adr5 = MontgomeryAdd();
component adr6 = MontgomeryAdd();
component adr7 = MontgomeryAdd();
component adr8 = MontgomeryAdd();
// in[0] -> 1*BASE
mux.c[0][0] <== base[0];
mux.c[1][0] <== base[1];
// in[1] -> 2*BASE
dbl2.in[0] <== base[0];
dbl2.in[1] <== base[1];
mux.c[0][1] <== dbl2.out[0];
mux.c[1][1] <== dbl2.out[1];
// in[2] -> 3*BASE
adr3.in1[0] <== base[0];
adr3.in1[1] <== base[1];
adr3.in2[0] <== dbl2.out[0];
adr3.in2[1] <== dbl2.out[1];
mux.c[0][2] <== adr3.out[0];
mux.c[1][2] <== adr3.out[1];
// in[3] -> 4*BASE
adr4.in1[0] <== base[0];
adr4.in1[1] <== base[1];
adr4.in2[0] <== adr3.out[0];
adr4.in2[1] <== adr3.out[1];
mux.c[0][3] <== adr4.out[0];
mux.c[1][3] <== adr4.out[1];
// in[4] -> 5*BASE
adr5.in1[0] <== base[0];
adr5.in1[1] <== base[1];
adr5.in2[0] <== adr4.out[0];
adr5.in2[1] <== adr4.out[1];
mux.c[0][4] <== adr5.out[0];
mux.c[1][4] <== adr5.out[1];
// in[5] -> 6*BASE
adr6.in1[0] <== base[0];
adr6.in1[1] <== base[1];
adr6.in2[0] <== adr5.out[0];
adr6.in2[1] <== adr5.out[1];
mux.c[0][5] <== adr6.out[0];
mux.c[1][5] <== adr6.out[1];
// in[6] -> 7*BASE
adr7.in1[0] <== base[0];
adr7.in1[1] <== base[1];
adr7.in2[0] <== adr6.out[0];
adr7.in2[1] <== adr6.out[1];
mux.c[0][6] <== adr7.out[0];
mux.c[1][6] <== adr7.out[1];
// in[7] -> 8*BASE
adr8.in1[0] <== base[0];
adr8.in1[1] <== base[1];
adr8.in2[0] <== adr7.out[0];
adr8.in2[1] <== adr7.out[1];
mux.c[0][7] <== adr8.out[0];
mux.c[1][7] <== adr8.out[1];
out8[0] <== adr8.out[0];
out8[1] <== adr8.out[1];
out[0] <== mux.out[0];
out[1] <== - mux.out[1]*2*in[3] + mux.out[1]; // Negate y if in[3] is one
}
/* nWindows must not exceed 50 */
template Segment(nWindows) {
signal input in[nWindows*4];
signal input base[2];
signal output out[2];
var i;
var j;
// Convert the base to montgomery
component e2m = Edwards2Montgomery();
e2m.in[0] <== base[0];
e2m.in[1] <== base[1];
component windows[nWindows];
component doublers1[nWindows-1];
component doublers2[nWindows-1];
component adders[nWindows-1];
for (i=0; i<nWindows; i++) {
windows[i] = Window4();
if (i==0) {
windows[i].base[0] <== e2m.out[0];
windows[i].base[1] <== e2m.out[1];
} else {
doublers1[i-1] = MontgomeryDouble();
doublers2[i-1] = MontgomeryDouble();
doublers1[i-1].in[0] <== windows[i-1].out8[0];
doublers1[i-1].in[1] <== windows[i-1].out8[1];
doublers2[i-1].in[0] <== doublers1[i-1].out[0];
doublers2[i-1].in[1] <== doublers1[i-1].out[1];
windows[i].base[0] <== doublers2[i-1].out[0];
windows[i].base[1] <== doublers2[i-1].out[1];
adders[i-1] = MontgomeryAdd();
if (i==1) {
adders[i-1].in1[0] <== windows[0].out[0];
adders[i-1].in1[1] <== windows[0].out[1];
} else {
adders[i-1].in1[0] <== adders[i-2].out[0];
adders[i-1].in1[1] <== adders[i-2].out[1];
}
adders[i-1].in2[0] <== windows[i].out[0];
adders[i-1].in2[1] <== windows[i].out[1];
}
for (j=0; j<4; j++) {
windows[i].in[j] <== in[4*i+j];
}
}
component m2e = Montgomery2Edwards();
if (nWindows > 1) {
m2e.in[0] <== adders[nWindows-2].out[0];
m2e.in[1] <== adders[nWindows-2].out[1];
} else {
m2e.in[0] <== windows[0].out[0];
m2e.in[1] <== windows[0].out[1];
}
out[0] <== m2e.out[0];
out[1] <== m2e.out[1];
}
template Pedersen(n) {
signal input in[n];
signal output out[2];
var BASE = [
[10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
[7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
[20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
[1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
[14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
[6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
[3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
[18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
]
var nSegments = ((n-1)\200)+1;
component segments[nSegments];
var i;
var j;
var nBits;
var nWindows;
for (i=0; i<nSegments; i++) {
nBits = (i == (nSegments-1)) ? n - (nSegments-1)*200 : 200;
nWindows = ((nBits - 1)\4)+1;
segments[i] = Segment(nWindows);
segments[i].base[0] <== BASE[i][0];
segments[i].base[1] <== BASE[i][1];
for (j = 0; j<nBits; j++) {
segments[i].in[j] <== in[i*200+j];
}
// Fill padding bits
for (j = nBits; j < nWindows*4; j++) {
segments[i].in[j] <== 0;
}
}
component adders[nSegments-1];
for (i=0; i<nSegments-1; i++) {
adders[i] = BabyAdd();
if (i==0) {
adders[i].x1 <== segments[0].out[0];
adders[i].y1 <== segments[0].out[1];
adders[i].x2 <== segments[1].out[0];
adders[i].y2 <== segments[1].out[1];
} else {
adders[i].x1 <== adders[i-1].xout;
adders[i].y1 <== adders[i-1].yout;
adders[i].x2 <== segments[i+1].out[0];
adders[i].y2 <== segments[i+1].out[1];
}
}
/*
coponent packPoint = PackPoint();
if (nSegments>1) {
packPoint.in[0] <== adders[nSegments-2].xout;
packPoint.in[1] <== adders[nSegments-2].yout;
} else {
packPoint.in[0] <== segments[0].out[0];
packPoint.in[1] <== segments[0].out[1];
}
out[0] <== packPoint.out[0];
out[1] <== packPoint.out[1];
*/
if (nSegments>1) {
out[0] <== adders[nSegments-2].xout;
out[1] <== adders[nSegments-2].yout;
} else {
out[0] <== segments[0].out[0];
out[1] <== segments[0].out[1];
}
}

View File

@ -0,0 +1,66 @@
/*
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 "escalarmul.circom";
template Pedersen(n) {
signal input in[n];
signal output out[2];
var nexps = ((n-1) \ 250) + 1;
var nlastbits = n - (nexps-1)*250;
component escalarMuls[nexps];
var PBASE = [
[10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
[7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
[20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
[1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
[14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
[6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
[3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
[18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
];
var i;
var j;
var nexpbits;
for (i=0; i<nexps; i++) {
nexpbits = (i == nexps-1) ? nlastbits : 250;
escalarMuls[i] = EscalarMul(nexpbits, PBASE[i]);
for (j=0; j<nexpbits; j++) {
escalarMuls[i].in[j] <== in[250*i + j];
}
if (i==0) {
escalarMuls[i].inp[0] <== 0;
escalarMuls[i].inp[1] <== 1;
} else {
escalarMuls[i].inp[0] <== escalarMuls[i-1].out[0];
escalarMuls[i].inp[1] <== escalarMuls[i-1].out[1];
}
}
escalarMuls[nexps-1].out[0] ==> out[0];
escalarMuls[nexps-1].out[1] ==> out[1];
}

163
circuits/pointbits.circom Normal file
View File

@ -0,0 +1,163 @@
/*
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 "bitify.circom";
include "aliascheck.circom";
include "compconstant.circom";
include "babyjub.circom";
function sqrt(n) {
if (n == 0) {
return 0;
}
// Test that have solution
var res = n ** ((-1) >> 1);
// if (res!=1) assert(false, "SQRT does not exists");
if (res!=1) return 0;
var m = 28;
var c = 19103219067921713944291392827692070036145651957329286315305642004821462161904;
var t = n ** 81540058820840996586704275553141814055101440848469862132140264610111;
var r = n ** ((81540058820840996586704275553141814055101440848469862132140264610111+1)>>1);
var sq;
var i;
var b;
var j;
while ((r != 0)&&(t != 1)) {
sq = t*t;
i = 1;
while (sq!=1) {
i++;
sq = sq*sq;
}
// b = c ^ m-i-1
b = c;
for (j=0; j< m-i-1; j ++) b = b*b;
m = i;
c = b*b;
t = t*c;
r = r*b;
}
if (r > ((-1) >> 1)) {
r = -r;
}
return r;
}
template Bits2Point() {
signal input in[256];
signal output out[2];
}
template Bits2Point_Strict() {
signal input in[256];
signal output out[2];
var i;
// Check aliasing
component aliasCheckY = AliasCheck();
for (i=0; i<254; i++) {
aliasCheckY.in[i] <== in[i];
}
in[254] === 0;
component b2nY = Bits2Num(254);
for (i=0; i<254; i++) {
b2nY.in[i] <== in[i];
}
out[1] <== b2nY.out;
var a = 168700;
var d = 168696;
var y2 = out[1] * out[1];
var x = sqrt( (1-y2)/(a - d*y2) );
if (in[255] == 1) x = -x;
out[0] <-- x;
component babyCheck = BabyCheck();
babyCheck.x <== out[0];
babyCheck.y <== out[1];
component n2bX = Num2Bits(254);
n2bX.in <== out[0];
component aliasCheckX = AliasCheck();
for (i=0; i<254; i++) {
aliasCheckX.in[i] <== n2bX.out[i];
}
component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808);
for (i=0; i<254; i++) {
signCalc.in[i] <== n2bX.out[i];
}
signCalc.out === in[255];
}
template Point2Bits() {
signal input in[2];
signal output out[256];
}
template Point2Bits_Strict() {
signal input in[2];
signal output out[256];
var i;
component n2bX = Num2Bits(254);
n2bX.in <== in[0];
component n2bY = Num2Bits(254);
n2bY.in <== in[1];
component aliasCheckX = AliasCheck();
component aliasCheckY = AliasCheck();
for (i=0; i<254; i++) {
aliasCheckX.in[i] <== n2bX.out[i];
aliasCheckY.in[i] <== n2bY.out[i];
}
component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808);
for (i=0; i<254; i++) {
signCalc.in[i] <== n2bX.out[i];
}
for (i=0; i<254; i++) {
out[i] <== n2bY.out[i];
}
out[254] <== 0;
out[255] <== signCalc.out;
}

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

46
circuits/sha256/ch.circom Normal file
View File

@ -0,0 +1,46 @@
/*
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/>.
*/
/* Ch
000 0
001 1
010 0
011 1
100 0
101 0
110 1
111 1
out = a&b ^ (!a)&c =>
out = a*(b-c) + c
*/
template Ch(n) {
signal input a[n];
signal input b[n];
signal input c[n];
signal output out[n];
for (var k=0; k<n; k++) {
out[k] <== a[k] * (b[k]-c[k]) + c[k];
}
}

View File

@ -0,0 +1,52 @@
/*
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 H(x) {
signal output out[32];
var c = [0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19];
for (var i=0; i<32; i++) {
out[i] <== (c[x] >> i) & 1;
}
}
template K(x) {
signal output out[32];
var c = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
for (var i=0; i<32; i++) {
out[i] <== (c[x] >> i) & 1;
}
}

View File

@ -0,0 +1,34 @@
/*
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 "sha256_2.jaz";
template Main() {
signal private input a;
signal private input b;
signal output out;
component sha256_2 = SHA256_2();
sha256_2.a <== a;
sha256_2.b <== a;
out <== sha256_2.out;
}
component main = Main();

View File

@ -0,0 +1,44 @@
/*
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/>.
*/
/* Maj function for sha256
out = a&b ^ a&c ^ b&c =>
out = a*b + a*c + b*c - 2*a*b*c =>
out = a*( b + c - 2*b*c ) + b*c =>
mid = b*c
out = a*( b + c - 2*mid ) + mid
*/
template Maj(n) {
signal input a[n];
signal input b[n];
signal input c[n];
signal output out[n];
signal mid[n];
for (var k=0; k<n; k++) {
mid[k] <== b[k]*c[k];
out[k] <== a[k] * (b[k]+c[k]-2*mid[k]) + mid[k];
}
}

View File

@ -0,0 +1,27 @@
/*
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 RotR(n, r) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
out[i] <== in[ (i+r)%n ];
}
}

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

@ -0,0 +1,90 @@
/*
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 "constants.circom";
include "sha256compression.circom";
include "../bitify.circom"
template Sha256_2() {
signal input a;
signal input b;
signal output out;
var i;
var k;
component bits2num = Bits2Num(216);
component num2bits[2];
num2bits[0] = Num2Bits(216);
num2bits[1] = Num2Bits(216);
num2bits[0].in <== a;
num2bits[1].in <== b;
component sha256compression = Sha256compression() ;
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component hf0 = H(5);
component hg0 = H(6);
component hh0 = H(7);
for (k=0; k<32; k++ ) {
sha256compression.hin[0*32+k] <== ha0.out[k];
sha256compression.hin[1*32+k] <== hb0.out[k];
sha256compression.hin[2*32+k] <== hc0.out[k];
sha256compression.hin[3*32+k] <== hd0.out[k];
sha256compression.hin[4*32+k] <== he0.out[k];
sha256compression.hin[5*32+k] <== hf0.out[k];
sha256compression.hin[6*32+k] <== hg0.out[k];
sha256compression.hin[7*32+k] <== hh0.out[k];
}
for (i=0; i<216; i++) {
sha256compression.inp[i] <== num2bits[0].out[215-i];
sha256compression.inp[i+216] <== num2bits[1].out[215-i];
}
sha256compression.inp[432] <== 1;
for (i=433; i<503; i++) {
sha256compression.inp[i] <== 0;
}
sha256compression.inp[503] <== 1;
sha256compression.inp[504] <== 1;
sha256compression.inp[505] <== 0;
sha256compression.inp[506] <== 1;
sha256compression.inp[507] <== 1;
sha256compression.inp[508] <== 0;
sha256compression.inp[509] <== 0;
sha256compression.inp[510] <== 0;
sha256compression.inp[511] <== 0;
for (i=0; i<216; i++) {
bits2num.in[i] <== sha256compression.out[255-i];
}
out <== bits2num.out;
}

View File

@ -0,0 +1,156 @@
/*
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 "constants.circom";
include "t1.circom";
include "t2.circom";
include "../binsum.circom";
include "sigmaplus.circom";
template Sha256compression() {
signal input hin[256];
signal input inp[512];
signal output out[256];
signal a[65][32];
signal b[65][32];
signal c[65][32];
signal d[65][32];
signal e[65][32];
signal f[65][32];
signal g[65][32];
signal h[65][32];
signal w[64][32];
var i;
component sigmaPlus[48];
for (i=0; i<48; i++) sigmaPlus[i] = SigmaPlus();
component ct_k[64];
for (i=0; i<64; i++) ct_k[i] = K(i);
component t1[64];
for (i=0; i<64; i++) t1[i] = T1();
component t2[64];
for (i=0; i<64; i++) t2[i] = T2();
component suma[64];
for (i=0; i<64; i++) suma[i] = BinSum(32, 2);
component sume[64];
for (i=0; i<64; i++) sume[i] = BinSum(32, 2);
component fsum[8];
for (i=0; i<8; i++) fsum[i] = BinSum(32, 2);
var k;
var t;
for (t=0; t<64; t++) {
if (t<16) {
for (k=0; k<32; k++) {
w[t][k] <== inp[t*32+31-k];
}
} else {
for (k=0; k<32; k++) {
sigmaPlus[t-16].in2[k] <== w[t-2][k];
sigmaPlus[t-16].in7[k] <== w[t-7][k];
sigmaPlus[t-16].in15[k] <== w[t-15][k];
sigmaPlus[t-16].in16[k] <== w[t-16][k];
w[t][k] <== sigmaPlus[t-16].out[k];
}
}
}
for (k=0; k<32; k++ ) {
a[0][k] <== hin[k];
b[0][k] <== hin[32*1 + k];
c[0][k] <== hin[32*2 + k];
d[0][k] <== hin[32*3 + k];
e[0][k] <== hin[32*4 + k];
f[0][k] <== hin[32*5 + k];
g[0][k] <== hin[32*6 + k];
h[0][k] <== hin[32*7 + k];
}
for (t = 0; t<64; t++) {
for (k=0; k<32; k++) {
t1[t].h[k] <== h[t][k];
t1[t].e[k] <== e[t][k];
t1[t].f[k] <== f[t][k];
t1[t].g[k] <== g[t][k];
t1[t].k[k] <== ct_k[t].out[k];
t1[t].w[k] <== w[t][k];
t2[t].a[k] <== a[t][k];
t2[t].b[k] <== b[t][k];
t2[t].c[k] <== c[t][k];
}
for (k=0; k<32; k++) {
sume[t].in[0][k] <== d[t][k];
sume[t].in[1][k] <== t1[t].out[k];
suma[t].in[0][k] <== t1[t].out[k];
suma[t].in[1][k] <== t2[t].out[k];
}
for (k=0; k<32; k++) {
h[t+1][k] <== g[t][k];
g[t+1][k] <== f[t][k];
f[t+1][k] <== e[t][k];
e[t+1][k] <== sume[t].out[k];
d[t+1][k] <== c[t][k];
c[t+1][k] <== b[t][k];
b[t+1][k] <== a[t][k];
a[t+1][k] <== suma[t].out[k];
}
}
for (k=0; k<32; k++) {
fsum[0].in[0][k] <== hin[32*0+k];
fsum[0].in[1][k] <== a[64][k];
fsum[1].in[0][k] <== hin[32*1+k];
fsum[1].in[1][k] <== b[64][k];
fsum[2].in[0][k] <== hin[32*2+k];
fsum[2].in[1][k] <== c[64][k];
fsum[3].in[0][k] <== hin[32*3+k];
fsum[3].in[1][k] <== d[64][k];
fsum[4].in[0][k] <== hin[32*4+k];
fsum[4].in[1][k] <== e[64][k];
fsum[5].in[0][k] <== hin[32*5+k];
fsum[5].in[1][k] <== f[64][k];
fsum[6].in[0][k] <== hin[32*6+k];
fsum[6].in[1][k] <== g[64][k];
fsum[7].in[0][k] <== hin[32*7+k];
fsum[7].in[1][k] <== h[64][k];
}
for (k=0; k<32; k++) {
out[31-k] <== fsum[0].out[k];
out[32+31-k] <== fsum[1].out[k];
out[64+31-k] <== fsum[2].out[k];
out[96+31-k] <== fsum[3].out[k];
out[128+31-k] <== fsum[4].out[k];
out[160+31-k] <== fsum[5].out[k];
out[192+31-k] <== fsum[6].out[k];
out[224+31-k] <== fsum[7].out[k];
}
}

View File

@ -0,0 +1,32 @@
/*
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 ShR(n, r) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
if (i+r >= n) {
out[i] <== 0;
} else {
out[i] <== in[ i+r ];
}
}
}

View File

@ -0,0 +1,68 @@
/*
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 "xor3.circom";
include "rotate.circom";
include "shift.circom";
template SmallSigma(ra, rb, rc) {
signal input in[32];
signal output out[32];
component xor3 = Xor3(32);
component rota = RotR(32, ra);
component rotb = RotR(32, rb);
component shrc = ShR(32, rc);
for (var k=0; k<32; k++) {
rota.in[k] <== in[k];
rotb.in[k] <== in[k];
shrc.in[k] <== in[k];
xor3.a[k] <== rota.out[k];
xor3.b[k] <== rotb.out[k];
xor3.c[k] <== shrc.out[k];
out[k] <== xor3.out[k];
}
}
template BigSigma(ra, rb, rc) {
signal input in[32];
signal output out[32];
component xor3 = Xor3(32);
component rota = RotR(32, ra);
component rotb = RotR(32, rb);
component rotc = RotR(32, rc);
for (var k=0; k<32; k++) {
rota.in[k] <== in[k];
rotb.in[k] <== in[k];
rotc.in[k] <== in[k];
xor3.a[k] <== rota.out[k];
xor3.b[k] <== rotb.out[k];
xor3.c[k] <== rotc.out[k];
out[k] <== xor3.out[k];
}
}

View File

@ -0,0 +1,45 @@
/*
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 "../binsum.circom"
include "sigma.circom"
template SigmaPlus() {
signal input in2[32];
signal input in7[32];
signal input in15[32];
signal input in16[32];
signal output out[32];
component sum = BinSum(32, 4);
component sigma1 = SmallSigma(17,19,10);
component sigma0 = SmallSigma(7, 18, 3);
for (var k=0; k<32; k++) {
sigma1.in[k] <== in2[k];
sigma0.in[k] <== in15[k];
sum.in[0][k] <== sigma1.out[k];
sum.in[1][k] <== in7[k];
sum.in[2][k] <== sigma0.out[k];
sum.in[3][k] <== in16[k];
out[k] <== sum.out[k];
}
}

52
circuits/sha256/t1.circom Normal file
View File

@ -0,0 +1,52 @@
/*
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 "../binsum.circom";
include "sigma.circom";
include "ch.circom";
template T1() {
signal input h[32];
signal input e[32];
signal input f[32];
signal input g[32];
signal input k[32];
signal input w[32];
signal output out[32];
component sum = BinSum(32, 5);
component ch = Ch(32);
component bigsigma1 = BigSigma(6, 11, 25);
for (var ki=0; ki<32; ki++) {
bigsigma1.in[ki] <== e[ki];
ch.a[ki] <== e[ki];
ch.b[ki] <== f[ki];
ch.c[ki] <== g[ki]
sum.in[0][ki] <== h[ki];
sum.in[1][ki] <== bigsigma1.out[ki];
sum.in[2][ki] <== ch.out[ki];
sum.in[3][ki] <== k[ki];
sum.in[4][ki] <== w[ki];
out[ki] <== sum.out[ki];
}
}

47
circuits/sha256/t2.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/>.
*/
include "../binsum.circom";
include "sigma.circom";
include "maj.circom"
template T2() {
signal input a[32];
signal input b[32];
signal input c[32];
signal output out[32];
component sum = BinSum(32, 2);
component bigsigma0 = BigSigma(2, 13, 22);
component maj = Maj(32);
for (var k=0; k<32; k++) {
bigsigma0.in[k] <== a[k];
maj.a[k] <== a[k];
maj.b[k] <== b[k];
maj.c[k] <== c[k];
sum.in[0][k] <== bigsigma0.out[k];
sum.in[1][k] <== maj.out[k];
out[k] <== sum.out[k];
}
}

View File

@ -0,0 +1,44 @@
/*
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/>.
*/
/* Xor3 function for sha256
out = a ^ b ^ c =>
out = a+b+c - 2*a*b - 2*a*c - 2*b*c + 4*a*b*c =>
out = a*( 1 - 2*b - 2*c + 4*b*c ) + b + c - 2*b*c =>
mid = b*c
out = a*( 1 - 2*b -2*c + 4*mid ) + b + c - 2 * mid
*/
template Xor3(n) {
signal input a[n];
signal input b[n];
signal input c[n];
signal output out[n];
signal mid[n];
for (var k=0; k<n; k++) {
mid[k] <== b[k]*c[k];
out[k] <== a[k] * (1 -2*b[k] -2*c[k] +4*mid[k]) + b[k] + c[k] -2*mid[k];
}
}

35
circuits/sign.circom Normal file
View File

@ -0,0 +1,35 @@
/*
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";
template Sign() {
signal input in[254];
signal output sign;
component comp = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808);
var i;
for (i=0; i<254; i++) {
comp.in[i] <== in[i];
}
sign <== comp.out;
}

View File

@ -0,0 +1,57 @@
/*
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 "../mimc.circom";
/*
Hash1 = H(1 | key | value)
*/
template SMTHash1() {
signal input key;
signal input value;
signal output out;
component h = MultiMiMC7(2, 91); // Constant
h.in[0] <== key;
h.in[1] <== value;
h.k <== 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 = MultiMiMC7(2, 91); // Constant
h.in[0] <== L;
h.in[1] <== R;
h.k <== 0;
out <== h.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

@ -0,0 +1,100 @@
/*
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/>.
*/
/*
This component finds the level where the oldInsert is done.
The rules are:
levIns[i] == 1 if its level and all the child levels have a sibling of 0 and
the parent level has a sibling != 0. Considere that the root level always has
a parent with a sibling != 0.
┌──────────────┐
│ │
│ │───▶ levIns[0] <== (1-done[i])
│ │
└──────────────┘
done[0]
done[i-1] <== levIns[i] + done[i]
┌───────────┐ ┌──────────────┐
│ │ │ │
sibling[i-1]───▶│IsZero[i-1]│─▶│ │───▶ levIns[i] <== (1-done[i])*(1-isZero[i-1].out)
│ │ │ │
└───────────┘ └──────────────┘
done[i]
done[n-2] <== levIns[n-1]
┌───────────┐ ┌──────────────┐
│ │ │ │
sibling[n-2]───▶│IsZero[n-2]│─▶│ │────▶ levIns[n-1] <== (1-isZero[n-2].out)
│ │ │ │
└───────────┘ └──────────────┘
┌───────────┐
│ │
sibling[n-1]───▶│IsZero[n-1]│────▶ === 0
│ │
└───────────┘
*/
template SMTLevIns(nLevels) {
signal input enabled;
signal input siblings[nLevels];
signal output levIns[nLevels];
signal done[nLevels-1]; // Indicates if the insLevel has aready been detected.
component isZero[nLevels];
for (var i=0; i<nLevels; i++) {
isZero[i] = IsZero();
isZero[i].in <== siblings[i];
}
// The last level must always have a sibling of 0. If not, then it cannot be inserted.
(isZero[nLevels-1].out - 1) * enabled === 0;
levIns[nLevels-1] <== (1-isZero[nLevels-2].out);
done[nLevels-2] <== levIns[nLevels-1];
for (var i=nLevels-2; i>0; i--) {
levIns[i] <== (1-done[i])*(1-isZero[i-1].out)
done[i-1] <== levIns[i] + done[i];
}
levIns[0] <== (1-done[0]);
}

View File

@ -0,0 +1,258 @@
/*
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/>.
*/
/***************************************************************************************************
SMTProcessor: Sparse Merkle Tree processor is a component to verify an insert/update/delete elements
into the Sparse Merkle tree.
Insert to an empty leaf
=======================
STATE OLD STATE NEW STATE
===== ========= =========
oldRoot newRoot
▲ ▲
│ │
┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
top │Sibling├────▶┃ Hash ┃◀─┐ │Sibling├────▶┃ Hash ┃◀─┐
└───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
│ │
│ │
┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐
top ┌─────▶┃ Hash ┃◀──┤Sibling│ ┌─────▶┃ Hash ┃◀──┤Sibling│
│ ┗━━━━━━━┛ └───────┘ │ ┗━━━━━━━┛ └───────┘
│ │
│ │
┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
top │Sibling├──▶┃ Hash ┃◀─────┐ │Sibling├──▶┃ Hash ┃◀─────┐
└───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
│ │
│ │
┌────┴────┐ ┌────┴────┐
old0 │ 0 │ │New1Leaf │
└─────────┘ └─────────┘
┏━━━━━━━┓ ┏━━━━━━━┓
na ┃ Hash ┃ ┃ Hash ┃
┗━━━━━━━┛ ┗━━━━━━━┛
┏━━━━━━━┓ ┏━━━━━━━┓
na ┃ Hash ┃ ┃ Hash ┃
┗━━━━━━━┛ ┗━━━━━━━┛
Insert to a used leaf.
=====================
STATE OLD STATE NEW STATE
===== ========= =========
oldRoot newRoot
▲ ▲
│ │
┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
top │Sibling├────▶┃ Hash ┃◀─┐ │Sibling├────▶┃ Hash ┃◀─┐
└───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
│ │
│ │
┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐
top ┌─────▶┃ Hash ┃◀──┤Sibling│ ┌─────▶┃ Hash ┃◀──┤Sibling│
│ ┗━━━━━━━┛ └───────┘ │ ┗━━━━━━━┛ └───────┘
│ │
│ │
┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
top │Sibling├──▶┃ Hash ┃◀─────┐ │Sibling├──▶┃ Hash ┃◀─────┐
└───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
│ │
│ │
┌────┴────┐ ┏━━━┻━━━┓ ┌───────┐
bot │Old1Leaf │ ┌─────▶┃ Hash ┃◀──┼─ 0 │
└─────────┘ │ ┗━━━━━━━┛ └───────┘
┏━━━━━━━┓ ┌───────┐ ┏━━━┻━━━┓
bot ┃ Hash ┃ │ 0 ─┼──▶┃ Hash ┃◀─────┐
┗━━━━━━━┛ └───────┘ ┗━━━━━━━┛ │
┏━━━━━━━┓ ┏━━━┻━━━┓ ┌───────┐
bot ┃ Hash ┃ ┌─────▶┃ Hash ┃◀──│ 0 │
┗━━━━━━━┛ │ ┗━━━━━━━┛ └───────┘
┏━━━━━━━┓ ┌─────────┐ ┏━━━┻━━━┓ ┌─────────┐
new1 ┃ Hash ┃ │Old1Leaf ├──▶┃ Hash ┃◀──│New1Leaf │
┗━━━━━━━┛ └─────────┘ ┗━━━━━━━┛ └─────────┘
┏━━━━━━━┓ ┏━━━━━━━┓
na ┃ Hash ┃ ┃ Hash ┃
┗━━━━━━━┛ ┗━━━━━━━┛
┏━━━━━━━┓ ┏━━━━━━━┓
na ┃ Hash ┃ ┃ Hash ┃
┗━━━━━━━┛ ┗━━━━━━━┛
Fnction
fnc[0] fnc[1]
0 0 NOP
0 1 UPDATE
1 0 INSERT
1 1 DELETE
***************************************************************************************************/
include "../gates.circom";
include "../bitify.circom";
include "../comparators.circom";
include "../switcher.circom";
include "smtlevins.circom";
include "smtprocessorlevel.circom";
include "smtprocessorsm.circom";
include "smthash_poseidon.circom";
template SMTProcessor(nLevels) {
signal input oldRoot;
signal output newRoot;
signal input siblings[nLevels];
signal input oldKey;
signal input oldValue;
signal input isOld0;
signal input newKey;
signal input newValue;
signal input fnc[2];
signal enabled;
enabled <== fnc[0] + fnc[1] - fnc[0]*fnc[1]
component hash1Old = SMTHash1();
hash1Old.key <== oldKey;
hash1Old.value <== oldValue;
component hash1New = SMTHash1();
hash1New.key <== newKey;
hash1New.value <== newValue;
component n2bOld = Num2Bits_strict();
component n2bNew = Num2Bits_strict();
n2bOld.in <== oldKey;
n2bNew.in <== newKey;
component smtLevIns = SMTLevIns(nLevels);
for (var i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
smtLevIns.enabled <== enabled;
component xors[nLevels];
for (var i=0; i<nLevels; i++) {
xors[i] = XOR();
xors[i].a <== n2bOld.out[i];
xors[i].b <== n2bNew.out[i];
}
component sm[nLevels];
for (var i=0; i<nLevels; i++) {
sm[i] = SMTProcessorSM();
if (i==0) {
sm[i].prev_top <== enabled;
sm[i].prev_old0 <== 0;
sm[i].prev_bot <== 0;
sm[i].prev_new1 <== 0;
sm[i].prev_na <== 1-enabled;
sm[i].prev_upd <== 0;
} else {
sm[i].prev_top <== sm[i-1].st_top;
sm[i].prev_old0 <== sm[i-1].st_old0;
sm[i].prev_bot <== sm[i-1].st_bot;
sm[i].prev_new1 <== sm[i-1].st_new1;
sm[i].prev_na <== sm[i-1].st_na;
sm[i].prev_upd <== sm[i-1].st_upd;
}
sm[i].is0 <== isOld0;
sm[i].xor <== xors[i].out;
sm[i].fnc[0] <== fnc[0];
sm[i].fnc[1] <== fnc[1];
sm[i].levIns <== smtLevIns.levIns[i];
}
sm[nLevels-1].st_na + sm[nLevels-1].st_new1 + sm[nLevels-1].st_old0 +sm[nLevels-1].st_upd === 1;
component levels[nLevels];
for (var i=nLevels-1; i != -1; i--) {
levels[i] = SMTProcessorLevel();
levels[i].st_top <== sm[i].st_top;
levels[i].st_old0 <== sm[i].st_old0;
levels[i].st_bot <== sm[i].st_bot;
levels[i].st_new1 <== sm[i].st_new1;
levels[i].st_na <== sm[i].st_na;
levels[i].st_upd <== sm[i].st_upd;
levels[i].sibling <== siblings[i];
levels[i].old1leaf <== hash1Old.out;
levels[i].new1leaf <== hash1New.out;
levels[i].newlrbit <== n2bNew.out[i];
if (i==nLevels-1) {
levels[i].oldChild <== 0;
levels[i].newChild <== 0;
} else {
levels[i].oldChild <== levels[i+1].oldRoot;
levels[i].newChild <== levels[i+1].newRoot;
}
}
component topSwitcher = Switcher();
topSwitcher.sel <== fnc[0]*fnc[1];
topSwitcher.L <== levels[0].oldRoot;
topSwitcher.R <== levels[0].newRoot;
component checkOldInput = ForceEqualIfEnabled();
checkOldInput.enabled <== enabled;
checkOldInput.in[0] <== oldRoot;
checkOldInput.in[1] <== topSwitcher.outL;
newRoot <== enabled * (topSwitcher.outR - oldRoot) + oldRoot;
// topSwitcher.outL === oldRoot*enabled;
// topSwitcher.outR === newRoot*enabled;
// Ckeck keys are equal if updating
component areKeyEquals = IsEqual();
areKeyEquals.in[0] <== oldKey;
areKeyEquals.in[1] <== newKey;
component keysOk = MultiAND(3);
keysOk.in[0] <== 1-fnc[0];
keysOk.in[1] <== fnc[1];
keysOk.in[2] <== 1-areKeyEquals.out;
keysOk.out === 0;
}

View File

@ -0,0 +1,94 @@
/*
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/>.
*/
/******
SMTProcessorLevel
This circuit has 2 hash
Outputs according to the state.
State oldRoot newRoot
===== ======= =======
top H'(oldChild, sibling) H'(newChild, sibling)
old0 0 new1leaf
bot old1leaf H'(newChild, 0)
new1 old1leaf H'(new1leaf, old1leaf)
na 0 0
upd old1leaf new1leaf
H' is the Hash function with the inputs shifted acordingly.
*****/
template SMTProcessorLevel() {
signal input st_top;
signal input st_old0;
signal input st_bot;
signal input st_new1;
signal input st_na;
signal input st_upd;
signal output oldRoot;
signal output newRoot;
signal input sibling;
signal input old1leaf;
signal input new1leaf;
signal input newlrbit;
signal input oldChild;
signal input newChild;
signal aux[4];
component oldProofHash = SMTHash2();
component newProofHash = SMTHash2();
component oldSwitcher = Switcher();
component newSwitcher = Switcher();
// Old side
oldSwitcher.L <== oldChild;
oldSwitcher.R <== sibling;
oldSwitcher.sel <== newlrbit;
oldProofHash.L <== oldSwitcher.outL;
oldProofHash.R <== oldSwitcher.outR;
aux[0] <== old1leaf * (st_bot + st_new1 + st_upd);
oldRoot <== aux[0] + oldProofHash.out * st_top;
// New side
aux[1] <== newChild * ( st_top + st_bot);
newSwitcher.L <== aux[1] + new1leaf*st_new1;
aux[2] <== sibling*st_top;
newSwitcher.R <== aux[2] + old1leaf*st_new1;
newSwitcher.sel <== newlrbit;
newProofHash.L <== newSwitcher.outL;
newProofHash.R <== newSwitcher.outR;
aux[3] <== newProofHash.out * (st_top + st_bot + st_new1);
newRoot <== aux[3] + new1leaf * (st_old0 + st_upd);
}

View File

@ -0,0 +1,164 @@
/*
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/>.
*/
/***************************************************************************************************
Each level on a SMTProcessor has a state.
The state of the level depends on the state of te botom level and on `xor` and
`is0` signals.
`isOldLev` 1 when is the level where oldLeaf is.
`xor` signal is 0 if the index bit at the current level is the same in the old
and the new index, and 1 if it is different.
`is0` signal, is 1 if we are inserting/deleting in an empty leaf and 0 if we
are inserting/deleting in a leaf that contains an element.
The states are:
top: While the index bits of the old and new insex in the top level is the same, whe are in the top state.
old0: When the we reach insert level, we go to old0 state
if `is0`=1.
btn: Once in insert level and `is0` =0 we go to btn or new1 level if xor=1
new1: This level is reached when xor=1. Here is where we insert/delete the hash of the
old and the new trees with just one element.
na: Not appliable. After processing it, we go to the na level.
Fnction
fnc[0] fnc[1]
0 0 NOP
0 1 UPDATE
1 0 INSERT
1 1 DELETE
###########
# #
┌────────────────────────────▶# upd #─────────────────────┐
│ ## ## │
│ ######### │
levIns=1 │ │
fnc[0]=0 │ │ any
│ │
│ │
│ │
│ ########### │
│ levIns=1 # # │
levIns=0 │ is0=1 ┌────────────▶# old0 #────────┐ │ any
┌─────┐ │ fnc[0]=1│ ## ## │ │ ┌──────┐
│ │ │ │ ######### │ any │ │ │
│ ▼ │ │ │ ▼ ▼ │
│ ########### │ │ ########### │
│ # # ────────────┘ └────────▶# #│
└──# top # # na #
## ## ───────────────────┐ levIns=1 ┌──▶## ##
######### │ is0=0 │ #########
│ │ fnc[0]=1 │
│ │ xor=1 ########### │ any
│ └──────────────────▶# # │
│ # new1 #──┘
│ ## ##
└────────────────────────────────┐ #########
levIns=1 │ ▲
is0=0 │ ┌─────┘
fnc[0]=1 │ ###########│ xor=1
xor=0 │ # #
▼# btn #
## ##
#########◀───────┐
│ │
│ │
└────────────┘
xor=0
***************************************************************************************************/
template SMTProcessorSM() {
signal input xor;
signal input is0;
signal input levIns;
signal input fnc[2];
signal input prev_top;
signal input prev_old0;
signal input prev_bot;
signal input prev_new1;
signal input prev_na;
signal input prev_upd;
signal output st_top;
signal output st_old0;
signal output st_bot;
signal output st_new1;
signal output st_na;
signal output st_upd;
signal aux1;
signal aux2;
aux1 <== prev_top * levIns;
aux2 <== aux1*fnc[0]; // prev_top * levIns * fnc[0]
// st_top = prev_top*(1-levIns)
// = + prev_top
// - prev_top * levIns = aux1
st_top <== prev_top - aux1;
// st_old0 = prev_top * levIns * is0 * fnc[0]
// = + prev_top * levIns * is0 * fnc[0] = aux2 * is0
st_old0 <== aux2 * is0; // prev_top * levIns * is0 * fnc[0]
// st_new1 = prev_top * levIns * (1-is0)*fnc[0] * xor + prev_bot*xor =
// = + prev_top * levIns * fnc[0] * xor = aux2 * xor
// - prev_top * levIns * is0 * fnc[0] * xor = st_old0 * xor
// + prev_bot * xor = prev_bot * xor
st_new1 <== (aux2 - st_old0 + prev_bot)*xor;
// st_bot = prev_top * levIns * (1-is0)*fnc[0] * (1-xor) + prev_bot*(1-xor);
// = + prev_top * levIns * fnc[0]
// - prev_top * levIns * is0 * fnc[0]
// - prev_top * levIns * fnc[0] * xor
// + prev_top * levIns * is0 * fnc[0] * xor
// + prev_bot
// - prev_bot * xor
st_bot <== (1-xor) * (aux2 - st_old0 + prev_bot)
// st_upd = prev_top * (1-fnc[0]) *levIns;
// = + prev_top * levIns
// - prev_top * levIns * fnc[0]
st_upd <== aux1 - aux2
// st_na = prev_new1 + prev_old0 + prev_na + prev_upd;
// = + prev_new1
// + prev_old0
// + prev_na
// + prev_upd
st_na <== prev_new1 + prev_old0 + prev_na + prev_upd;
}

View File

@ -0,0 +1,135 @@
/*
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/>.
*/
/*
SMTVerifier is a component to verify inclusion/exclusion of an element in the tree
fnc: 0 -> VERIFY INCLUSION
1 -> VERIFY NOT INCLUSION
*/
include "../gates.circom";
include "../bitify.circom";
include "../comparators.circom";
include "../switcher.circom";
include "smtlevins.circom";
include "smtverifierlevel.circom";
include "smtverifiersm.circom";
include "smthash_poseidon.circom";
template SMTVerifier(nLevels) {
signal input enabled;
signal input root;
signal input siblings[nLevels];
signal input oldKey;
signal input oldValue;
signal input isOld0;
signal input key;
signal input value;
signal input fnc;
component hash1Old = SMTHash1();
hash1Old.key <== oldKey;
hash1Old.value <== oldValue;
component hash1New = SMTHash1();
hash1New.key <== key;
hash1New.value <== value;
component n2bOld = Num2Bits_strict();
component n2bNew = Num2Bits_strict();
n2bOld.in <== oldKey;
n2bNew.in <== key;
component smtLevIns = SMTLevIns(nLevels);
for (var i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
smtLevIns.enabled <== enabled;
component sm[nLevels];
for (var i=0; i<nLevels; i++) {
sm[i] = SMTVerifierSM();
if (i==0) {
sm[i].prev_top <== enabled;
sm[i].prev_i0 <== 0;
sm[i].prev_inew <== 0;
sm[i].prev_iold <== 0;
sm[i].prev_na <== 1-enabled;
} else {
sm[i].prev_top <== sm[i-1].st_top;
sm[i].prev_i0 <== sm[i-1].st_i0;
sm[i].prev_inew <== sm[i-1].st_inew;
sm[i].prev_iold <== sm[i-1].st_iold;
sm[i].prev_na <== sm[i-1].st_na;
}
sm[i].is0 <== isOld0;
sm[i].fnc <== fnc;
sm[i].levIns <== smtLevIns.levIns[i];
}
sm[nLevels-1].st_na + sm[nLevels-1].st_iold + sm[nLevels-1].st_inew + sm[nLevels-1].st_i0 === 1;
component levels[nLevels];
for (var i=nLevels-1; i != -1; i--) {
levels[i] = SMTVerifierLevel();
levels[i].st_top <== sm[i].st_top;
levels[i].st_i0 <== sm[i].st_i0;
levels[i].st_inew <== sm[i].st_inew;
levels[i].st_iold <== sm[i].st_iold;
levels[i].st_na <== sm[i].st_na;
levels[i].sibling <== siblings[i];
levels[i].old1leaf <== hash1Old.out;
levels[i].new1leaf <== hash1New.out;
levels[i].lrbit <== n2bNew.out[i];
if (i==nLevels-1) {
levels[i].child <== 0;
} else {
levels[i].child <== levels[i+1].root;
}
}
// Check that if checking for non inclussuin and isOld0==0 then key!=old
component areKeyEquals = IsEqual();
areKeyEquals.in[0] <== oldKey;
areKeyEquals.in[1] <== key;
component keysOk = MultiAND(4);
keysOk.in[0] <== fnc;
keysOk.in[1] <== 1-isOld0;
keysOk.in[2] <== areKeyEquals.out;
keysOk.in[3] <== enabled;
keysOk.out === 0;
// Check the root
component checkRoot = ForceEqualIfEnabled();
checkRoot.enabled <== enabled;
checkRoot.in[0] <== levels[0].root;
checkRoot.in[1] <== root;
// levels[0].root === root;
}

View File

@ -0,0 +1,71 @@
/*
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/>.
*/
/******
SMTVerifierLevel
This circuit has 1 hash
Outputs according to the state.
State root
===== =======
top H'(child, sibling)
i0 0
iold old1leaf
inew new1leaf
na 0
H' is the Hash function with the inputs shifted acordingly.
*****/
template SMTVerifierLevel() {
signal input st_top;
signal input st_i0;
signal input st_iold;
signal input st_inew;
signal input st_na;
signal output root;
signal input sibling;
signal input old1leaf;
signal input new1leaf;
signal input lrbit;
signal input child;
signal aux[2];
component proofHash = SMTHash2();
component switcher = Switcher();
switcher.L <== child;
switcher.R <== sibling;
switcher.sel <== lrbit;
proofHash.L <== switcher.outL;
proofHash.R <== switcher.outR;
aux[0] <== proofHash.out * st_top;
aux[1] <== old1leaf*st_iold;
root <== aux[0] + aux[1] + new1leaf*st_inew;
}

View File

@ -0,0 +1,105 @@
/*
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/>.
*/
/*
Each level in the SMTVerifier has a state.
This is the state machine.
The signals are
levIns: 1 if we are in the level where the insertion should happen
xor: 1 if the bitKey of the old and new keys are different in this level
is0: Input that indicates that the oldKey is 0
fnc: 0 -> VERIFY INCLUSION
1 -> VERIFY NOT INCLUSION
err state is not a state itself. It's a lack of state.
The end of the last level will have to be `na`
levIns=0 any
┌────┐ ┌────┐
│ │ │ │
│ ▼ levIns=1 ▼ │
│ ########### is0=1 ########### ########### │
│ # # fnc=1 # # any # # │
└──# top # ─────────────────────▶# i0 #───────────────▶# na #──┘
## ## ──────────┐ ## ## ┌───────▶## ##
########─────────────┐│ ######### │┌────────▶#########
││ levIns=1 ││
││ is0=0 ########### ││
││ fnc=1 # # any│
│└──────────▶ # iold #────────┘│
│ ## ## │
│ ######### │
│ │
│ levIns=1 ########### │
│ fnc=0 # # any
└────────────▶# inew #─────────┘
## ##
#########
*/
template SMTVerifierSM() {
signal input is0;
signal input levIns;
signal input fnc;
signal input prev_top;
signal input prev_i0;
signal input prev_iold;
signal input prev_inew;
signal input prev_na;
signal output st_top;
signal output st_i0;
signal output st_iold;
signal output st_inew;
signal output st_na;
signal prev_top_lev_ins;
signal prev_top_lev_ins_fnc;
prev_top_lev_ins <== prev_top * levIns;
prev_top_lev_ins_fnc <== prev_top_lev_ins*fnc; // prev_top * levIns * fnc
// st_top = prev_top * (1-levIns)
// = + prev_top
// - prev_top * levIns
st_top <== prev_top - prev_top_lev_ins;
// st_inew = prev_top * levIns * (1-fnc)
// = + prev_top * levIns
// - prev_top * levIns * fnc
st_inew <== prev_top_lev_ins - prev_top_lev_ins_fnc;
// st_iold = prev_top * levIns * (1-is0)*fnc
// = + prev_top * levIns * fnc
// - prev_top * levIns * fnc * is0
st_iold <== prev_top_lev_ins_fnc * (1 - is0);
// st_i0 = prev_top * levIns * is0
// = + prev_top * levIns * is0
st_i0 <== prev_top_lev_ins * is0;
st_na <== prev_na + prev_inew + prev_iold + prev_i0;
}

40
circuits/switcher.circom Normal file
View File

@ -0,0 +1,40 @@
/*
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/>.
*/
/*
Assume sel is binary.
If sel == 0 then outL = L and outR=R
If sel == 1 then outL = R and outR=L
*/
template Switcher() {
signal input sel;
signal input L;
signal input R;
signal output outL;
signal output outR;
signal aux;
aux <== (R-L)*sel; // We create aux in order to have only one multiplication
outL <== aux + L;
outR <== -aux + R;
}

BIN
doc/root_transfer.monopic Normal file

Binary file not shown.

BIN
doc/smt_diagram_0.monopic Normal file

Binary file not shown.

BIN
doc/smt_diagram_1.monopic Normal file

Binary file not shown.

BIN
doc/smt_hash.monopic Normal file

Binary file not shown.

BIN
doc/smt_levins.monopic Normal file

Binary file not shown.

BIN
doc/smt_sm.monopic Normal file

Binary file not shown.

BIN
doc/smt_verifier_sm.monopic Normal file

Binary file not shown.

BIN
doc/voting.monopic Normal file

Binary file not shown.

9
index.js Normal file
View File

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

3669
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

114
src/babyjub.js Normal file
View File

@ -0,0 +1,114 @@
const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("@tornado/snarkjs").bigInt;
exports.addPoint = addPoint;
exports.mulPointEscalar = mulPointEscalar;
exports.inCurve = inCurve;
exports.inSubgroup = inSubgroup;
exports.packPoint = packPoint;
exports.unpackPoint = unpackPoint;
exports.Generator = [
bigInt("995203441582195749578291179787384436505546430278305826713579947235728471134"),
bigInt("5472060717959818805561601436314318772137091100104008585924551046643952123905"),
];
exports.Base8 = [
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203"),
];
exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328");
exports.subOrder = exports.order.shr(3);
exports.p = bn128.r;
exports.A = bigInt("168700");
exports.D = bigInt("168696");
function addPoint(a, b) {
const q = bn128.r;
const res = [];
/* does the equivalent of:
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
*/
res[0] = bigInt(
bigInt(a[0])
.mul(b[1])
.add(bigInt(b[0]).mul(a[1]))
.mul(bigInt(bigInt("1").add(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))
).affine(q);
res[1] = bigInt(
bigInt(a[1])
.mul(b[1])
.sub(exports.A.mul(a[0]).mul(b[0]))
.mul(bigInt(bigInt("1").sub(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))
).affine(q);
return res;
}
function mulPointEscalar(base, e) {
let res = [bigInt("0"), bigInt("1")];
let rem = bigInt(e);
let exp = base;
while (!rem.isZero()) {
if (rem.isOdd()) {
res = addPoint(res, exp);
}
exp = addPoint(exp, exp);
rem = rem.shr(1);
}
return res;
}
function inSubgroup(P) {
if (!inCurve(P)) return false;
const res = mulPointEscalar(P, exports.subOrder);
return res[0].equals(bigInt(0)) && res[1].equals(bigInt(1));
}
function inCurve(P) {
const F = bn128.Fr;
const x2 = F.square(P[0]);
const y2 = F.square(P[1]);
if (!F.equals(F.add(F.mul(exports.A, x2), y2), F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false;
return true;
}
function packPoint(P) {
const buff = bigInt.leInt2Buff(P[1], 32);
if (P[0].greater(exports.p.shr(1))) {
buff[31] = buff[31] | 0x80;
}
return buff;
}
function unpackPoint(_buff) {
const F = bn128.Fr;
const buff = Buffer.from(_buff);
let sign = false;
const P = new Array(2);
if (buff[31] & 0x80) {
sign = true;
buff[31] = buff[31] & 0x7f;
}
P[1] = bigInt.leBuff2int(buff);
if (P[1].greaterOrEquals(exports.p)) return null;
const y2 = F.square(P[1]);
let x = F.sqrt(F.div(F.sub(F.one, y2), F.sub(exports.A, F.mul(exports.D, y2))));
if (x == null) return null;
if (sign) x = F.neg(x);
P[0] = F.affine(x);
return P;
}

225
src/eddsa.js Normal file
View File

@ -0,0 +1,225 @@
const createBlakeHash = require("blake-hash");
const bigInt = require("@tornado/snarkjs").bigInt;
const babyJub = require("./babyjub");
const pedersenHash = require("./pedersenHash").hash;
const mimc7 = require("./mimc7");
const poseidon = require("./poseidon.js");
const mimcsponge = require("./mimcsponge");
exports.prv2pub = prv2pub;
exports.sign = sign;
exports.signMiMC = signMiMC;
exports.signPoseidon = signPoseidon;
exports.signMiMCSponge = signMiMCSponge;
exports.verify = verify;
exports.verifyMiMC = verifyMiMC;
exports.verifyPoseidon = verifyPoseidon;
exports.verifyMiMCSponge = verifyMiMCSponge;
exports.packSignature = packSignature;
exports.unpackSignature = unpackSignature;
exports.pruneBuffer = pruneBuffer;
function pruneBuffer(_buff) {
const buff = Buffer.from(_buff);
buff[0] = buff[0] & 0xf8;
buff[31] = buff[31] & 0x7f;
buff[31] = buff[31] | 0x40;
return buff;
}
function prv2pub(prv) {
const sBuff = pruneBuffer(createBlakeHash("blake512").update(prv).digest().slice(0, 32));
let s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
return A;
}
function sign(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 rBuff = createBlakeHash("blake512")
.update(Buffer.concat([h1.slice(32, 64), msg]))
.digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const R8p = babyJub.packPoint(R8);
const Ap = babyJub.packPoint(A);
const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
const hm = bigInt.leBuff2int(hmBuff);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return {
R8: R8,
S: S,
};
}
function signMiMC(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 = mimc7.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 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,
};
}
function verify(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 R8p = babyJub.packPoint(sig.R8);
const Ap = babyJub.packPoint(A);
const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
const hm = bigInt.leBuff2int(hmBuff);
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 verifyMiMC(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 = mimc7.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 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) {
const R8p = babyJub.packPoint(sig.R8);
const Sp = bigInt.leInt2Buff(sig.S, 32);
return Buffer.concat([R8p, Sp]);
}
function unpackSignature(sigBuff) {
return {
R8: babyJub.unpackPoint(sigBuff.slice(0, 32)),
S: bigInt.leBuff2int(sigBuff.slice(32, 64)),
};
}

208
src/evmasm.js Normal file
View File

@ -0,0 +1,208 @@
// Copyright (c) 2018 Jordi Baylina
// License: LGPL-3.0+
//
const Web3Utils = require("web3-utils");
class Contract {
constructor() {
this.code = [];
this.labels = {};
this.pendingLabels = {};
}
createTxData() {
let C;
// Check all labels are defined
const pendingLabels = Object.keys(this.pendingLabels);
if (pendingLabels.length>0) {
throw new Error("Lables not defined: "+ pendingLabels.join(", "));
}
let setLoaderLength = 0;
let genLoadedLength = -1;
while (genLoadedLength!=setLoaderLength) {
setLoaderLength = genLoadedLength;
C = new module.exports();
C.codesize();
C.push(setLoaderLength);
C.push(0);
C.codecopy();
C.push(this.code.length);
C.push(0);
C.return();
genLoadedLength = C.code.length;
}
return Web3Utils.bytesToHex(C.code.concat(this.code));
}
stop() { this.code.push(0x00); }
add() { this.code.push(0x01); }
mul() { this.code.push(0x02); }
sub() { this.code.push(0x03); }
div() { this.code.push(0x04); }
sdiv() { this.code.push(0x05); }
mod() { this.code.push(0x06); }
smod() { this.code.push(0x07); }
addmod() { this.code.push(0x08); }
mulmod() { this.code.push(0x09); }
exp() { this.code.push(0x0a); }
signextend() { this.code.push(0x0b); }
lt() { this.code.push(0x10); }
gt() { this.code.push(0x11); }
slt() { this.code.push(0x12); }
sgt() { this.code.push(0x13); }
eq() { this.code.push(0x14); }
iszero() { this.code.push(0x15); }
and() { this.code.push(0x16); }
or() { this.code.push(0x17); }
shor() { this.code.push(0x18); }
not() { this.code.push(0x19); }
byte() { this.code.push(0x1a); }
keccak() { this.code.push(0x20); }
sha3() { this.code.push(0x20); } // alias
address() { this.code.push(0x30); }
balance() { this.code.push(0x31); }
origin() { this.code.push(0x32); }
caller() { this.code.push(0x33); }
callvalue() { this.code.push(0x34); }
calldataload() { this.code.push(0x35); }
calldatasize() { this.code.push(0x36); }
calldatacopy() { this.code.push(0x37); }
codesize() { this.code.push(0x38); }
codecopy() { this.code.push(0x39); }
gasprice() { this.code.push(0x3a); }
extcodesize() { this.code.push(0x3b); }
extcodecopy() { this.code.push(0x3c); }
returndatasize() { this.code.push(0x3d); }
returndatacopy() { this.code.push(0x3e); }
blockhash() { this.code.push(0x40); }
coinbase() { this.code.push(0x41); }
timestamp() { this.code.push(0x42); }
number() { this.code.push(0x43); }
difficulty() { this.code.push(0x44); }
gaslimit() { this.code.push(0x45); }
pop() { this.code.push(0x50); }
mload() { this.code.push(0x51); }
mstore() { this.code.push(0x52); }
mstore8() { this.code.push(0x53); }
sload() { this.code.push(0x54); }
sstore() { this.code.push(0x55); }
_pushLabel(label) {
if (typeof this.labels[label] != "undefined") {
this.push(this.labels[label]);
} else {
this.pendingLabels[label] = this.pendingLabels[label] || [];
this.pendingLabels[label].push(this.code.length);
this.push("0x000000");
}
}
_fillLabel(label) {
if (!this.pendingLabels[label]) return;
let dst = this.labels[label];
const dst3 = [dst >> 16, (dst >> 8) & 0xFF, dst & 0xFF];
this.pendingLabels[label].forEach((p) => {
for (let i=0; i<3; i++) {
this.code[p+i+1] = dst3[i];
}
});
delete this.pendingLabels[label];
}
jmp(label) {
if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x56);
}
jmpi(label) {
if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x57);
}
pc() { this.code.push(0x58); }
msize() { this.code.push(0x59); }
gas() { this.code.push(0x5a); }
label(name) {
if (typeof this.labels[name] != "undefined") {
throw new Error("Label already defined");
}
this.labels[name] = this.code.length;
this.code.push(0x5b);
this._fillLabel(name);
}
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));
if (d.length == 0 || d.length > 32) {
throw new Error("Assertion failed");
}
this.code = this.code.concat([0x5F + d.length], d);
}
dup(n) {
if (n < 0 || n >= 16) {
throw new Error("Assertion failed");
}
this.code.push(0x80 + n);
}
swap(n) {
if (n < 1 || n > 16) {
throw new Error("Assertion failed");
}
this.code.push(0x8f + n);
}
log0() { this.code.push(0xa0); }
log1() { this.code.push(0xa1); }
log2() { this.code.push(0xa2); }
log3() { this.code.push(0xa3); }
log4() { this.code.push(0xa4); }
create() { this.code.push(0xf0); }
call() { this.code.push(0xf1); }
callcode() { this.code.push(0xf2); }
return() { this.code.push(0xf3); }
delegatecall() { this.code.push(0xf4); }
staticcall() { this.code.push(0xfa); }
revert() { this.code.push(0xfd); }
invalid() { this.code.push(0xfe); }
selfdestruct() { this.code.push(0xff); }
}
module.exports = Contract;

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;

58
src/mimc7.js Normal file
View File

@ -0,0 +1,58 @@
const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("@tornado/snarkjs").bigInt;
const Web3Utils = require("web3-utils");
const F = bn128.Fr;
const SEED = "mimc";
const NROUNDS = 91;
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);
return cts;
};
const cts = exports.getConstants(SEED, 91);
exports.hash = (_x_in, _k) => {
const x_in = bigInt(_x_in);
const k = bigInt(_k);
let r;
for (let i = 0; i < NROUNDS; i++) {
const c = cts[i];
const t = i == 0 ? F.add(x_in, k) : F.add(F.add(r, k), c);
r = F.exp(t, 7);
}
return F.affine(F.add(r, k));
};
exports.multiHash = (arr, key) => {
let r;
if (typeof key === "undefined") {
r = F.zero;
} else {
r = key;
}
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);
};

114
src/mimc_gencontract.js Normal file
View File

@ -0,0 +1,114 @@
// 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(0x44);
C.push("0x00");
C.push("0x00");
C.calldatacopy();
C.push("0x0100000000000000000000000000000000000000000000000000000000");
C.push("0x00");
C.mload();
C.div();
C.push("0xd15ca109"); // MiMCpe7(uint256,uint256)
// C.push("0x8c42199e"); // MiMCpe7(uint256,uint256,uint256)
C.eq();
C.jmpi("start");
C.invalid();
C.label("start");
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
C.push("0x24");
C.mload(); // k q
C.dup(1); // q k q
C.dup(0); // q q k q
C.push("0x04");
C.mload(); // x q q k q
C.dup(3); // k x q q k q
C.addmod(); // t=x+k q k q
C.dup(1); // q t q k q
C.dup(0); // q q t q k q
C.dup(2); // t q q t q k q
C.dup(0); // t t q q t q k q
C.mulmod(); // a=t^2 q t q k q
C.dup(1); // q a q t q k q
C.dup(1); // a q a q t q k q
C.dup(0); // a a q a q t q k q
C.mulmod(); // b=t^4 a q t q k q
C.mulmod(); // c=t^6 t q k q
C.mulmod(); // r=t^7 k q
for (let i=0; i<n-1; i++) {
ci = Web3Utils.keccak256(ci);
C.dup(2); // q r k q
C.dup(0); // q q r k q
C.dup(0); // q q q r k q
C.swap(3); // r q q q k q
C.push(ci); // c r q q k q
C.addmod(); // s=c+r q q k q
C.dup(3); // k s q q k q
C.addmod(); // t=s+k q k q
C.dup(1); // q t q k q
C.dup(0); // q q t q k q
C.dup(2); // t q q t q k q
C.dup(0); // t t q q t q k q
C.mulmod(); // a=t^2 q t q k q
C.dup(1); // q a q t q k q
C.dup(1); // a q a q t q k q
C.dup(0); // a a q a q t q k q
C.mulmod(); // b=t^4 a q t q k q
C.mulmod(); // c=t^6 t q k q
C.mulmod(); // r=t^7 k q
}
C.addmod(); // res=t^7+k
C.push("0x00");
C.mstore(); // Save it to pos 0;
C.push("0x20");
C.push("0x00");
C.return();
return C.createTxData();
}
module.exports.abi = [
{
"constant": true,
"inputs": [
{
"name": "in_x",
"type": "uint256"
},
{
"name": "in_k",
"type": "uint256"
}
],
"name": "MiMCpe7",
"outputs": [
{
"name": "out_x",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
];
module.exports.createCode = createCode;

3
src/mimc_print_iv.js Normal file
View File

@ -0,0 +1,3 @@
const mimc7 = require("./mimc7.js");
console.log("IV: "+mimc7.getIV().toString());

View File

@ -0,0 +1,13 @@
const mimc7 = require("./mimc7.js");
const nRounds = 91;
let S = "[\n";
const cts = mimc7.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);

13
src/mimc_printcontract.js Normal file
View File

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

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

107
src/pedersenHash.js Normal file
View File

@ -0,0 +1,107 @@
const bn128 = require("@tornado/snarkjs").bn128;
const bigInt = require("@tornado/snarkjs").bigInt;
const babyJub = require("./babyjub");
const createBlakeHash = require("blake-hash");
const GENPOINT_PREFIX = "PedersenGenerator";
const windowSize = 4;
const nWindowsPerSegment = 50;
exports.hash = pedersenHash;
exports.getBasePoint = getBasePoint;
function pedersenHash(msg) {
const bitsPerSegment = windowSize * nWindowsPerSegment;
const bits = buffer2bits(msg);
const nSegments = Math.floor((bits.length - 1) / (windowSize * nWindowsPerSegment)) + 1;
let accP = [bigInt.zero, bigInt.one];
for (let s = 0; s < nSegments; s++) {
let nWindows;
if (s == nSegments - 1) {
nWindows = Math.floor((bits.length - (nSegments - 1) * bitsPerSegment - 1) / windowSize) + 1;
} else {
nWindows = nWindowsPerSegment;
}
let escalar = bigInt.zero;
let exp = bigInt.one;
for (let w = 0; w < nWindows; w++) {
let o = s * bitsPerSegment + w * windowSize;
let acc = bigInt.one;
for (let b = 0; b < windowSize - 1 && o < bits.length; b++) {
if (bits[o]) {
acc = acc.add(bigInt.one.shl(b));
}
o++;
}
if (o < bits.length) {
if (bits[o]) {
acc = acc.neg();
}
o++;
}
escalar = escalar.add(acc.mul(exp));
exp = exp.shl(windowSize + 1);
}
if (escalar.lesser(bigInt.zero)) {
escalar = babyJub.subOrder.add(escalar);
}
accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(s), escalar));
}
return babyJub.packPoint(accP);
}
let bases = [];
function getBasePoint(pointIdx) {
if (pointIdx < bases.length) return bases[pointIdx];
let p = null;
let tryIdx = 0;
while (p == null) {
const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32);
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)
p = babyJub.unpackPoint(h);
tryIdx++;
}
const p8 = babyJub.mulPointEscalar(p, 8);
if (!babyJub.inSubgroup(p8)) {
throw new Error("Point not in curve");
}
bases[pointIdx] = p8;
return p8;
}
function padLeftZeros(idx, n) {
let sidx = "" + idx;
while (sidx.length < n) sidx = "0" + sidx;
return sidx;
}
/*
Input a buffer
Returns an array of booleans. 0 is LSB of first byte and so on.
*/
function buffer2bits(buff) {
const res = new Array(buff.length * 8);
for (let i = 0; i < buff.length; i++) {
const b = buff[i];
res[i * 8] = b & 0x01;
res[i * 8 + 1] = b & 0x02;
res[i * 8 + 2] = b & 0x04;
res[i * 8 + 3] = b & 0x08;
res[i * 8 + 4] = b & 0x10;
res[i * 8 + 5] = b & 0x20;
res[i * 8 + 6] = b & 0x40;
res[i * 8 + 7] = b & 0x80;
}
return res;
}

View File

@ -0,0 +1,13 @@
const pedersenHash = require("./pedersenHash.js");
let nBases;
if (typeof process.argv[2] != "undefined") {
nBases = parseInt(process.argv[2]);
} else {
nBases = 5;
}
for (let i=0; i < nBases; i++) {
const p = pedersenHash.getBasePoint(i);
console.log(`[${p[0]},${p[1]}]`);
}

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

306
src/smt.js Normal file
View File

@ -0,0 +1,306 @@
const bigInt = require("@tornado/snarkjs").bigInt;
const SMTMemDB = require("./smt_memdb");
const { hash0, hash1 } = require("./smt_hashes_poseidon");
class SMT {
constructor(db, root) {
this.db = db;
this.root = root;
}
_splitBits(_key) {
let k = bigInt(_key);
const res = [];
while (!k.isZero()) {
if (k.isOdd()) {
res.push(true);
} else {
res.push(false);
}
k = k.shr(1);
}
while (res.length < 256) res.push(false);
return res;
}
async update(_key, _newValue) {
const key = bigInt(_key);
const newValue = bigInt(_newValue);
const resFind = await this.find(key);
const res = {};
res.oldRoot = this.root;
res.oldKey = key;
res.oldValue = resFind.foundValue;
res.newKey = key;
res.newValue = newValue;
res.siblings = resFind.siblings;
const ins = [];
const dels = [];
let rtOld = hash1(key, resFind.foundValue);
let rtNew = hash1(key, newValue);
ins.push([rtNew, [1, key, newValue]]);
dels.push(rtOld);
const keyBits = this._splitBits(key);
for (let level = resFind.siblings.length - 1; level >= 0; level--) {
let oldNode, newNode;
const sibling = resFind.siblings[level];
if (keyBits[level]) {
oldNode = [sibling, rtOld];
newNode = [sibling, rtNew];
} else {
oldNode = [rtOld, sibling];
newNode = [rtNew, sibling];
}
rtOld = hash0(oldNode[0], oldNode[1]);
rtNew = hash0(newNode[0], newNode[1]);
dels.push(rtOld);
ins.push([rtNew, newNode]);
}
res.newRoot = rtNew;
await this.db.multiIns(ins);
await this.db.setRoot(rtNew);
this.root = rtNew;
await this.db.multiDel(dels);
return res;
}
async delete(_key) {
const key = bigInt(_key);
const resFind = await this.find(key);
if (!resFind.found) throw new Error("Key does not exists");
const res = {
siblings: [],
delKey: key,
delValue: resFind.foundValue,
};
const dels = [];
const ins = [];
let rtOld = hash1(key, resFind.foundValue);
let rtNew;
dels.push(rtOld);
let mixed;
if (resFind.siblings.length > 0) {
const record = await this.db.get(resFind.siblings[resFind.siblings.length - 1]);
if (record.length == 3 && record[0].equals(bigInt.one)) {
mixed = false;
res.oldKey = record[1];
res.oldValue = record[2];
res.isOld0 = false;
rtNew = resFind.siblings[resFind.siblings.length - 1];
} else if (record.length == 2) {
mixed = true;
res.oldKey = key;
res.oldValue = bigInt(0);
res.isOld0 = true;
rtNew = bigInt.zero;
} else {
throw new Error("Invalid node. Database corrupted");
}
} else {
rtNew = bigInt.zero;
res.oldKey = key;
res.oldValue = bigInt(0);
res.isOld0 = true;
}
const keyBits = this._splitBits(key);
for (let level = resFind.siblings.length - 1; level >= 0; level--) {
let newSibling = resFind.siblings[level];
if (level == resFind.siblings.length - 1 && !res.isOld0) {
newSibling = bigInt.zero;
}
const oldSibling = resFind.siblings[level];
if (keyBits[level]) {
rtOld = hash0(oldSibling, rtOld);
} else {
rtOld = hash0(rtOld, oldSibling);
}
dels.push(rtOld);
if (!newSibling.isZero()) {
mixed = true;
}
if (mixed) {
res.siblings.unshift(resFind.siblings[level]);
let newNode;
if (keyBits[level]) {
newNode = [newSibling, rtNew];
} else {
newNode = [rtNew, newSibling];
}
rtNew = hash0(newNode[0], newNode[1]);
ins.push([rtNew, newNode]);
}
}
await this.db.multiIns(ins);
await this.db.setRoot(rtNew);
this.root = rtNew;
await this.db.multiDel(dels);
res.newRoot = rtNew;
res.oldRoot = rtOld;
return res;
}
async insert(_key, _value) {
const key = bigInt(_key);
const value = bigInt(_value);
let addedOne = false;
const res = {};
res.oldRoot = this.root;
const newKeyBits = this._splitBits(key);
let rtOld;
const resFind = await this.find(key);
if (resFind.found) throw new Error("Key already exists");
res.siblings = resFind.siblings;
let mixed;
if (!resFind.isOld0) {
const oldKeyits = this._splitBits(resFind.notFoundKey);
for (let i = res.siblings.length; oldKeyits[i] == newKeyBits[i]; i++) {
res.siblings.push(bigInt.zero);
}
rtOld = hash1(resFind.notFoundKey, resFind.notFoundValue);
res.siblings.push(rtOld);
addedOne = true;
mixed = false;
} else if (res.siblings.length > 0) {
mixed = true;
rtOld = bigInt.zero;
}
const inserts = [];
const dels = [];
let rt = hash1(key, value);
inserts.push([rt, [1, key, value]]);
for (let i = res.siblings.length - 1; i >= 0; i--) {
if (i < res.siblings.length - 1 && !res.siblings[i].isZero()) {
mixed = true;
}
if (mixed) {
const oldSibling = resFind.siblings[i];
if (newKeyBits[i]) {
rtOld = hash0(oldSibling, rtOld);
} else {
rtOld = hash0(rtOld, oldSibling);
}
dels.push(rtOld);
}
let newRt;
if (newKeyBits[i]) {
newRt = hash0(res.siblings[i], rt);
inserts.push([newRt, [res.siblings[i], rt]]);
} else {
newRt = hash0(rt, res.siblings[i]);
inserts.push([newRt, [rt, res.siblings[i]]]);
}
rt = newRt;
}
if (addedOne) res.siblings.pop();
while (res.siblings.length > 0 && res.siblings[res.siblings.length - 1].isZero()) {
res.siblings.pop();
}
res.oldKey = resFind.notFoundKey;
res.oldValue = resFind.notFoundValue;
res.newRoot = rt;
res.isOld0 = resFind.isOld0;
await this.db.multiIns(inserts);
await this.db.setRoot(rt);
this.root = rt;
await this.db.multiDel(dels);
return res;
}
async find(key) {
const keyBits = this._splitBits(key);
return await this._find(key, keyBits, this.root, 0);
}
async _find(key, keyBits, root, level) {
if (typeof root === "undefined") root = this.root;
let res;
if (root.isZero()) {
res = {
found: false,
siblings: [],
notFoundKey: key,
notFoundValue: bigInt.zero,
isOld0: true,
};
return res;
}
const record = await this.db.get(root);
if (record.length == 3 && record[0].equals(bigInt.one)) {
if (record[1].equals(key)) {
res = {
found: true,
siblings: [],
foundValue: record[2],
isOld0: false,
};
} else {
res = {
found: false,
siblings: [],
notFoundKey: record[1],
notFoundValue: record[2],
isOld0: false,
};
}
} else {
if (keyBits[level] == 0) {
res = await this._find(key, keyBits, record[0], level + 1);
res.siblings.unshift(record[1]);
} else {
res = await this._find(key, keyBits, record[1], level + 1);
res.siblings.unshift(record[0]);
}
}
return res;
}
}
async function loadFromFile(fileName) {}
async function newMemEmptyTrie() {
const db = new SMTMemDB();
const rt = await db.getRoot();
const smt = new SMT(db, rt);
return smt;
}
module.exports.loadFromFile = loadFromFile;
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]);
};

58
src/smt_memdb.js Normal file
View File

@ -0,0 +1,58 @@
const bigInt = require("@tornado/snarkjs").bigInt;
class SMTMemDb {
constructor() {
this.nodes = {};
this.root = bigInt(0);
}
async getRoot() {
return this.root;
}
_key2str(k) {
// const keyS = bigInt(key).leInt2Buff(32).toString("hex");
const keyS = bigInt(k).toString();
return keyS;
}
_normalize(n) {
for (let i = 0; i < n.length; i++) {
n[i] = bigInt(n[i]);
}
}
async get(key) {
const keyS = this._key2str(key);
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) {
this.root = rt;
}
async multiIns(inserts) {
for (let i = 0; i < inserts.length; i++) {
const keyS = this._key2str(inserts[i][0]);
this._normalize(inserts[i][1]);
this.nodes[keyS] = inserts[i][1];
}
}
async multiDel(dels) {
for (let i = 0; i < dels.length; i++) {
const keyS = this._key2str(dels[i]);
delete this.nodes[keyS];
}
}
}
module.exports = SMTMemDb;

74
test/aliascheck.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 q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
describe("Aliascheck test", () => {
let circuit;
before(async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "aliascheck_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
});
it("Satisfy the aliastest 0", async () => {
const inp = getBits(bigInt.zero, 254);
circuit.calculateWitness({ in: inp });
});
it("Satisfy the aliastest 3", async () => {
const inp = getBits(bigInt(3), 254);
circuit.calculateWitness({ in: inp });
});
it("Satisfy the aliastest q-1", async () => {
const inp = getBits(q.sub(bigInt.one), 254);
circuit.calculateWitness({ in: inp });
});
it("Nhot not satisfy an input of q", async () => {
const inp = getBits(q, 254);
try {
circuit.calculateWitness({ in: inp });
assert(false);
} catch (err) {
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 () => {
const inp = getBits(bigInt(1).shl(254).sub(bigInt(1)), 254);
try {
circuit.calculateWitness({ in: inp });
assert(false);
} catch (err) {
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);
}
});
});

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