114 Commits

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

View File

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

View File

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

View File

@@ -64,8 +64,8 @@ function generatePoint(S) {
const g = [
bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")];
bigInt("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203")];
// Sanity check
if (!babyJub.inCurve(g)) {

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, nRounds, nOutputs)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MiMCFeistel(nrounds)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### montgomery
- `Edwards2Montgomery()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Montgomery2Edwards()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MontgomeryAdd()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `MontgomeryDouble()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### multiplexer
- `log2(a)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `EscalarProduct(w)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Decoder(w)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Multiplexer(wIn, nIn)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux1
- `MultiMux1(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux1()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux2
- `MultiMux2(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux2()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux3
- `MultiMux3(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux3()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### mux4
- `MultiMux4(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mux4()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### pedersen_old
Old version of the Pedersen hash (do not use any
more?).
### pedersen
- `Window4()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Segment(nWindows)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Pedersen(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### pointbits
- `sqrt(n)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Bits2Point()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Bits2Point_Strict()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Point2Bits`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Point2Bits_Strict`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### poseidon
Implementation of Poseidon hash function (LINK)
- `Sigma()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Ark(t, C, r)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Mix(t, M)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
- `Poseidon(nInputs)`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### sign
- `Sign()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE
### switcher
- `Switcher()`
- DESCRIPTION
- SCHEMA
- INPUT
- OUTPUT
- BENCHMARKS
- EXAMPLE

View File

@@ -17,6 +17,9 @@
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;
@@ -77,3 +80,27 @@ template BabyCheck() {
a*x2 + y2 === 1 + d*x2*y2;
}
// Extracts the public key from private key
template BabyPbk() {
signal private input in;
signal output Ax;
signal output Ay;
var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component pvkBits = Num2Bits(253);
pvkBits.in <== in;
component mulFix = EscalarMulFix(253, BASE8);
var i;
for (i=0; i<253; i++) {
mulFix.e[i] <== pvkBits.out[i];
}
Ax <== mulFix.out[0];
Ay <== mulFix.out[1];
}

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -122,9 +122,9 @@ template EdDSAVerifier(n) {
// Calculate left side of equation left = S*B8
var BASE8 = [
17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475
var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(256, BASE8);
for (i=0; i<256; i++) {

View File

@@ -58,6 +58,7 @@ template EdDSAMiMCVerifier() {
hash.in[2] <== Ax;
hash.in[3] <== Ay;
hash.in[4] <== M;
hash.k <== 0;
component h2bits = Num2Bits_strict();
h2bits.in <== hash.out;
@@ -99,9 +100,9 @@ template EdDSAMiMCVerifier() {
// Calculate left side of equation left = S*B8
var BASE8 = [
17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475
var BASE8[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<253; i++) {

View File

@@ -0,0 +1,123 @@
/*
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 "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(253);
snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
for (i=0; i<253; i++) {
snum2bits.out[i] ==> compConstant.in[i];
}
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg)
component hash = MiMCSponge(5, 220, 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[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<253; 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 "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(253);
snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
for (i=0; i<253; i++) {
snum2bits.out[i] ==> compConstant.in[i];
}
compConstant.in[253] <== 0;
compConstant.out*enabled === 0;
// 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[2] = [
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203
];
component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<253; i++) {
mulFix.e[i] <== snum2bits.out[i];
}
// Do the comparation left == right if enabled;
component eqCheckX = ForceEqualIfEnabled();
eqCheckX.enabled <== enabled;
eqCheckX.in[0] <== mulFix.out[0];
eqCheckX.in[1] <== addRight.xout;
component eqCheckY = ForceEqualIfEnabled();
eqCheckY.enabled <== enabled;
eqCheckY.in[0] <== mulFix.out[1];
eqCheckY.in[1] <== addRight.yout;
}

View File

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

View File

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

View File

@@ -28,6 +28,22 @@ include "babyjub.circom";
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
*/
template WindowMulFix() {
signal input in[3];
signal input base[2];
@@ -140,54 +156,60 @@ template SegmentMulFix(nWindows) {
e2m.in[1] <== base[1];
component windows[nWindows];
component adders[nWindows-1];
component cadders[nWindows-1];
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];
adders[i-1] = MontgomeryAdd();
cadders[i-1] = MontgomeryAdd();
if (i==1) {
adders[i-1].in1[0] <== windows[0].out[0];
adders[i-1].in1[1] <== windows[0].out[1];
cadders[i-1].in1[0] <== e2m.out[0];
cadders[i-1].in1[1] <== e2m.out[1];
} else {
adders[i-1].in1[0] <== adders[i-2].out[0];
adders[i-1].in1[1] <== adders[i-2].out[1];
cadders[i-1].in1[0] <== cadders[i-2].out[0];
cadders[i-1].in1[1] <== cadders[i-2].out[1];
}
adders[i-1].in2[0] <== windows[i].out[0];
adders[i-1].in2[1] <== windows[i].out[1];
cadders[i-1].in2[0] <== windows[i-1].out8[0];
cadders[i-1].in2[1] <== windows[i-1].out8[1];
cadders[i].in1[0] <== cadders[i-1].out[0];
cadders[i].in1[1] <== cadders[i-1].out[1];
}
for (j=0; j<3; j++) {
windows[i].in[j] <== e[3*i+j];
}
if (i<nWindows-1) {
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 (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();
if (nWindows > 1) {
m2e.in[0] <== adders[nWindows-2].out[0];
m2e.in[1] <== adders[nWindows-2].out[1];
cm2e.in[0] <== cadders[nWindows-2].out[0];
cm2e.in[1] <== cadders[nWindows-2].out[1];
} else {
m2e.in[0] <== windows[0].out[0];
m2e.in[1] <== windows[0].out[1];
cm2e.in[0] <== e2m.out[0];
cm2e.in[1] <== e2m.out[1];
}
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];
@@ -195,7 +217,6 @@ template SegmentMulFix(nWindows) {
cAdd.x2 <== -cm2e.out[0];
cAdd.y2 <== cm2e.out[1];
cAdd.xout ==> out[0];
cAdd.yout ==> out[1];
@@ -214,7 +235,7 @@ template EscalarMulFix(n, BASE) {
signal input e[n]; // Input in binary format
signal output out[2]; // Point (Twisted format)
var nsegments = (n-1)\249 +1;
var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
var nlastsegment = n - (nsegments-1)*249;
component segments[nsegments];
@@ -225,7 +246,7 @@ template EscalarMulFix(n, BASE) {
var s;
var i;
var nseg;
var nWindows
var nWindows;
for (s=0; s<nsegments; s++) {

View File

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

View File

@@ -67,6 +67,7 @@ template NOR() {
template MultiAND(n) {
signal input in[n];
signal output out;
var i;
if (n==1) {
out <== in[0];
} else if (n==2) {
@@ -81,8 +82,8 @@ template MultiAND(n) {
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];
for (i=0; i<n1; i++) ands[0].in[i] <== in[i];
for (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;

View File

@@ -22,7 +22,7 @@ template MiMC7(nrounds) {
signal input k;
signal output out;
var c = [
var c[91] = [
0,
20888961410941983456478427210666206549300505294776164667214940546594746570981,
15265126113435022738560151911929040668591755459209400716467504685752745317193,
@@ -137,18 +137,19 @@ template MiMC7(nrounds) {
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);
if (i==0) {
mims[i].x_in <== 15021630795539610737508582392395901278341266317943626182700664337106830745361;
} else {
mims[i].x_in <== mims[i-1].out;
}
mims[i].k <== in[i];
mims[i].x_in <== in[i];
mims[i].k <== r[i];
r[i+1] <== r[i] + in[i] + mims[i].out;
}
out <== mims[nInputs-1].out;
out <== r[nInputs];
}

290
circuits/mimcsponge.circom Normal file
View File

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

View File

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

47
circuits/mux1.circom Normal file
View File

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

62
circuits/mux2.circom Normal file
View File

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

View File

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

View File

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

View File

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

98
circuits/poseidon.circom Normal file
View File

@@ -0,0 +1,98 @@
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 N_ROUNDS_P[8] = [56, 57, 56, 60, 60, 63, 64, 63];
var t = nInputs + 1;
var nRoundsF = 8;
var nRoundsP = N_ROUNDS_P[t - 2];
var C[t*(nRoundsF + nRoundsP)] = POSEIDON_C(t);
var M[t][t] = POSEIDON_M(t);
component ark[nRoundsF + nRoundsP - 1];
component sigmaF[nRoundsF - 1][t];
component sigmaP[nRoundsP];
component mix[nRoundsF + nRoundsP - 1];
var k;
for (var i=0; i<nRoundsF + nRoundsP - 1; i++) {
ark[i] = Ark(t, C, t*i);
for (var j=0; j<t; j++) {
if (i==0) {
if (j<nInputs) {
ark[i].in[j] <== inputs[j];
} else {
ark[i].in[j] <== 0;
}
} else {
ark[i].in[j] <== mix[i-1].out[j];
}
}
if (i < nRoundsF/2 || i >= nRoundsP + nRoundsF/2) {
k = i < nRoundsF/2 ? i : i - nRoundsP;
mix[i] = Mix(t, M);
for (var j=0; j<t; j++) {
sigmaF[k][j] = Sigma();
sigmaF[k][j].in <== ark[i].out[j];
mix[i].in[j] <== sigmaF[k][j].out;
}
} else {
k = i - nRoundsF/2;
mix[i] = Mix(t, M);
sigmaP[k] = Sigma();
sigmaP[k].in <== ark[i].out[0];
mix[i].in[0] <== sigmaP[k].out;
for (var j=1; j<t; j++) {
mix[i].in[j] <== ark[i].out[j];
}
}
}
// last round is done only for the first word, so we do it manually to save constraints
component lastSigmaF = Sigma();
lastSigmaF.in <== mix[nRoundsF + nRoundsP - 2].out[0] + C[t*(nRoundsF + nRoundsP - 1)];
out <== lastSigmaF.out;
}

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

@@ -22,8 +22,11 @@ include "t1.circom";
include "t2.circom";
include "../binsum.circom";
include "sigmaplus.circom";
include "sha256compression_function.circom";
template Sha256compression() {
signal input hin[256];
signal input inp[512];
signal output out[256];
signal a[65][32];
@@ -36,7 +39,11 @@ template Sha256compression() {
signal h[65][32];
signal w[64][32];
var outCalc[256] = sha256compression(hin, inp);
var i;
for (i=0; i<256; i++) out[i] <-- outCalc[i];
component sigmaPlus[48];
for (i=0; i<48; i++) sigmaPlus[i] = SigmaPlus();
@@ -44,15 +51,6 @@ template Sha256compression() {
component ct_k[64];
for (i=0; i<64; i++) ct_k[i] = K(i);
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component hf0 = H(5);
component hg0 = H(6);
component hh0 = H(7);
component t1[64];
for (i=0; i<64; i++) t1[i] = T1();
@@ -82,20 +80,23 @@ template Sha256compression() {
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];
}
for (k=0; k<32; k++) {
w[t][k] <== sigmaPlus[t-16].out[k];
}
}
}
for (k=0; k<32; k++ ) {
a[0][k] <== ha0.out[k]
b[0][k] <== hb0.out[k]
c[0][k] <== hc0.out[k]
d[0][k] <== hd0.out[k]
e[0][k] <== he0.out[k]
f[0][k] <== hf0.out[k]
g[0][k] <== hg0.out[k]
h[0][k] <== hh0.out[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++) {
@@ -133,32 +134,32 @@ template Sha256compression() {
}
for (k=0; k<32; k++) {
fsum[0].in[0][k] <== ha0.out[k];
fsum[0].in[0][k] <== hin[32*0+k];
fsum[0].in[1][k] <== a[64][k];
fsum[1].in[0][k] <== hb0.out[k];
fsum[1].in[0][k] <== hin[32*1+k];
fsum[1].in[1][k] <== b[64][k];
fsum[2].in[0][k] <== hc0.out[k];
fsum[2].in[0][k] <== hin[32*2+k];
fsum[2].in[1][k] <== c[64][k];
fsum[3].in[0][k] <== hd0.out[k];
fsum[3].in[0][k] <== hin[32*3+k];
fsum[3].in[1][k] <== d[64][k];
fsum[4].in[0][k] <== he0.out[k];
fsum[4].in[0][k] <== hin[32*4+k];
fsum[4].in[1][k] <== e[64][k];
fsum[5].in[0][k] <== hf0.out[k];
fsum[5].in[0][k] <== hin[32*5+k];
fsum[5].in[1][k] <== f[64][k];
fsum[6].in[0][k] <== hg0.out[k];
fsum[6].in[0][k] <== hin[32*6+k];
fsum[6].in[1][k] <== g[64][k];
fsum[7].in[0][k] <== hh0.out[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];
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,112 @@
// signal input hin[256];
// signal input inp[512];
// signal output out[256];
function rrot(x, n) {
return ((x >> n) | (x << (32-n))) & 0xFFFFFFFF;
}
function bsigma0(x) {
return rrot(x,2) ^ rrot(x,13) ^ rrot(x,22);
}
function bsigma1(x) {
return rrot(x,6) ^ rrot(x,11) ^ rrot(x,25);
}
function ssigma0(x) {
return rrot(x,7) ^ rrot(x,18) ^ (x >> 3);
}
function ssigma1(x) {
return rrot(x,17) ^ rrot(x,19) ^ (x >> 10);
}
function Maj(x, y, z) {
return (x&y) ^ (x&z) ^ (y&z);
}
function Ch(x, y, z) {
return (x & y) ^ ((0xFFFFFFFF ^x) & z);
}
function sha256K(i) {
var k[64] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
return k[i];
}
function sha256compression(hin, inp) {
var H[8];
var a;
var b;
var c;
var d;
var e;
var f;
var g;
var h;
var out[256];
for (var i=0; i<8; i++) {
H[i] = 0;
for (var j=0; j<32; j++) {
H[i] += hin[i*32+j] << j;
}
}
a=H[0];
b=H[1];
c=H[2];
d=H[3];
e=H[4];
f=H[5];
g=H[6];
h=H[7];
var w[64];
var T1;
var T2;
for (var i=0; i<64; i++) {
if (i<16) {
w[i]=0;
for (var j=0; j<32; j++) {
w[i] += inp[i*32+31-j]<<j;
}
} else {
w[i] = (ssigma1(w[i-2]) + w[i-7] + ssigma0(w[i-15]) + w[i-16]) & 0xFFFFFFFF;
}
T1 = (h + bsigma1(e) + Ch(e,f,g) + sha256K(i) + w[i]) & 0xFFFFFFFF;
T2 = (bsigma0(a) + Maj(a,b,c)) & 0xFFFFFFFF;
h=g;
g=f;
f=e;
e=(d+T1) & 0xFFFFFFFF;
d=c;
c=b;
b=a;
a=(T1+T2) & 0xFFFFFFFF;
}
H[0] = H[0] + a;
H[1] = H[1] + b;
H[2] = H[2] + c;
H[3] = H[3] + d;
H[4] = H[4] + e;
H[5] = H[5] + f;
H[6] = H[6] + g;
H[7] = H[7] + h;
for (var i=0; i<8; i++) {
for (var j=0; j<32; j++) {
out[i*32+31-j] = (H[i] >> j) & 1;
}
}
return out;
}

View File

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

View File

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

View File

@@ -30,23 +30,28 @@ template T1() {
signal input w[32];
signal output out[32];
component sum = BinSum(32, 5);
component ch = Ch(32);
var ki;
component ch = Ch(32);
component bigsigma1 = BigSigma(6, 11, 25);
for (var ki=0; ki<32; ki++) {
for (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]
ch.c[ki] <== g[ki];
}
component sum = BinSum(32, 5);
for (ki=0; ki<32; 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];
}
for (ki=0; ki<32; ki++) {
out[ki] <== sum.out[ki];
}
}

View File

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

View File

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

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

View File

@@ -135,7 +135,7 @@ include "../switcher.circom";
include "smtlevins.circom";
include "smtprocessorlevel.circom";
include "smtprocessorsm.circom";
include "smthash.circom";
include "smthash_poseidon.circom";
template SMTProcessor(nLevels) {
signal input oldRoot;
@@ -150,6 +150,8 @@ template SMTProcessor(nLevels) {
signal enabled;
var i;
enabled <== fnc[0] + fnc[1] - fnc[0]*fnc[1]
component hash1Old = SMTHash1();
@@ -167,18 +169,18 @@ template SMTProcessor(nLevels) {
n2bNew.in <== newKey;
component smtLevIns = SMTLevIns(nLevels);
for (var i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
for (i=0; i<nLevels; i++) smtLevIns.siblings[i] <== siblings[i];
smtLevIns.enabled <== enabled;
component xors[nLevels];
for (var i=0; i<nLevels; i++) {
for (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++) {
for (i=0; i<nLevels; i++) {
sm[i] = SMTProcessorSM();
if (i==0) {
sm[i].prev_top <== enabled;
@@ -204,7 +206,7 @@ template SMTProcessor(nLevels) {
sm[nLevels-1].st_na + sm[nLevels-1].st_new1 + sm[nLevels-1].st_old0 +sm[nLevels-1].st_upd === 1;
component levels[nLevels];
for (var i=nLevels-1; i != -1; i--) {
for (i=nLevels-1; i != -1; i--) {
levels[i] = SMTProcessorLevel();
levels[i].st_top <== sm[i].st_top;

View File

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

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,12 @@
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");

14036
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "circomlib",
"version": "0.0.6",
"version": "0.3.0",
"description": "Basic circuits library for Circom",
"main": "index.js",
"directories": {
@@ -25,13 +25,14 @@
"license": "GPL-3.0",
"dependencies": {
"blake-hash": "^1.1.0",
"snarkjs": "0.1.11",
"web3": "^1.0.0-beta.36"
"blake2b": "^2.1.3",
"circom": "0.5.33",
"ffjavascript": "0.1.0"
},
"devDependencies": {
"circom": "0.0.24",
"eslint-plugin-mocha": "^5.2.0",
"ganache-cli": "^6.2.3",
"mocha": "^5.2.0"
"eslint": "^6.8.0",
"ganache-cli": "^6.12.1",
"mocha": "^7.1.1",
"web3": "^1.3.0"
}
}

View File

@@ -1,5 +1,6 @@
const bn128 = require("snarkjs").bn128;
const bigInt = require("snarkjs").bigInt;
const F1Field = require("ffjavascript").F1Field;
const Scalar = require("ffjavascript").Scalar;
const utils = require("ffjavascript").utils;
exports.addPoint = addPoint;
exports.mulPointEscalar = mulPointEscalar;
@@ -7,37 +8,68 @@ exports.inCurve = inCurve;
exports.inSubgroup = inSubgroup;
exports.packPoint = packPoint;
exports.unpackPoint = unpackPoint;
exports.Base8 = [
bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"),
bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475")
exports.p = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const F = new F1Field(exports.p);
exports.F = F;
exports.Generator = [
F.e("995203441582195749578291179787384436505546430278305826713579947235728471134"),
F.e("5472060717959818805561601436314318772137091100104008585924551046643952123905")
];
exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328");
exports.subOrder = exports.order.shr(3);
exports.p = bn128.r;
exports.Base8 = [
F.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
F.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
];
exports.order = Scalar.fromString("21888242871839275222246405745257275088614511777268538073601725287587578984328");
exports.subOrder = Scalar.shiftRight(exports.order, 3);
exports.A = F.e("168700");
exports.D = F.e("168696");
function addPoint(a,b) {
const q = bn128.r;
const cta = bigInt("168700");
const d = bigInt("168696");
const res = [];
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
/* does the equivalent of:
res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
*/
const beta = F.mul(a[0],b[1]);
const gamma = F.mul(a[1],b[0]);
const delta = F.mul(
F.sub(a[1], F.mul(exports.A, a[0])),
F.add(b[0], b[1])
);
const tau = F.mul(beta, gamma);
const dtau = F.mul(exports.D, tau);
res[0] = F.div(
F.add(beta, gamma),
F.add(F.one, dtau)
);
res[1] = F.div(
F.add(delta, F.sub(F.mul(exports.A,beta), gamma)),
F.sub(F.one, dtau)
);
return res;
}
function mulPointEscalar(base, e) {
let res = [bigInt("0"),bigInt("1")];
let rem = bigInt(e);
let res = [F.e("0"),F.e("1")];
let rem = e;
let exp = base;
while (! rem.isZero()) {
if (rem.isOdd()) {
while (! Scalar.isZero(rem)) {
if (Scalar.isOdd(rem)) {
res = addPoint(res, exp);
}
exp = addPoint(exp, exp);
rem = rem.shr(1);
rem = Scalar.shiftRight(rem, 1);
}
return res;
@@ -46,36 +78,30 @@ function mulPointEscalar(base, e) {
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)));
return (F.isZero(res[0]) && F.eq(res[1], F.one));
}
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]);
if (!F.equals(
F.add(F.mul(a, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), d)))) return false;
if (!F.eq(
F.add(F.mul(exports.A, x2), y2),
F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false;
return true;
}
function packPoint(P) {
const buff = bigInt.leInt2Buff(P[1], 32);
if (P[0].greater(exports.p.shr(1))) {
const buff = utils.leInt2Buff(P[1], 32);
if (F.lt(P[0], F.zero)) {
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);
@@ -83,23 +109,20 @@ function unpackPoint(_buff) {
sign = true;
buff[31] = buff[31] & 0x7F;
}
P[1] = bigInt.leBuff2int(buff);
if (P[1].greaterOrEquals(exports.p)) return null;
const a = bigInt("168700");
const d = bigInt("168696");
P[1] = utils.leBuff2int(buff);
if (Scalar.gt(P[1], exports.p)) return null;
const y2 = F.square(P[1]);
let x = F.sqrt(F.div(
F.sub(F.one, y2),
F.sub(a, F.mul(d, 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);
P[0] = x;
return P;
}

View File

@@ -1,14 +1,23 @@
const createBlakeHash = require("blake-hash");
const bigInt = require("snarkjs").bigInt;
const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field;
const babyJub = require("./babyjub");
const utils = require("ffjavascript").utils;
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;
@@ -24,26 +33,27 @@ function pruneBuffer(_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));
let s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s,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 s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r);
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);
const hm = utils.leBuff2int(hmBuff);
const S = Fr.add(r , Fr.mul(hm, s));
return {
R8: R8,
S: S
@@ -53,16 +63,57 @@ function sign(prv, msg) {
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 s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = bigInt.leInt2Buff(msg, 32);
const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r);
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);
const S = Fr.add(r , Fr.mul(hm, s));
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 = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]);
const S = Fr.add(r , Fr.mul(hm, s));
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 = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = poseidon([R8[0], R8[1], A[0], A[1], msg]);
const S = Fr.add(r , Fr.mul(hm, s));
return {
R8: R8,
S: S
@@ -83,14 +134,14 @@ function verify(msg, sig, A) {
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 hm = utils.leBuff2int(hmBuff);
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm,8));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false;
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
return true;
}
@@ -108,24 +159,69 @@ function verifyMiMC(msg, sig, A) {
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")));
let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!Pleft[0].equals(Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false;
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],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, Scalar.mul(hm, 8));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],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.times(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright);
if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
return true;
}
function packSignature(sig) {
const R8p = babyJub.packPoint(sig.R8);
const Sp = bigInt.leInt2Buff(sig.S, 32);
const Sp = utils.leInt2Buff(sig.S, 32);
return Buffer.concat([R8p, Sp]);
}
function unpackSignature(sigBuff) {
return {
R8: babyJub.unpackPoint(sigBuff.slice(0,32)),
S: bigInt.leBuff2int(sigBuff.slice(32,64))
S: utils.leBuff2int(sigBuff.slice(32,64))
};
}

View File

@@ -127,12 +127,16 @@ class Contract {
jmp(label) {
this._pushLabel(label);
if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x56);
}
jmpi(label) {
this._pushLabel(label);
if (typeof label !== "undefined") {
this._pushLabel(label);
}
this.code.push(0x57);
}
@@ -150,6 +154,17 @@ class Contract {
}
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");

582
src/g2_gencontract.js Normal file
View File

@@ -0,0 +1,582 @@
// Copyright (c) 2018 Jordi Baylina
// License: LGPL-3.0+
//
const Contract = require("./evmasm");
const G2 = require("snarkjs").bn128.G2;
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, i));
for (let j=0; j<2; j++) {
for (let k=0; k<2; k++) {
C.push(toHex256(MP[j][k])); // MP[0][0] p
C.dup(1); // p MP[0][0] p
C.mstore(); // p
C.push(32); // 32 p
C.add(); // p+32
}
}
}
}
}
module.exports.abi = [
{
"constant": true,
"inputs": [
{
"name": "escalar",
"type": "uint256"
}
],
"name": "mulexp",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
];
module.exports.createCode = createCode;

View File

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

86
src/mimcsponge.js Normal file
View File

@@ -0,0 +1,86 @@
const Scalar = require("ffjavascript").Scalar
const Web3Utils = require("web3-utils");
const ZqField = require("ffjavascript").ZqField;
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
const SEED = "mimcsponge";
const NROUNDS = 220;
exports.getIV = (seed) => {
if (typeof seed === "undefined") seed = SEED;
const c = Web3Utils.keccak256(seed+"_iv");
const cn = Scalar.fromString(Web3Utils.toBN(c).toString());
const iv = cn.mod(F.p);
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.p.toString()));
const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64);
cts[i] = F.e(Web3Utils.toBN(c2).toString());
}
cts[0] = F.e(0);
cts[cts.length - 1] = F.e(0);
return cts;
};
const cts = exports.getConstants(SEED, NROUNDS);
exports.hash = (_xL_in, _xR_in, _k) =>{
let xL = F.e(_xL_in);
let xR = F.e(_xR_in);
const k = F.e(_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 = F.e(xR);
if (i < (NROUNDS - 1)) {
xR = xL;
xL = F.add(xR_tmp, F.pow(t, 5));
} else {
xR = F.add(xR_tmp, F.pow(t, 5));
}
}
return {
xL: F.normalize(xL),
xR: F.normalize(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, F.e(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.normalize(outputs[0]);
} else {
return outputs.map(x => F.normalize(x));
}
};

View File

@@ -0,0 +1,128 @@
// 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("0x3f1a1187"); // MiMCSponge(uint256,uint256,uint256)
C.eq();
C.jmpi("start");
C.invalid();
C.label("start");
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
C.push("0x44");
C.mload(); // k q
C.push("0x04");
C.mload(); // xL k q
C.dup(2); // q xL k q
C.push("0x24");
C.mload(); // xR q xL k q
C.dup(1); // q xR q xL k q
C.dup(0); // q q xR q xL k q
C.dup(4); // xL q q xR q xL k q
C.dup(6); // k xL q q xR q xL k q
C.addmod(); // t=k+xL q xR q xL k q
C.dup(1); // q t q xR q xL k q
C.dup(0); // q q t q xR q xL k q
C.dup(2); // t q q t q xR q xL k q
C.dup(0); // t t q q t q xR q xL k q
C.mulmod(); // b=t^2 q t q xR q xL k q
C.dup(0); // b b q t q xR q xL k q
C.mulmod(); // c=t^4 t q xR q xL k q
C.mulmod(); // d=t^5 xR q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
for (let i=0; i<n-1; i++) {
if (i < n-2) {
ci = Web3Utils.keccak256(ci);
} else {
ci = "0x00";
}
C.swap(1); // xR xL k q
C.dup(3); // q xR xL k q
C.dup(3); // k q xR xL k q
C.dup(1); // q k q xR xL k q
C.dup(4); // xL q k q xR xL k q
C.push(ci); // ci xL q k q xR xL k q
C.addmod(); // a=ci+xL k q xR xL k q
C.addmod(); // t=a+k xR xL k q
C.dup(4); // q t xR xL k q
C.swap(1); // t q xR xL k q
C.dup(1); // q t q xR xL k q
C.dup(0); // q q t q xR xL k q
C.dup(2); // t q q t q xR xL k q
C.dup(0); // t t q q t q xR xL k q
C.mulmod(); // b=t^2 q t q xR xL k q
C.dup(0); // b b q t q xR xL k q
C.mulmod(); // c=t^4 t q xR xL k q
C.mulmod(); // d=t^5 xR xL k q
C.dup(4); // q d xR xL k q
C.swap(2); // xR d q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
}
C.push("0x20");
C.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": "k",
"type": "uint256"
}
],
"name": "MiMCSponge",
"outputs": [
{
"name": "xL",
"type": "uint256"
},
{
"name": "xR",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
];
module.exports.createCode = createCode;

View File

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

View File

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

View File

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

View File

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

49
src/poseidon.js Normal file
View File

@@ -0,0 +1,49 @@
const assert = require("assert");
const Scalar = require("ffjavascript").Scalar;
const ZqField = require("ffjavascript").ZqField;
const { unstringifyBigInts } = require("ffjavascript").utils;
// 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 = [56, 57, 56, 60, 60, 63, 64, 63];
const pow5 = a => F.mul(a, F.square(F.square(a, a)));
function poseidon(inputs) {
assert(inputs.length > 0);
assert(inputs.length < N_ROUNDS_P.length - 1);
const t = inputs.length + 1;
const nRoundsF = N_ROUNDS_F;
const nRoundsP = N_ROUNDS_P[t - 2];
let state = [...inputs.map(a => F.e(a)), F.zero];
for (let r = 0; r < nRoundsF + nRoundsP; r++) {
state = state.map((a, i) => F.add(a, C[t - 2][r * t + i]));
if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
state = state.map(a => pow5(a));
} else {
state[0] = pow5(state[0]);
}
// no matrix multiplication in the last round
if (r < nRoundsF + nRoundsP - 1) {
state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(M[t - 2][j][i], a)), F.zero)
);
}
}
return F.normalize(state[0]);
}
module.exports = poseidon;

3449
src/poseidon_constants.json Normal file

File diff suppressed because it is too large Load Diff

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

View File

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

View File

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

View File

@@ -1,7 +1,6 @@
const bigInt = require("snarkjs").bigInt;
const Scalar = require("ffjavascript").Scalar;
const SMTMemDB = require("./smt_memdb");
const mimc7 = require("./mimc7");
const {hash0, hash1, F} = require("./smt_hashes_poseidon");
class SMT {
@@ -11,18 +10,7 @@ class SMT {
}
_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);
}
const res = Scalar.bits(_key);
while (res.length<256) res.push(false);
@@ -30,8 +18,8 @@ class SMT {
}
async update(_key, _newValue) {
const key = bigInt(_key);
const newValue = bigInt(_newValue);
const key = Scalar.e(_key);
const newValue = F.e(_newValue);
const resFind = await this.find(key);
@@ -46,8 +34,8 @@ class SMT {
const ins = [];
const dels = [];
let rtOld = mimc7.multiHash([1, key, resFind.foundValue]);
let rtNew = mimc7.multiHash([1, key, newValue]);
let rtOld = hash1(key, resFind.foundValue);
let rtNew = hash1(key, newValue);
ins.push([rtNew, [1, key, newValue ]]);
dels.push(rtOld);
@@ -59,27 +47,27 @@ class SMT {
oldNode = [sibling, rtOld];
newNode = [sibling, rtNew];
} else {
oldNode = [rtOld, sibling, ];
newNode = [rtNew, sibling, ];
oldNode = [rtOld, sibling];
newNode = [rtNew, sibling];
}
rtOld = mimc7.multiHash(oldNode);
rtNew = mimc7.multiHash(newNode);
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.multiDel(dels);
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 key = Scalar.e(_key);
const resFind = await this.find(key);
if (!resFind.found) throw new Error("Key does not exists");
@@ -92,14 +80,14 @@ class SMT {
const dels = [];
const ins = [];
let rtOld = mimc7.multiHash([1, key, resFind.foundValue]);
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))) {
if ((record.length == 3)&&(F.eq(record[0], F.one))) {
mixed = false;
res.oldKey = record[1];
res.oldValue = record[2];
@@ -108,16 +96,16 @@ class SMT {
} else if (record.length == 2) {
mixed = true;
res.oldKey = key;
res.oldValue = bigInt(0);
res.oldValue = F.zero;
res.isOld0 = true;
rtNew = bigInt.zero;
rtNew = F.zero;
} else {
throw new Error("Invalid node. Database corrupted");
}
} else {
rtNew = bigInt.zero;
rtNew = F.zero;
res.oldKey = key;
res.oldValue = bigInt(0);
res.oldValue = F.zero;
res.isOld0 = true;
}
@@ -126,16 +114,16 @@ class SMT {
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;
newSibling = F.zero;
}
const oldSibling = resFind.siblings[level];
if (keyBits[level]) {
rtOld = mimc7.multiHash([oldSibling, rtOld]);
rtOld = hash0(oldSibling, rtOld);
} else {
rtOld = mimc7.multiHash([rtOld, oldSibling]);
rtOld = hash0(rtOld, oldSibling);
}
dels.push(rtOld);
if (!newSibling.isZero()) {
if (!F.isZero(newSibling)) {
mixed = true;
}
@@ -147,7 +135,7 @@ class SMT {
} else {
newNode = [rtNew, newSibling];
}
rtNew = mimc7.multiHash(newNode);
rtNew = hash0(newNode[0], newNode[1]);
ins.push([rtNew, newNode]);
}
}
@@ -164,8 +152,8 @@ class SMT {
}
async insert(_key, _value) {
const key = bigInt(_key);
const value = bigInt(_value);
const key = Scalar.e(_key);
const value = F.e(_value);
let addedOne = false;
const res = {};
res.oldRoot = this.root;
@@ -183,33 +171,33 @@ class SMT {
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);
res.siblings.push(F.zero);
}
rtOld = mimc7.multiHash([1, resFind.notFoundKey, resFind.notFoundValue]);
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;
rtOld = F.zero;
}
const inserts = [];
const dels = [];
let rt = mimc7.multiHash([1, key, value]);
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())) {
if ((i<res.siblings.length-1)&&(!F.isZero(res.siblings[i]))) {
mixed = true;
}
if (mixed) {
const oldSibling = resFind.siblings[i];
if (newKeyBits[i]) {
rtOld = mimc7.multiHash([oldSibling, rtOld]);
rtOld = hash0(oldSibling, rtOld);
} else {
rtOld = mimc7.multiHash([rtOld, oldSibling]);
rtOld = hash0(rtOld, oldSibling);
}
dels.push(rtOld);
}
@@ -217,17 +205,17 @@ class SMT {
let newRt;
if (newKeyBits[i]) {
newRt = mimc7.multiHash([res.siblings[i], rt]);
newRt = hash0(res.siblings[i], rt);
inserts.push([newRt,[res.siblings[i], rt]] );
} else {
newRt = mimc7.multiHash([rt, res.siblings[i]]);
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())) {
while ((res.siblings.length>0) && (F.isZero(res.siblings[res.siblings.length-1]))) {
res.siblings.pop();
}
res.oldKey = resFind.notFoundKey;
@@ -253,12 +241,12 @@ class SMT {
if (typeof root === "undefined") root = this.root;
let res;
if (root.isZero()) {
if (F.isZero(root)) {
res = {
found: false,
siblings: [],
notFoundKey: key,
notFoundValue: bigInt.zero,
notFoundValue: F.zero,
isOld0: true
};
return res;
@@ -266,8 +254,8 @@ class SMT {
const record = await this.db.get(root);
if ((record.length==3)&&(record[0].equals(bigInt.one))) {
if (record[1].equals(key)) {
if ((record.length==3)&&(F.eq(record[0],F.one))) {
if (F.eq(record[1],key)) {
res = {
found: true,
siblings: [],
@@ -309,3 +297,5 @@ async function newMemEmptyTrie() {
module.exports.loadFromFile = loadFromFile;
module.exports.newMemEmptyTrie = newMemEmptyTrie;
module.exports.SMT = SMT;
module.exports.SMTMemDB = SMTMemDB;

12
src/smt_hashes_mimc.js Normal file
View File

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

View File

@@ -0,0 +1,18 @@
const ZqField = require("ffjavascript").ZqField;
const Scalar = require("ffjavascript").Scalar;
const poseidon = require("./poseidon");
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
exports.hash0 = function (left, right) {
return poseidon([left, right]);
};
exports.hash1 = function(key, value) {
return poseidon([key, value, F.one]);
};
exports.F = F;

View File

@@ -1,9 +1,14 @@
const bigInt = require("snarkjs").bigInt;
const Scalar = require("ffjavascript").Scalar;
const ZqField = require("ffjavascript").ZqField;
// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
class SMTMemDb {
constructor() {
this.nodes = {};
this.root = bigInt(0);
this.root = F.zero;
}
async getRoot() {
@@ -12,13 +17,13 @@ class SMTMemDb {
_key2str(k) {
// const keyS = bigInt(key).leInt2Buff(32).toString("hex");
const keyS = bigInt(k).toString();
const keyS = k.toString();
return keyS;
}
_normalize(n) {
for (let i=0; i<n.length; i++) {
n[i] = bigInt(n[i]);
n[i] = F.e(n[i]);
}
}
@@ -27,6 +32,14 @@ class SMTMemDb {
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;
}

View File

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

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

164
test/babyjub_js.js Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

81
test/eddsa_js.js Normal file
View File

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

View File

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

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