Compare commits

..

1 Commits

Author SHA1 Message Date
Jordi Baylina
2fc1bf5e97 Stars specifying wasm 2018-10-17 18:20:30 +02:00
49 changed files with 6325 additions and 962 deletions

View File

@@ -1,16 +1,12 @@
# Circom # Circon
Circom is a language designed to write arithmetic circuits that can be used in zero knowledge proofs. Circon 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).
## Usage ## Usage
### Tutorial
A good starting point [is this tutorial](https://iden3.io/blog/circom-and-snarkjs-tutorial2.html)
### First circuit ### First circuit
Creation of a circuit. This is an example of a NAND door: Creation of a circuit. This is an example of a NAND door:
@@ -29,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 following constraints: The language uses mainly JavaScript/C syntax together with 5 extra operators to define the 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.
@@ -43,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 by typing: First of all, the compiler must be installed typing:
``` ```
npm install -g circom npm install -g circom
@@ -52,7 +48,7 @@ npm install -g circom
The circuit is compiled with the following command: The circuit is compiled with the following command:
``` ```
circom mycircuit.circom -o mycircuit.json circom -s 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).
@@ -95,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 at compilation time, but it holds a linear combination and it is used in the last constraint: This variable does not hold a value in compilation time, but it holds a linear combination and it is used in the last constraint:
``` ```
lc1 === in; lc1 === in;
@@ -258,14 +254,9 @@ component main = Adder();
In this example we have shown how to design a top-down circuit with many subcircuits and how to connect them together. One can also see that auxiliary functions to do specific computations can be created. In this example we have shown how to design a top-down circuit with many subcircuits and how to connect them together. One can also see that auxiliary functions to do specific computations can be created.
### More examples.
You can find more examples in this library of basic circits [circomlib](https://github.com/iden3/circomlib)
## License ## License
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. 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.

View File

@@ -1,44 +0,0 @@
{
"mainCode": "{\n}\n",
"signalName2Idx": {
"one": 0,
"main.out": 1
},
"components": [
{
"name": "main",
"params": {},
"template": "A",
"inputSignals": 0
}
],
"componentName2Idx": {
"main": 0
},
"signals": [
{
"names": [
"one"
],
"triggerComponents": []
},
{
"names": [
"main.out"
],
"triggerComponents": []
}
],
"constraints": [],
"templates": {
"A": "function(ctx) {\n ctx.setSignal(\"out\", [], \"3\");\n ctx.assert(ctx.getSignal(\"out\", []), \"3\");\n}\n"
},
"functions": {},
"nPrvInputs": 0,
"nPubInputs": 0,
"nInputs": 0,
"nOutputs": 0,
"nVars": 1,
"nConstants": 1,
"nSignals": 2
}

49
circuits/gates.circom Normal file
View File

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

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
template Num2Bits(n) {
signal input in;
signal output out[n];
var lc1=0;
for (var i = 0; i<n; i++) {
out[i] <-- (in >> i) & 1;
out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * 2**i;
}
lc1 === in;
}
template Bits2Num(n) {
signal input in[n];
signal output out;
var lc1=0;
for (var i = 0; i<n; i++) {
lc1 += in[i] * 2**i;
}
lc1 ==> out;
}

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

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

View File

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

View File

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

View File

@@ -0,0 +1,15 @@
include "sha256_2.jaz";
template Main() {
signal private input a;
signal private input b;
signal output out;
component sha256_2 = SHA256_2();
sha256_2.a <== a;
sha256_2.b <== a;
out <== sha256_2.out;
}
component main = Main();

View File

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

View File

@@ -0,0 +1,10 @@
template RotR(n, r) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
out[i] <== in[ (i+r)%n ];
}
}

View File

@@ -0,0 +1,49 @@
include "sha256compression.circom";
include "bitify.circom"
template Sha256_2() {
signal input a;
signal input b;
signal output out;
component bits2num = Bits2Num(216);
component num2bits[2];
num2bits[0] = Num2Bits(216);
num2bits[1] = Num2Bits(216);
num2bits[0].in <== a;
num2bits[1].in <== b;
component sha256compression = Sha256compression() ;
var i;
for (i=0; i<216; i++) {
sha256compression.inp[i] <== num2bits[0].out[215-i];
sha256compression.inp[i+216] <== num2bits[1].out[215-i];
}
sha256compression.inp[432] <== 1;
for (i=433; i<503; i++) {
sha256compression.inp[i] <== 0;
}
sha256compression.inp[503] <== 1;
sha256compression.inp[504] <== 1;
sha256compression.inp[505] <== 0;
sha256compression.inp[506] <== 1;
sha256compression.inp[507] <== 1;
sha256compression.inp[508] <== 0;
sha256compression.inp[509] <== 0;
sha256compression.inp[510] <== 0;
sha256compression.inp[511] <== 0;
for (i=0; i<216; i++) {
bits2num.in[i] <== sha256compression.out[255-i];
}
out <== bits2num.out;
}

View File

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

View File

@@ -0,0 +1,14 @@
template ShR(n, r) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
if (i+r >= n) {
out[i] <== 0;
} else {
out[i] <== in[ i+r ];
}
}
}

View File

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

View File

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

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

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

28
circuits/sha256/t2.circom Normal file
View File

@@ -0,0 +1,28 @@
include "binsum.circom";
include "sigma.circom";
include "maj.circom"
template T2() {
signal input a[32];
signal input b[32];
signal input c[32];
signal output out[32];
component sum = BinSum(32, 2);
component bigsigma0 = BigSigma(2, 13, 22);
component maj = Maj(32);
for (var k=0; k<32; k++) {
bigsigma0.in[k] <== a[k];
maj.a[k] <== a[k];
maj.b[k] <== b[k];
maj.c[k] <== c[k];
sum.in[0][k] <== bigsigma0.out[k];
sum.in[1][k] <== maj.out[k];
out[k] <== sum.out[k];
}
}

View File

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

20
circuits/tobin.circom Normal file
View File

@@ -0,0 +1,20 @@
template toBin(n) {
signal input inp;
signal output out[n];
var lc1=0;
for (var i = 0; i<n; i++) {
out[i] <-- (inp >> i) & 1;
out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * 2**i;
}
lc1 === inp;
}
component toBin(3) main;

47
cli.js
View File

@@ -3,20 +3,20 @@
/* /*
Copyright 2018 0KIMS association. Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler). This file is part of jaz (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it jaz is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT jaz is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details. License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>. along with jaz. If not, see <https://www.gnu.org/licenses/>.
*/ */
/* eslint-disable no-console */ /* eslint-disable no-console */
@@ -30,11 +30,13 @@ const version = require("./package").version;
const argv = require("yargs") const argv = require("yargs")
.version(version) .version(version)
.usage("circom [input source circuit file] -o [output definition circuit file]") .usage("circom -s [input source circuit file] -o [output definition circuit file]")
.alias("s", "source")
.alias("o", "output") .alias("o", "output")
.alias("c", "cfile")
.require(["s","o"])
.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
@@ -42,35 +44,14 @@ 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.source);
let inputFile; compiler(fullFileName, argv.cfile).then( (cir) => {
if (argv._.length == 0) { fs.writeFileSync(argv.output, JSON.stringify(cir, null, 1), "utf8");
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";
compiler(fullFileName).then( (cir) => {
fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8");
process.exit(0);
}, (err) => { }, (err) => {
// console.log(err); console.log(err);
console.log(err.stack); console.error(`ERROR at ${err.errFile}:${err.pos.first_line},${err.pos.first_column}-${err.pos.last_line},${err.pos.last_column} ${err.errStr}`);
if (err.pos) { console.error(JSON.stringify(err.ast, null, 1));
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));
}
process.exit(1); process.exit(1);
}); });

83
out.c Normal file
View File

@@ -0,0 +1,83 @@
// File: ../../circuits/sha256/bitify.circom
function Num2Bits(ctx)
{
ctx.setVar("lc1", [], "0");
for (ctx.setVar("i", [], "0");bigInt(ctx.getVar("i",[])).lt(bigInt(ctx.getVar("n",[]))) ? 1 : 0;(ctx.setVar("i", [], bigInt(ctx.getVar("i",[])).add(bigInt("1")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))
{
ctx.setSignal("out", [ctx.getVar("i",[])], bigInt(bigInt(ctx.getVar("i",[])).greater(bigInt(256)) ? 0 : bigInt(ctx.getSignal("in", [])).shr(bigInt(ctx.getVar("i",[]))).and(__MASK__)).and(bigInt("1")).and(__MASK__));
ctx.assert(bigInt(ctx.getSignal("out", [ctx.getVar("i",[])])).mul(bigInt(bigInt(ctx.getSignal("out", [ctx.getVar("i",[])])).add(__P__).sub(bigInt("1")).mod(__P__))).mod(__P__), "0");
ctx.setVar("lc1", [], bigInt(ctx.getVar("lc1",[])).add(bigInt(bigInt(ctx.getSignal("out", [ctx.getVar("i",[])])).mul(bigInt(bigInt("2").modPow(bigInt(ctx.getVar("i",[])), __P__))).mod(__P__))).mod(__P__));
}
ctx.assert(ctx.getVar("lc1",[]), ctx.getSignal("in", []));
}
function Bits2Num(ctx)
{
ctx.setVar("lc1", [], "0");
for (ctx.setVar("i", [], "0");bigInt(ctx.getVar("i",[])).lt(bigInt(ctx.getVar("n",[]))) ? 1 : 0;(ctx.setVar("i", [], bigInt(ctx.getVar("i",[])).add(bigInt("1")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))
{
ctx.setVar("lc1", [], bigInt(ctx.getVar("lc1",[])).add(bigInt(bigInt(ctx.getSignal("in", [ctx.getVar("i",[])])).mul(bigInt(bigInt("2").modPow(bigInt(ctx.getVar("i",[])), __P__))).mod(__P__))).mod(__P__));
}
ctx.setSignal("out", [], ctx.getVar("lc1",[]));
ctx.assert(ctx.getSignal("out", []), ctx.getVar("lc1",[]));
}
// File: ../../circuits/sha256/binsum.circom
function nbits(ctx) {
ctx.setVar("n", [], "1");
ctx.setVar("r", [], "0");
while (bigInt(bigInt(ctx.getVar("n",[])).add(__P__).sub(bigInt("1")).mod(__P__)).lt(bigInt(ctx.getVar("a",[]))) ? 1 : 0) {
(ctx.setVar("r", [], bigInt(ctx.getVar("r",[])).add(bigInt("1")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__);
ctx.setVar("n", [], bigInt(ctx.getVar("n",[])).mul(bigInt("2")).mod(__P__));
}
return ctx.getVar("r",[]);;
}
function BinSum(ctx)
{
ctx.setVar("nout", [], ctx.callFunction("nbits", [bigInt(bigInt(bigInt("2").modPow(bigInt(ctx.getVar("n",[])), __P__)).add(__P__).sub(bigInt("1")).mod(__P__)).mul(bigInt(ctx.getVar("ops",[]))).mod(__P__)]));
ctx.setVar("lin", [], "0");
ctx.setVar("lout", [], "0");
for (ctx.setVar("k", [], "0");bigInt(ctx.getVar("k",[])).lt(bigInt(ctx.getVar("n",[]))) ? 1 : 0;(ctx.setVar("k", [], bigInt(ctx.getVar("k",[])).add(bigInt("1")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))
{
for (ctx.setVar("j", [], "0");bigInt(ctx.getVar("j",[])).lt(bigInt(ctx.getVar("ops",[]))) ? 1 : 0;(ctx.setVar("j", [], bigInt(ctx.getVar("j",[])).add(bigInt("1")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))
{
ctx.setVar("lin", [], bigInt(ctx.getVar("lin",[])).add(bigInt(bigInt(ctx.getSignal("in", [ctx.getVar("j",[]),ctx.getVar("k",[])])).mul(bigInt(bigInt("2").modPow(bigInt(ctx.getVar("k",[])), __P__))).mod(__P__))).mod(__P__));
}
}
for (ctx.setVar("k", [], "0");bigInt(ctx.getVar("k",[])).lt(bigInt(ctx.getVar("nout",[]))) ? 1 : 0;(ctx.setVar("k", [], bigInt(ctx.getVar("k",[])).add(bigInt("1")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))
{
ctx.setSignal("out", [ctx.getVar("k",[])], bigInt(bigInt(ctx.getVar("k",[])).greater(bigInt(256)) ? 0 : bigInt(ctx.getVar("lin",[])).shr(bigInt(ctx.getVar("k",[]))).and(__MASK__)).and(bigInt("1")).and(__MASK__));
ctx.assert(bigInt(ctx.getSignal("out", [ctx.getVar("k",[])])).mul(bigInt(bigInt(ctx.getSignal("out", [ctx.getVar("k",[])])).add(__P__).sub(bigInt("1")).mod(__P__))).mod(__P__), "0");
ctx.setVar("lout", [], bigInt(ctx.getVar("lout",[])).add(bigInt(bigInt(ctx.getSignal("out", [ctx.getVar("k",[])])).mul(bigInt(bigInt("2").modPow(bigInt(ctx.getVar("k",[])), __P__))).mod(__P__))).mod(__P__));
}
ctx.assert(ctx.getVar("lin",[]), ctx.getVar("lout",[]));
}
function A(ctx)
{
ctx.setPin("n2ba", [], "in", [], ctx.getSignal("a", []));
ctx.assert(ctx.getPin("n2ba", [], "in", []), ctx.getSignal("a", []));
ctx.setPin("n2bb", [], "in", [], ctx.getSignal("b", []));
ctx.assert(ctx.getPin("n2bb", [], "in", []), ctx.getSignal("b", []));
for (ctx.setVar("i", [], "0");bigInt(ctx.getVar("i",[])).lt(bigInt("32")) ? 1 : 0;(ctx.setVar("i", [], bigInt(ctx.getVar("i",[])).add(bigInt("1")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))
{
ctx.setPin("sum", [], "in", ["0",ctx.getVar("i",[])], ctx.getPin("n2ba", [], "out", [ctx.getVar("i",[])]));
ctx.assert(ctx.getPin("sum", [], "in", ["0",ctx.getVar("i",[])]), ctx.getPin("n2ba", [], "out", [ctx.getVar("i",[])]));
ctx.setPin("sum", [], "in", ["1",ctx.getVar("i",[])], ctx.getPin("n2bb", [], "out", [ctx.getVar("i",[])]));
ctx.assert(ctx.getPin("sum", [], "in", ["1",ctx.getVar("i",[])]), ctx.getPin("n2bb", [], "out", [ctx.getVar("i",[])]));
ctx.setPin("b2n", [], "in", [ctx.getVar("i",[])], ctx.getPin("sum", [], "out", [ctx.getVar("i",[])]));
ctx.assert(ctx.getPin("b2n", [], "in", [ctx.getVar("i",[])]), ctx.getPin("sum", [], "out", [ctx.getVar("i",[])]));
}
ctx.setSignal("out", [], ctx.getPin("b2n", [], "out", []));
ctx.assert(ctx.getSignal("out", []), ctx.getPin("b2n", [], "out", []));
}

2341
out.cir Normal file

File diff suppressed because one or more lines are too long

432
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.0.24", "version": "0.0.7",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -137,12 +137,6 @@
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true "dev": true
}, },
"astral-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
"babel-code-frame": { "babel-code-frame": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -1474,252 +1468,6 @@
"is-fullwidth-code-point": "^2.0.0" "is-fullwidth-code-point": "^2.0.0"
} }
}, },
"snarkjs": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.7.tgz",
"integrity": "sha512-S7un4ESi5vjE4pVt50kPEraiP9Bt5ZfNfMiqnUE+zvRyBPa/dX4vU3osAyOxp/RbBUi+MofNRdrES2TO/DET1g==",
"dev": true,
"requires": {
"big-integer": "^1.6.35",
"chai": "^4.1.2",
"eslint": "^5.3.0",
"yargs": "^12.0.2"
},
"dependencies": {
"acorn": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz",
"integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==",
"dev": true
},
"acorn-jsx": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz",
"integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==",
"dev": true
},
"ajv": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz",
"integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ansi-regex": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz",
"integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==",
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"big-integer": {
"version": "1.6.40",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.40.tgz",
"integrity": "sha512-CjhtJp0BViLzP1ZkEnoywjgtFQXS2pomKjAJtIISTCnuHILkLcAXLdFLG/nxsHc4s9kJfc+82Xpg8WNyhfACzQ==",
"dev": true
},
"chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
"debug": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
"integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"eslint": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.10.0.tgz",
"integrity": "sha512-HpqzC+BHULKlnPwWae9MaVZ5AXJKpkxCVXQHrFaRw3hbDj26V/9ArYM4Rr/SQ8pi6qUPLXSSXC4RBJlyq2Z2OQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"ajv": "^6.5.3",
"chalk": "^2.1.0",
"cross-spawn": "^6.0.5",
"debug": "^4.0.1",
"doctrine": "^2.1.0",
"eslint-scope": "^4.0.0",
"eslint-utils": "^1.3.1",
"eslint-visitor-keys": "^1.0.0",
"espree": "^5.0.0",
"esquery": "^1.0.1",
"esutils": "^2.0.2",
"file-entry-cache": "^2.0.0",
"functional-red-black-tree": "^1.0.1",
"glob": "^7.1.2",
"globals": "^11.7.0",
"ignore": "^4.0.6",
"imurmurhash": "^0.1.4",
"inquirer": "^6.1.0",
"js-yaml": "^3.12.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.3.0",
"lodash": "^4.17.5",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"path-is-inside": "^1.0.2",
"pluralize": "^7.0.0",
"progress": "^2.0.0",
"regexpp": "^2.0.1",
"require-uncached": "^1.0.3",
"semver": "^5.5.1",
"strip-ansi": "^4.0.0",
"strip-json-comments": "^2.0.1",
"table": "^5.0.2",
"text-table": "^0.2.0"
}
},
"espree": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-5.0.0.tgz",
"integrity": "sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA==",
"dev": true,
"requires": {
"acorn": "^6.0.2",
"acorn-jsx": "^5.0.0",
"eslint-visitor-keys": "^1.0.0"
}
},
"external-editor": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
"integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
"dev": true,
"requires": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"dev": true
},
"inquirer": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
"integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
"dev": true,
"requires": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^3.0.0",
"figures": "^2.0.0",
"lodash": "^4.17.10",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rxjs": "^6.1.0",
"string-width": "^2.1.0",
"strip-ansi": "^5.0.0",
"through": "^2.3.6"
},
"dependencies": {
"strip-ansi": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz",
"integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==",
"dev": true,
"requires": {
"ansi-regex": "^4.0.0"
}
}
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
},
"regexpp": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
"integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
"dev": true
},
"rxjs": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
"integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
"dev": true
},
"slice-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz",
"integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
"astral-regex": "^1.0.0",
"is-fullwidth-code-point": "^2.0.0"
}
},
"table": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/table/-/table-5.1.1.tgz",
"integrity": "sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==",
"dev": true,
"requires": {
"ajv": "^6.6.1",
"lodash": "^4.17.11",
"slice-ansi": "2.0.0",
"string-width": "^2.1.1"
},
"dependencies": {
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
}
}
}
}
},
"source-map": { "source-map": {
"version": "0.1.43", "version": "0.1.43",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
@@ -1973,6 +1721,184 @@
"requires": { "requires": {
"camelcase": "^4.1.0" "camelcase": "^4.1.0"
} }
},
"zksnark": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/zksnark/-/zksnark-0.0.11.tgz",
"integrity": "sha512-YIOk93pLvc8NDVvedB0SDM1kGjPTdTYC/sgAvc9Dm6qMSYnS7tzCr844QaUlMApFTldz7D/6xlF1l24ttTGLXw==",
"dev": true,
"requires": {
"big-integer": "^1.6.35",
"chai": "^4.1.2",
"eslint": "^5.3.0"
},
"dependencies": {
"ajv": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz",
"integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"big-integer": {
"version": "1.6.36",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz",
"integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==",
"dev": true
},
"chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
"debug": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
"integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"eslint": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz",
"integrity": "sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"ajv": "^6.5.3",
"chalk": "^2.1.0",
"cross-spawn": "^6.0.5",
"debug": "^4.0.1",
"doctrine": "^2.1.0",
"eslint-scope": "^4.0.0",
"eslint-utils": "^1.3.1",
"eslint-visitor-keys": "^1.0.0",
"espree": "^4.0.0",
"esquery": "^1.0.1",
"esutils": "^2.0.2",
"file-entry-cache": "^2.0.0",
"functional-red-black-tree": "^1.0.1",
"glob": "^7.1.2",
"globals": "^11.7.0",
"ignore": "^4.0.6",
"imurmurhash": "^0.1.4",
"inquirer": "^6.1.0",
"is-resolvable": "^1.1.0",
"js-yaml": "^3.12.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.3.0",
"lodash": "^4.17.5",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"path-is-inside": "^1.0.2",
"pluralize": "^7.0.0",
"progress": "^2.0.0",
"regexpp": "^2.0.1",
"require-uncached": "^1.0.3",
"semver": "^5.5.1",
"strip-ansi": "^4.0.0",
"strip-json-comments": "^2.0.1",
"table": "^5.0.2",
"text-table": "^0.2.0"
}
},
"external-editor": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
"integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
"dev": true,
"requires": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"dev": true
},
"inquirer": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz",
"integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==",
"dev": true,
"requires": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^3.0.0",
"figures": "^2.0.0",
"lodash": "^4.17.10",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rxjs": "^6.1.0",
"string-width": "^2.1.0",
"strip-ansi": "^4.0.0",
"through": "^2.3.6"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
},
"regexpp": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
"integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
"dev": true
},
"rxjs": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
"integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
"dev": true
},
"table": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz",
"integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==",
"dev": true,
"requires": {
"ajv": "^6.5.3",
"lodash": "^4.17.10",
"slice-ansi": "1.0.0",
"string-width": "^2.1.1"
}
}
}
} }
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.0.24", "version": "0.0.7",
"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.9" "zksnark": "0.0.11"
} }
} }

View File

@@ -1,22 +1,3 @@
/*
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/>.
*/
/* description: Construct AST for jaz language. */ /* description: Construct AST for jaz language. */
/* lexical grammar */ /* lexical grammar */
@@ -78,7 +59,6 @@ include { return 'include'; }
\- { return '-'; } \- { return '-'; }
\* { return '*'; } \* { return '*'; }
\/ { return '/'; } \/ { return '/'; }
\\ { return '\\'; }
\% { return '%'; } \% { return '%'; }
\^ { return '^'; } \^ { return '^'; }
\& { return '&'; } \& { return '&'; }
@@ -119,7 +99,7 @@ include { return 'include'; }
%left '<<' '>>' %left '<<' '>>'
%left '+' '-' %left '+' '-'
%left '*' '/' '\\' '%' %left '*' '/' '%'
%left '**' %left '**'
%right '++' '--' UMINUS UPLUS '!' '~' %right '++' '--' UMINUS UPLUS '!' '~'
%left '.' %left '.'
@@ -628,7 +608,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;
$$ = {type: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) }; $$ = {t1ype: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) };
} else { } else {
$$ = { type: "OP", op: ">>", values: [$1, $3] }; $$ = { type: "OP", op: ">>", values: [$1, $3] };
} }
@@ -685,15 +665,6 @@ 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")) {

File diff suppressed because one or more lines are too long

View File

@@ -1,20 +1,20 @@
/* /*
Copyright 2018 0KIMS association. Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler). This file is part of jaz (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it jaz is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT jaz is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details. License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>. along with jaz. If not, see <https://www.gnu.org/licenses/>.
*/ */
const fs = require("fs"); const fs = require("fs");
@@ -23,17 +23,20 @@ const bigInt = require("big-integer");
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const __MASK__ = new bigInt(2).pow(253).minus(1); const __MASK__ = new bigInt(2).pow(253).minus(1);
const assert = require("assert"); const assert = require("assert");
const gen = require("./gencode"); const genCode = require("./gencode");
const exec = require("./exec"); const exec = require("./exec");
const lc = require("./lcalgebra"); const lc = require("./lcalgebra");
const util = require("util");
const fs_writeFile = util.promisify(fs.writeFile)
module.exports = compile; module.exports = compile;
const parser = require("../parser/jaz.js").parser; const parser = require("../parser/jaz.js").parser;
const timeout = ms => new Promise(res => setTimeout(res, ms)); const timeout = ms => new Promise(res => setTimeout(res, ms))
async function compile(srcFile) { async function compile(srcFile, cFile) {
const fullFileName = srcFile; const fullFileName = srcFile;
const fullFilePath = path.dirname(fullFileName); const fullFilePath = path.dirname(fullFileName);
@@ -62,13 +65,8 @@ 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);
@@ -87,9 +85,13 @@ async function compile(srcFile) {
ctx.scopes = [{}]; ctx.scopes = [{}];
const mainCode = gen(ctx,ast); const mainCode = genCode(ctx,ast);
if (ctx.error) throw(ctx.error); if (ctx.error) throw(ctx.error);
if (cFile) {
await fs_writeFile(cFile, mainCode);
}
const def = buildCircuitDef(ctx, mainCode); const def = buildCircuitDef(ctx, mainCode);
return def; return def;
@@ -259,11 +261,11 @@ function reduceConstrains(ctx) {
} }
} }
for (let j=0; j<newConstraints.length; j++) { for (let j=0; j<ctx.constraints.length; j++ ) {
newConstraints[j] = lc.substitute(newConstraints[j], isolatedSignal, isolatedSignalEquivalence); const c2 = ctx.constraints[j];
} if (i!=j) {
for (let j=i+1; j<ctx.constraints.length; j++ ) { lc.substitute(c2, isolatedSignal, isolatedSignalEquivalence);
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence); }
} }
c.a={ type: "LINEARCOMBINATION", values: {} }; c.a={ type: "LINEARCOMBINATION", values: {} };
c.b={ type: "LINEARCOMBINATION", values: {} }; c.b={ type: "LINEARCOMBINATION", values: {} };
@@ -404,4 +406,9 @@ function buildConstraints(ctx) {
} }
function generateCCode(ctx) {
}

View File

@@ -1,20 +1,20 @@
/* /*
Copyright 2018 0KIMS association. Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler). This file is part of jaz (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it jaz is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT jaz is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details. License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>. along with jaz. If not, see <https://www.gnu.org/licenses/>.
*/ */
const path = require("path"); const path = require("path");
@@ -78,22 +78,10 @@ function exec(ctx, ast) {
return execPlusPlusRight(ctx, ast); return execPlusPlusRight(ctx, ast);
} else if (ast.op == "PLUSPLUSLEFT") { } else if (ast.op == "PLUSPLUSLEFT") {
return execPlusPlusLeft(ctx, ast); return execPlusPlusLeft(ctx, ast);
} else if (ast.op == "MINUSMINUSRIGHT") {
return execMinusMinusRight(ctx, ast);
} else if (ast.op == "MINUSMINUSLEFT") {
return execMinusMinusLeft(ctx, ast);
} else if (ast.op == "/") {
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 == ">>") {
@@ -108,8 +96,6 @@ 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 {
@@ -162,8 +148,7 @@ function error(ctx, ast, errStr) {
}, },
errStr: errStr, errStr: errStr,
errFile: ctx.fileName, errFile: ctx.fileName,
ast: ast, ast: ast
message: errStr
}; };
} }
@@ -191,7 +176,7 @@ function setScope(ctx, name, selectors, value) {
function setScopeArray(a, sels) { function setScopeArray(a, sels) {
if (sels.length == 1) { if (sels.length == 1) {
a[sels[0].value] = value; a[sels[0]] = value;
} else { } else {
setScopeArray(a[sels[0]], sels.slice(1)); setScopeArray(a[sels[0]], sels.slice(1));
} }
@@ -329,7 +314,8 @@ 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;
paramValues.push(v); if (v.type != "NUMBER") return error(ctx, fn.params[i], "expected a number");
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");
@@ -340,15 +326,6 @@ 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]);
@@ -372,12 +349,13 @@ function execInstantiateComponet(ctx, vr, fn) {
ctx.scopes = oldScopes.slice(0, scopeLevel+1); ctx.scopes = oldScopes.slice(0, scopeLevel+1);
if (template.params.length != paramValues.length) return error(ctx, fn, "Invalid number of parameters: " + templateName);
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]] = paramValues[i]; scope[template.params[i]] = {
ctx.components[ctx.currentComponent].params[template.params[i]] = extractValue(paramValues[i]); type: "NUMBER",
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;
@@ -408,7 +386,8 @@ function execFunctionCall(ctx, ast) {
const v = exec(ctx, ast.params[i]); const v = exec(ctx, ast.params[i]);
if (ctx.error) return; if (ctx.error) return;
paramValues.push(v); if (v.type != "NUMBER") return error(ctx, ast.params[i], "expected a number");
paramValues.push( v.value);
} }
if (ast.params.length != paramValues.length) error(ctx, ast, "Invalid Number of parameters"); if (ast.params.length != paramValues.length) error(ctx, ast, "Invalid Number of parameters");
@@ -422,7 +401,10 @@ function execFunctionCall(ctx, ast) {
const scope = {}; const scope = {};
for (let i=0; i< fnc.params.length; i++) { for (let i=0; i< fnc.params.length; i++) {
scope[fnc.params[i]] = paramValues[i]; scope[fnc.params[i]] = {
type: "NUMBER",
value: paramValues[i]
};
} }
ctx.fileName = fnc.fileName; ctx.fileName = fnc.fileName;
@@ -525,14 +507,6 @@ function execVariable(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (!v) return error(ctx, ast, "Variable not defined"); if (!v) return error(ctx, ast, "Variable not defined");
// If the signal has an assigned value (constant) just return the constant
if ((v.type == "SIGNAL") && (ctx.signals[v.fullName].value)) {
return {
type: "NUMBER",
value: ctx.signals[v.fullName].value
};
}
let res; let res;
res=v; res=v;
return res; return res;
@@ -559,41 +533,34 @@ 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;
exec(ctx, ast.step); exec(ctx, ast.step);
if (ctx.error) return; if (ctx.error) return;
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;
v = exec(ctx, ast.condition); v = exec(ctx, ast.condition);
if (ctx.error) return; if (ctx.error) return;
}
} }
} }
@@ -601,16 +568,12 @@ 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; } else {
} else { exec(ctx, ast.else);
if (ast.else) { if (ctx.error) return;
exec(ctx, ast.else);
if (ctx.error) return;
}
}
} }
} }
@@ -629,8 +592,6 @@ function execVarAssignement(ctx, ast) {
if ((typeof(num) != "object")||(num == null)) return error(ctx, ast, "Variable not defined"); if ((typeof(num) != "object")||(num == null)) return error(ctx, ast, "Variable not defined");
if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]); if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);
if (ctx.error) return;
// if (num.type == "SIGNAL") return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops");
const res = exec(ctx, ast.values[1]); const res = exec(ctx, ast.values[1]);
if (ctx.error) return; if (ctx.error) return;
@@ -711,20 +672,6 @@ 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]);
@@ -740,34 +687,6 @@ 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;
@@ -827,36 +746,6 @@ function execExp(ctx, ast) {
}; };
} }
function execDiv(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.times(b.value.modInv(__P__)).mod(__P__)
};
}
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;
@@ -933,23 +822,6 @@ function execPlusPlusLeft(ctx, ast) {
return resAfter; return resAfter;
} }
function execMinusMinusRight(ctx, ast) {
const resBefore = exec(ctx, ast.values[0]);
if (ctx.error) return;
const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
if (ctx.error) return;
execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
return resBefore;
}
function execMinusMinusLeft(ctx, ast) {
if (ctx.error) return;
const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
if (ctx.error) return;
execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
return resAfter;
}
function execTerCon(ctx, ast) { function execTerCon(ctx, ast) {
const cond = exec(ctx, ast.values[0]); const cond = exec(ctx, ast.values[0]);
if (ctx.error) return; if (ctx.error) return;

View File

@@ -1,70 +0,0 @@
module.exports = genOpt;
function genOpt(ctx, ast) {
if (ast.type == "OP") {
if (ast.op == "=") {
return genOptVarAssignement(ctx, ast);
} else {
error(ctx, ast, "GENOPT -> Invalid operation: " + ast.op);
}
} else if (ast.type == "TEMPLATEDEF") {
return genOptTemplateDef(ctx, ast);
} else {
error(ctx, ast, "GENOPT -> Invalid AST node type: " + ast.type);
}
}
function error(ctx, ast, errStr) {
ctx.error = {
pos: {
first_line: ast.first_line,
first_column: ast.first_column,
last_line: ast.last_line,
last_column: ast.last_column
},
errStr: errStr,
errFile: ctx.fileName,
ast: ast
};
}
function genOptTemplateDef(ctx, ast) {
if (ctx.templates[ast.name]) {
return error(ctx, ast, "Template name already exists: "+ast.name);
}
ctx.templates[ast.name] = {
type: "TEMPLATE",
params: ast.params,
block: ast.block,
fileName: ctx.fileName,
filePath: ctx.filePath
};
}
function genOptVarAssignement(ctx, ast) {
let varName;
if (ast.values[0].type == "DECLARE") {
varName = genOptCode(ctx, ast.values[0]);
if (ctx.error) return;
} else {
varName = ast.values[0];
}
const varContent = getScope(ctx, varName.name, varName.selectors);
if (ctx.error) return;
if ((typeof(varContent) != "object")||(varContent == null)) return error(ctx, ast, "Variable not defined");
if (varContent.type == "COMPONENT") return genOptInstantiateComponet(ctx, varName, ast.values[1]);
if (varContent.type == "SIGNAL") return error(ctx, ast, "Cannot assig to a signal with `=` use <-- or <== ops");
const res = genOpt(ctx, ast.values[1]);
if (ctx.error) return;
setScope(ctx, varName.name, varName.selectors, res);
return v;
}

View File

@@ -1,25 +1,25 @@
/* /*
Copyright 2018 0KIMS association. Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler). This file is part of jaz (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it jaz is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT jaz is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details. License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>. along with jaz. If not, see <https://www.gnu.org/licenses/>.
*/ */
const bigInt = require("big-integer"); const bigInt = require("big-integer");
module.exports = gen; module.exports = genCode;
function ident(text) { function ident(text) {
let lines = text.split("\n"); let lines = text.split("\n");
@@ -63,22 +63,10 @@ function gen(ctx, ast) {
return genPlusPlusRight(ctx, ast); return genPlusPlusRight(ctx, ast);
} else if (ast.op == "PLUSPLUSLEFT") { } else if (ast.op == "PLUSPLUSLEFT") {
return genPlusPlusLeft(ctx, ast); return genPlusPlusLeft(ctx, ast);
} else if (ast.op == "MINUSMINUSRIGHT") {
return genMinusMinusRight(ctx, ast);
} else if (ast.op == "MINUSMINUSLEFT") {
return genMinusMinusLeft(ctx, ast);
} else if (ast.op == "**") { } else if (ast.op == "**") {
return genExp(ctx, ast); return genExp(ctx, ast);
} else if (ast.op == "/") {
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 == ">>") {
@@ -93,8 +81,6 @@ 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 {
@@ -147,8 +133,7 @@ function error(ctx, ast, errStr) {
last_column: ast.last_column last_column: ast.last_column
}, },
errStr: errStr, errStr: errStr,
ast: ast, ast: ast
message: errStr
}; };
} }
@@ -185,8 +170,9 @@ function genBlock(ctx, ast) {
return "{\n"+ident(body)+"}\n"; return "{\n"+ident(body)+"}\n";
} }
function genTemplateDef(ctx, ast) { function genTemplateDef(ctx, ast) {
let S = "function(ctx) "; let S = `function ${ast.name}(ctx)\n`;
const newScope = {}; const newScope = {};
for (let i=0; i< ast.params.length; i++) { for (let i=0; i< ast.params.length; i++) {
@@ -195,6 +181,7 @@ function genTemplateDef(ctx, ast) {
ctx.scopes.push(newScope); ctx.scopes.push(newScope);
S += genBlock(ctx, ast.block); S += genBlock(ctx, ast.block);
S += "\n";
ctx.scopes.pop(); ctx.scopes.pop();
// const scope = ctx.scopes[ctx.scopes.length-1]; // const scope = ctx.scopes[ctx.scopes.length-1];
@@ -205,11 +192,11 @@ function genTemplateDef(ctx, ast) {
}; };
ctx.templates[ast.name] = S; ctx.templates[ast.name] = S;
return ""; return S;
} }
function genFunctionDef(ctx, ast) { function genFunctionDef(ctx, ast) {
let S = "function(ctx) "; let S = `function ${ast.name}(ctx) `;
const newScope = {}; const newScope = {};
const params = []; const params = [];
@@ -231,11 +218,10 @@ function genFunctionDef(ctx, ast) {
ctx.functions[ast.name] = S; ctx.functions[ast.name] = S;
ctx.functionParams[ast.name] = params; ctx.functionParams[ast.name] = params;
return ""; return S;
} }
function genFor(ctx, ast) { function genFor(ctx, ast) {
ctx.scopes.push({});
const init = gen(ctx, ast.init); const init = gen(ctx, ast.init);
if (ctx.error) return; if (ctx.error) return;
const condition = gen(ctx, ast.condition); const condition = gen(ctx, ast.condition);
@@ -244,8 +230,7 @@ function genFor(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
const body = gen(ctx, ast.body); const body = gen(ctx, ast.body);
if (ctx.error) return; if (ctx.error) return;
ctx.scopes.pop(); return `for (${init};${condition};${step})\n${body}\n`;
return `for (${init};${condition};${step}) { \n${body}\n }\n`;
} }
function genWhile(ctx, ast) { function genWhile(ctx, ast) {
@@ -253,7 +238,7 @@ function genWhile(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
const body = gen(ctx, ast.body); const body = gen(ctx, ast.body);
if (ctx.error) return; if (ctx.error) return;
return `while (${condition}) {\n${body}\n}\n`; return `while (${condition}) ${body}\n`;
} }
function genIf(ctx, ast) { function genIf(ctx, ast) {
@@ -261,13 +246,9 @@ function genIf(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
const thenBody = gen(ctx, ast.then); const thenBody = gen(ctx, ast.then);
if (ctx.error) return; if (ctx.error) return;
if (ast.else) { const elseBody = gen(ctx, ast.else);
const elseBody = gen(ctx, ast.else); if (ctx.error) return;
if (ctx.error) return; return `if (${condition}) ${thenBody} else ${elseBody}\n`;
return `if (${condition}) {\n${thenBody}\n} else {\n${elseBody}\n}\n`;
} else {
return `if (${condition}) {\n${thenBody}\n}\n`;
}
} }
@@ -329,9 +310,7 @@ 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") {
@@ -437,14 +416,6 @@ function genPlusPlusLeft(ctx, ast) {
return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]});
} }
function genMinusMinusRight(ctx, ast) {
return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`;
}
function genMinusMinusLeft(ctx, ast) {
return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]});
}
function genAdd(ctx, ast) { function genAdd(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,24 +440,6 @@ function genSub(ctx, ast) {
return `bigInt(${a}).add(__P__).sub(bigInt(${b})).mod(__P__)`; return `bigInt(${a}).add(__P__).sub(bigInt(${b})).mod(__P__)`;
} }
function genDiv(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}).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;
@@ -503,22 +456,6 @@ 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;
@@ -580,15 +517,7 @@ 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) {
@@ -608,7 +537,21 @@ function genTerCon(ctx, ast) {
} }
function genInclude(ctx, ast) { function genInclude(ctx, ast) {
return ast.block ? gen(ctx, ast.block) : ""; let body = genCode(ctx, ast.block);
return `// File: ${ast.file}\n` +body+"\n";
}
function genCode(ctx, ast) {
let body = "";
for (let i=0; i<ast.statements.length; i++) {
const l = gen(ctx, ast.statements[i]);
if (ctx.error) return;
if (l) {
body += l;
if (body[body.length-1] != "\n") body += ";\n";
}
}
return body;
} }
function genArray(ctx, ast) { function genArray(ctx, ast) {

View File

@@ -1,20 +1,20 @@
/* /*
Copyright 2018 0KIMS association. Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler). This file is part of jaz (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it jaz is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT jaz is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details. License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>. along with jaz. If not, see <https://www.gnu.org/licenses/>.
*/ */
/* /*
@@ -434,73 +434,59 @@ function toString(a, ctx) {
function canonize(ctx, a) { function canonize(ctx, a) {
if (a.type == "LINEARCOMBINATION") { if (a.type == "LINEARCOMBINATION") {
const res = clone(a);
for (let k in a.values) { for (let k in a.values) {
let s = k; let s = k;
while (ctx.signals[s].equivalence) s= ctx.signals[s].equivalence; while (ctx.signals[s].equivalence) s= ctx.signals[s].equivalence;
if ((typeof(ctx.signals[s].value) != "undefined")&&(k != "one")) { if ((typeof(ctx.signals[s].value) != "undefined")&&(k != "one")) {
const v = res.values[k].times(ctx.signals[s].value).mod(__P__); const v = a.values[k].times(ctx.signals[s].value).mod(__P__);
if (!res.values["one"]) { if (!a.values["one"]) {
res.values["one"]=v; a.values["one"]=v;
} else { } else {
res.values["one"]= res.values["one"].add(v).mod(__P__); a.values["one"]= a.values["one"].add(v).mod(__P__);
} }
delete res.values[k]; delete a.values[k];
} else if (s != k) { } else if (s != k) {
if (!res.values[s]) { if (!a.values[s]) {
res.values[s]=bigInt(res.values[k]); a.values[s]=bigInt(a.values[k]);
} else { } else {
res.values[s]= res.values[s].add(res.values[k]).mod(__P__); a.values[s]= a.values[s].add(a.values[k]).mod(__P__);
} }
delete res.values[k]; delete a.values[k];
} }
} }
for (let k in res.values) { for (let k in a.values) {
if (res.values[k].isZero()) delete res.values[k]; if (a.values[k].isZero()) delete a.values[k];
} }
return res;
} else if (a.type == "QEQ") {
const res = {
type: "QEQ",
a: canonize(ctx, a.a),
b: canonize(ctx, a.b),
c: canonize(ctx, a.c)
};
return res;
} else {
return a; return a;
} else if (a.type == "QEQ") {
a.a = canonize(ctx, a.a);
a.b = canonize(ctx, a.b);
a.c = canonize(ctx, a.c);
} }
return a;
} }
function substitute(where, signal, equivalence) { function substitute(where, signal, equivalence) {
if (equivalence.type != "LINEARCOMBINATION") throw new Error("Equivalence must be a Linear Combination"); if (equivalence.type != "LINEARCOMBINATION") throw new Error("Equivalence must be a Linear Combination");
if (where.type == "LINEARCOMBINATION") { if (where.type == "LINEARCOMBINATION") {
if (!where.values[signal] || where.values[signal].isZero()) return where; if (!where.values[signal] || where.values[signal].isZero()) return where;
const res=clone(where); const coef = where.values[signal];
const coef = res.values[signal];
for (let k in equivalence.values) { for (let k in equivalence.values) {
if (k != signal) { if (k != signal) {
const v = coef.times(equivalence.values[k]).mod(__P__); const v = coef.times(equivalence.values[k]).mod(__P__);
if (!res.values[k]) { if (!where.values[k]) {
res.values[k]=v; where.values[k]=v;
} else { } else {
res.values[k]= res.values[k].add(v).mod(__P__); where.values[k]= where.values[k].add(v).mod(__P__);
} }
if (res.values[k].isZero()) delete res.values[k]; if (where.values[k].isZero()) delete where.values[k];
} }
} }
delete res.values[signal]; delete where.values[signal];
return res;
} else if (where.type == "QEQ") { } else if (where.type == "QEQ") {
const res = { substitute(where.a, signal, equivalence);
type: "QEQ", substitute(where.b, signal, equivalence);
a: substitute(where.a, signal, equivalence), substitute(where.c, signal, equivalence);
b: substitute(where.b, signal, equivalence),
c: substitute(where.c, signal, equivalence)
};
return res;
} else {
return where;
} }
} }

View File

@@ -1,52 +0,0 @@
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;
async function assertThrowsAsync(fn, regExp) {
let f = () => {};
try {
await fn();
} catch(e) {
f = () => { throw e; };
} finally {
assert.throws(f, regExp);
}
}
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)));
});
// it("Should assign signal ERROR", async () => {
// await assertThrowsAsync(async () => {
// await compiler(path.join(__dirname, "circuits", "assignsignal.circom"));
// }, /Cannot assign to a signal .*/);
// });
});

View File

@@ -1,7 +0,0 @@
template A() {
signal output out;
out = 3; // This is an error that compile should detect
}
component main = A();

View File

@@ -0,0 +1,18 @@
include "../../circuits/sha256/constants.circom"
template A() {
signal input in;
component h0;
h0 = K(8);
var lc = 0;
var e = 1;
for (var i=0; i<32; i++) {
lc = lc + e*h0.out[i];
e *= 2;
}
lc === in;
}
component main = A();

View File

@@ -1,12 +0,0 @@
template A() {
signal a;
}
template B() {
component a[2] = A();
}
component main = B();

View File

@@ -1,19 +0,0 @@
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();

View File

@@ -1,14 +0,0 @@
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();

2371
test/circuits/out.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
include "../../circuits/sha256/sha256_2.circom";
template Main() {
signal private input a;
signal private input b;
signal output out;
component sha256_2 = Sha256_2();
sha256_2.a <== a;
sha256_2.b <== b;
out <== sha256_2.out;
}
component main = Main();

View File

@@ -0,0 +1,26 @@
include "../../circuits/sha256/bitify.circom"
include "../../circuits/sha256/binsum.circom"
template A() {
signal private input a;
signal input b;
signal output out;
component n2ba = Num2Bits(32);
component n2bb = Num2Bits(32);
component sum = BinSum(32,2);
component b2n = Bits2Num(32);
n2ba.in <== a;
n2bb.in <== b;
for (var i=0; i<32; i++) {
sum.in[0][i] <== n2ba.out[i];
sum.in[1][i] <== n2bb.out[i];
b2n.in[i] <== sum.out[i];
}
out <== b2n.out;
}
component main = A();

View File

@@ -1,14 +0,0 @@
template X() {
signal input i;
signal input j;
signal output out;
if (i == 0) {
out <-- i;
}
else {
out <-- j;
}
}
component main = X();

178
test/helpers/sha256.js Normal file
View File

@@ -0,0 +1,178 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* SHA-256 (FIPS 180-4) implementation in JavaScript (c) Chris Veness 2002-2017 */
/* MIT Licence */
/* www.movable-type.co.uk/scripts/sha256.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
'use strict';
/**
* SHA-256 hash function reference implementation.
*
* This is an annotated direct implementation of FIPS 180-4, without any optimisations. It is
* intended to aid understanding of the algorithm rather than for production use.
*
* While it could be used where performance is not critical, I would recommend using the Web
* Cryptography API (developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest) for the browser,
* or the crypto library (nodejs.org/api/crypto.html#crypto_class_hash) in Node.js.
*
* See csrc.nist.gov/groups/ST/toolkit/secure_hashing.html
* csrc.nist.gov/groups/ST/toolkit/examples.html
*/
class Sha256 {
/**
* Generates SHA-256 hash of string.
*
* @param {string} msg - (Unicode) string to be hashed.
* @param {Object} [options]
* @param {string} [options.msgFormat=string] - Message format: 'string' for JavaScript string
* (gets converted to UTF-8 for hashing); 'hex-bytes' for string of hex bytes ('616263' ≡ 'abc') .
* @param {string} [options.outFormat=hex] - Output format: 'hex' for string of contiguous
* hex bytes; 'hex-w' for grouping hex bytes into groups of (4 byte / 8 character) words.
* @returns {string} Hash of msg as hex character string.
*/
static hash(msg, options) {
const defaults = { msgFormat: 'string', outFormat: 'hex' };
const opt = Object.assign(defaults, options);
// note use throughout this routine of 'n >>> 0' to coerce Number 'n' to unsigned 32-bit integer
switch (opt.msgFormat) {
default: // default is to convert string to UTF-8, as SHA only deals with byte-streams
case 'string': msg = utf8Encode(msg); break;
case 'hex-bytes':msg = hexBytesToString(msg); break; // mostly for running tests
}
// constants [§4.2.2]
const K = [
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 ];
// initial hash value [§5.3.3]
const H = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ];
// PREPROCESSING [§6.2.1]
msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
// convert string msg into 512-bit blocks (array of 16 32-bit integers) [§5.2.1]
const l = msg.length/4 + 2; // length (in 32-bit integers) of msg + 1 + appended length
const N = Math.ceil(l/16); // number of 16-integer (512-bit) blocks required to hold 'l' ints
const M = new Array(N); // message M is N×16 array of 32-bit integers
for (let i=0; i<N; i++) {
M[i] = new Array(16);
for (let j=0; j<16; j++) { // encode 4 chars per integer (64 per block), big-endian encoding
M[i][j] = (msg.charCodeAt(i*64+j*4+0)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16)
| (msg.charCodeAt(i*64+j*4+2)<< 8) | (msg.charCodeAt(i*64+j*4+3)<< 0);
} // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
}
// add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
// note: most significant word would be (len-1)*8 >>> 32, but since JS converts
// bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
const lenHi = ((msg.length-1)*8) / Math.pow(2, 32);
const lenLo = ((msg.length-1)*8) >>> 0;
M[N-1][14] = Math.floor(lenHi);
M[N-1][15] = lenLo;
// HASH COMPUTATION [§6.2.2]
for (let i=0; i<N; i++) {
const W = new Array(64);
// 1 - prepare message schedule 'W'
for (let t=0; t<16; t++) W[t] = M[i][t];
for (let t=16; t<64; t++) {
W[t] = (Sha256.σ1(W[t-2]) + W[t-7] + Sha256.σ0(W[t-15]) + W[t-16]) >>> 0;
}
// 2 - initialise working variables a, b, c, d, e, f, g, h with previous hash value
let a = H[0], b = H[1], c = H[2], d = H[3], e = H[4], f = H[5], g = H[6], h = H[7];
// 3 - main loop (note '>>> 0' for 'addition modulo 2^32')
for (let t=0; t<64; t++) {
const T1 = h + Sha256.Σ1(e) + Sha256.Ch(e, f, g) + K[t] + W[t];
const T2 = Sha256.Σ0(a) + Sha256.Maj(a, b, c);
h = g;
g = f;
f = e;
e = (d + T1) >>> 0;
d = c;
c = b;
b = a;
a = (T1 + T2) >>> 0;
}
// 4 - compute the new intermediate hash value (note '>>> 0' for 'addition modulo 2^32')
H[0] = (H[0]+a) >>> 0;
H[1] = (H[1]+b) >>> 0;
H[2] = (H[2]+c) >>> 0;
H[3] = (H[3]+d) >>> 0;
H[4] = (H[4]+e) >>> 0;
H[5] = (H[5]+f) >>> 0;
H[6] = (H[6]+g) >>> 0;
H[7] = (H[7]+h) >>> 0;
}
// convert H0..H7 to hex strings (with leading zeros)
for (let h=0; h<H.length; h++) H[h] = ('00000000'+H[h].toString(16)).slice(-8);
// concatenate H0..H7, with separator if required
const separator = opt.outFormat=='hex-w' ? ' ' : '';
return H.join(separator);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
function utf8Encode(str) {
try {
return new TextEncoder().encode(str, 'utf-8').reduce((prev, curr) => prev + String.fromCharCode(curr), '');
} catch (e) { // no TextEncoder available?
return unescape(encodeURIComponent(str)); // monsur.hossa.in/2012/07/20/utf-8-in-javascript.html
}
}
function hexBytesToString(hexStr) { // convert string of hex numbers to a string of chars (eg '616263' -> 'abc').
const str = hexStr.replace(' ', ''); // allow space-separated groups
return str=='' ? '' : str.match(/.{2}/g).map(byte => String.fromCharCode(parseInt(byte, 16))).join('');
}
}
/**
* Rotates right (circular right shift) value x by n positions [§3.2.4].
* @private
*/
static ROTR(n, x) {
return (x >>> n) | (x << (32-n));
}
/**
* Logical functions [§4.1.2].
* @private
*/
static Σ0(x) { return Sha256.ROTR(2, x) ^ Sha256.ROTR(13, x) ^ Sha256.ROTR(22, x); }
static Σ1(x) { return Sha256.ROTR(6, x) ^ Sha256.ROTR(11, x) ^ Sha256.ROTR(25, x); }
static σ0(x) { return Sha256.ROTR(7, x) ^ Sha256.ROTR(18, x) ^ (x>>>3); }
static σ1(x) { return Sha256.ROTR(17, x) ^ Sha256.ROTR(19, x) ^ (x>>>10); }
static Ch(x, y, z) { return (x & y) ^ (~x & z); } // 'choice'
static Maj(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); } // 'majority'
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (typeof module != 'undefined' && module.exports) module.exports = Sha256; // ≡ export default Sha256

4
test/input_sum_test.json Normal file
View File

@@ -0,0 +1,4 @@
{
"a": "111",
"b": "222"
}

82
test/sha256.js Normal file
View File

@@ -0,0 +1,82 @@
const chai = require("chai");
const path = require("path");
const zkSnark = require("zksnark");
const crypto = require("crypto");
const compiler = require("../index.js");
const assert = chai.assert;
const sha256 = require("./helpers/sha256");
const bigInt = require("big-integer");
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);
}
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 zkSnark.Circuit(cirDef);
const witness = circuit.calculateWitness({ "in": "0xd807aa98" });
assert(witness[0].equals(zkSnark.bigInt(1)));
assert(witness[1].equals(zkSnark.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 zkSnark.Circuit(cirDef);
const witness = circuit.calculateWitness({ "a": "111", "b": "222" });
assert(witness[0].equals(zkSnark.bigInt(1)));
assert(witness[1].equals(zkSnark.bigInt("333")));
});
it("Should calculate a hash", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_2_test.circom"));
const circuit = new zkSnark.Circuit(cirDef);
console.log("Vars: "+circuit.nVars);
console.log("Constraints: "+circuit.nConstraints);
const witness = circuit.calculateWitness({ "a": "1", "b": "2" });
const b = new Buffer.alloc(54);
b[26] = 1;
b[53] = 2;
const hash = crypto.createHash("sha256")
.update(b)
.digest("hex");
const r = "0x" + hash.slice(10);
const hash2 = sha256.hash(b.toString("hex"), {msgFormat: "hex-bytes"});
assert.equal(hash, hash2);
assert(witness[1].equals(zkSnark.bigInt(r)));
}).timeout(1000000);
});

36
wasm/AddSum.cpp Normal file
View File

@@ -0,0 +1,36 @@
class Value {
}
class Var : Value {
}
class Ctx {
char *currentComponent;
Var getParam(char *);
Var getSignal(char *, ...);
Var newVar(char *);
}
void Num2Bits::Num2Bits(ctx) {
Var n = ctx.getParam("n");
Var in = ctx.getSignal("in");
Var out = ctx.getSignal("out");
(Var lc1 = ctx.newVar()) = _0x0;
for ((Var i = ctx.newVar()) = _0x0 ; i<n; i++ ) {
out[i] = (in >> i) & _0x1;
assert(out[i]*(out[i] - _0x1), _0x0);
lc1 += out[i] * (2**i);
}
assert(lc1, in);
}

0
wasm/context.h Normal file
View File