Compare commits

..

23 Commits

Author SHA1 Message Date
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
Marta Belles
97b870b725 Updated README files 2019-09-06 17:14:45 +02:00
41 changed files with 1347 additions and 157 deletions

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

View File

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

View File

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

View File

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

View File

@@ -21,6 +21,7 @@ include "comparators.circom";
include "aliascheck.circom"; include "aliascheck.circom";
/* This doesn't check aliasing, so for n > 253 there are multiple bit strings for each number */
template Num2Bits(n) { template Num2Bits(n) {
signal input in; signal input in;
signal output out[n]; signal output out[n];
@@ -76,6 +77,7 @@ template Bits2Num_strict() {
b2n.out ==> out; b2n.out ==> out;
} }
/* n must not exceed 253 */
template Num2BitsNeg(n) { template Num2BitsNeg(n) {
signal input in; signal input in;
signal output out[n]; signal output out[n];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,11 +1,13 @@
// implements MiMC-2n/n as hash using a sponge construction. // implements MiMC-2n/n as hash using a sponge construction.
// log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110 // log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110
// => nRounds should be 220 // => nRounds should be 220
template MiMCSponge(nInputs, nRounds, nOutputs) { template MiMCSponge(nInputs, nOutputs) {
signal input ins[nInputs]; signal input ins[nInputs];
signal input k; signal input k;
signal output outs[nOutputs]; signal output outs[nOutputs];
var nRounds = 220;
// S = R||C // S = R||C
component S[nInputs + nOutputs - 1]; component S[nInputs + nOutputs - 1];
@@ -21,7 +23,7 @@ template MiMCSponge(nInputs, nRounds, nOutputs) {
} }
} }
outs[0] = S[nInputs - 1].xL_out; outs[0] <== S[nInputs - 1].xL_out;
for (var i = 0; i < nOutputs - 1; i++) { for (var i = 0; i < nOutputs - 1; i++) {
S[nInputs + i] = MiMCFeistel(nRounds); S[nInputs + i] = MiMCFeistel(nRounds);
@@ -39,8 +41,8 @@ template MiMCFeistel(nrounds) {
signal output xL_out; signal output xL_out;
signal output xR_out; signal output xR_out;
var c = [ // doesn't contain the first and last round constants, which are always zero
0, var c_partial = [
7120861356467848435263064379192047478074060781135320967663101236819528304084, 7120861356467848435263064379192047478074060781135320967663101236819528304084,
5024705281721889198577876690145313457398658950011302225525409148828000436681, 5024705281721889198577876690145313457398658950011302225525409148828000436681,
17980351014018068290387269214713820287804403312720763401943303895585469787384, 17980351014018068290387269214713820287804403312720763401943303895585469787384,
@@ -258,8 +260,7 @@ template MiMCFeistel(nrounds) {
18224457394066545825553407391290108485121649197258948320896164404518684305122, 18224457394066545825553407391290108485121649197258948320896164404518684305122,
274945154732293792784580363548970818611304339008964723447672490026510689427, 274945154732293792784580363548970818611304339008964723447672490026510689427,
11050822248291117548220126630860474473945266276626263036056336623671308219529, 11050822248291117548220126630860474473945266276626263036056336623671308219529,
2119542016932434047340813757208803962484943912710204325088879681995922344971, 2119542016932434047340813757208803962484943912710204325088879681995922344971
0
]; ];
var t; var t;
@@ -268,13 +269,19 @@ template MiMCFeistel(nrounds) {
signal xL[nrounds-1]; signal xL[nrounds-1];
signal xR[nrounds-1]; signal xR[nrounds-1];
var c;
for (var i=0; i<nrounds; i++) { for (var i=0; i<nrounds; i++) {
t = (i==0) ? k+xL_in : k + xL[i-1] + c[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; t2[i] <== t*t;
t4[i] <== t2[i]*t2[i]; t4[i] <== t2[i]*t2[i];
if (i<nrounds-1) { if (i<nrounds-1) {
xL[i] <== ((i==0) ? xR_in : xR[i-1]) + t4[i]*t; xL[i] <== ((i==0) ? xR_in : xR[i-1]) + t4[i]*t;
xR[i] = (i==0) ? xL_in : xL[i-1]; xR[i] <== (i==0) ? xL_in : xL[i-1];
} else { } else {
xR_out <== xR[i-1] + t4[i]*t; xR_out <== xR[i-1] + t4[i]*t;
xL_out <== xL[i-1]; xL_out <== xL[i-1];

View File

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

View File

@@ -108,6 +108,7 @@ template Window4() {
} }
/* nWindows must not exceed 50 */
template Segment(nWindows) { template Segment(nWindows) {
signal input in[nWindows*4]; signal input in[nWindows*4];
signal input base[2]; signal input base[2];

26
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "circomlib", "name": "circomlib",
"version": "0.0.17", "version": "0.0.20",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -348,9 +348,9 @@
} }
}, },
"big-integer": { "big-integer": {
"version": "1.6.44", "version": "1.6.46",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.44.tgz", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.46.tgz",
"integrity": "sha512-7MzElZPTyJ2fNvBkPxtFQ2fWIkVmuzw41+BZHSzpEq3ymB2MfeKp1+yXl/tS75xCx+WnyV+yb0kp+K1C3UNwmQ==" "integrity": "sha512-Vj2TNtZ8Y0XaL6HCkzJiEqfykjtv/9wVCWIutMe+QVIXLPe2tCLEzULtYvcX9WRtmNIj3Jqi5tNjIsR0N4QOsg=="
}, },
"binary-extensions": { "binary-extensions": {
"version": "1.13.1", "version": "1.13.1",
@@ -601,9 +601,9 @@
} }
}, },
"circom": { "circom": {
"version": "0.0.28", "version": "0.0.34",
"resolved": "https://registry.npmjs.org/circom/-/circom-0.0.28.tgz", "resolved": "https://registry.npmjs.org/circom/-/circom-0.0.34.tgz",
"integrity": "sha512-cYivdFVPUAVsGFgx3/W3BQe50fwiu+w8Mq9rWA/UYLWwjAgY0Ctk+obpxGL5v9ZHJpO6pvmczLnOXmV/KqiB5g==", "integrity": "sha512-R7yNW8PtX2xREtLYWZ/o5cfKHT/qa+CveXsGVAX1ej7mPrTat9mlEMXEy2vX//IuP9/cnYTY/KxJ2SN05PUeGA==",
"dev": true, "dev": true,
"requires": { "requires": {
"big-integer": "^1.6.32", "big-integer": "^1.6.32",
@@ -3929,9 +3929,9 @@
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg=="
}, },
"p-limit": { "p-limit": {
"version": "2.2.0", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
"integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
"requires": { "requires": {
"p-try": "^2.0.0" "p-try": "^2.0.0"
} }
@@ -4703,9 +4703,9 @@
} }
}, },
"snarkjs": { "snarkjs": {
"version": "0.1.18", "version": "0.1.20",
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.18.tgz", "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.20.tgz",
"integrity": "sha512-JWZMBvPPIL424+QCY0PtreIiHTRoX4h4qYvKv3nqKPVZl0T7sw3B/ZeizrCVRz7Jr9vrwZxmzJ0XIg6D1yC8Mg==", "integrity": "sha512-tYmWiVm1sZiB44aIh5w/3HUaTntTUC4fv+CWs4rR0gfkt2KbHTpArOqZW++/Lxujrn9IypXVhdKVUr/eE6Hxfg==",
"requires": { "requires": {
"big-integer": "^1.6.43", "big-integer": "^1.6.43",
"chai": "^4.2.0", "chai": "^4.2.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "circomlib", "name": "circomlib",
"version": "0.0.17", "version": "0.0.20",
"description": "Basic circuits library for Circom", "description": "Basic circuits library for Circom",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@@ -31,7 +31,7 @@
"web3": "^1.0.0-beta.55" "web3": "^1.0.0-beta.55"
}, },
"devDependencies": { "devDependencies": {
"circom": "0.0.32", "circom": "0.0.35",
"eslint-plugin-mocha": "^5.2.0", "eslint-plugin-mocha": "^5.2.0",
"ganache-cli": "^6.4.4", "ganache-cli": "^6.4.4",
"mocha": "^5.2.0" "mocha": "^5.2.0"

View File

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

View File

@@ -27,6 +27,14 @@ class SMTMemDb {
return this.nodes[keyS]; return this.nodes[keyS];
} }
async multiGet(keys) {
const promises = [];
for (let i=0; i<keys.length; i++) {
promises.push(this.get(keys[i]));
}
return await Promise.all(promises);
}
async setRoot(rt) { async setRoot(rt) {
this.root = rt; this.root = rt;
} }

View File

@@ -56,7 +56,8 @@ describe("Aliascheck test", () => {
circuit.calculateWitness({in: inp}); circuit.calculateWitness({in: inp});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
assert(err.message.indexOf("1 != 0") >= 0);
} }
}); });
@@ -67,7 +68,8 @@ describe("Aliascheck test", () => {
circuit.calculateWitness({in: inp}); circuit.calculateWitness({in: inp});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
assert(err.message.indexOf("1 != 0") >= 0);
} }
}); });

75
test/aliascheckbabyjub.js Normal file
View File

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

View File

@@ -100,11 +100,12 @@ describe("Baby Jub test", function () {
circuitTest.calculateWitness({x: 1, y: 0}); circuitTest.calculateWitness({x: 1, y: 0});
assert(false, "Should be a valid point"); assert(false, "Should be a valid point");
} catch(err) { } catch(err) {
assert.equal(err.message, "Constraint doesn't match: 168700 != 1"); assert(/Constraint\sdoesn't\smatch(.*)168700\s!=\s1/.test(err.message) );
assert(err.message.indexOf("168700 != 1") >= 0);
} }
}); });
it("Should extract the public key from the private one", async () => { it("Should extract the public key from the private one", async () => {
const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex"); const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex");
const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0,32)); const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0,32));

View File

@@ -23,7 +23,7 @@ describe("Sum test", () => {
it("Should create a sum circuit", async () => { it("Should create a sum circuit", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom"));
assert.equal(cirDef.nVars, 101); assert.equal(cirDef.nVars, 97); // 32 (in1) + 32(in2) + 32(out) + 1 (carry)
const circuit = new snarkjs.Circuit(cirDef); const circuit = new snarkjs.Circuit(cirDef);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,10 +7,10 @@ template Main() {
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553, var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]; 16950150798460657717958625567821834550301663161624707787222815936182638968203];
component escalarMul = EscalarMulW4Table(base, 0); var escalarMul = EscalarMulW4Table(base, 0);
for (var i=0; i<16; i++) { for (var i=0; i<16; i++) {
out[i][0] <== escalarMul.out[i][0]*in; out[i][0] <== escalarMul[i][0]*in;
out[i][1] <== escalarMul.out[i][1]*in; out[i][1] <== escalarMul[i][1]*in;
} }
} }

View File

@@ -7,10 +7,10 @@ template Main() {
var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553, var base = [5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203]; 16950150798460657717958625567821834550301663161624707787222815936182638968203];
component escalarMul = EscalarMulW4Table(base, 3); var escalarMul = EscalarMulW4Table(base, 3);
for (var i=0; i<16; i++) { for (var i=0; i<16; i++) {
out[i][0] <== escalarMul.out[i][0]*in; out[i][0] <== escalarMul[i][0]*in;
out[i][1] <== escalarMul.out[i][1]*in; out[i][1] <== escalarMul[i][1]*in;
} }
} }

View File

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

View File

@@ -67,7 +67,7 @@ describe("EdDSA MiMC test", function () {
M: msg}); M: msg});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
} }
}); });

99
test/eddsamimcsponge.js Normal file
View File

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

View File

@@ -67,7 +67,7 @@ describe("EdDSA Poseidon test", function () {
M: msg}); M: msg});
assert(false); assert(false);
} catch(err) { } catch(err) {
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
} }
}); });

View File

@@ -38,6 +38,8 @@ describe("Exponentioation test", () => {
const w = circuit.calculateWitness({in: 1}); const w = circuit.calculateWitness({in: 1});
assert(circuit.checkWitness(w));
let g = [bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), let g = [bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")] bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
@@ -46,12 +48,12 @@ describe("Exponentioation test", () => {
for (let i=0; i<16; i++) { for (let i=0; i<16; i++) {
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)]; const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)]; const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
/*
console.log(xout1.toString()); // console.log(xout1.toString());
console.log(yout1.toString()); // console.log(yout1.toString());
console.log(dbl[0]); // console.log(dbl[0]);
console.log(dbl[1]); // console.log(dbl[1]);
*/
assert(xout1.equals(dbl[0])); assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1])); assert(yout1.equals(dbl[1]));
@@ -74,6 +76,8 @@ describe("Exponentioation test", () => {
const w = circuit.calculateWitness({in: 1}); const w = circuit.calculateWitness({in: 1});
assert(circuit.checkWitness(w));
let g = [snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"), let g = [snarkjs.bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")] snarkjs.bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")]
@@ -87,12 +91,12 @@ describe("Exponentioation test", () => {
const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)]; const xout1 = w[circuit.getSignalIdx(`main.out[${i}][0]`)];
const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)]; const yout1 = w[circuit.getSignalIdx(`main.out[${i}][1]`)];
/*
console.log(xout1.toString()); // console.log(xout1.toString());
console.log(yout1.toString()); // console.log(yout1.toString());
console.log(dbl[0]); // console.log(dbl[0]);
console.log(dbl[1]); // console.log(dbl[1]);
*/
assert(xout1.equals(dbl[0])); assert(xout1.equals(dbl[0]));
assert(yout1.equals(dbl[1])); assert(yout1.equals(dbl[1]));
@@ -102,7 +106,7 @@ describe("Exponentioation test", () => {
}); });
it("Should exponentiate g^31", async () => { it("Should exponentiate g^31", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmul_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "escalarmul_test.circom"), {reduceConstraints: true});
// console.log(JSON.stringify(cirDef, null, 1)); // console.log(JSON.stringify(cirDef, null, 1));
@@ -146,12 +150,12 @@ describe("Exponentioation test", () => {
c = addPoint(c,c); c = addPoint(c,c);
} }
c = addPoint(c,g); c = addPoint(c,g);
/*
console.log(xout2.toString()); // console.log(xout2.toString());
console.log(yout2.toString()); // console.log(yout2.toString());
console.log(c[0].toString()); // console.log(c[0].toString());
console.log(c[1].toString()); // console.log(c[1].toString());
*/
assert(xout2.equals(c[0])); assert(xout2.equals(c[0]));
assert(yout2.equals(c[1])); assert(yout2.equals(c[1]));

View File

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

View File

@@ -43,6 +43,8 @@ describe("Mux4 test", () => {
for (let i=0; i<16; i++) { for (let i=0; i<16; i++) {
const w = circuit.calculateWitness({ "selector": i }); const w = circuit.calculateWitness({ "selector": i });
assert(circuit.checkWitness(w));
assert(w[0].equals(bigInt(1))); assert(w[0].equals(bigInt(1)));
// console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString()); // console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());
@@ -96,6 +98,8 @@ describe("Mux4 test", () => {
for (let i=0; i<4; i++) { for (let i=0; i<4; i++) {
const w = circuit.calculateWitness({ "selector": i }); const w = circuit.calculateWitness({ "selector": i });
assert(circuit.checkWitness(w));
assert(w[0].equals(bigInt(1))); assert(w[0].equals(bigInt(1)));
// console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString()); // console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());
@@ -118,6 +122,8 @@ describe("Mux4 test", () => {
for (let i=0; i<2; i++) { for (let i=0; i<2; i++) {
const w = circuit.calculateWitness({ "selector": i }); const w = circuit.calculateWitness({ "selector": i });
assert(circuit.checkWitness(w));
assert(w[0].equals(bigInt(1))); assert(w[0].equals(bigInt(1)));
// console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString()); // console.log(i + " -> " + w[circuit.getSignalIdx("main.out")].toString());

23
test/rawsmt3.circom Normal file
View File

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

View File

@@ -111,5 +111,28 @@ describe("SMT test", function () {
assert(circuit.checkWitness(w)); assert(circuit.checkWitness(w));
}); });
it("Check inclussion Adria case", async () => {
const e1_hi= bigInt("17124152697573569611556136390143205198134245887034837071647643529178599000839");
const e1_hv= bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const e2ok_hi= bigInt("16498254692537945203721083102154618658340563351558973077349594629411025251262");
const e2ok_hv= bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const e2fail_hi= bigInt("17195092312975762537892237130737365903429674363577646686847513978084990105579");
const e2fail_hv= bigInt("19650379996168153643111744440707177573540245771926102415571667548153444658179");
const tree1 = await smt.newMemEmptyTrie();
await tree1.insert(e1_hi,e1_hv);
await tree1.insert(e2ok_hi,e2ok_hv);
await testInclusion(tree1, e2ok_hi, circuit);
const tree2 = await smt.newMemEmptyTrie();
await tree2.insert(e1_hi,e1_hv);
await tree2.insert(e2fail_hi,e2fail_hv);
await testInclusion(tree2, e2fail_hi, circuit);
});
}); });

98
test/smtverifier_adria.js Normal file
View File

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