mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-07 11:16:42 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1965dd7f78 | ||
|
|
145a3eefeb | ||
|
|
38fa024745 | ||
|
|
5020d3f4ee | ||
|
|
ed63f08aeb | ||
|
|
c2a54e9187 | ||
|
|
d35d438107 | ||
|
|
5b45bafaac | ||
|
|
3f99f4eb53 | ||
|
|
dcfb9ab8b4 | ||
|
|
bfdf17fd89 | ||
|
|
9d0b27a7e8 | ||
|
|
4d79038fd8 | ||
|
|
95755c4afe | ||
|
|
afc60ec033 | ||
|
|
77393e2d0c | ||
|
|
2db08a0a34 | ||
|
|
23255de508 | ||
|
|
7c03ae4033 | ||
|
|
5e58584a01 | ||
|
|
cb9a5b536e | ||
|
|
70c88be334 |
12
README.md
12
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Circom
|
# Circom
|
||||||
|
|
||||||
Circon is a language designed to write arithmetic circuits that can be used in zero knowledge proofs.
|
Circom is a language designed to write arithmetic circuits that can be used in zero knowledge proofs.
|
||||||
|
|
||||||
In particular, it is designed to work in [zksnarks JavaScript library](https://github.com/iden3/zksnark).
|
In particular, it is designed to work in [zksnarks JavaScript library](https://github.com/iden3/zksnark).
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ template NAND() {
|
|||||||
component main = NAND();
|
component main = NAND();
|
||||||
```
|
```
|
||||||
|
|
||||||
The language uses mainly JavaScript/C syntax together with 5 extra operators to define the constraints:
|
The language uses mainly JavaScript/C syntax together with 5 extra operators to define the following constraints:
|
||||||
|
|
||||||
`<==` , `==>` : These two operators are used to connect signals and at the same time imply a constraint.
|
`<==` , `==>` : These two operators are used to connect signals and at the same time imply a constraint.
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ In the above example, both inputs are forced to be binary by adding the constrai
|
|||||||
|
|
||||||
### Compilation the circuit
|
### Compilation the circuit
|
||||||
|
|
||||||
First of all, the compiler must be installed typing:
|
First of all, the compiler must be installed by typing:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install -g circom
|
npm install -g circom
|
||||||
@@ -48,7 +48,7 @@ npm install -g circom
|
|||||||
The circuit is compiled with the following command:
|
The circuit is compiled with the following command:
|
||||||
|
|
||||||
```
|
```
|
||||||
circom -s mycircuit.circom -o mycircuit.json
|
circom mycircuit.circom -o mycircuit.json
|
||||||
```
|
```
|
||||||
|
|
||||||
The resulting output ( `mycircuit.json` ) can be used in the [zksnarks JavaScript library](https://github.com/iden3/zksnark).
|
The resulting output ( `mycircuit.json` ) can be used in the [zksnarks JavaScript library](https://github.com/iden3/zksnark).
|
||||||
@@ -91,7 +91,7 @@ in === out[0]*2**0 + out[1]*2**1 + out[2]*2**2 + ... + out[n-1]*2**(n-1)
|
|||||||
```
|
```
|
||||||
|
|
||||||
We do this by using a variable `lc1` and adding each signal multiplied by its coefficient.
|
We do this by using a variable `lc1` and adding each signal multiplied by its coefficient.
|
||||||
This variable does not hold a value in compilation time, but it holds a linear combination and it is used in the last constraint:
|
This variable does not hold a value at compilation time, but it holds a linear combination and it is used in the last constraint:
|
||||||
|
|
||||||
```
|
```
|
||||||
lc1 === in;
|
lc1 === in;
|
||||||
@@ -256,7 +256,7 @@ In this example we have shown how to design a top-down circuit with many subcirc
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Circon is part of the iden3 project copyright 2018 0KIMS association and published with GPL-3 license. Please check the COPYING file for more details.
|
Circom is part of the iden3 project copyright 2018 0KIMS association and published with GPL-3 license. Please check the COPYING file for more details.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
include "comparators.circom";
|
||||||
|
|
||||||
|
|
||||||
template Num2Bits(n) {
|
template Num2Bits(n) {
|
||||||
signal input in;
|
signal input in;
|
||||||
signal output out[n];
|
signal output out[n];
|
||||||
@@ -43,3 +46,27 @@ template Bits2Num(n) {
|
|||||||
|
|
||||||
lc1 ==> out;
|
lc1 ==> out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template Num2BitsNeg(n) {
|
||||||
|
signal input in;
|
||||||
|
signal output out[n];
|
||||||
|
var lc1=0;
|
||||||
|
|
||||||
|
component isZero;
|
||||||
|
|
||||||
|
isZero = IsZero();
|
||||||
|
|
||||||
|
var neg = n == 0 ? 0 : 2**n - in;
|
||||||
|
|
||||||
|
for (var i = 0; i<n; i++) {
|
||||||
|
out[i] <-- (neg >> i) & 1;
|
||||||
|
out[i] * (out[i] -1 ) === 0;
|
||||||
|
lc1 += out[i] * 2**i;
|
||||||
|
}
|
||||||
|
|
||||||
|
in ==> isZero.in;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
lc1 + isZero.out * 2**n === 2**n - in;
|
||||||
|
}
|
||||||
55
circuits/comparators.circom
Normal file
55
circuits/comparators.circom
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
include "bitify.circom";
|
||||||
|
include "binsum.circom";
|
||||||
|
|
||||||
|
template IsZero() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
signal inv;
|
||||||
|
|
||||||
|
inv <-- in!=0 ? 1/in : 0;
|
||||||
|
|
||||||
|
out <== -in*inv +1;
|
||||||
|
in*out === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template IsEqual() {
|
||||||
|
signal input in[2];
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
component isz = IsZero();
|
||||||
|
|
||||||
|
in[1] - in[0] ==> isz.in;
|
||||||
|
|
||||||
|
isz.out ==> out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// N is the number of bits the input have.
|
||||||
|
// The MSF is the sign bit.
|
||||||
|
template LessThan(n) {
|
||||||
|
signal input in[2];
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
component num2Bits0;
|
||||||
|
component num2Bits1;
|
||||||
|
|
||||||
|
component adder;
|
||||||
|
|
||||||
|
adder = BinSum(n, 2);
|
||||||
|
|
||||||
|
num2Bits0 = Num2Bits(n);
|
||||||
|
num2Bits1 = Num2BitsNeg(n);
|
||||||
|
|
||||||
|
in[0] ==> num2Bits0.in;
|
||||||
|
in[1] ==> num2Bits1.in;
|
||||||
|
|
||||||
|
var i;
|
||||||
|
for (i=0;i<n;i++) {
|
||||||
|
num2Bits0.out[i] ==> adder.in[0][i];
|
||||||
|
num2Bits1.out[i] ==> adder.in[1][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
adder.out[n-1] ==> out;
|
||||||
|
}
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 0KIMS association.
|
|
||||||
|
|
||||||
This file is part of circom (Zero Knowledge Circuit Compiler).
|
|
||||||
|
|
||||||
circom is a free software: you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
circom is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
template XOR() {
|
|
||||||
signal input a;
|
|
||||||
signal input b;
|
|
||||||
signal output out;
|
|
||||||
|
|
||||||
out <== a + b - 2*a*b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template AND() {
|
|
||||||
signal input a;
|
|
||||||
signal input b;
|
|
||||||
signal output out;
|
|
||||||
|
|
||||||
out <== a*b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template OR() {
|
|
||||||
signal input a;
|
|
||||||
signal input b;
|
|
||||||
signal output out;
|
|
||||||
|
|
||||||
out <== a + b - a*b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template NOT() {
|
|
||||||
signal input in;
|
|
||||||
signal output out;
|
|
||||||
|
|
||||||
out <== 1 + in - 2*in;
|
|
||||||
}
|
|
||||||
|
|
||||||
template NAND() {
|
|
||||||
signal input a;
|
|
||||||
signal input b;
|
|
||||||
signal output out;
|
|
||||||
|
|
||||||
out <== 1 - a*b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template NOR() {
|
|
||||||
signal input a;
|
|
||||||
signal input b;
|
|
||||||
signal output out;
|
|
||||||
|
|
||||||
out <== a*b + 1 - a - b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
include "sha256compression.circom";
|
include "sha256compression.circom";
|
||||||
include "bitify.circom"
|
include "../bitify.circom"
|
||||||
|
|
||||||
template Sha256_2() {
|
template Sha256_2() {
|
||||||
signal input a;
|
signal input a;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
include "constants.circom";
|
include "constants.circom";
|
||||||
include "t1.circom";
|
include "t1.circom";
|
||||||
include "t2.circom";
|
include "t2.circom";
|
||||||
include "binsum.circom";
|
include "../binsum.circom";
|
||||||
include "sigmaplus.circom";
|
include "sigmaplus.circom";
|
||||||
|
|
||||||
template Sha256compression() {
|
template Sha256compression() {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
include "binsum.circom"
|
include "../binsum.circom"
|
||||||
include "sigma.circom"
|
include "sigma.circom"
|
||||||
|
|
||||||
template SigmaPlus() {
|
template SigmaPlus() {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
include "binsum.circom";
|
include "../binsum.circom";
|
||||||
include "sigma.circom";
|
include "sigma.circom";
|
||||||
include "ch.circom";
|
include "ch.circom";
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
include "binsum.circom";
|
include "../binsum.circom";
|
||||||
include "sigma.circom";
|
include "sigma.circom";
|
||||||
include "maj.circom"
|
include "maj.circom"
|
||||||
|
|
||||||
|
|||||||
25
cli.js
25
cli.js
@@ -34,6 +34,7 @@ const argv = require("yargs")
|
|||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
.help("h")
|
.help("h")
|
||||||
.alias("h", "help")
|
.alias("h", "help")
|
||||||
|
.alias("v", "verbose")
|
||||||
.epilogue(`Copyright (C) 2018 0kims association
|
.epilogue(`Copyright (C) 2018 0kims association
|
||||||
This program comes with ABSOLUTELY NO WARRANTY;
|
This program comes with ABSOLUTELY NO WARRANTY;
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
@@ -41,15 +42,35 @@ const argv = require("yargs")
|
|||||||
repo directory at https://github.com/iden3/circom `)
|
repo directory at https://github.com/iden3/circom `)
|
||||||
.argv;
|
.argv;
|
||||||
|
|
||||||
const fullFileName = path.resolve(process.cwd(), argv._[0]);
|
|
||||||
|
let inputFile;
|
||||||
|
if (argv._.length == 0) {
|
||||||
|
inputFile = "circuit.circom";
|
||||||
|
} else if (argv._.length == 1) {
|
||||||
|
inputFile = argv._[0];
|
||||||
|
} else {
|
||||||
|
console.log("Only one circuit at a time is permited");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullFileName = path.resolve(process.cwd(), inputFile);
|
||||||
const outName = argv.output ? argv.output : "circuit.json";
|
const outName = argv.output ? argv.output : "circuit.json";
|
||||||
|
|
||||||
compiler(fullFileName).then( (cir) => {
|
compiler(fullFileName).then( (cir) => {
|
||||||
fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8");
|
fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8");
|
||||||
|
process.exit(0);
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
console.log(err);
|
// console.log(err);
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.pos) {
|
||||||
console.error(`ERROR at ${err.errFile}:${err.pos.first_line},${err.pos.first_column}-${err.pos.last_line},${err.pos.last_column} ${err.errStr}`);
|
console.error(`ERROR at ${err.errFile}:${err.pos.first_line},${err.pos.first_column}-${err.pos.last_line},${err.pos.last_column} ${err.errStr}`);
|
||||||
|
} else {
|
||||||
|
console.log(err.message);
|
||||||
|
if (argv.verbose) console.log(err.stack);
|
||||||
|
}
|
||||||
|
if (err.ast) {
|
||||||
console.error(JSON.stringify(err.ast, null, 1));
|
console.error(JSON.stringify(err.ast, null, 1));
|
||||||
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
20
package-lock.json
generated
20
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "circom",
|
"name": "circom",
|
||||||
"version": "0.0.13",
|
"version": "0.0.21",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1469,9 +1469,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"snarkjs": {
|
"snarkjs": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.5.tgz",
|
||||||
"integrity": "sha512-z5HhuNt019ZzNzUztETK31rpjRRSz3Uzy8TjGgSROf+9ZT9i6dbdWkjTC3fh5o9H+R/2+hcR+7IKAmpIR56V+A==",
|
"integrity": "sha512-4GiP60ONIitWRnC5+Gsl7nIO62fvkGN9Y9jsDWBKORZI34eNXJBrMjhCbT+0X57FS2XjY0MsR0/Qvg2cs1H0sQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"big-integer": "^1.6.35",
|
"big-integer": "^1.6.35",
|
||||||
@@ -1481,9 +1481,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "6.5.4",
|
"version": "6.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz",
|
||||||
"integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==",
|
"integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fast-deep-equal": "^2.0.1",
|
"fast-deep-equal": "^2.0.1",
|
||||||
@@ -1514,9 +1514,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eslint": {
|
"eslint": {
|
||||||
"version": "5.7.0",
|
"version": "5.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.9.0.tgz",
|
||||||
"integrity": "sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A==",
|
"integrity": "sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.0.0",
|
"@babel/code-frame": "^7.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "circom",
|
"name": "circom",
|
||||||
"version": "0.0.13",
|
"version": "0.0.21",
|
||||||
"description": "Language to generate logic circuits",
|
"description": "Language to generate logic circuits",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
@@ -38,6 +38,6 @@
|
|||||||
"eslint": "^5.0.1",
|
"eslint": "^5.0.1",
|
||||||
"eslint-plugin-mocha": "^5.0.0",
|
"eslint-plugin-mocha": "^5.0.0",
|
||||||
"jison": "^0.4.18",
|
"jison": "^0.4.18",
|
||||||
"snarkjs": "0.1.4"
|
"snarkjs": "0.1.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ include { return 'include'; }
|
|||||||
\- { return '-'; }
|
\- { return '-'; }
|
||||||
\* { return '*'; }
|
\* { return '*'; }
|
||||||
\/ { return '/'; }
|
\/ { return '/'; }
|
||||||
|
\\ { return '\\'; }
|
||||||
\% { return '%'; }
|
\% { return '%'; }
|
||||||
\^ { return '^'; }
|
\^ { return '^'; }
|
||||||
\& { return '&'; }
|
\& { return '&'; }
|
||||||
@@ -118,7 +119,7 @@ include { return 'include'; }
|
|||||||
%left '<<' '>>'
|
%left '<<' '>>'
|
||||||
|
|
||||||
%left '+' '-'
|
%left '+' '-'
|
||||||
%left '*' '/' '%'
|
%left '*' '/' '\\' '%'
|
||||||
%left '**'
|
%left '**'
|
||||||
%right '++' '--' UMINUS UPLUS '!' '~'
|
%right '++' '--' UMINUS UPLUS '!' '~'
|
||||||
%left '.'
|
%left '.'
|
||||||
@@ -627,7 +628,7 @@ e7
|
|||||||
{
|
{
|
||||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||||
let v = $3.value.greater(256) ? 256 : $3.value.value;
|
let v = $3.value.greater(256) ? 256 : $3.value.value;
|
||||||
$$ = {t1ype: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) };
|
$$ = {type: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) };
|
||||||
} else {
|
} else {
|
||||||
$$ = { type: "OP", op: ">>", values: [$1, $3] };
|
$$ = { type: "OP", op: ">>", values: [$1, $3] };
|
||||||
}
|
}
|
||||||
@@ -684,6 +685,15 @@ e5
|
|||||||
}
|
}
|
||||||
setLines($$, @1, @3);
|
setLines($$, @1, @3);
|
||||||
}
|
}
|
||||||
|
| e5 '\\' e4
|
||||||
|
{
|
||||||
|
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||||
|
$$ = { type: "NUMBER", value: ($1.value.divide($3.value)) };
|
||||||
|
} else {
|
||||||
|
$$ = { type: "OP", op: "\\", values: [$1, $3] };
|
||||||
|
}
|
||||||
|
setLines($$, @1, @3);
|
||||||
|
}
|
||||||
| e5 '%' e4
|
| e5 '%' e4
|
||||||
{
|
{
|
||||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||||
|
|||||||
144
parser/jaz.js
144
parser/jaz.js
File diff suppressed because one or more lines are too long
@@ -62,8 +62,13 @@ async function compile(srcFile) {
|
|||||||
fileName: fullFileName
|
fileName: fullFileName
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
exec(ctx, ast);
|
exec(ctx, ast);
|
||||||
|
|
||||||
|
if (!ctx.components["main"]) {
|
||||||
|
throw new Error("A main component must be defined");
|
||||||
|
}
|
||||||
|
|
||||||
classifySignals(ctx);
|
classifySignals(ctx);
|
||||||
reduceConstants(ctx);
|
reduceConstants(ctx);
|
||||||
|
|
||||||
|
|||||||
93
src/exec.js
93
src/exec.js
@@ -80,10 +80,16 @@ function exec(ctx, ast) {
|
|||||||
return execPlusPlusLeft(ctx, ast);
|
return execPlusPlusLeft(ctx, ast);
|
||||||
} else if (ast.op == "/") {
|
} else if (ast.op == "/") {
|
||||||
return execDiv(ctx, ast);
|
return execDiv(ctx, ast);
|
||||||
|
} else if (ast.op == "\\") {
|
||||||
|
return execIDiv(ctx, ast);
|
||||||
} else if (ast.op == "**") {
|
} else if (ast.op == "**") {
|
||||||
return execExp(ctx, ast);
|
return execExp(ctx, ast);
|
||||||
} else if (ast.op == "&") {
|
} else if (ast.op == "&") {
|
||||||
return execBAnd(ctx, ast);
|
return execBAnd(ctx, ast);
|
||||||
|
} else if (ast.op == "&&") {
|
||||||
|
return execAnd(ctx, ast);
|
||||||
|
} else if (ast.op == "||") {
|
||||||
|
return execOr(ctx, ast);
|
||||||
} else if (ast.op == "<<") {
|
} else if (ast.op == "<<") {
|
||||||
return execShl(ctx, ast);
|
return execShl(ctx, ast);
|
||||||
} else if (ast.op == ">>") {
|
} else if (ast.op == ">>") {
|
||||||
@@ -98,6 +104,8 @@ function exec(ctx, ast) {
|
|||||||
return execGte(ctx, ast);
|
return execGte(ctx, ast);
|
||||||
} else if (ast.op == "==") {
|
} else if (ast.op == "==") {
|
||||||
return execEq(ctx, ast);
|
return execEq(ctx, ast);
|
||||||
|
} else if (ast.op == "!=") {
|
||||||
|
return execNeq(ctx, ast);
|
||||||
} else if (ast.op == "?") {
|
} else if (ast.op == "?") {
|
||||||
return execTerCon(ctx, ast);
|
return execTerCon(ctx, ast);
|
||||||
} else {
|
} else {
|
||||||
@@ -316,8 +324,7 @@ function execInstantiateComponet(ctx, vr, fn) {
|
|||||||
const v = exec(ctx, fn.params[i]);
|
const v = exec(ctx, fn.params[i]);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
|
|
||||||
if (v.type != "NUMBER") return error(ctx, fn.params[i], "expected a number");
|
paramValues.push(v);
|
||||||
paramValues.push( v.value);
|
|
||||||
}
|
}
|
||||||
if (template.params.length != paramValues.length) error(ctx, fn, "Invalid Number of parameters");
|
if (template.params.length != paramValues.length) error(ctx, fn, "Invalid Number of parameters");
|
||||||
|
|
||||||
@@ -328,6 +335,15 @@ function execInstantiateComponet(ctx, vr, fn) {
|
|||||||
instantiateComponent(vv);
|
instantiateComponent(vv);
|
||||||
|
|
||||||
function instantiateComponent(varVal) {
|
function instantiateComponent(varVal) {
|
||||||
|
|
||||||
|
function extractValue(v) {
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
return v.map(extractValue);
|
||||||
|
} else {
|
||||||
|
return v.value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(varVal)) {
|
if (Array.isArray(varVal)) {
|
||||||
for (let i =0; i<varVal.length; i++) {
|
for (let i =0; i<varVal.length; i++) {
|
||||||
instantiateComponent(varVal[i]);
|
instantiateComponent(varVal[i]);
|
||||||
@@ -353,11 +369,8 @@ function execInstantiateComponet(ctx, vr, fn) {
|
|||||||
|
|
||||||
const scope = {};
|
const scope = {};
|
||||||
for (let i=0; i< template.params.length; i++) {
|
for (let i=0; i< template.params.length; i++) {
|
||||||
scope[template.params[i]] = {
|
scope[template.params[i]] = paramValues[i];
|
||||||
type: "NUMBER",
|
ctx.components[ctx.currentComponent].params[template.params[i]] = extractValue(paramValues[i]);
|
||||||
value: paramValues[i]
|
|
||||||
};
|
|
||||||
ctx.components[ctx.currentComponent].params[template.params[i]] = paramValues[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.components[ctx.currentComponent].template = templateName;
|
ctx.components[ctx.currentComponent].template = templateName;
|
||||||
@@ -539,12 +552,15 @@ function execPin(ctx, ast) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function execFor(ctx, ast) {
|
function execFor(ctx, ast) {
|
||||||
|
|
||||||
|
ctx.scopes.push({});
|
||||||
exec(ctx, ast.init);
|
exec(ctx, ast.init);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
|
|
||||||
let v = exec(ctx, ast.condition);
|
let v = exec(ctx, ast.condition);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
if (typeof v.value != "undefined") {
|
||||||
while ((v.value.neq(0))&&(!ctx.returnValue)) {
|
while ((v.value.neq(0))&&(!ctx.returnValue)) {
|
||||||
exec(ctx, ast.body);
|
exec(ctx, ast.body);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
@@ -555,12 +571,15 @@ function execFor(ctx, ast) {
|
|||||||
v = exec(ctx, ast.condition);
|
v = exec(ctx, ast.condition);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ctx.scopes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
function execWhile(ctx, ast) {
|
function execWhile(ctx, ast) {
|
||||||
let v = exec(ctx, ast.condition);
|
let v = exec(ctx, ast.condition);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
if (typeof v.value != "undefined") {
|
||||||
while ((v.value.neq(0))&&(!ctx.returnValue)) {
|
while ((v.value.neq(0))&&(!ctx.returnValue)) {
|
||||||
exec(ctx, ast.body);
|
exec(ctx, ast.body);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
@@ -568,12 +587,14 @@ function execWhile(ctx, ast) {
|
|||||||
v = exec(ctx, ast.condition);
|
v = exec(ctx, ast.condition);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function execIf(ctx, ast) {
|
function execIf(ctx, ast) {
|
||||||
let v = exec(ctx, ast.condition);
|
let v = exec(ctx, ast.condition);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
if (typeof v.value != "undefined") {
|
||||||
if ((v.value.neq(0))&&(!ctx.returnValue)) {
|
if ((v.value.neq(0))&&(!ctx.returnValue)) {
|
||||||
exec(ctx, ast.then);
|
exec(ctx, ast.then);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
@@ -583,6 +604,7 @@ function execIf(ctx, ast) {
|
|||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -680,6 +702,20 @@ function execEq(ctx, ast) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function execNeq(ctx, ast) {
|
||||||
|
const a = exec(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (a.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
const b = exec(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (b.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
if (!a.value || !b.value) return { type: "NUMBER" };
|
||||||
|
return {
|
||||||
|
type: "NUMBER",
|
||||||
|
value: a.value.eq(b.value) ? bigInt(0) : bigInt(1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function execBAnd(ctx, ast) {
|
function execBAnd(ctx, ast) {
|
||||||
const a = exec(ctx, ast.values[0]);
|
const a = exec(ctx, ast.values[0]);
|
||||||
@@ -695,6 +731,34 @@ function execBAnd(ctx, ast) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function execAnd(ctx, ast) {
|
||||||
|
const a = exec(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (a.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
const b = exec(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (b.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
if (!a.value || !b.value) return { type: "NUMBER" };
|
||||||
|
return {
|
||||||
|
type: "NUMBER",
|
||||||
|
value: (a.value.neq(0) && a.value.neq(0)) ? bigInt(1) : bigInt(0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function execOr(ctx, ast) {
|
||||||
|
const a = exec(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (a.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
const b = exec(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (b.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
if (!a.value || !b.value) return { type: "NUMBER" };
|
||||||
|
return {
|
||||||
|
type: "NUMBER",
|
||||||
|
value: (a.value.neq(0) || a.value.neq(0)) ? bigInt(1) : bigInt(0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function execShl(ctx, ast) {
|
function execShl(ctx, ast) {
|
||||||
const a = exec(ctx, ast.values[0]);
|
const a = exec(ctx, ast.values[0]);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
@@ -769,6 +833,21 @@ function execDiv(ctx, ast) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function execIDiv(ctx, ast) {
|
||||||
|
const a = exec(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (a.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
const b = exec(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
if (b.type != "NUMBER") return { type: "NUMBER" };
|
||||||
|
if (!a.value || !b.value) return { type: "NUMBER" };
|
||||||
|
if (b.value.isZero()) return error(ctx, ast, "Division by zero");
|
||||||
|
return {
|
||||||
|
type: "NUMBER",
|
||||||
|
value: a.value.divide(b.value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function execAdd(ctx, ast) {
|
function execAdd(ctx, ast) {
|
||||||
const a = exec(ctx, ast.values[0]);
|
const a = exec(ctx, ast.values[0]);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
|
|||||||
@@ -67,8 +67,14 @@ function gen(ctx, ast) {
|
|||||||
return genExp(ctx, ast);
|
return genExp(ctx, ast);
|
||||||
} else if (ast.op == "/") {
|
} else if (ast.op == "/") {
|
||||||
return genDiv(ctx, ast);
|
return genDiv(ctx, ast);
|
||||||
|
} else if (ast.op == "\\") {
|
||||||
|
return genIDiv(ctx, ast);
|
||||||
} else if (ast.op == "&") {
|
} else if (ast.op == "&") {
|
||||||
return genBAnd(ctx, ast);
|
return genBAnd(ctx, ast);
|
||||||
|
} else if (ast.op == "&&") {
|
||||||
|
return genAnd(ctx, ast);
|
||||||
|
} else if (ast.op == "||") {
|
||||||
|
return genOr(ctx, ast);
|
||||||
} else if (ast.op == "<<") {
|
} else if (ast.op == "<<") {
|
||||||
return genShl(ctx, ast);
|
return genShl(ctx, ast);
|
||||||
} else if (ast.op == ">>") {
|
} else if (ast.op == ">>") {
|
||||||
@@ -83,6 +89,8 @@ function gen(ctx, ast) {
|
|||||||
return genGte(ctx, ast);
|
return genGte(ctx, ast);
|
||||||
} else if (ast.op == "==") {
|
} else if (ast.op == "==") {
|
||||||
return genEq(ctx, ast);
|
return genEq(ctx, ast);
|
||||||
|
} else if (ast.op == "!=") {
|
||||||
|
return genNeq(ctx, ast);
|
||||||
} else if (ast.op == "?") {
|
} else if (ast.op == "?") {
|
||||||
return genTerCon(ctx, ast);
|
return genTerCon(ctx, ast);
|
||||||
} else {
|
} else {
|
||||||
@@ -314,7 +322,9 @@ function genVariable(ctx, ast) {
|
|||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!v) {
|
||||||
|
return error(ctx, ast, "Invalid left operand");
|
||||||
|
}
|
||||||
if (v.type == "VARIABLE") {
|
if (v.type == "VARIABLE") {
|
||||||
return `ctx.getVar("${ast.name}",[${sels.join(",")}])`;
|
return `ctx.getVar("${ast.name}",[${sels.join(",")}])`;
|
||||||
} else if (v.type == "SIGNAL") {
|
} else if (v.type == "SIGNAL") {
|
||||||
@@ -453,6 +463,15 @@ function genDiv(ctx, ast) {
|
|||||||
return `bigInt(${a}).mul( bigInt(${b}).inverse(__P__) ).mod(__P__)`;
|
return `bigInt(${a}).mul( bigInt(${b}).inverse(__P__) ).mod(__P__)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function genIDiv(ctx, ast) {
|
||||||
|
const a = gen(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
const b = gen(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
return `bigInt(${a}).div( bigInt(${b}))`;
|
||||||
|
}
|
||||||
|
|
||||||
function genExp(ctx, ast) {
|
function genExp(ctx, ast) {
|
||||||
const a = gen(ctx, ast.values[0]);
|
const a = gen(ctx, ast.values[0]);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
@@ -469,6 +488,22 @@ function genBAnd(ctx, ast) {
|
|||||||
return `bigInt(${a}).and(bigInt(${b})).and(__MASK__)`;
|
return `bigInt(${a}).and(bigInt(${b})).and(__MASK__)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function genAnd(ctx, ast) {
|
||||||
|
const a = gen(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
const b = gen(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
return `((bigInt(${a}).neq(bigInt(0)) && bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function genOr(ctx, ast) {
|
||||||
|
const a = gen(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
const b = gen(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
return `((bigInt(${a}).neq(bigInt(0)) || bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
|
||||||
|
}
|
||||||
|
|
||||||
function genShl(ctx, ast) {
|
function genShl(ctx, ast) {
|
||||||
const a = gen(ctx, ast.values[0]);
|
const a = gen(ctx, ast.values[0]);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
@@ -530,7 +565,15 @@ function genEq(ctx, ast) {
|
|||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
const b = gen(ctx, ast.values[1]);
|
const b = gen(ctx, ast.values[1]);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
return `bigInt(${a}).eq(bigInt(${b})) ? 1 : 0`;
|
return `(bigInt(${a}).eq(bigInt(${b})) ? 1 : 0)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function genNeq(ctx, ast) {
|
||||||
|
const a = gen(ctx, ast.values[0]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
const b = gen(ctx, ast.values[1]);
|
||||||
|
if (ctx.error) return;
|
||||||
|
return `(bigInt(${a}).eq(bigInt(${b})) ? 0 : 1)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function genUMinus(ctx, ast) {
|
function genUMinus(ctx, ast) {
|
||||||
|
|||||||
36
test/cases.js
Normal file
36
test/cases.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const path = require("path");
|
||||||
|
const snarkjs = require("snarkjs");
|
||||||
|
|
||||||
|
const bigInt = snarkjs.bigInt;
|
||||||
|
|
||||||
|
const compiler = require("../index.js");
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
describe("Sum test", () => {
|
||||||
|
it("Should compile a code with an undefined if", async () => {
|
||||||
|
await compiler(path.join(__dirname, "circuits", "undefinedif.circom"));
|
||||||
|
});
|
||||||
|
it("Should compile a code with vars inside a for", async () => {
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "forvariables.circom"));
|
||||||
|
|
||||||
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
const witness = circuit.calculateWitness({ "in": 111});
|
||||||
|
assert(witness[0].equals(bigInt(1)));
|
||||||
|
assert(witness[1].equals(bigInt(114)));
|
||||||
|
assert(witness[2].equals(bigInt(111)));
|
||||||
|
|
||||||
|
});
|
||||||
|
it("Should compile a code with an undefined if", async () => {
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "mixvarsignal.circom"));
|
||||||
|
|
||||||
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
const witness = circuit.calculateWitness({ "i": 111});
|
||||||
|
assert(witness[0].equals(bigInt(1)));
|
||||||
|
assert(witness[1].equals(bigInt(111)));
|
||||||
|
assert(witness[2].equals(bigInt(111)));
|
||||||
|
});
|
||||||
|
});
|
||||||
12
test/circuits/declareandistantiate.circom
Normal file
12
test/circuits/declareandistantiate.circom
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template A() {
|
||||||
|
signal a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template B() {
|
||||||
|
component a[2] = A();
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = B();
|
||||||
19
test/circuits/forvariables.circom
Normal file
19
test/circuits/forvariables.circom
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
template A() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var acc = 0;
|
||||||
|
for (var i=0; i<3; i++) {
|
||||||
|
if (i==1) {
|
||||||
|
var accIn = 0;
|
||||||
|
for (var j=0; j<3; j++) {
|
||||||
|
accIn= accIn+1;
|
||||||
|
}
|
||||||
|
acc = acc + accIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out <== in + acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = A();
|
||||||
4
test/circuits/isequal.circom
Normal file
4
test/circuits/isequal.circom
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
include "../../circuits/comparators.circom";
|
||||||
|
|
||||||
|
component main = IsEqual();
|
||||||
5
test/circuits/iszero.circom
Normal file
5
test/circuits/iszero.circom
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
include "../../circuits/comparators.circom";
|
||||||
|
|
||||||
|
component main = IsZero();
|
||||||
4
test/circuits/lessthan.circom
Normal file
4
test/circuits/lessthan.circom
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
include "../../circuits/comparators.circom";
|
||||||
|
|
||||||
|
component main = LessThan(32);
|
||||||
14
test/circuits/mixvarsignal.circom
Normal file
14
test/circuits/mixvarsignal.circom
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
template X() {
|
||||||
|
signal input i;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var r = 0;
|
||||||
|
for (var n=0; n<i; n++) {
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i === r;
|
||||||
|
out <== r;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = X();
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
include "../../circuits/sha256/bitify.circom"
|
include "../../circuits/bitify.circom"
|
||||||
include "../../circuits/sha256/binsum.circom"
|
include "../../circuits/binsum.circom"
|
||||||
|
|
||||||
template A() {
|
template A() {
|
||||||
signal private input a;
|
signal private input a;
|
||||||
|
|||||||
14
test/circuits/undefinedif.circom
Normal file
14
test/circuits/undefinedif.circom
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
template X() {
|
||||||
|
signal input i;
|
||||||
|
signal input j;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
out <-- i;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out <-- j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = X();
|
||||||
77
test/comparators.js
Normal file
77
test/comparators.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const path = require("path");
|
||||||
|
const snarkjs = require("snarkjs");
|
||||||
|
const crypto = require("crypto");
|
||||||
|
|
||||||
|
const compiler = require("../index.js");
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
describe("Sum test", () => {
|
||||||
|
it("Should create a iszero circuit", async() => {
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "iszero.circom"));
|
||||||
|
|
||||||
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
let witness;
|
||||||
|
witness = circuit.calculateWitness({ "in": 111});
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(0)));
|
||||||
|
|
||||||
|
witness = circuit.calculateWitness({ "in": 0 });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(1)));
|
||||||
|
});
|
||||||
|
it("Should create a isequal circuit", async() => {
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "isequal.circom"));
|
||||||
|
|
||||||
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
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 = circuit.calculateWitness({ "in[0]": "444", "in[1]": "444" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(1)));
|
||||||
|
});
|
||||||
|
it("Should create a comparison", async() => {
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "lessthan.circom"));
|
||||||
|
|
||||||
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
let witness;
|
||||||
|
witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(1)));
|
||||||
|
|
||||||
|
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(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 = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(1)));
|
||||||
|
|
||||||
|
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(1)));
|
||||||
|
|
||||||
|
witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(0)));
|
||||||
|
|
||||||
|
witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(0)));
|
||||||
|
|
||||||
|
witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" });
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt(0)));
|
||||||
|
});
|
||||||
|
});
|
||||||
22
test/helpers/printsignal.js
Normal file
22
test/helpers/printsignal.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
const snarkjs = require("snarkjs");
|
||||||
|
|
||||||
|
const bigInt = snarkjs.bigInt;
|
||||||
|
|
||||||
|
module.exports = function hexBits(cir, witness, sig, nBits) {
|
||||||
|
let v = bigInt(0);
|
||||||
|
for (let i=nBits-1; i>=0; i--) {
|
||||||
|
v = v.shiftLeft(1);
|
||||||
|
const name = sig+"["+i+"]";
|
||||||
|
const idx = cir.getSignalIdx(name);
|
||||||
|
const vbit = bigInt(witness[idx].toString());
|
||||||
|
if (vbit.equals(bigInt(1))) {
|
||||||
|
v = v.add(bigInt(1));
|
||||||
|
} else if (vbit.equals(bigInt(0))) {
|
||||||
|
v;
|
||||||
|
} else {
|
||||||
|
console.log("Not Binary: "+name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v.toString(16);
|
||||||
|
};
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"a": "111",
|
|
||||||
"b": "222"
|
|
||||||
}
|
|
||||||
@@ -8,51 +8,11 @@ const compiler = require("../index.js");
|
|||||||
const assert = chai.assert;
|
const assert = chai.assert;
|
||||||
|
|
||||||
const sha256 = require("./helpers/sha256");
|
const sha256 = require("./helpers/sha256");
|
||||||
const bigInt = require("big-integer");
|
|
||||||
|
|
||||||
function hexBits(cir, witness, sig, nBits) {
|
// const printSignal = require("./helpers/printsignal");
|
||||||
let v = bigInt(0);
|
|
||||||
for (let i=nBits-1; i>=0; i--) {
|
|
||||||
v = v.shiftLeft(1);
|
|
||||||
const name = sig+"["+i+"]";
|
|
||||||
const idx = cir.getSignalIdx(name);
|
|
||||||
const vbit = bigInt(witness[idx].toString());
|
|
||||||
if (vbit.equals(bigInt(1))) {
|
|
||||||
v = v.add(bigInt(1));
|
|
||||||
} else if (vbit.equals(bigInt(0))) {
|
|
||||||
v;
|
|
||||||
} else {
|
|
||||||
console.log("Not Binary: "+name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.toString(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("SHA256 test", () => {
|
describe("SHA256 test", () => {
|
||||||
it("Should create a constant circuit", async () => {
|
|
||||||
|
|
||||||
const cirDef = await compiler(path.join(__dirname, "circuits", "constants_test.circom"));
|
|
||||||
assert.equal(cirDef.nVars, 2);
|
|
||||||
|
|
||||||
const circuit = new snarkjs.Circuit(cirDef);
|
|
||||||
|
|
||||||
const witness = circuit.calculateWitness({ "in": "0xd807aa98" });
|
|
||||||
|
|
||||||
assert(witness[0].equals(snarkjs.bigInt(1)));
|
|
||||||
assert(witness[1].equals(snarkjs.bigInt("0xd807aa98")));
|
|
||||||
});
|
|
||||||
it("Should create a sum circuit", async () => {
|
|
||||||
|
|
||||||
const cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom"));
|
|
||||||
assert.equal(cirDef.nVars, 101);
|
|
||||||
|
|
||||||
const circuit = new snarkjs.Circuit(cirDef);
|
|
||||||
|
|
||||||
const witness = circuit.calculateWitness({ "a": "111", "b": "222" });
|
|
||||||
|
|
||||||
assert(witness[0].equals(snarkjs.bigInt(1)));
|
|
||||||
assert(witness[1].equals(snarkjs.bigInt("333")));
|
|
||||||
});
|
|
||||||
it("Should calculate a hash", async () => {
|
it("Should calculate a hash", async () => {
|
||||||
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_2_test.circom"));
|
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_2_test.circom"));
|
||||||
const circuit = new snarkjs.Circuit(cirDef);
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|||||||
35
test/sum.js
Normal file
35
test/sum.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const path = require("path");
|
||||||
|
const snarkjs = require("snarkjs");
|
||||||
|
const crypto = require("crypto");
|
||||||
|
|
||||||
|
const compiler = require("../index.js");
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
describe("Sum test", () => {
|
||||||
|
it("Should create a constant circuit", async () => {
|
||||||
|
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "constants_test.circom"));
|
||||||
|
assert.equal(cirDef.nVars, 2);
|
||||||
|
|
||||||
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
const witness = circuit.calculateWitness({ "in": "0xd807aa98" });
|
||||||
|
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt("0xd807aa98")));
|
||||||
|
});
|
||||||
|
it("Should create a sum circuit", async () => {
|
||||||
|
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom"));
|
||||||
|
assert.equal(cirDef.nVars, 101);
|
||||||
|
|
||||||
|
const circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
const witness = circuit.calculateWitness({ "a": "111", "b": "222" });
|
||||||
|
|
||||||
|
assert(witness[0].equals(snarkjs.bigInt(1)));
|
||||||
|
assert(witness[1].equals(snarkjs.bigInt("333")));
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user