@ -0,0 +1,33 @@ |
|||
module.exports = { |
|||
"plugins": [ |
|||
"mocha" |
|||
], |
|||
"env": { |
|||
"es6": true, |
|||
"node": true, |
|||
"mocha": true |
|||
}, |
|||
"parserOptions": { |
|||
"ecmaVersion": 2017 |
|||
}, |
|||
"extends": "eslint:recommended", |
|||
"rules": { |
|||
"indent": [ |
|||
"error", |
|||
4 |
|||
], |
|||
"linebreak-style": [ |
|||
"error", |
|||
"unix" |
|||
], |
|||
"quotes": [ |
|||
"error", |
|||
"double" |
|||
], |
|||
"semi": [ |
|||
"error", |
|||
"always" |
|||
], |
|||
"mocha/no-exclusive-tests": "error" |
|||
} |
|||
}; |
@ -0,0 +1,63 @@ |
|||
# Logs |
|||
logs |
|||
*.log |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
|
|||
# Runtime data |
|||
pids |
|||
*.pid |
|||
*.seed |
|||
*.pid.lock |
|||
|
|||
# Directory for instrumented libs generated by jscoverage/JSCover |
|||
lib-cov |
|||
|
|||
# Coverage directory used by tools like istanbul |
|||
coverage |
|||
|
|||
# nyc test coverage |
|||
.nyc_output |
|||
|
|||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) |
|||
.grunt |
|||
|
|||
# Bower dependency directory (https://bower.io/) |
|||
bower_components |
|||
|
|||
# node-waf configuration |
|||
.lock-wscript |
|||
|
|||
# Compiled binary addons (https://nodejs.org/api/addons.html) |
|||
build/Release |
|||
|
|||
# Dependency directories |
|||
node_modules/ |
|||
jspm_packages/ |
|||
|
|||
# Typescript v1 declaration files |
|||
typings/ |
|||
|
|||
# Optional npm cache directory |
|||
.npm |
|||
|
|||
# Optional eslint cache |
|||
.eslintcache |
|||
|
|||
# Optional REPL history |
|||
.node_repl_history |
|||
|
|||
# Output of 'npm pack' |
|||
*.tgz |
|||
|
|||
# Yarn Integrity file |
|||
.yarn-integrity |
|||
|
|||
# dotenv environment variables file |
|||
.env |
|||
|
|||
# next.js build output |
|||
.next |
|||
|
|||
tmp |
@ -0,0 +1,11 @@ |
|||
template AND() { |
|||
signal input s1; |
|||
signal input s2; |
|||
signal output s3; |
|||
|
|||
s3 <== s1*s2; |
|||
s1*(s1-1) === 0; |
|||
s2*(s2-1) === 0; |
|||
} |
|||
|
|||
component main = AND(); |
@ -0,0 +1,74 @@ |
|||
// --> Assignation without constrain |
|||
// <-- Assignation without constrain |
|||
// === Constrain |
|||
// <== Assignation with constrain |
|||
// ==> Assignation with constrain |
|||
// 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; |
|||
|
|||
|
@ -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 Constrain: |
|||
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; |
|||
} |
@ -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; |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -0,0 +1,67 @@ |
|||
|
|||
template XOR() { |
|||
signal input a; |
|||
signal input b; |
|||
signal output out; |
|||
|
|||
out <== a + b - 2*a*b; |
|||
} |
|||
|
|||
template AND() { |
|||
signal input a; |
|||
signal input b; |
|||
signal output out; |
|||
|
|||
out <== a*b; |
|||
} |
|||
|
|||
template OR() { |
|||
signal input a; |
|||
signal input b; |
|||
signal output out; |
|||
|
|||
out <== a + b - a*b; |
|||
} |
|||
|
|||
template NOT() { |
|||
signal input in; |
|||
signal output out; |
|||
|
|||
out <== 1 + in - 2*in; |
|||
} |
|||
|
|||
template NAND() { |
|||
signal input a; |
|||
signal input b; |
|||
signal output out; |
|||
|
|||
out <== 1 - a*b; |
|||
} |
|||
|
|||
template NOR() { |
|||
signal input a; |
|||
signal input b; |
|||
signal output out; |
|||
|
|||
out <== a*b + 1 - a - b; |
|||
} |
|||
|
|||
template Xor3(n) { |
|||
signal input a[n]; |
|||
signal input b[n]; |
|||
signal input c[n]; |
|||
signal output out[n]; |
|||
|
|||
component xor1[n] = XOR(); |
|||
component xor2[n] = XOR(); |
|||
|
|||
for (var k=0; k<n; k++) { |
|||
xor1[k].a <== a[k]; |
|||
xor1[k].b <== b[k]; |
|||
|
|||
xor2[k].a <== xor1[k].out; |
|||
xor2[k].b <== c[k]; |
|||
|
|||
out[k] <== xor2[k].out; |
|||
} |
|||
} |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"in": "0xd807aa98" |
|||
} |
@ -0,0 +1,4 @@ |
|||
{ |
|||
"a": "111", |
|||
"b": "222" |
|||
} |
@ -0,0 +1,50 @@ |
|||
|
|||
/* |
|||
include "sha256_2.jaz"; |
|||
|
|||
component main = SHA256_2(); |
|||
*/ |
|||
|
|||
/* |
|||
include "constants.jaz" |
|||
|
|||
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(); |
|||
*/ |
|||
|
|||
include "bitify.jaz" |
|||
|
|||
template A() { |
|||
signal input in; |
|||
signal output out; |
|||
|
|||
component n2b; |
|||
component b2n; |
|||
|
|||
n2b = Num2Bits(216); |
|||
b2n = Bits2Num(216); |
|||
|
|||
n2b.in <== in; |
|||
|
|||
for (var i=0; i<216; i++) { |
|||
b2n.in[i] <== n2b.out[i]; |
|||
} |
|||
|
|||
out <== b2n.out; |
|||
} |
|||
|
|||
component main = A(); |
@ -0,0 +1,10 @@ |
|||
|
|||
|
|||
template RotR(n, r) { |
|||
signal input in[n]; |
|||
signal output out[n]; |
|||
|
|||
for (i=0; i<n; i++) { |
|||
out[i] <== in[ (i+r)%n ]; |
|||
} |
|||
} |
@ -0,0 +1,44 @@ |
|||
|
|||
include "sha256compression.jaz"; |
|||
include "bitify.jaz" |
|||
|
|||
component sha256_2() { |
|||
signal input a; |
|||
signal input b; |
|||
signal output out; |
|||
|
|||
component num2bits[2] = Num2Bits(216); |
|||
component bits2num = Bits2Num(216); |
|||
|
|||
num2bits[0].inp <== a; |
|||
num2bits[1].inp <== b; |
|||
|
|||
component sha256compression = Sha256compression() ; |
|||
|
|||
var i; |
|||
|
|||
for (i=0; i<216; i++) { |
|||
sha256compression.inp[i] <== num2bits[0].out[i]; |
|||
sha256compression.inp[i+216] <== num2bits[1].out[i]; |
|||
} |
|||
|
|||
for (i=432; i<247; i++) { |
|||
sha256compression.inp[i] <== 0; |
|||
} |
|||
|
|||
sha256compression.inp[247] <== 1; |
|||
sha256compression.inp[248] <== 1; |
|||
sha256compression.inp[249] <== 0; |
|||
sha256compression.inp[250] <== 1; |
|||
sha256compression.inp[251] <== 1; |
|||
sha256compression.inp[252] <== 0; |
|||
sha256compression.inp[253] <== 0; |
|||
sha256compression.inp[254] <== 0; |
|||
sha256compression.inp[255] <== 0; |
|||
|
|||
for (i=0; i<216; i++) { |
|||
bits2num.inp[i] <== sha256compression.out[i]; |
|||
} |
|||
|
|||
out <== bits2num.out; |
|||
} |
@ -0,0 +1,145 @@ |
|||
|
|||
include "constants.jaz"; |
|||
include "t1.jaz"; |
|||
include "t2.jaz"; |
|||
include "sum.jaz"; |
|||
include "sigmaplus.jaz"; |
|||
|
|||
template sha256compression() { |
|||
signal input inp[512]; |
|||
signal output out[256]; |
|||
signal a[64][32]; |
|||
signal b[64][32]; |
|||
signal c[64][32]; |
|||
signal d[64][32]; |
|||
signal e[64][32]; |
|||
signal f[64][32]; |
|||
signal g[64][32]; |
|||
signal h[64][32]; |
|||
signal w[64][512]; |
|||
|
|||
var i; |
|||
|
|||
component sigmaPlus[48] = SigmaPlus(); |
|||
|
|||
component k[64]; |
|||
for (i=0; i<64; i++) k[i] = K(i); |
|||
|
|||
component ha0 = H0(0); |
|||
component hb0 = H0(1); |
|||
component hc0 = H0(2); |
|||
component hd0 = H0(3); |
|||
component he0 = H0(4); |
|||
component hf0 = H0(5); |
|||
component hg0 = H0(6); |
|||
component hh0 = H0(7); |
|||
|
|||
component t1[64] = T1(); |
|||
component t2[64] = T2(); |
|||
|
|||
component suma[64] = Sum2(32); |
|||
component sume[64] = Sum2(32); |
|||
component fsum[8] = Sum2(32); |
|||
|
|||
var k; |
|||
var t; |
|||
|
|||
for (t=0; t<64; t++) { |
|||
if (t<16) { |
|||
for (k=0; k<256; k++) { |
|||
w[t][k] <== inp[k]; |
|||
} |
|||
} else { |
|||
for (k=0; k<256; k++) { |
|||
sigmaPlus[t-16].in2[k] <== w[t-2][k]; |
|||
sigmaPlus[t-16].in7[k] <== w[t-2][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<63; t++) { |
|||
for (k=0; k<32; k++) { |
|||
t1[t].h[k] <== h[k]; |
|||
t1[t].e[k] <== e[k]; |
|||
t1[t].f[k] <== f[k]; |
|||
t1[t].g[k] <== g[k]; |
|||
if (t<20) { |
|||
t1[t].g[k] <== K0.out[k]; |
|||
} else if (t<40) { |
|||
t1[t].g[k] <== K20.out[k]; |
|||
} else if (t<60) { |
|||
t1[t].g[k] <== K40.out[k]; |
|||
} else { |
|||
t1[t].g[k] <== K60.out[k]; |
|||
} |
|||
t1[t].w[k] <== w[t][k]; |
|||
|
|||
t2[t].a[k] <== a[k]; |
|||
t2[t].b[k] <== a[k]; |
|||
t2[t].c[k] <== a[k]; |
|||
} |
|||
|
|||
for (k=0; k<32; k++) { |
|||
sume[t].a[k] <== d[k]; |
|||
sume[t].b[k] <== t1[t].out[k]; |
|||
|
|||
suma[t].a[k] <== t1[t].out[k]; |
|||
suma[t].b[k] <== t2[t].out[k]; |
|||
} |
|||
|
|||
for (k=0; k<32; k++) { |
|||
h[t+1] <== g[t]; |
|||
g[t+1] <== f[t]; |
|||
f[t+1] <== e[t]; |
|||
e[t+1] <== sume[t].out[k]; |
|||
d[t+1] <== c[t]; |
|||
c[t+1] <== b[t]; |
|||
b[t+1] <== a[t]; |
|||
a[t+1] <== suma[t].out[k]; |
|||
} |
|||
} |
|||
|
|||
for (k=0; k<32; k++) { |
|||
fsum[0].a[k] <== ha0.out[k]; |
|||
fsum[0].b[k] <== a[64][k]; |
|||
fsum[1].a[k] <== hb0.out[k]; |
|||
fsum[1].b[k] <== b[64][k]; |
|||
fsum[2].a[k] <== hc0.out[k]; |
|||
fsum[2].b[k] <== c[64][k]; |
|||
fsum[3].a[k] <== hd0.out[k]; |
|||
fsum[3].b[k] <== d[64][k]; |
|||
fsum[4].a[k] <== he0.out[k]; |
|||
fsum[4].b[k] <== e[64][k]; |
|||
fsum[5].a[k] <== hf0.out[k]; |
|||
fsum[5].b[k] <== f[64][k]; |
|||
fsum[6].a[k] <== hg0.out[k]; |
|||
fsum[6].b[k] <== g[64][k]; |
|||
fsum[7].a[k] <== hh0.out[k]; |
|||
fsum[7].b[k] <== h[64][k]; |
|||
} |
|||
|
|||
for (k=0; k<32; k++) { |
|||
out[k] <== fsum[0].out[k]; |
|||
out[32+k] <== fsum[1].out[k]; |
|||
out[64+k] <== fsum[2].out[k]; |
|||
out[96+k] <== fsum[2].out[k]; |
|||
out[128+k] <== fsum[2].out[k]; |
|||
out[160+k] <== fsum[2].out[k]; |
|||
out[192+k] <== fsum[2].out[k]; |
|||
out[224+k] <== fsum[2].out[k]; |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
include "gates.jaz"; |
|||
include "rotate.jaz"; |
|||
|
|||
template Sigma(ra, rb, rc) { |
|||
signal input in; |
|||
signal output out; |
|||
|
|||
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]; |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
include "sum.jaz" |
|||
include "sigma.jaz" |
|||
|
|||
template SigmaPlus() { |
|||
signal input in2[32]; |
|||
signal input in7[32]; |
|||
signal input in15[32]; |
|||
signal input in16[32]; |
|||
signal output out[32]; |
|||
|
|||
component sum = Sum(32, 4); |
|||
component sigma1 = Sigma(17,19,10); |
|||
component sigma0 = Sigma(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]; |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
include "bitify.jaz" |
|||
include "binsum.jaz" |
|||
|
|||
template A() { |
|||
signal 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(); |
@ -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; |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"inp": "3" |
|||
} |
@ -0,0 +1,4 @@ |
|||
{ |
|||
"s1": "24", |
|||
"s2": "1" |
|||
} |
@ -0,0 +1,27 @@ |
|||
{ |
|||
"inp[0][0]": 100, |
|||
"inp[0][1]": 101, |
|||
"inp[0][2]": 102, |
|||
"inp[0][3]": 103, |
|||
"inp[0][4]": 104, |
|||
"inp[0][5]": 105, |
|||
"inp[0][6]": 106, |
|||
"inp[0][7]": 107, |
|||
"inp[1][0]": 110, |
|||
"inp[1][1]": 111, |
|||
"inp[1][2]": 112, |
|||
"inp[1][3]": 113, |
|||
"inp[1][4]": 114, |
|||
"inp[1][5]": 115, |
|||
"inp[1][6]": 116, |
|||
"inp[1][7]": 117, |
|||
"inp[2][0]": 120, |
|||
"inp[2][1]": 121, |
|||
"inp[2][2]": 122, |
|||
"inp[2][3]": 123, |
|||
"inp[2][4]": 124, |
|||
"inp[2][5]": 125, |
|||
"inp[2][6]": 126, |
|||
"inp[2][7]": 127, |
|||
"sel": 1 |
|||
} |
@ -0,0 +1,154 @@ |
|||
const bigInt = require("big-integer"); |
|||
const __P__ = new bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583"); |
|||
const __MASK__ = new bigInt(2).pow(253).minus(1); |
|||
const circuit = {}; |
|||
module.exports = circuit; |
|||
|
|||
circuit.signals={ |
|||
"one": { |
|||
"fullName": "one", |
|||
"value": "1", |
|||
"equivalence": "", |
|||
"direction": "", |
|||
"id": 0 |
|||
}, |
|||
"main.s1": { |
|||
"fullName": "main.s1", |
|||
"direction": "IN", |
|||
"component": "main", |
|||
"equivalence": "", |
|||
"alias": [ |
|||
"main.s1" |
|||
], |
|||
"id": 1 |
|||
}, |
|||
"main.s2": { |
|||
"fullName": "main.s2", |
|||
"direction": "IN", |
|||
"component": "main", |
|||
"equivalence": "", |
|||
"alias": [ |
|||
"main.s2" |
|||
], |
|||
"id": 2 |
|||
}, |
|||
"main.s3": { |
|||
"fullName": "main.s3", |
|||
"direction": "OUT", |
|||
"component": "main", |
|||
"equivalence": "", |
|||
"alias": [ |
|||
"main.s3" |
|||
], |
|||
"id": 3 |
|||
} |
|||
}; |
|||
|
|||
circuit.components={ |
|||
"main": { |
|||
"signals": [ |
|||
"main.s1", |
|||
"main.s2", |
|||
"main.s3" |
|||
], |
|||
"params": {}, |
|||
"template": "AND", |
|||
"inputSignals": 2 |
|||
} |
|||
}; |
|||
|
|||
circuit.signalConstrains=[ |
|||
{ |
|||
"type": "QEQ", |
|||
"a": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.s1": "21888242871839275222246405745257275088696311157297823662689037894645226208582" |
|||
} |
|||
}, |
|||
"b": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.s2": "1" |
|||
} |
|||
}, |
|||
"c": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.s3": "1" |
|||
} |
|||
} |
|||
}, |
|||
{ |
|||
"type": "QEQ", |
|||
"a": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.s1": "1" |
|||
} |
|||
}, |
|||
"b": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.s1": "1", |
|||
"one": "21888242871839275222246405745257275088696311157297823662689037894645226208582" |
|||
} |
|||
}, |
|||
"c": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": {} |
|||
} |
|||
}, |
|||
{ |
|||
"type": "QEQ", |
|||
"a": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.s2": "1" |
|||
} |
|||
}, |
|||
"b": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.s2": "1", |
|||
"one": "21888242871839275222246405745257275088696311157297823662689037894645226208582" |
|||
} |
|||
}, |
|||
"c": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": {} |
|||
} |
|||
} |
|||
]; |
|||
|
|||
circuit.witnessNames=[ |
|||
[ |
|||
"one" |
|||
], |
|||
[ |
|||
"main.s1" |
|||
], |
|||
[ |
|||
"main.s2" |
|||
], |
|||
[ |
|||
"main.s3" |
|||
] |
|||
]; |
|||
|
|||
{ |
|||
} |
|||
|
|||
circuit.templates = {}; |
|||
|
|||
circuit.templates["AND"] = function(ctx) { |
|||
ctx.setSignal("s3", [], bigInt(ctx.getSignal("s1", [])).times(ctx.getSignal("s2", [])).mod(__P__)); |
|||
ctx.assert(ctx.getSignal("s3", []), bigInt(ctx.getSignal("s1", [])).times(ctx.getSignal("s2", [])).mod(__P__)); |
|||
ctx.assert(bigInt(ctx.getSignal("s1", [])).times(bigInt(ctx.getSignal("s1", [])).add(__P__).minus("1").mod(__P__)).mod(__P__), "0"); |
|||
ctx.assert(bigInt(ctx.getSignal("s2", [])).times(bigInt(ctx.getSignal("s2", [])).add(__P__).minus("1").mod(__P__)).mod(__P__), "0"); |
|||
} |
|||
; |
|||
circuit.functionParams={}; |
|||
|
|||
|
|||
circuit.functions = {}; |
@ -0,0 +1 @@ |
|||
["1","0","1","0"] |
@ -0,0 +1 @@ |
|||
["1","100","101","102","103","104","105","106","107","110","111","112","113","114","115","116","117","120","121","122","123","124","125","126","127","1","110","111","112","113","114","115","116","117","0","1","0","1","0","110","0","0","111","0","0","112","0","0","113","0","0","114","0","0","115","0","0","116","0","0","117","0"] |
@ -0,0 +1,31 @@ |
|||
{ |
|||
"name": "jaz", |
|||
"version": "0.0.1", |
|||
"description": "Language to generate logica circuits", |
|||
"main": "index.js", |
|||
"directories": { |
|||
"test": "test" |
|||
}, |
|||
"scripts": { |
|||
"test": "echo \"Error: no test specified\" && exit 1" |
|||
}, |
|||
"keywords": [ |
|||
"zkSnarks", |
|||
"r1cs", |
|||
"circuits", |
|||
"zero", |
|||
"knowlage", |
|||
"ethereum", |
|||
"zcash" |
|||
], |
|||
"author": "Jordi Baylina", |
|||
"license": "GPL-3.0", |
|||
"dependencies": { |
|||
"big-integer": "^1.6.32", |
|||
"optimist": "^0.6.1" |
|||
}, |
|||
"devDependencies": { |
|||
"eslint": "^5.0.1", |
|||
"eslint-plugin-mocha": "^5.0.0" |
|||
} |
|||
} |
@ -0,0 +1,892 @@ |
|||
/* description: Construct AST for jaz language. */ |
|||
|
|||
/* lexical grammar */ |
|||
%lex |
|||
|
|||
%% |
|||
|
|||
\s+ { /* skip whitespace */ } |
|||
\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/ { /* console.log("MULTILINE COMMENT: "+yytext); */ } |
|||
\/\/.* { /* console.log("SINGLE LINE COMMENT: "+yytext); */ } |
|||
var { return 'var'; } |
|||
signal { return 'signal'; } |
|||
input { return 'input'; } |
|||
output { return 'output'; } |
|||
linearCombination { return 'linearCombination'; } |
|||
component { return 'component'; } |
|||
template { return 'template'; } |
|||
function { return 'function'; } |
|||
if { return 'if'; } |
|||
else { return 'else'; } |
|||
for { return 'for'; } |
|||
while { return 'while'; } |
|||
do { return 'do'; } |
|||
return { return 'return'; } |
|||
include { return 'include'; } |
|||
0x[0-9A-Fa-f]* { return 'HEXNUMBER'; } |
|||
[0-9]+ { return 'DECNUMBER'; } |
|||
[a-zA-Z][a-zA-Z$_0-9]* { return 'IDENTIFIER'; } |
|||
\"[^"]+\" { yytext = yytext.slice(1,-1); return 'STRING'; } |
|||
\=\=\> { return '==>'; } |
|||
\<\=\= { return '<=='; } |
|||
\-\-\> { return '-->'; } |
|||
\<\-\- { return '<--'; } |
|||
\=\=\= { return '==='; } |
|||
\>\>\= { return '>>='; } |
|||
\<\<\= { return '<<='; } |
|||
\&\& { return '&&'; } |
|||
\|\| { return '||'; } |
|||
\=\= { return '=='; } |
|||
\<\= { return '<='; } |
|||
\>\= { return '>='; } |
|||
\!\= { return '!='; } |
|||
\>\> { return '>>'; } |
|||
\<\< { return '<<'; } |
|||
\*\* { return '**'; } |
|||
\+\+ { return '++'; } |
|||
\-\- { return '--'; } |
|||
\+\= { return '+='; } |
|||
\-\= { return '-='; } |
|||
\*\= { return '*='; } |
|||
\/\= { return '/='; } |
|||
\%\= { return '%='; } |
|||
\|\= { return '|='; } |
|||
\&\= { return '&='; } |
|||
\^\= { return '^='; } |
|||
\= { return '='; } |
|||
\+ { return '+'; } |
|||
\- { return '-'; } |
|||
\* { return '*'; } |
|||
\/ { return '/'; } |
|||
\% { return '%'; } |
|||
\^ { return '^'; } |
|||
\& { return '&'; } |
|||
\| { return '|'; } |
|||
\! { return '!'; } |
|||
\< { return '<'; } |
|||
\> { return '>'; } |
|||
\! { return '!'; } |
|||
\? { return '?'; } |
|||
\: { return ':'; } |
|||
\( { return '('; } |
|||
\) { return ')'; } |
|||
\[ { return '['; } |
|||
\] { return ']'; } |
|||
\{ { return '{'; } |
|||
\} { return '}'; } |
|||
\; { return ';'; } |
|||
\, { return ','; } |
|||
\. { return '.'; } |
|||
<<EOF>> { return 'EOF'; } |
|||
. { console.log("INVALID: " + yytext); return 'INVALID'} |
|||
|
|||
/lex |
|||
|
|||
%left ';' |
|||
%right 'if' 'else' |
|||
%left EMPTY |
|||
%left IDLIST |
|||
%left ',' |
|||
%right '?' ':' TERCOND '=' '+=' '-=' '*=' '/=' '%=' '>>=' '<<=' '&=' '|=' '^=' '<==' '==>' '===' '<--' '-->' |
|||
%left '||' |
|||
%left '&&' |
|||
%left '|' |
|||
%left '^' |
|||
%left '&' |
|||
%left '==' '!=' |
|||
%left '<=' '>=' '<' '>' |
|||
%left '<<' '>>' |
|||
|
|||
%left '+' '-' |
|||
%left '*' '/' '%' |
|||
%left '**' |
|||
%right '++' '--' UMINUS UPLUS '!' '~' |
|||
%left '.' |
|||
%left DECL |
|||
%left PLUSPLUSRIGHT MINUSMINUSRIGHT '[' ']' '(' ')' |
|||
%left HIGH |
|||
|
|||
|
|||
|
|||
%{ |
|||
const bigInt = require('big-integer'); |
|||
const util = require('util'); |
|||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); |
|||
const __MASK__ = new bigInt(2).pow(253).minus(1); |
|||
|
|||
function setLines(dst, first, last) { |
|||
last = last || first; |
|||
dst.first_line = first.first_line; |
|||
dst.first_column = first.first_column; |
|||
dst.last_line = last.last_line; |
|||
dst.last_column = last.last_column; |
|||
} |
|||
|
|||
%} |
|||
|
|||
%start allStatments |
|||
|
|||
%% /* language grammar */ |
|||
|
|||
|
|||
allStatments |
|||
: statmentList EOF |
|||
{ |
|||
// console.log(JSON.stringify($1, null, 1)); |
|||
$$ = { type: "BLOCK", statements: $1.statments }; |
|||
setLines($$, @1); |
|||
return $$ |
|||
} |
|||
; |
|||
|
|||
statmentList |
|||
: statmentList statment |
|||
{ |
|||
$1.statments.push($2); |
|||
setLines($1, @1, @2); |
|||
} |
|||
| statment |
|||
{ |
|||
$$ = { type: "STATMENTLIST", statments: [$1] }; |
|||
setLines($$, @1); |
|||
} |
|||
; |
|||
|
|||
statment |
|||
: functionDefinitionStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| templateDefinitionStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| ifStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| forStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| whileStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| doWhileStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| returnStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| block |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| expressionStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| includeStatment |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
|
|||
functionDefinitionStatment |
|||
: 'function' IDENTIFIER '(' identifierList ')' block |
|||
{ |
|||
$$ = { type: "FUNCTIONDEF", name: $2, params: $4.identifiers, block: $6}; |
|||
setLines($$, @1, @6); |
|||
} |
|||
| 'function' IDENTIFIER '(' ')' block |
|||
{ |
|||
$$ = { type: "FUNCTIONDEF", name: $2, params: [], block: $5 }; |
|||
setLines($$, @1, @5); |
|||
} |
|||
; |
|||
|
|||
templateDefinitionStatment |
|||
: 'template' IDENTIFIER '(' identifierList ')' block |
|||
{ |
|||
$$ = { type: "TEMPLATEDEF", name: $2, params: $4.identifiers, block: $6 }; |
|||
setLines($$, @1, @6); |
|||
} |
|||
| 'template' IDENTIFIER '(' ')' block |
|||
{ |
|||
$$ = { type: "TEMPLATEDEF", name: $2, params: [], block: $5 }; |
|||
setLines($$, @1, @5); |
|||
} |
|||
; |
|||
|
|||
|
|||
identifierList |
|||
: identifierList ',' IDENTIFIER |
|||
{ |
|||
$1.identifiers.push($3); |
|||
setLines($1, @1, @3); |
|||
} |
|||
| IDENTIFIER %prec EMPTY |
|||
{ |
|||
$$ = { type: "IDENTIFIERLIST", identifiers: [$1] }; |
|||
setLines($$, @1); |
|||
} |
|||
; |
|||
|
|||
ifStatment |
|||
: 'if' '(' expression ')' statment 'else' statment |
|||
{ |
|||
if ($3.type == "NUMBER") { |
|||
$$ = !$3.value.eq(0) ? $5 : $7; |
|||
} else { |
|||
$$ = { type: "IF", condition: $3, then: $5, else: $7 }; |
|||
} |
|||
setLines($$, @1, @7); |
|||
} |
|||
| 'if' '(' expression ')' statment |
|||
{ |
|||
if ($3.type == "NUMBER") { |
|||
$$ = !$3.value.eq(0) ? $5 : { type: "NUMBER", value: bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "IF", condition: $3, then: $5 }; |
|||
} |
|||
setLines($$, @1, @5); |
|||
} |
|||
; |
|||
|
|||
forStatment |
|||
: 'for' '(' expression ';' expression ';' expression ')' statment |
|||
{ |
|||
$$ = { type: "FOR", init: $3, condition: $5, step: $7, body: $9 }; |
|||
setLines($$, @1, @9); |
|||
} |
|||
; |
|||
|
|||
whileStatment |
|||
: 'while' '(' expression ')' statment |
|||
{ |
|||
$$ = { type: "WHILE", condition: $3, body: $5 }; |
|||
setLines($$, @1, @5); |
|||
} |
|||
; |
|||
|
|||
doWhileStatment |
|||
: 'do' statment 'while' '(' expression ')' |
|||
{ |
|||
$$ = { type: "DOWHILE", condition: $5, body: $2 }; |
|||
setLines($$, @1, @6); |
|||
} |
|||
; |
|||
|
|||
returnStatment |
|||
: 'return' expression ';' |
|||
{ |
|||
$$ = { type: "RETURN", value: $2 }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| 'return' expression %prec ';' |
|||
{ |
|||
$$ = { type: "RETURN", value: $2 } |
|||
setLines($$, @1, @2); |
|||
} |
|||
; |
|||
|
|||
includeStatment |
|||
: 'include' STRING ';' |
|||
{ |
|||
$$ = { type: "INCLUDE", file: $2 }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| 'include' STRING %prec ';' |
|||
{ |
|||
$$ = { type: "INCLUDE", file: $2 } |
|||
setLines($$, @1, @2); |
|||
} |
|||
; |
|||
|
|||
block |
|||
: '{' statmentList '}' |
|||
{ |
|||
$$ = { type: "BLOCK", statements: $2.statments }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
; |
|||
|
|||
expressionStatment |
|||
: expression ';' %prec ';' |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| expression %prec ';' |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
expression |
|||
: e17 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e17 |
|||
: leftHandExpression '=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '+=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "+=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '-=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "-=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '*=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "*=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '/=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "/=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '%=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "%=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '<<=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "<<=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '>>=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: ">>=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '&=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "&=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '|=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "|=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '^=' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "^=", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '<==' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "<==", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e17 '==>' leftHandExpression |
|||
{ |
|||
$$ = { type: "OP", op: "<==", values: [$3, $1] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| leftHandExpression '<--' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "<--", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e17 '-->' leftHandExpression |
|||
{ |
|||
$$ = { type: "OP", op: "<--", values: [$3, $1] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e16 '===' e17 |
|||
{ |
|||
$$ = { type: "OP", op: "===", values: [$1, $3] }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e17 '?' e17 ':' e17 %prec TERCOND |
|||
{ |
|||
if ($1.type == "NUMBER") { |
|||
$$ = !$1.value.eq(0) ? $3 : $5; |
|||
} else { |
|||
$$ = { type: "OP", op: "?", values: [$1, $3, $5] }; |
|||
} |
|||
setLines($$, @1, @5); |
|||
} |
|||
| e16 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e16 |
|||
: rightArray |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| e15 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e15 |
|||
: e15 '||' e14 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: !$1.value.eq(0) || !$3.value.eq(0) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "||", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e14 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e14 |
|||
: e14 '&&' e13 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: !$1.value.eq(0) && !$3.value.eq(0) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "&&", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e13 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e13 |
|||
: e13 '|' e12 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.or($3.value).and(__MASK__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "|", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e12 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
|
|||
e12 |
|||
: e12 '^' e11 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.or($3.value).and(__MASK__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "^", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e11 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e11 |
|||
: e11 '&' e10 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.and($3.value).and(__MASK__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "&", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e10 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
|
|||
|
|||
|
|||
e10 |
|||
: e10 '==' e9 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.equals($3.value) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "==", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e10 '!=' e9 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.eq($3.value) ? bigInt(0) : bigInt(1) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "!=", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e9 %prec EMPTY |
|||
{ |
|||
$$ = $1 |
|||
} |
|||
; |
|||
|
|||
e9 |
|||
: e9 '<=' e7 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.lesserOrEquals($3.value) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "<=", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e9 '>=' e7 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.greaterOrEquals($3.value) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: ">=", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e9 '<' e7 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.lesser($3.value) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "<", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e9 '>' e7 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.greater($3.value) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: ">", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e7 %prec EMPTY |
|||
{ |
|||
$$ = $1 |
|||
} |
|||
; |
|||
|
|||
e7 |
|||
: e7 '<<' e6 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
let v = $3.value.greater(256) ? 256 : $3.value.value; |
|||
$$ = { type: "NUMBER", value: $1.value.shiftLeft(v).and(__MASK__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "<<", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e7 '>>' e6 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
let v = $3.value.greater(256) ? 256 : $3.value.value; |
|||
$$ = {t1ype: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: ">>", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e6 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e6 |
|||
: e6 '+' e5 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: ($1.value.plus($3.value)).mod(__P__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "+", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e6 '-' e5 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: ($1.value.plus(__P__).minus($3.value)).mod(__P__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "-", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e5 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
|
|||
e5 |
|||
: e5 '*' e4 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: ($1.value.times($3.value)).mod(__P__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "*", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e5 '/' e4 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: ($1.value.times($3.value.modInv(__P__))).mod(__P__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "/", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e5 '%' e4 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.mod($3.value) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "%", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e4 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e4 |
|||
: e4 '**' e3 |
|||
{ |
|||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { |
|||
$$ = { type: "NUMBER", value: $1.value.modPow($3.value, __P__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "**", values: [$1, $3] }; |
|||
} |
|||
setLines($$, @1, @3); |
|||
} |
|||
| e3 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
|
|||
e3 |
|||
: '++' leftHandExpression |
|||
{ |
|||
$$ = { type: "OP", op: "PLUSPLUSLEFT", values: [$2] }; |
|||
setLines($$, @1, @2); |
|||
} |
|||
| '--' leftHandExpression |
|||
{ |
|||
$$ = { type: "OP", op: "MINUSMINUSLEFT", values: [$2] }; |
|||
setLines($$, @1, @2); |
|||
} |
|||
| '+' e3 %prec UPLUS |
|||
{ |
|||
$$ = $2; |
|||
setLines($$, @1, @2); |
|||
} |
|||
| '-' e3 %prec UMINUS |
|||
{ |
|||
if ($2.type == "NUMBER") { |
|||
$$ = { type: "NUMBER", value: __P__.minus($2.value).mod(__P__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "UMINUS", values: [$2] }; |
|||
} |
|||
setLines($$, @1, @2); |
|||
} |
|||
| '!' e3 |
|||
{ |
|||
if ($2.type == "NUMBER") { |
|||
$$ = { type: "NUMBER", value: $2.value.eq(0) ? bigInt(1) : bigInt(0) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "!", values: [$2] }; |
|||
} |
|||
setLines($$, @1, @2); |
|||
} |
|||
| '~' e3 |
|||
{ |
|||
if ($2.type == "NUMBER") { |
|||
$$ = { type: "NUMBER", value: $2.value.xor(__MASK__) }; |
|||
} else { |
|||
$$ = { type: "OP", op: "~", values: [$2] }; |
|||
} |
|||
setLines($$, @1, @2); |
|||
} |
|||
| e2 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e2 |
|||
: leftHandExpression '++' %prec PLUSPLUSRIGHT |
|||
{ |
|||
$$ = {type: "OP", op: "PLUSPLUSRIGHT", values: [$1] }; |
|||
setLines($$, @1, @2); |
|||
} |
|||
| leftHandExpression '--' %prec MINUSMINUSRIGHT |
|||
{ |
|||
$$ = {type: "OP", op: "MINUSMINUSRIGHT", values: [$1] }; |
|||
setLines($$, @1, @2); |
|||
} |
|||
| functionCall |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
| e0 %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
e0 |
|||
: leftHandExpression %prec EMPTY |
|||
{ |
|||
$$ = $1 |
|||
} |
|||
| DECNUMBER |
|||
{ |
|||
$$ = {type: "NUMBER", value: bigInt($1).mod(__P__) } |
|||
setLines($$, @1); |
|||
} |
|||
| HEXNUMBER |
|||
{ |
|||
$$ = {type: "NUMBER", value: bigInt($1.substr(2).toUpperCase(), 16).mod(__P__) } |
|||
setLines($$, @1); |
|||
} |
|||
| '(' expression ')' %prec EMPTY |
|||
{ |
|||
$$ = $2; |
|||
setLines($$, @1, @3); |
|||
} |
|||
; |
|||
|
|||
leftHandExpression |
|||
: simpleLeftHandExpression '.' simpleLeftHandExpression %prec EMPTY |
|||
{ |
|||
$$ = {type: "PIN", component: $1, pin: $3 }; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| declaration %prec DECL |
|||
{ |
|||
$$ = $1 |
|||
} |
|||
| simpleLeftHandExpression %prec EMPTY |
|||
{ |
|||
$$ = $1 |
|||
} |
|||
; |
|||
|
|||
|
|||
|
|||
declaration |
|||
: 'var' simpleLeftHandExpression %prec DECL |
|||
{ |
|||
$$ = {type: "DECLARE", declareType: "VARIABLE", name: $2} |
|||
setLines($$, @1, @2); |
|||
} |
|||
| 'signal' simpleLeftHandExpression %prec DECL |
|||
{ |
|||
$$ = {type: "DECLARE", declareType: "SIGNAL", name: $2} |
|||
setLines($$, @1, @2); |
|||
} |
|||
| 'signal' 'input' simpleLeftHandExpression %prec DECL |
|||
{ |
|||
$$ = {type: "DECLARE", declareType: "SIGNALIN", name: $3}; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| 'signal' 'output' simpleLeftHandExpression %prec DECL |
|||
{ |
|||
$$ = {type: "DECLARE", declareType: "SIGNALOUT", name: $3}; |
|||
setLines($$, @1, @3); |
|||
} |
|||
| 'component' simpleLeftHandExpression %prec DECL |
|||
{ |
|||
$$ = {type: "DECLARE", declareType: "COMPONENT", name: $2} |
|||
setLines($$, @1, @2); |
|||
} |
|||
; |
|||
|
|||
simpleLeftHandExpression |
|||
: simpleLeftHandExpression array |
|||
{ |
|||
for (let i=0; i< $2.values.length; i++) { |
|||
$1.selectors.push($2.values[i]); |
|||
} |
|||
setLines($1, @1, @2); |
|||
} |
|||
| IDENTIFIER %prec EMPTY |
|||
{ |
|||
$$ = {type: "VARIABLE", name: $1 , selectors: []}; |
|||
setLines($$, @1); |
|||
} |
|||
; |
|||
|
|||
functionCall |
|||
: IDENTIFIER '(' expressionList ')' |
|||
{ |
|||
$$ = {type: "FUNCTIONCALL", name: $1, params: $3.expressions} |
|||
setLines($$, @1, @4); |
|||
} |
|||
| IDENTIFIER '(' ')' |
|||
{ |
|||
$$ = {type: "FUNCTIONCALL", name: $1, params: []} |
|||
setLines($$, @1, @3); |
|||
} |
|||
; |
|||
|
|||
expressionList |
|||
: expressionList ',' expression |
|||
{ |
|||
$1.expressions.push($3); |
|||
setLines($$, @1, @3); |
|||
} |
|||
| expression %prec ',' |
|||
{ |
|||
$$ = {type: "EXPRESSIONLST", expressions: [$1]}; |
|||
setLines($$, @1); |
|||
} |
|||
; |
|||
|
|||
rightArray |
|||
: array %prec EMPTY |
|||
{ |
|||
$$ = $1; |
|||
} |
|||
; |
|||
|
|||
array |
|||
: '[' expressionList ']' |
|||
{ |
|||
$$ = { type: "ARRAY", values: $2.expressions}; |
|||
setLines($$, @1, @3); |
|||
} |
|||
; |
|||
|
@ -0,0 +1 @@ |
|||
["1","3624381080","3624381080","0","0","0","1","1","0","0","1","0","1","0","1","0","1","0","1","1","1","1","0","0","0","0","0","0","0","0","1","1","0","1","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"] |
@ -0,0 +1,209 @@ |
|||
const bigInt = require("big-integer"); |
|||
|
|||
module.exports = calculateWitness; |
|||
|
|||
function calculateWitness(circuit, inputSignals) { |
|||
const ctx = new RTCtx(circuit); |
|||
|
|||
function iterateSelector(values, sels, cb) { |
|||
if (!Array.isArray(values)) { |
|||
return cb(sels, values); |
|||
} |
|||
for (let i=0; i<values.length; i++) { |
|||
sels.push(i); |
|||
iterateSelector(values[i], sels, cb); |
|||
sels.pop(i); |
|||
} |
|||
} |
|||
|
|||
ctx.setSignal("one", [], bigInt(1)); |
|||
|
|||
for (let c in ctx.notInitSignals) { |
|||
if (ctx.notInitSignals[c] == 0) ctx.triggerComponent(c); |
|||
} |
|||
|
|||
for (let s in inputSignals) { |
|||
ctx.currentComponent = "main"; |
|||
iterateSelector(inputSignals[s], [], function(selector, value) { |
|||
ctx.setSignal(s, selector, bigInt(value)); |
|||
}); |
|||
} |
|||
|
|||
for (let i=0; i<ctx.witness.length; i++) { |
|||
if (typeof(ctx.witness[i]) == "undefined") { |
|||
throw("Signal not assigned: " + ctx.circuit.witnessNames[i].join(", ")); |
|||
} |
|||
console.log(ctx.circuit.witnessNames[i].join(",") + " --> " + ctx.witness[i].toString()); |
|||
} |
|||
return ctx.witness; |
|||
} |
|||
|
|||
class RTCtx { |
|||
constructor(circuit) { |
|||
this.scopes = []; |
|||
this.circuit = circuit; |
|||
this.witness = []; |
|||
this.notInitSignals = {}; |
|||
for (let c in this.circuit.components) { |
|||
this.notInitSignals[c] = this.circuit.components[c].inputSignals; |
|||
if (this.notInitSignals == 0) { |
|||
this.currentComponent = c; |
|||
this.components.calc(this); |
|||
this.currentComponent = null; |
|||
} |
|||
} |
|||
} |
|||
|
|||
_sels2str(sels) { |
|||
let res = ""; |
|||
for (let i=0; i<sels.length; i++) { |
|||
res += `[${sels[i]}]`; |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
setPin(componentName, componentSels, signalName, signalSels, value) { |
|||
let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName; |
|||
fullName += this._sels2str(componentSels) + |
|||
"."+ |
|||
signalName+ |
|||
this._sels2str(signalSels); |
|||
this.setSignalFullName(fullName, value); |
|||
} |
|||
|
|||
setSignal(name, sels, value) { |
|||
let fullName = this.currentComponent ? this.currentComponent + "." + name : name; |
|||
fullName += this._sels2str(sels); |
|||
this.setSignalFullName(fullName, value); |
|||
} |
|||
|
|||
triggerComponent(c) { |
|||
console.log("Component Treiggered: " + c); |
|||
|
|||
// Set notInitSignals to -1 to not initialize again
|
|||
this.notInitSignals[c] --; |
|||
const oldComponent = this.currentComponent; |
|||
this.currentComponent = c; |
|||
const template = this.circuit.components[c].template; |
|||
|
|||
const newScope = {}; |
|||
for (let p in this.circuit.components[c].params) { |
|||
newScope[p] = this.circuit.components[c].params[p]; |
|||
} |
|||
|
|||
const oldScope = this.scopes; |
|||
this.scopes = [ this.scopes[0], newScope ]; |
|||
|
|||
// TODO set params.
|
|||
|
|||
this.circuit.templates[template](this); |
|||
this.scopes = oldScope; |
|||
this.currentComponent = oldComponent; |
|||
} |
|||
|
|||
callFunction(functionName, params) { |
|||
|
|||
const newScope = {}; |
|||
for (let p=0; p<this.circuit.functionParams[functionName].length; p++) { |
|||
const paramName = this.circuit.functionParams[functionName][p]; |
|||
newScope[paramName] = params[p]; |
|||
} |
|||
|
|||
const oldScope = this.scopes; |
|||
this.scopes = [ this.scopes[0], newScope ]; |
|||
|
|||
// TODO set params.
|
|||
|
|||
const res = this.circuit.functions[functionName](this); |
|||
this.scopes = oldScope; |
|||
|
|||
return res; |
|||
} |
|||
|
|||
setSignalFullName(fullName, value) { |
|||
console.log("set " + fullName + " <-- " + value.toString()); |
|||
const sId = this.circuit.signals[fullName].id; |
|||
let firstInit =false; |
|||
if (!this.witness[sId]) { |
|||
firstInit = true; |
|||
} |
|||
this.witness[sId] = value; |
|||
const callComponents = []; |
|||
for (let i=0; i<this.circuit.witnessNames[sId].length; i++) { |
|||
const ss = this.circuit.witnessNames[sId][i]; |
|||
if (this.circuit.signals[ss].direction == "IN") { |
|||
if (firstInit) this.notInitSignals[ this.circuit.signals[ss].component] --; |
|||
callComponents.push(this.circuit.signals[ss].component); |
|||
} |
|||
} |
|||
for (let i in callComponents) { |
|||
const c= callComponents[i]; |
|||
if (this.notInitSignals[c] == 0) this.triggerComponent(c); |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
setVar(name, sels, value) { |
|||
function setVarArray(a, sels2, value) { |
|||
if (sels2.length == 1) { |
|||
a[sels2[0]] = value; |
|||
} else { |
|||
if (typeof(a[sels2[0]]) == "undefined") a[sels2[0]] = []; |
|||
setVarArray(a[sels2[0]], sels2.slice(1), value); |
|||
} |
|||
} |
|||
const scope = this.scopes[this.scopes.length-1]; |
|||
if (sels.length == 0) { |
|||
scope[name] = value; |
|||
} else { |
|||
if (typeof(scope[name]) == "undefined") scope[name] = []; |
|||
setVarArray(scope[name], sels, value); |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
getVar(name, sels) { |
|||
function select(a, sels2) { |
|||
return (sels2.length == 0) ? a : select(a[sels2[0]], sels2.slice(1)); |
|||
} |
|||
for (let i=this.scopes.length-1; i>=0; i--) { |
|||
if (typeof(this.scopes[i][name]) != "undefined") return select(this.scopes[i][name], sels); |
|||
} |
|||
throw new Error("Variable not defined: " + name); |
|||
} |
|||
|
|||
getSignal(name, sels) { |
|||
let fullName = name=="one" ? "one" : this.currentComponent + "." + name; |
|||
fullName += this._sels2str(sels); |
|||
return this.getSignalFullName(fullName); |
|||
} |
|||
|
|||
|
|||
getPin(componentName, componentSels, signalName, signalSels) { |
|||
let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName; |
|||
fullName += this._sels2str(componentSels) + |
|||
"."+ |
|||
signalName+ |
|||
this._sels2str(signalSels); |
|||
return this.getSignalFullName(fullName); |
|||
} |
|||
|
|||
getSignalFullName(fullName) { |
|||
const sId = this.circuit.signals[fullName].id; |
|||
if (typeof(this.witness[sId]) == "undefined") { |
|||
throw new Error("Signal not initialized: "+fullName); |
|||
} |
|||
console.log("get --->" + fullName + " = " + this.witness[sId].toString() ); |
|||
return this.witness[sId]; |
|||
} |
|||
|
|||
assert(a,b) { |
|||
const ba = bigInt(a); |
|||
const bb = bigInt(b); |
|||
if (!ba.equals(bb)) { |
|||
throw new Error("Constrain doesn't match: " + ba.toString() + " != " + bb.toString()); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,156 @@ |
|||
|
|||
const fs = require("fs"); |
|||
const path = require("path"); |
|||
const bigInt = require("big-integer"); |
|||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); |
|||
const __MASK__ = new bigInt(2).pow(253).minus(1); |
|||
const assert = require("assert"); |
|||
const gen = require("./gencode"); |
|||
const exec = require("./exec"); |
|||
const lc = require("./lcalgebra"); |
|||
|
|||
|
|||
const argv = require("optimist") |
|||
.alias("c", "circuit") |
|||
.alias("o", "output") |
|||
.alias("w", "witnes") |
|||
.argv; |
|||
|
|||
const parser = require("../jaz.js").parser; |
|||
|
|||
const fullFileName = path.resolve(process.cwd(), argv.circuit); |
|||
const fullFilePath = path.dirname(fullFileName); |
|||
|
|||
const src = fs.readFileSync(fullFileName, "utf8"); |
|||
const ast = parser.parse(src); |
|||
|
|||
assert(ast.type == "BLOCK"); |
|||
|
|||
const ctx = { |
|||
scopes: [{}], |
|||
signals: { |
|||
one: { |
|||
fullName: "one", |
|||
value: bigInt(1), |
|||
equivalence: "", |
|||
direction: "" |
|||
} |
|||
}, |
|||
currentComponent: "", |
|||
constrains: [], |
|||
components: {}, |
|||
templates: {}, |
|||
functions: {}, |
|||
functionParams: {}, |
|||
filePath: fullFilePath, |
|||
fileName: fullFileName |
|||
}; |
|||
|
|||
exec(ctx, ast); |
|||
|
|||
reduceConstrains(ctx); |
|||
generateWitnessNames(ctx); |
|||
generateWitnessConstrains(ctx); |
|||
|
|||
if (ctx.error) { |
|||
console.log(`ERROR at ${ctx.error.errFile}:${ctx.error.pos.first_line},${ctx.error.pos.first_column}-${ctx.error.pos.last_line},${ctx.error.pos.last_column} ${ctx.error.errStr}`); |
|||
console.log(JSON.stringify(ctx.error.ast, null, 1)); |
|||
process.exit(1); |
|||
} |
|||
|
|||
/* |
|||
console.log("SIGNALS"); |
|||
console.log("=========="); |
|||
for (let key in ctx.signals) { |
|||
const signal = ctx.signals[key]; |
|||
console.log(signal.fullName); |
|||
} |
|||
|
|||
console.log("CONSTRAINS"); |
|||
console.log("=========="); |
|||
for (let i=0; i<ctx.constrains.length; i++) { |
|||
console.log(lc.toString(ctx.constrains[i], ctx) + " === 0"); |
|||
} |
|||
*/ |
|||
ctx.scopes = [{}]; |
|||
|
|||
const mainCode = gen(ctx,ast); |
|||
if (ctx.error) { |
|||
console.log(`ERROR at ${ctx.error.pos.first_line},${ctx.error.pos.first_column}-${ctx.error.pos.last_line},${ctx.error.pos.last_column} ${ctx.error.errStr}`); |
|||
console.log(JSON.stringify(ctx.error.ast, null, 1)); |
|||
process.exit(1); |
|||
} |
|||
|
|||
|
|||
let outCode = ""; |
|||
outCode += "const bigInt = require(\"big-integer\");\n"; |
|||
outCode += "const __P__ = new bigInt(\"21888242871839275222246405745257275088696311157297823662689037894645226208583\");\n"; |
|||
outCode += "const __MASK__ = new bigInt(2).pow(253).minus(1);\n"; |
|||
outCode += "const circuit = {};\n"; |
|||
outCode += "module.exports = circuit;\n\n"; |
|||
outCode += `circuit.signals=${JSON.stringify(ctx.signals, null, 1)};\n\n`; |
|||
outCode += `circuit.components=${JSON.stringify(ctx.components, null, 1)};\n\n`; |
|||
outCode += `circuit.signalConstrains=${JSON.stringify(ctx.constrains, null, 1)};\n\n`; |
|||
outCode += `circuit.witnessNames=${JSON.stringify(ctx.witnessNames, null, 1)};\n\n`; |
|||
outCode += mainCode; |
|||
outCode += "\ncircuit.templates = {};\n"; |
|||
for (let t in ctx.templates) { |
|||
outCode += `\ncircuit.templates["${t}"] = ${ctx.templates[t]};\n`; |
|||
} |
|||
outCode += `circuit.functionParams=${JSON.stringify(ctx.functionParams, null, 1)};\n\n`; |
|||
outCode += "\ncircuit.functions = {};\n"; |
|||
for (let f in ctx.functions) { |
|||
outCode += `\ncircuit.functions["${f}"] = ${ctx.functions[f]};\n`; |
|||
} |
|||
|
|||
/* |
|||
console.log("CODE"); |
|||
console.log("===="); |
|||
console.log(outCode); |
|||
*/ |
|||
|
|||
|
|||
console.log("#Constrains:" +ctx.constrains.length); |
|||
|
|||
fs.writeFileSync(argv.output, outCode, "utf8"); |
|||
|
|||
function generateWitnessNames(ctx) { |
|||
ctx.witnessNames = []; |
|||
for (let c in ctx.components) { |
|||
ctx.components[c].inputSignals = 0; |
|||
} |
|||
for (let s in ctx.signals) { |
|||
const signal = ctx.signals[s]; |
|||
let lSignal = signal; |
|||
while (lSignal.equivalence) { |
|||
lSignal = ctx.signals[lSignal.equivalence]; |
|||
} |
|||
if ( typeof(lSignal.id) === "undefined" ) { |
|||
lSignal.id = ctx.witnessNames.length; |
|||
ctx.witnessNames.push([]); |
|||
} |
|||
if (signal.direction == "IN") { |
|||
ctx.components[signal.component].inputSignals++; |
|||
} |
|||
|
|||
signal.id = lSignal.id; |
|||
ctx.witnessNames[signal.id].push(signal.fullName); |
|||
} |
|||
} |
|||
|
|||
function reduceConstrains(ctx) { |
|||
const newConstrains = []; |
|||
for (let i=0; i<ctx.constrains.length; i++) { |
|||
const c = lc.canonize(ctx, ctx.constrains[i]); |
|||
if (!lc.isZero(c)) { |
|||
newConstrains.push(c); |
|||
} |
|||
} |
|||
ctx.constrains = newConstrains; |
|||
} |
|||
|
|||
function generateWitnessConstrains(ctx) { |
|||
|
|||
} |
|||
|
|||
|
@ -0,0 +1,874 @@ |
|||
const path = require("path"); |
|||
const fs = require("fs"); |
|||
|
|||
const bigInt = require("big-integer"); |
|||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); |
|||
const __MASK__ = new bigInt(2).pow(253).minus(1); |
|||
|
|||
const lc = require("./lcalgebra"); |
|||
const parser = require("../jaz.js").parser; |
|||
|
|||
/* TODO: Add lines information |
|||
|
|||
function setLines(dst, first, last) { |
|||
last = last || first; |
|||
dst.first_line = first.first_line; |
|||
dst.first_column = first.first_column; |
|||
dst.last_line = last.last_line; |
|||
dst.last_column = last.last_column; |
|||
} |
|||
*/ |
|||
|
|||
module.exports = exec; |
|||
|
|||
|
|||
function exec(ctx, ast) { |
|||
if (!ast) { |
|||
return error(ctx, ast, "Null AST"); |
|||
} |
|||
if ((ast.type == "NUMBER") || (ast.type == "LINEARCOMBINATION") || (ast.type =="SIGNAL") || (ast.type == "QEQ")) { |
|||
return ast; |
|||
} else if (ast.type == "VARIABLE") { |
|||
return execVariable(ctx, ast); |
|||
} else if (ast.type == "PIN") { |
|||
return execPin(ctx, ast); |
|||
} else if (ast.type == "OP") { |
|||
if (ast.op == "=") { |
|||
return execVarAssignement(ctx, ast); |
|||
} else if (ast.op == "<--") { |
|||
return execSignalAssign(ctx, ast); |
|||
} else if (ast.op == "<==") { |
|||
return execSignalAssignConstrain(ctx, ast); |
|||
} else if (ast.op == "===") { |
|||
return execConstrain(ctx, ast); |
|||
} else if (ast.op == "+=") { |
|||
return execVarAddAssignement(ctx, ast); |
|||
} else if (ast.op == "*=") { |
|||
return execVarMulAssignement(ctx, ast); |
|||
} else if (ast.op == "+") { |
|||
return execAdd(ctx, ast); |
|||
} else if (ast.op == "-") { |
|||
return execSub(ctx, ast); |
|||
} else if (ast.op == "UMINUS") { |
|||
return execUMinus(ctx, ast); |
|||
} else if (ast.op == "*") { |
|||
return execMul(ctx, ast); |
|||
} else if (ast.op == "PLUSPLUSRIGHT") { |
|||
return execPlusPlusRight(ctx, ast); |
|||
} else if (ast.op == "PLUSPLUSLEFT") { |
|||
return execPlusPlusLeft(ctx, ast); |
|||
} else if (ast.op == "**") { |
|||
return execExp(ctx, ast); |
|||
} else if (ast.op == "&") { |
|||
return execBAnd(ctx, ast); |
|||
} else if (ast.op == "<<") { |
|||
return execShl(ctx, ast); |
|||
} else if (ast.op == ">>") { |
|||
return execShr(ctx, ast); |
|||
} else if (ast.op == "<") { |
|||
return execLt(ctx, ast); |
|||
} else if (ast.op == "==") { |
|||
return execEq(ctx, ast); |
|||
} else if (ast.op == "?") { |
|||
return execTerCon(ctx, ast); |
|||
} else { |
|||
error(ctx, ast, "Invalid operation: " + ast.op); |
|||
} |
|||
} else if (ast.type == "DECLARE") { |
|||
if (ast.declareType == "COMPONENT") { |
|||
return execDeclareComponent(ctx, ast); |
|||
} else if ((ast.declareType == "SIGNALIN")|| |
|||
(ast.declareType == "SIGNALOUT")|| |
|||
(ast.declareType == "SIGNAL")) { |
|||
return execDeclareSignal(ctx, ast); |
|||
} else if (ast.declareType == "VARIABLE") { |
|||
return execDeclareVariable(ctx, ast); |
|||
} else { |
|||
error(ctx, ast, "Invalid declaration: " + ast.declareType); |
|||
} |
|||
} else if (ast.type == "FUNCTIONCALL") { |
|||
return execFunctionCall(ctx, ast); |
|||
} else if (ast.type == "BLOCK") { |
|||
return execBlock(ctx, ast); |
|||
} else if (ast.type == "FOR") { |
|||
return execFor(ctx, ast); |
|||
} else if (ast.type == "WHILE") { |
|||
return execWhile(ctx, ast); |
|||
} else if (ast.type == "RETURN") { |
|||
return execReturn(ctx, ast); |
|||
} else if (ast.type == "TEMPLATEDEF") { |
|||
return execTemplateDef(ctx, ast); |
|||
} else if (ast.type == "FUNCTIONDEF") { |
|||
return execFunctionDef(ctx, ast); |
|||
} else if (ast.type == "INCLUDE") { |
|||
return execInclude(ctx, ast); |
|||
} else if (ast.type == "ARRAY") { |
|||
return execArray(ctx, ast); |
|||
} else { |
|||
error(ctx, ast, "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 iterateSelectors(ctx, sizes, baseName, fn) { |
|||
if (sizes.length == 0) { |
|||
return fn(baseName); |
|||
} |
|||
const res = []; |
|||
for (let i=0; i<sizes[0]; i++) { |
|||
res.push(iterateSelectors(ctx, sizes.slice(1), baseName+"["+i+"]", fn)); |
|||
if (ctx.error) return null; |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
function setScope(ctx, name, selectors, value) { |
|||
let l = getScopeLevel(ctx, name); |
|||
if (l==-1) l= ctx.scopes.length-1; |
|||
|
|||
if (selectors.length == 0) { |
|||
ctx.scopes[l][name] = value; |
|||
} else { |
|||
setScopeArray(ctx.scopes[l][name], selectors); |
|||
} |
|||
|
|||
function setScopeArray(a, sels) { |
|||
if (sels.length == 1) { |
|||
a[sels[0]] = value; |
|||
} else { |
|||
setScopeArray(a[sels[0]], sels.slice(1)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function getScope(ctx, name, selectors) { |
|||
|
|||
const sels = []; |
|||
if (selectors) { |
|||
for (let i=0; i< selectors.length; i++) { |
|||
const idx = exec(ctx, selectors[i]); |
|||
if (ctx.error) return; |
|||
|
|||
if (idx.type != "NUMBER") return error(ctx, selectors[i], "expected a number"); |
|||
sels.push( idx.value.toJSNumber() ); |
|||
} |
|||
} |
|||
|
|||
|
|||
function select(v, s) { |
|||
s = s || []; |
|||
if (s.length == 0) return v; |
|||
return select(v[s[0]], s.slice(1)); |
|||
} |
|||
|
|||
for (let i=ctx.scopes.length-1; i>=0; i--) { |
|||
if (ctx.scopes[i][name]) return select(ctx.scopes[i][name], sels); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
function getScopeLevel(ctx, name) { |
|||
for (let i=ctx.scopes.length-1; i>=0; i--) { |
|||
if (ctx.scopes[i][name]) return i; |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
function execBlock(ctx, ast) { |
|||
for (let i=0; i<ast.statements.length; i++) { |
|||
exec(ctx, ast.statements[i]); |
|||
if (ctx.returnValue) return; |
|||
if (ctx.error) return; |
|||
} |
|||
} |
|||
|
|||
function execTemplateDef(ctx, ast) { |
|||
const scope = ctx.scopes[0]; // Lets put templates always in top scope.
|
|||
// const scope = ctx.scopes[ctx.scopes.length-1];
|
|||
if (getScope(ctx, ast.name)) { |
|||
return error(ctx, ast, "Name already exists: "+ast.name); |
|||
} |
|||
scope[ast.name] = { |
|||
type: "TEMPLATE", |
|||
params: ast.params, |
|||
block: ast.block, |
|||
fileName: ctx.fileName, |
|||
filePath: ctx.filePath, |
|||
scopes: copyScope(ctx.scopes) |
|||
}; |
|||
} |
|||
|
|||
function execFunctionDef(ctx, ast) { |
|||
const scope = ctx.scopes[0]; // Lets put functions always in top scope.
|
|||
// const scope = ctx.scopes[ctx.scopes.length-1];
|
|||
if (getScope(ctx, ast.name)) { |
|||
return error(ctx, ast, "Name already exists: "+ast.name); |
|||
} |
|||
ctx.functionParams[ast.name] = ast.params; |
|||
scope[ast.name] = { |
|||
type: "FUNCTION", |
|||
params: ast.params, |
|||
block: ast.block, |
|||
fileName: ctx.fileName, |
|||
filePath: ctx.filePath, |
|||
scopes: copyScope(ctx.scopes) |
|||
}; |
|||
} |
|||
|
|||
|
|||
function execDeclareComponent(ctx, ast) { |
|||
const scope = ctx.scopes[ctx.scopes.length-1]; |
|||
|
|||
if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); |
|||
if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); |
|||
|
|||
const baseName = ctx.currentComponent ? ctx.currentComponent + "." + ast.name.name : ast.name.name; |
|||
|
|||
const sizes=[]; |
|||
for (let i=0; i< ast.name.selectors.length; i++) { |
|||
const size = exec(ctx, ast.name.selectors[i]); |
|||
if (ctx.error) return; |
|||
|
|||
if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number"); |
|||
|
|||
sizes.push( size.value.toJSNumber() ); |
|||
} |
|||
|
|||
|
|||
scope[ast.name.name] = iterateSelectors(ctx, sizes, baseName, function(fullName) { |
|||
|
|||
ctx.components[fullName] = "UNINSTANTIATED"; |
|||
|
|||
return { |
|||
type: "COMPONENT", |
|||
fullName: fullName |
|||
}; |
|||
}); |
|||
|
|||
return { |
|||
type: "VARIABLE", |
|||
name: ast.name.name, |
|||
selectors: [] |
|||
}; |
|||
} |
|||
|
|||
function execInstantiateComponet(ctx, vr, fn) { |
|||
|
|||
if (vr.type != "VARIABLE") return error(ctx, fn, "Left hand instatiate component must be a variable"); |
|||
if (fn.type != "FUNCTIONCALL") return error(ctx, fn, "Right type of instantiate component must be a function call"); |
|||
|
|||
const componentName = vr.name; |
|||
const templateName = fn.name; |
|||
|
|||
const scopeLevel = getScopeLevel(ctx, templateName); |
|||
if (scopeLevel == -1) return error(ctx,fn, "Invalid Template"); |
|||
const template = getScope(ctx, templateName); |
|||
|
|||
if (template.type != "TEMPLATE") return error(ctx, fn, "Invalid Template"); |
|||
|
|||
|
|||
const paramValues = []; |
|||
for (let i=0; i< fn.params.length; i++) { |
|||
const v = exec(ctx, fn.params[i]); |
|||
if (ctx.error) return; |
|||
|
|||
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"); |
|||
|
|||
const vv = getScope(ctx, componentName, vr.selectors); |
|||
|
|||
instantiateComponent(vv); |
|||
|
|||
function instantiateComponent(varVal) { |
|||
if (Array.isArray(varVal)) { |
|||
for (let i =0; i<varVal.length; i++) { |
|||
instantiateComponent(varVal[i]); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
if (ctx.components[varVal.fullName] != "UNINSTANTIATED") error(ctx, fn, "Component already instantiated"); |
|||
|
|||
const oldComponent = ctx.currentComponent; |
|||
const oldFileName = ctx.fileName; |
|||
const oldFilePath = ctx.filePath; |
|||
ctx.currentComponent = varVal.fullName; |
|||
|
|||
ctx.components[ctx.currentComponent] = { |
|||
signals: [], |
|||
params: {} |
|||
}; |
|||
|
|||
const oldScopes = ctx.scopes; |
|||
|
|||
ctx.scopes = oldScopes.slice(0, scopeLevel+1); |
|||
|
|||
const scope = {}; |
|||
for (let i=0; i< template.params.length; i++) { |
|||
scope[template.params[i]] = { |
|||
type: "NUMBER", |
|||
value: paramValues[i] |
|||
}; |
|||
ctx.components[ctx.currentComponent].params[template.params[i]] = paramValues[i]; |
|||
} |
|||
|
|||
ctx.components[ctx.currentComponent].template = templateName; |
|||
ctx.fileName = template.fileName; |
|||
ctx.filePath = template.filePath; |
|||
ctx.scopes = copyScope( template.scopes ); |
|||
ctx.scopes.push(scope); |
|||
|
|||
execBlock(ctx, template.block); |
|||
|
|||
ctx.fileName = oldFileName; |
|||
ctx.filePath = oldFilePath; |
|||
ctx.currentComponent = oldComponent; |
|||
ctx.scopes = oldScopes; |
|||
} |
|||
} |
|||
|
|||
function execFunctionCall(ctx, ast) { |
|||
|
|||
const scopeLevel = getScopeLevel(ctx, ast.name); |
|||
if (scopeLevel == -1) return error(ctx, ast, "Function not defined: " + ast.name); |
|||
const fnc = getScope(ctx, ast.name); |
|||
|
|||
if (fnc.type != "FUNCTION") return error(ctx, ast, "Not a function: " + ast.name); |
|||
|
|||
const paramValues = []; |
|||
for (let i=0; i< ast.params.length; i++) { |
|||
const v = exec(ctx, ast.params[i]); |
|||
if (ctx.error) return; |
|||
|
|||
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"); |
|||
|
|||
const oldFileName = ctx.fileName; |
|||
const oldFilePath = ctx.filePath; |
|||
|
|||
const oldScopes = ctx.scopes; |
|||
|
|||
ctx.scopes = oldScopes.slice(0, scopeLevel+1); |
|||
|
|||
const scope = {}; |
|||
for (let i=0; i< fnc.params.length; i++) { |
|||
scope[fnc.params[i]] = { |
|||
type: "NUMBER", |
|||
value: paramValues[i] |
|||
}; |
|||
} |
|||
|
|||
ctx.fileName = fnc.fileName; |
|||
ctx.filePath = fnc.filePath; |
|||
ctx.scopes = copyScope( fnc.scopes ); |
|||
ctx.scopes.push(scope); |
|||
|
|||
execBlock(ctx, fnc.block); |
|||
|
|||
const res = ctx.returnValue; |
|||
ctx.returnValue = null; |
|||
|
|||
ctx.fileName = oldFileName; |
|||
ctx.filePath = oldFilePath; |
|||
ctx.scopes = oldScopes; |
|||
|
|||
return res; |
|||
} |
|||
|
|||
function execReturn(ctx, ast) { |
|||
ctx.returnValue = exec(ctx, ast.value); |
|||
return; |
|||
} |
|||
|
|||
function execDeclareSignal(ctx, ast) { |
|||
const scope = ctx.scopes[ctx.scopes.length-1]; |
|||
|
|||
if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); |
|||
if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); |
|||
|
|||
const baseName = ctx.currentComponent ? ctx.currentComponent + "." + ast.name.name : ast.name.name; |
|||
|
|||
const sizes=[]; |
|||
for (let i=0; i< ast.name.selectors.length; i++) { |
|||
const size = exec(ctx, ast.name.selectors[i]); |
|||
if (ctx.error) return; |
|||
|
|||
if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number"); |
|||
sizes.push( size.value.toJSNumber() ); |
|||
} |
|||
|
|||
scope[ast.name.name] = iterateSelectors(ctx, sizes, baseName, function(fullName) { |
|||
ctx.signals[fullName] = { |
|||
fullName: fullName, |
|||
direction: ast.declareType == "SIGNALIN" ? "IN" : (ast.declareType == "SIGNALOUT" ? "OUT" : ""), |
|||
component: ctx.currentComponent, |
|||
equivalence: "", |
|||
alias: [fullName] |
|||
}; |
|||
ctx.components[ctx.currentComponent].signals.push(fullName); |
|||
return { |
|||
type: "SIGNAL", |
|||
fullName: fullName, |
|||
}; |
|||
}); |
|||
return { |
|||
type: "VARIABLE", |
|||
name: ast.name.name, |
|||
selectors: [] |
|||
}; |
|||
} |
|||
|
|||
function execDeclareVariable(ctx, ast) { |
|||
const scope = ctx.scopes[ctx.scopes.length-1]; |
|||
|
|||
if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid linear combination name"); |
|||
if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); |
|||
|
|||
const sizes=[]; |
|||
for (let i=0; i< ast.name.selectors.length; i++) { |
|||
const size = exec(ctx, ast.name.selectors[i]); |
|||
if (ctx.error) return; |
|||
|
|||
if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number"); |
|||
sizes.push( size.value.toJSNumber() ); |
|||
} |
|||
|
|||
scope[ast.name.name] = iterateSelectors(ctx, sizes, "", function() { |
|||
return { |
|||
type: "NUMBER", |
|||
value: bigInt(0) |
|||
}; |
|||
}); |
|||
|
|||
return { |
|||
type: "VARIABLE", |
|||
name: ast.name.name, |
|||
selectors: [] |
|||
}; |
|||
} |
|||
|
|||
function execVariable(ctx, ast) { |
|||
const v = getScope(ctx, ast.name, ast.selectors); |
|||
if (ctx.error) return; |
|||
|
|||
if (!v) return error(ctx, ast, "Variable not defined"); |
|||
let res; |
|||
res=v; |
|||
return res; |
|||
} |
|||
|
|||
function execPin(ctx, ast) { |
|||
const component = getScope(ctx, ast.component.name, ast.component.selectors); |
|||
if (!component) return error(ctx, ast.component, "Component does not exists: "+ast.component.name); |
|||
if (ctx.error) return; |
|||
let signalFullName = component.fullName + "." + ast.pin.name; |
|||
for (let i=0; i< ast.pin.selectors.length; i++) { |
|||
const sel = exec(ctx, ast.pin.selectors[i]); |
|||
if (ctx.error) return; |
|||
|
|||
if (sel.type != "NUMBER") return error(ctx, ast.pin.selectors[i], "expected a number"); |
|||
|
|||
signalFullName += "[" + sel.value.toJSNumber() + "]"; |
|||
} |
|||
if (!ctx.signals[signalFullName]) error(ctx, ast, "Signal not defined:" + signalFullName); |
|||
return { |
|||
type: "SIGNAL", |
|||
fullName: signalFullName |
|||
}; |
|||
} |
|||
|
|||
function execFor(ctx, ast) { |
|||
exec(ctx, ast.init); |
|||
if (ctx.error) return; |
|||
|
|||
let v = exec(ctx, ast.condition); |
|||
if (ctx.error) return; |
|||
|
|||
while ((v.value.neq(0))&&(!ctx.returnValue)) { |
|||
exec(ctx, ast.body); |
|||
if (ctx.error) return; |
|||
|
|||
exec(ctx, ast.step); |
|||
if (ctx.error) return; |
|||
|
|||
v = exec(ctx, ast.condition); |
|||
if (ctx.error) return; |
|||
} |
|||
} |
|||
|
|||
function execWhile(ctx, ast) { |
|||
let v = exec(ctx, ast.condition); |
|||
if (ctx.error) return; |
|||
|
|||
while ((v.value.neq(0))&&(!ctx.returnValue)) { |
|||
exec(ctx, ast.body); |
|||
if (ctx.error) return; |
|||
|
|||
v = exec(ctx, ast.condition); |
|||
if (ctx.error) return; |
|||
} |
|||
} |
|||
|
|||
|
|||
function execVarAssignement(ctx, ast) { |
|||
let v; |
|||
if (ast.values[0].type == "DECLARE") { |
|||
v = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
} else { |
|||
v = ast.values[0]; |
|||
} |
|||
const num = getScope(ctx, v.name, v.selectors); |
|||
if (ctx.error) return; |
|||
|
|||
if (typeof(num) != "object") return error(ctx, ast, "Variable not defined"); |
|||
|
|||
if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]); |
|||
|
|||
const res = exec(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
|
|||
setScope(ctx, v.name, v.selectors, res); |
|||
|
|||
return v; |
|||
} |
|||
|
|||
function execLt(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.lt(b.value) ? bigInt(1) : bigInt(0) |
|||
}; |
|||
} |
|||
|
|||
function execEq(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(1) : bigInt(0) |
|||
}; |
|||
} |
|||
|
|||
|
|||
function execBAnd(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.and(b.value).and(__MASK__) |
|||
}; |
|||
} |
|||
|
|||
function execShl(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" }; |
|||
const v = b.value.greater(256) ? 256 : b.value.value; |
|||
return { |
|||
type: "NUMBER", |
|||
value: a.value.shiftLeft(v).and(__MASK__) |
|||
}; |
|||
} |
|||
|
|||
function execShr(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" }; |
|||
const v = b.value.greater(256) ? 256 : b.value.value; |
|||
return { |
|||
type: "NUMBER", |
|||
value: a.value.shiftRight(v).and(__MASK__) |
|||
}; |
|||
} |
|||
|
|||
function execExp(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.modPow(b.value, __P__) |
|||
}; |
|||
} |
|||
|
|||
function execAdd(ctx, ast) { |
|||
const a = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
const b = exec(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
|
|||
const res = lc.add(a,b); |
|||
if (res.type == "ERROR") return error(ctx, ast, res.errStr); |
|||
|
|||
return res; |
|||
} |
|||
|
|||
function execSub(ctx, ast) { |
|||
const a = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
const b = exec(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
|
|||
const res = lc.sub(a,b); |
|||
if (res.type == "ERROR") return error(ctx, ast, res.errStr); |
|||
|
|||
return res; |
|||
} |
|||
|
|||
function execUMinus(ctx, ast) { |
|||
const a = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
|
|||
const res = lc.negate(a); |
|||
if (res.type == "ERROR") return error(ctx, ast, res.errStr); |
|||
|
|||
return res; |
|||
} |
|||
|
|||
function execMul(ctx, ast) { |
|||
const a = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
const b = exec(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
|
|||
const res = lc.mul(a,b); |
|||
if (res.type == "ERROR") return error(ctx, ast, res.errStr); |
|||
|
|||
return res; |
|||
} |
|||
|
|||
function execVarAddAssignement(ctx, ast) { |
|||
const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } ); |
|||
if (ctx.error) return; |
|||
return execVarAssignement(ctx, { values: [ast.values[0], res] }); |
|||
} |
|||
|
|||
function execVarMulAssignement(ctx, ast) { |
|||
const res = execMul(ctx,{ values: [ast.values[0], ast.values[1]] } ); |
|||
if (ctx.error) return; |
|||
return execVarAssignement(ctx, { values: [ast.values[0], res] }); |
|||
} |
|||
|
|||
function execPlusPlusRight(ctx, ast) { |
|||
const resBefore = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } ); |
|||
if (ctx.error) return; |
|||
execVarAssignement(ctx, { values: [ast.values[0], resAfter] }); |
|||
return resBefore; |
|||
} |
|||
|
|||
function execPlusPlusLeft(ctx, ast) { |
|||
if (ctx.error) return; |
|||
const resAfter = execAdd(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) { |
|||
const cond = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
|
|||
if (!cond.value) return { type: "NUMBER" }; |
|||
|
|||
if (cond.value.neq(0)) { |
|||
return exec(ctx, ast.values[1]); |
|||
} else { |
|||
return exec(ctx, ast.values[2]); |
|||
} |
|||
} |
|||
|
|||
function execSignalAssign(ctx, ast) { |
|||
let vDest; |
|||
if (ast.values[0].type == "DECLARE") { |
|||
vDest = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
} else { |
|||
vDest = ast.values[0]; |
|||
} |
|||
|
|||
let dst; |
|||
if (vDest.type == "VARIABLE") { |
|||
dst = getScope(ctx, vDest.name, vDest.selectors); |
|||
if (ctx.error) return; |
|||
} else if (vDest.type == "PIN") { |
|||
dst = execPin(ctx, vDest); |
|||
if (ctx.error) return; |
|||
} else { |
|||
error(ctx, ast, "Bad assignement"); |
|||
} |
|||
|
|||
if (!dst) return error(ctx, ast, "Signal not defined"); |
|||
if (dst.type != "SIGNAL") return error(ctx, ast, "Signal assigned to a non signal"); |
|||
|
|||
let sDest=ctx.signals[dst.fullName]; |
|||
if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.fullName); |
|||
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence]; |
|||
|
|||
if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice"); |
|||
|
|||
let src = exec(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
|
|||
|
|||
/* |
|||
let vSrc; |
|||
if (ast.values[1].type == "DECLARE") { |
|||
vSrc = exec(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
} else { |
|||
vSrc = ast.values[1]; |
|||
} |
|||
|
|||
if (vSrc.type == "VARIABLE") { |
|||
src = getScope(ctx, vSrc.name, vSrc.selectors); |
|||
if (!src) error(ctx, ast, "Variable not defined: " + vSrc.name); |
|||
if (ctx.error) return; |
|||
} else if (vSrc.type == "PIN") { |
|||
src = execPin(ctx, vSrc); |
|||
} |
|||
*/ |
|||
|
|||
let assignValue = true; |
|||
if (src.type == "SIGNAL") { |
|||
sDest.equivalence = src.fullName; |
|||
sDest.alias = sDest.alias.concat(src.alias); |
|||
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence]; |
|||
assignValue = false; |
|||
} |
|||
|
|||
if (assignValue) { |
|||
// const resLC = exec(ctx, vSrc);
|
|||
if (ctx.error) return; |
|||
|
|||
// const v = lc.evaluate(ctx, resLC);
|
|||
const v = lc.evaluate(ctx, src); |
|||
|
|||
if (v.value) { |
|||
sDest.value = v.value; |
|||
} |
|||
} |
|||
|
|||
return vDest; |
|||
} |
|||
|
|||
function execConstrain(ctx, ast) { |
|||
const a = exec(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
const b = exec(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
|
|||
const res = lc.sub(a,b); |
|||
if (res.type == "ERROR") return error(ctx, ast, res.errStr); |
|||
|
|||
if (!lc.isZero(res)) { |
|||
ctx.constrains.push(lc.toQEQ(res)); |
|||
} |
|||
|
|||
return res; |
|||
} |
|||
|
|||
function execSignalAssignConstrain(ctx, ast) { |
|||
const v = execSignalAssign(ctx,ast); |
|||
if (ctx.error) return; |
|||
execConstrain(ctx, ast); |
|||
if (ctx.error) return; |
|||
return v; |
|||
} |
|||
|
|||
function execInclude(ctx, ast) { |
|||
const incFileName = path.resolve(ctx.filePath, ast.file); |
|||
const incFilePath = path.dirname(incFileName); |
|||
|
|||
console.log("Include: "+incFileName); |
|||
|
|||
ctx.includedFiles = ctx.includedFiles || []; |
|||
if (ctx.includedFiles[incFileName]) return; |
|||
|
|||
ctx.includedFiles[incFileName] = true; |
|||
|
|||
const src = fs.readFileSync(incFileName, "utf8"); |
|||
|
|||
if (!src) return error(ctx, ast, "Include file not found: "+incFileName); |
|||
|
|||
const incAst = parser.parse(src); |
|||
|
|||
const oldFilePath = ctx.filePath; |
|||
const oldFileName = ctx.fileName; |
|||
ctx.filePath = incFilePath; |
|||
ctx.fileName = incFileName; |
|||
|
|||
exec(ctx, incAst); |
|||
|
|||
ast.block = incAst; |
|||
|
|||
ctx.filePath = oldFilePath; |
|||
ctx.fileName = oldFileName; |
|||
} |
|||
|
|||
function execArray(ctx, ast) { |
|||
const res = []; |
|||
|
|||
for (let i=0; i<ast.values.length; i++) { |
|||
res.push(exec(ctx, ast.values[i])); |
|||
} |
|||
|
|||
return res; |
|||
} |
|||
|
|||
function copyScope(scope) { |
|||
var scopesClone = []; |
|||
for (let i=0; i<scope.length; i++) { |
|||
scopesClone.push(scope[i]); |
|||
} |
|||
return scopesClone; |
|||
} |
|||
|
@ -0,0 +1,479 @@ |
|||
const bigInt = require("big-integer"); |
|||
|
|||
module.exports = gen; |
|||
|
|||
|
|||
function ident(text) { |
|||
let lines = text.split("\n"); |
|||
for (let i=0; i<lines.length; i++) { |
|||
if (lines[i]) lines[i] = " "+lines[i]; |
|||
} |
|||
return lines.join("\n"); |
|||
} |
|||
|
|||
function gen(ctx, ast) { |
|||
if ((ast.type == "NUMBER") ) { |
|||
return genNumber(ctx, ast); |
|||
} else if (ast.type == "VARIABLE") { |
|||
return genVariable(ctx, ast); |
|||
} else if (ast.type == "PIN") { |
|||
return genPin(ctx, ast); |
|||
} else if (ast.type == "OP") { |
|||
if (ast.op == "=") { |
|||
return genVarAssignement(ctx, ast); |
|||
} else if (ast.op == "<--") { |
|||
return genVarAssignement(ctx, ast); |
|||
} else if (ast.op == "<==") { |
|||
return genSignalAssignConstrain(ctx, ast); |
|||
} else if (ast.op == "===") { |
|||
return genConstrain(ctx, ast); |
|||
} else if (ast.op == "+=") { |
|||
return genVarAddAssignement(ctx, ast); |
|||
} else if (ast.op == "*=") { |
|||
return genVarMulAssignement(ctx, ast); |
|||
} else if (ast.op == "+") { |
|||
return genAdd(ctx, ast); |
|||
} else if (ast.op == "-") { |
|||
return genSub(ctx, ast); |
|||
} else if (ast.op == "UMINUS") { |
|||
return genUMinus(ctx, ast); |
|||
} else if (ast.op == "*") { |
|||
return genMul(ctx, ast); |
|||
} else if (ast.op == "PLUSPLUSRIGHT") { |
|||
return genPlusPlusRight(ctx, ast); |
|||
} else if (ast.op == "PLUSPLUSLEFT") { |
|||
return genPlusPlusLeft(ctx, ast); |
|||
} else if (ast.op == "**") { |
|||
return genExp(ctx, ast); |
|||
} else if (ast.op == "&") { |
|||
return genBAnd(ctx, ast); |
|||
} else if (ast.op == "<<") { |
|||
return genShl(ctx, ast); |
|||
} else if (ast.op == ">>") { |
|||
return genShr(ctx, ast); |
|||
} else if (ast.op == "<") { |
|||
return genLt(ctx, ast); |
|||
} else if (ast.op == "==") { |
|||
return genEq(ctx, ast); |
|||
} else if (ast.op == "?") { |
|||
return genTerCon(ctx, ast); |
|||
} else { |
|||
error(ctx, ast, "Invalid operation: " + ast.op); |
|||
} |
|||
} else if (ast.type == "DECLARE") { |
|||
if (ast.declareType == "COMPONENT") { |
|||
return genDeclareComponent(ctx, ast); |
|||
} else if ((ast.declareType == "SIGNALIN")|| |
|||
(ast.declareType == "SIGNALOUT")|| |
|||
(ast.declareType == "SIGNAL")) { |
|||
return genDeclareSignal(ctx, ast); |
|||
} else if (ast.declareType == "VARIABLE") { |
|||
return genDeclareVariable(ctx, ast); |
|||
} else { |
|||
error(ctx, ast, "Invalid declaration: " + ast.declareType); |
|||
} |
|||
} else if (ast.type == "FUNCTIONCALL") { |
|||
return genFunctionCall(ctx, ast); |
|||
} else if (ast.type == "BLOCK") { |
|||
return genBlock(ctx, ast); |
|||
} else if (ast.type == "FOR") { |
|||
return genFor(ctx, ast); |
|||
} else if (ast.type == "WHILE") { |
|||
return genWhile(ctx, ast); |
|||
} else if (ast.type == "RETURN") { |
|||
return genReturn(ctx, ast); |
|||
} else if (ast.type == "TEMPLATEDEF") { |
|||
return genTemplateDef(ctx, ast); |
|||
} else if (ast.type == "FUNCTIONDEF") { |
|||
return genFunctionDef(ctx, ast); |
|||
} else if (ast.type == "INCLUDE") { |
|||
return genInclude(ctx, ast); |
|||
} else if (ast.type == "ARRAY") { |
|||
return genArray(ctx, ast); |
|||
} else { |
|||
error(ctx, ast, "GEN -> 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, |
|||
ast: ast |
|||
}; |
|||
} |
|||
|
|||
|
|||
function getScope(ctx, name) { |
|||
for (let i=ctx.scopes.length-1; i>=0; i--) { |
|||
if (ctx.scopes[i][name]) return ctx.scopes[i][name]; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
|
|||
function genFunctionCall(ctx, ast) { |
|||
let S = "["; |
|||
for (let i=0; i<ast.params.length; i++) { |
|||
if (i>0) S += ","; |
|||
S += gen(ctx, ast.params[i]); |
|||
} |
|||
S+="]"; |
|||
|
|||
return `ctx.callFunction("${ast.name}", ${S})`; |
|||
} |
|||
|
|||
function genBlock(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 "{\n"+ident(body)+"}\n"; |
|||
} |
|||
|
|||
function genTemplateDef(ctx, ast) { |
|||
let S = "function(ctx) "; |
|||
|
|||
const newScope = {}; |
|||
for (let i=0; i< ast.params.length; i++) { |
|||
newScope[ast.params[i]] = { type: "VARIABLE" }; |
|||
} |
|||
|
|||
ctx.scopes.push(newScope); |
|||
S += genBlock(ctx, ast.block); |
|||
ctx.scopes.pop(); |
|||
|
|||
// const scope = ctx.scopes[ctx.scopes.length-1];
|
|||
const scope = ctx.scopes[0]; // Scope for templates is top
|
|||
|
|||
scope[ast.name] = { |
|||
type: "TEMPLATE" |
|||
}; |
|||
|
|||
ctx.templates[ast.name] = S; |
|||
return ""; |
|||
} |
|||
|
|||
function genFunctionDef(ctx, ast) { |
|||
let S = "function(ctx) "; |
|||
|
|||
const newScope = {}; |
|||
const params = []; |
|||
for (let i=0; i< ast.params.length; i++) { |
|||
newScope[ast.params[i]] = { type: "VARIABLE" }; |
|||
params.push(ast.params[i]); |
|||
} |
|||
|
|||
ctx.scopes.push(newScope); |
|||
S += genBlock(ctx, ast.block); |
|||
ctx.scopes.pop(); |
|||
|
|||
// const scope = ctx.scopes[0]; // Scope for templates is top
|
|||
const scope = ctx.scopes[ctx.scopes.length-1]; |
|||
|
|||
scope[ast.name] = { |
|||
type: "FUNCTION" |
|||
}; |
|||
|
|||
ctx.functions[ast.name] = S; |
|||
ctx.functionParams[ast.name] = params; |
|||
return ""; |
|||
} |
|||
|
|||
function genFor(ctx, ast) { |
|||
const init = gen(ctx, ast.init); |
|||
if (ctx.error) return; |
|||
const condition = gen(ctx, ast.condition); |
|||
if (ctx.error) return; |
|||
const step = gen(ctx, ast.step); |
|||
if (ctx.error) return; |
|||
const body = gen(ctx, ast.body); |
|||
if (ctx.error) return; |
|||
return `for (${init};${condition};${step})\n${body}`; |
|||
} |
|||
|
|||
function genWhile(ctx, ast) { |
|||
const condition = gen(ctx, ast.condition); |
|||
if (ctx.error) return; |
|||
const body = gen(ctx, ast.body); |
|||
if (ctx.error) return; |
|||
return `while (${condition})\n${body}`; |
|||
} |
|||
|
|||
function genReturn(ctx, ast) { |
|||
const value = gen(ctx, ast.value); |
|||
if (ctx.error) return; |
|||
return `return ${value};`; |
|||
} |
|||
|
|||
function genDeclareComponent(ctx, ast) { |
|||
const scope = ctx.scopes[ctx.scopes.length - 1]; |
|||
|
|||
if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); |
|||
if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); |
|||
|
|||
scope[ast.name.name] = { |
|||
type: "COMPONENT" |
|||
}; |
|||
|
|||
return ""; |
|||
} |
|||
|
|||
function genDeclareSignal(ctx, ast) { |
|||
const scope = ctx.scopes[ctx.scopes.length-1]; |
|||
|
|||
if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); |
|||
if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); |
|||
|
|||
scope[ast.name.name] = { |
|||
type: "SIGNAL" |
|||
}; |
|||
|
|||
return ""; |
|||
} |
|||
|
|||
function genDeclareVariable(ctx, ast) { |
|||
const scope = ctx.scopes[ctx.scopes.length-1]; |
|||
|
|||
if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); |
|||
if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); |
|||
|
|||
scope[ast.name.name] = { |
|||
type: "VARIABLE" |
|||
}; |
|||
|
|||
return ""; |
|||
} |
|||
|
|||
function genNumber(ctx, ast) { |
|||
return `"${ast.value.toString()}"`; |
|||
} |
|||
|
|||
function genVariable(ctx, ast) { |
|||
const v = getScope(ctx, ast.name); |
|||
|
|||
const sels = []; |
|||
for (let i=0; i<ast.selectors.length; i++) { |
|||
sels.push(gen(ctx, ast.selectors[i])); |
|||
if (ctx.error) return; |
|||
} |
|||
|
|||
|
|||
if (v.type == "VARIABLE") { |
|||
return `ctx.getVar("${ast.name}",[${sels.join(",")}])`; |
|||
} else if (v.type == "SIGNAL") { |
|||
return `ctx.getSignal("${ast.name}", [${sels.join(",")}])`; |
|||
} else { |
|||
error(ctx, ast, "Invalid Variable type"); |
|||
} |
|||
} |
|||
|
|||
function genPin(ctx, ast) { |
|||
let componentName = ast.component.name; |
|||
let componentSelectors = []; |
|||
for (let i=0; i<ast.component.selectors.length; i++) { |
|||
componentSelectors.push(gen(ctx, ast.component.selectors[i])); |
|||
} |
|||
componentSelectors = "["+ componentSelectors.join(",") + "]"; |
|||
let pinName = ast.pin.name; |
|||
let pinSelectors = []; |
|||
for (let i=0; i<ast.pin.selectors.length; i++) { |
|||
pinSelectors.push(gen(ctx, ast.pin.selectors[i])); |
|||
} |
|||
pinSelectors = "["+ pinSelectors.join(",") + "]"; |
|||
return `ctx.getPin("${componentName}", ${componentSelectors}, "${pinName}", ${pinSelectors})`; |
|||
} |
|||
|
|||
function genVarAssignement(ctx, ast) { |
|||
|
|||
const sels = []; |
|||
let vName; |
|||
|
|||
if (ctx.error) return; |
|||
|
|||
if (ast.values[0].type == "PIN") { |
|||
let componentName = ast.values[0].component.name; |
|||
let componentSelectors = []; |
|||
for (let i=0; i<ast.values[0].component.selectors.length; i++) { |
|||
componentSelectors.push(gen(ctx, ast.values[0].component.selectors[i])); |
|||
} |
|||
componentSelectors = "["+ componentSelectors.join(",") + "]"; |
|||
let pinName = ast.values[0].pin.name; |
|||
let pinSelectors = []; |
|||
for (let i=0; i<ast.values[0].pin.selectors.length; i++) { |
|||
pinSelectors.push(gen(ctx, ast.values[0].pin.selectors[i])); |
|||
} |
|||
pinSelectors = "["+ pinSelectors.join(",") + "]"; |
|||
const res = gen(ctx, ast.values[1]); |
|||
return `ctx.setPin("${componentName}", ${componentSelectors}, "${pinName}", ${pinSelectors}, ${res})`; |
|||
} |
|||
|
|||
if (ast.values[0].type == "DECLARE") { |
|||
gen(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
vName = ast.values[0].name.name; |
|||
} else { |
|||
vName = ast.values[0].name; |
|||
for (let i=0; i<ast.values[0].selectors.length; i++) { |
|||
sels.push(gen(ctx, ast.values[0].selectors[i])); |
|||
if (ctx.error) return; |
|||
} |
|||
} |
|||
|
|||
|
|||
const v = getScope(ctx, vName); |
|||
|
|||
// Component instantiation is already done.
|
|||
if (v.type == "COMPONENT") return ""; |
|||
|
|||
const res = gen(ctx, ast.values[1]); |
|||
if (v.type == "VARIABLE") { |
|||
return `ctx.setVar("${vName}", [${sels.join(",")}], ${res})`; |
|||
} else if (v.type == "SIGNAL") { |
|||
return `ctx.setSignal("${vName}", [${sels.join(",")}], ${res})`; |
|||
} else { |
|||
return error(ctx, ast, "Assigning to invalid"); |
|||
} |
|||
} |
|||
|
|||
function genConstrain(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 `ctx.assert(${a}, ${b})`; |
|||
} |
|||
|
|||
function genSignalAssignConstrain(ctx, ast) { |
|||
return genVarAssignement(ctx, ast) + ";\n" + genConstrain(ctx, ast); |
|||
} |
|||
|
|||
function genVarAddAssignement(ctx, ast) { |
|||
return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]}); |
|||
} |
|||
|
|||
function genVarMulAssignement(ctx, ast) { |
|||
return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]}); |
|||
} |
|||
|
|||
function genPlusPlusRight(ctx, ast) { |
|||
return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).minus(1).mod(__P__)`; |
|||
} |
|||
|
|||
function genPlusPlusLeft(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) { |
|||
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}).add(${b}).mod(__P__)`; |
|||
} |
|||
|
|||
function genMul(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}).times(${b}).mod(__P__)`; |
|||
} |
|||
|
|||
function genSub(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}).add(__P__).minus(${b}).mod(__P__)`; |
|||
} |
|||
|
|||
function genExp(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}).modPow(${b}, __P__)`; |
|||
} |
|||
|
|||
function genBAnd(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}).and(${b}).and(__MASK__)`; |
|||
} |
|||
|
|||
function genShl(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(${b}).greater(256) ? 0 : bigInt(${a}).shiftLeft(bigInt(${b}).value).and(__MASK__)`; |
|||
} |
|||
|
|||
function genShr(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(${b}).greater(256) ? 0 : bigInt(${a}).shiftRight(bigInt(${b}).value).and(__MASK__)`; |
|||
} |
|||
|
|||
function genLt(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}).lt(${b}) ? 1 : 0`; |
|||
} |
|||
|
|||
function genEq(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(${b}) ? 1 : 0`; |
|||
} |
|||
|
|||
function genUMinus(ctx, ast) { |
|||
const a = gen(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
return `__P__.minus(bigInt(${a})).mod(__P__)`; |
|||
} |
|||
|
|||
function genTerCon(ctx, ast) { |
|||
const a = gen(ctx, ast.values[0]); |
|||
if (ctx.error) return; |
|||
const b = gen(ctx, ast.values[1]); |
|||
if (ctx.error) return; |
|||
const c = gen(ctx, ast.values[2]); |
|||
if (ctx.error) return; |
|||
return `bigInt(${a}).neq(0) ? (${b}) : (${c})`; |
|||
} |
|||
|
|||
function genInclude(ctx, ast) { |
|||
return ast.block ? gen(ctx, ast.block) : ""; |
|||
} |
|||
|
|||
function genArray(ctx, ast) { |
|||
let S = "["; |
|||
for (let i=0; i<ast.values.length; i++) { |
|||
if (i>0) S += ","; |
|||
S += gen(ctx, ast.values[i]); |
|||
} |
|||
S+="]"; |
|||
return S; |
|||
} |
|||
|
@ -0,0 +1,441 @@ |
|||
/* |
|||
|
|||
NUMBER: a |
|||
|
|||
{ |
|||
type: "NUMBER", |
|||
value: bigInt(a) |
|||
} |
|||
|
|||
LINEARCOMBINATION: c1*s1 + c2*s2 + c3*s3 |
|||
|
|||
{ |
|||
type: "LINEARCOMBINATION", |
|||
values: { |
|||
s1: bigInt(c1), |
|||
s2: bigInt(c2), |
|||
s3: bigInt(c3) |
|||
} |
|||
} |
|||
|
|||
|
|||
QEQ: a*b + c WHERE a,b,c are LINEARCOMBINATION |
|||
{ |
|||
type: "QEQ" |
|||
a: { type: LINEARCOMBINATION, values: {...} }, |
|||
b: { type: LINEARCOMBINATION, values: {...} }, |
|||
c: { type: LINEARCOMBINATION, values: {...} } |
|||
} |
|||
*/ |
|||
|
|||
/* |
|||
+ NUM LC QEQ |
|||
NUM NUM LC QEQ |
|||
LC LC LC QEQ |
|||
QEQ QEQ QEQ ERR |
|||
|
|||
* NUM LC QEQ |
|||
NUM NUM LC QEQ |
|||
LC LC QEQ ERR |
|||
QEQ QEQ ERR ERR |
|||
*/ |
|||
|
|||
const bigInt = require("big-integer"); |
|||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); |
|||
|
|||
exports.add = add; |
|||
exports.mul = mul; |
|||
exports.evaluate = evaluate; |
|||
exports.negate = negate; |
|||
exports.sub = sub; |
|||
exports.toQEQ = toQEQ; |
|||
exports.isZero = isZero; |
|||
exports.toString = toString; |
|||
exports.canonize = canonize; |
|||
|
|||
function signal2lc(a) { |
|||
let lc; |
|||
if (a.type == "SIGNAL") { |
|||
lc = { |
|||
type: "LINEARCOMBINATION", |
|||
values: {} |
|||
}; |
|||
lc.values[a.fullName] = bigInt(1); |
|||
return lc; |
|||
} else { |
|||
return a; |
|||
} |
|||
} |
|||
|
|||
function clone(a) { |
|||
const res = {}; |
|||
res.type = a.type; |
|||
if (a.type == "NUMBER") { |
|||
res.value = bigInt(a.value); |
|||
} else if (a.type == "LINEARCOMBINATION") { |
|||
res.values = {}; |
|||
for (let k in a.values) { |
|||
res.values[k] = bigInt(a.values[k]); |
|||
} |
|||
} else if (a.type == "QEQ") { |
|||
res.a = clone(a.a); |
|||
res.b = clone(a.b); |
|||
res.c = clone(a.c); |
|||
} else if (a.type == "ERROR") { |
|||
res.errStr = a.errStr; |
|||
} else { |
|||
res.type = "ERROR"; |
|||
res.errStr = "Invilid type when clonning: "+a.type; |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
function add(_a, _b) { |
|||
const a = signal2lc(_a); |
|||
const b = signal2lc(_b); |
|||
if (a.type == "ERROR") return a; |
|||
if (b.type == "ERROR") return b; |
|||
if (a.type == "NUMBER") { |
|||
if (b.type == "NUMBER") { |
|||
return addNumNum(a,b); |
|||
} else if (b.type=="LINEARCOMBINATION") { |
|||
return addLCNum(b,a); |
|||
} else if (b.type=="QEQ") { |
|||
return addQEQNum(b,a); |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Add Invalid Type 2: "+b.type }; |
|||
} |
|||
} else if (a.type=="LINEARCOMBINATION") { |
|||
if (b.type == "NUMBER") { |
|||
return addLCNum(a,b); |
|||
} else if (b.type=="LINEARCOMBINATION") { |
|||
return addLCLC(a,b); |
|||
} else if (b.type=="QEQ") { |
|||
return addQEQLC(b,a); |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Add Invalid Type 2: "+b.type }; |
|||
} |
|||
} else if (a.type=="QEQ") { |
|||
if (b.type == "NUMBER") { |
|||
return addQEQNum(a,b); |
|||
} else if (b.type=="LINEARCOMBINATION") { |
|||
return addQEQLC(a,b); |
|||
} else if (b.type=="QEQ") { |
|||
return { type: "ERROR", errStr: "QEQ + QEQ" }; |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Add Invalid Type 2: "+b.type }; |
|||
} |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Add Invalid Type 1: "+a.type }; |
|||
} |
|||
} |
|||
|
|||
function addNumNum(a,b) { |
|||
if (!a.value || !b.value) return { type: "NUMBER" }; |
|||
return { |
|||
type: "NUMBER", |
|||
value: a.value.add(b.value).mod(__P__) |
|||
}; |
|||
} |
|||
|
|||
function addLCNum(a,b) { |
|||
let res = clone(a); |
|||
if (!b.value) { |
|||
return { type: "ERROR", errStr: "LinearCombination + undefined" }; |
|||
} |
|||
if (b.value.isZero()) return res; |
|||
if (!res.values["one"]) { |
|||
res.values["one"]=bigInt(b.value); |
|||
} else { |
|||
res.values["one"]= res.values["one"].add(b.value).mod(__P__); |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
function addLCLC(a,b) { |
|||
let res = clone(a); |
|||
for (let k in b.values) { |
|||
if (!res.values[k]) { |
|||
res.values[k]=bigInt(b.values[k]); |
|||
} else { |
|||
res.values[k]= res.values[k].add(b.values[k]).mod(__P__); |
|||
} |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
function addQEQNum(a,b) { |
|||
let res = clone(a); |
|||
res.c = addLCNum(res.c, b); |
|||
if (res.c.type == "ERROR") return res.c; |
|||
return res; |
|||
} |
|||
|
|||
function addQEQLC(a,b) { |
|||
let res = clone(a); |
|||
res.c = addLCLC(res.c, b); |
|||
if (res.c.type == "ERROR") return res.c; |
|||
return res; |
|||
} |
|||
|
|||
function mul(_a, _b) { |
|||
const a = signal2lc(_a); |
|||
const b = signal2lc(_b); |
|||
if (a.type == "ERROR") return a; |
|||
if (b.type == "ERROR") return b; |
|||
if (a.type == "NUMBER") { |
|||
if (b.type == "NUMBER") { |
|||
return mulNumNum(a,b); |
|||
} else if (b.type=="LINEARCOMBINATION") { |
|||
return mulLCNum(b,a); |
|||
} else if (b.type=="QEQ") { |
|||
return mulQEQNum(b,a); |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Mul Invalid Type 2: "+b.type }; |
|||
} |
|||
} else if (a.type=="LINEARCOMBINATION") { |
|||
if (b.type == "NUMBER") { |
|||
return mulLCNum(a,b); |
|||
} else if (b.type=="LINEARCOMBINATION") { |
|||
return mulLCLC(a,b); |
|||
} else if (b.type=="QEQ") { |
|||
return { type: "ERROR", errStr: "LC * QEQ" }; |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Mul Invalid Type 2: "+b.type }; |
|||
} |
|||
} else if (a.type=="QEQ") { |
|||
if (b.type == "NUMBER") { |
|||
return mulQEQNum(a,b); |
|||
} else if (b.type=="LINEARCOMBINATION") { |
|||
return { type: "ERROR", errStr: "QEC * LC" }; |
|||
} else if (b.type=="QEQ") { |
|||
return { type: "ERROR", errStr: "QEQ * QEQ" }; |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Mul Invalid Type 2: "+b.type }; |
|||
} |
|||
} else { |
|||
return { type: "ERROR", errStr: "LC Mul Invalid Type 1: "+a.type }; |
|||
} |
|||
} |
|||
|
|||
|
|||
function mulNumNum(a,b) { |
|||
if (!a.value || !b.value) return { type: "NUMBER" }; |
|||
return { |
|||
type: "NUMBER", |
|||
value: a.value.times(b.value).mod(__P__) |
|||
}; |
|||
} |
|||
|
|||
function mulLCNum(a,b) { |
|||
let res = clone(a); |
|||
if (!b.value) { |
|||
return {type: "ERROR", errStr: "LinearCombination * undefined"}; |
|||
} |
|||
for (let k in res.values) { |
|||
res.values[k] = res.values[k].times(b.value).mod(__P__); |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
function mulLCLC(a,b) { |
|||
return { |
|||
type: "QEQ", |
|||
a: clone(a), |
|||
b: clone(b), |
|||
c: { type: "LINEARCOMBINATION", values: {}} |
|||
}; |
|||
} |
|||
|
|||
function mulQEQNum(a,b) { |
|||
let res = { |
|||
type: "QEQ", |
|||
a: mulLCNum(a.a, b), |
|||
b: clone(a.b), |
|||
c: mulLCNum(a.c, b) |
|||
}; |
|||
if (res.a.type == "ERROR") return res.a; |
|||
if (res.c.type == "ERROR") return res.a; |
|||
return res; |
|||
} |
|||
|
|||
function getSignalValue(ctx, signalName) { |
|||
const s = ctx.signals[signalName]; |
|||
if (s.equivalence != "") { |
|||
return getSignalValue(ctx, s.equivalence); |
|||
} else { |
|||
const res = { |
|||
type: "NUMBER" |
|||
}; |
|||
if (s.value) { |
|||
res.value = s.value; |
|||
} |
|||
return res; |
|||
} |
|||
} |
|||
|
|||
function evaluate(ctx, n) { |
|||
if (n.type == "NUMBER") { |
|||
return n; |
|||
} else if (n.type == "SIGNAL") { |
|||
return getSignalValue(ctx, n.fullName); |
|||
} else if (n.type == "LINEARCOMBINATION") { |
|||
const v= { |
|||
type: "NUMBER", |
|||
value: bigInt(0) |
|||
}; |
|||
for (let k in n.values) { |
|||
const s = getSignalValue(ctx, k); |
|||
if (s.type != "NUMBER") return {type: "ERROR", errStr: "Invalid signal in linear Combination: " + k}; |
|||
if (!s.value) return { type: "NUMBER" }; |
|||
v.value = v.value.add( n.values[k].times(s.value)).mod(__P__); |
|||
} |
|||
return v; |
|||
} else if (n.type == "QEQ") { |
|||
const a = evaluate(ctx, n.a); |
|||
if (a.type == "ERROR") return a; |
|||
if (!a.value) return { type: "NUMBER" }; |
|||
const b = evaluate(ctx, n.b); |
|||
if (b.type == "ERROR") return b; |
|||
if (!b.value) return { type: "NUMBER" }; |
|||
const c = evaluate(ctx, n.c); |
|||
if (c.type == "ERROR") return c; |
|||
if (!c.value) return { type: "NUMBER" }; |
|||
|
|||
return { |
|||
type: "NUMBER", |
|||
value: (a.value.times(b.value).add(c.value)).mod(__P__) |
|||
}; |
|||
} else if (n.type == "ERROR") { |
|||
return n; |
|||
} else { |
|||
return {type: "ERROR", errStr: "Invalid type in evaluate: "+n.type}; |
|||
} |
|||
} |
|||
|
|||
function negate(_a) { |
|||
const a = signal2lc(_a); |
|||
let res = clone(a); |
|||
if (res.type == "NUMBER") { |
|||
res.value = __P__.minus(a.value).mod(__P__); |
|||
} else if (res.type == "LINEARCOMBINATION") { |
|||
for (let k in res.values) { |
|||
res.values[k] = __P__.minus(res.values[k]).mod(__P__); |
|||
} |
|||
} else if (res.type == "QEQ") { |
|||
res.a = negate(res.a); |
|||
res.c = negate(res.c); |
|||
} else if (res.type == "ERROR") { |
|||
return res; |
|||
} else { |
|||
res = {type: "ERROR", errStr: "LC Negate invalid Type: "+res.type}; |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
function sub(a, b) { |
|||
return add(a, negate(b)); |
|||
} |
|||
|
|||
function toQEQ(a) { |
|||
if (a.type == "NUMBER") { |
|||
return { |
|||
type: "QEQ", |
|||
a: {type: "LINEARCOMBINATION", values: {}}, |
|||
b: {type: "LINEARCOMBINATION", values: {}}, |
|||
c: {type: "LINEARCOMBINATION", values: {"one": bigInt(a.value)}} |
|||
}; |
|||
} else if (a.type == "LINEARCOMBINATION") { |
|||
return { |
|||
type: "QEQ", |
|||
a: {type: "LINEARCOMBINATION", values: {}}, |
|||
b: {type: "LINEARCOMBINATION", values: {}}, |
|||
c: clone(a) |
|||
}; |
|||
} else if (a.type == "QEQ") { |
|||
return clone(a); |
|||
} else if (a.type == "ERROR") { |
|||
return clone(a); |
|||
} else { |
|||
return {type: "ERROR", errStr: "toQEQ invalid Type: "+a.type}; |
|||
} |
|||
} |
|||
|
|||
function isZero(a) { |
|||
if (a.type == "NUMBER") { |
|||
return a.value.isZero(); |
|||
} else if (a.type == "LINEARCOMBINATION") { |
|||
for (let k in a.values) { |
|||
if (!a.values[k].isZero()) return false; |
|||
} |
|||
return true; |
|||
} else if (a.type == "QEQ") { |
|||
return (isZero(a.a) || isZero(a.b)) && isZero(a.c); |
|||
} else if (a.type == "ERROR") { |
|||
return false; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
function toString(a, ctx) { |
|||
if (a.type == "NUMBER") { |
|||
return a.value.toString(); |
|||
} else if (a.type == "LINEARCOMBINATION") { |
|||
let S=""; |
|||
for (let k in a.values) { |
|||
if (!a.values[k].isZero()) { |
|||
let c; |
|||
if (a.values[k].greater(__P__.divide(2))) { |
|||
S = S + "-"; |
|||
c = __P__.minus(a.values[k]); |
|||
} else { |
|||
if (S!="") S=S+" + "; |
|||
c = a.values[k]; |
|||
} |
|||
if (!c.equals(1)) { |
|||
S = S + c.toString() + "*"; |
|||
} |
|||
let sigName = k; |
|||
if (ctx) { |
|||
while (ctx.signals[sigName].equivalence) sigName = ctx.signals[sigName].equivalence; |
|||
} |
|||
S = S + sigName; |
|||
} |
|||
} |
|||
if (S=="") return "0"; else return S; |
|||
} else if (a.type == "QEQ") { |
|||
return "( "+toString(a.a, ctx)+" ) * ( "+toString(a.b, ctx)+" ) + " + toString(a.c, ctx); |
|||
} else if (a.type == "ERROR") { |
|||
return "ERROR: "+a.errStr; |
|||
} else { |
|||
return "INVALID"; |
|||
} |
|||
} |
|||
|
|||
function canonize(ctx, a) { |
|||
if (a.type == "LINEARCOMBINATION") { |
|||
for (let k in a.values) { |
|||
let s = k; |
|||
while (ctx.signals[s].equivalence) s= ctx.signals[s].equivalence; |
|||
if (s != k) { |
|||
if (!a.values[s]) { |
|||
a.values[s]=bigInt(a.values[k]); |
|||
} else { |
|||
a.values[s]= a.values[s].add(a.values[k]).mod(__P__); |
|||
} |
|||
delete a.values[k]; |
|||
} |
|||
} |
|||
for (let k in a.values) { |
|||
if (a.values[k].isZero()) delete a.values[k]; |
|||
} |
|||
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; |
|||
} |
|||
|
@ -0,0 +1,27 @@ |
|||
const fs = require("fs"); |
|||
const path = require("path"); |
|||
|
|||
const calculateWitness = require("./calculateWitness.js"); |
|||
|
|||
const argv = require("optimist") |
|||
.alias("i", "input") |
|||
.alias("o", "output") |
|||
.alias("c", "circuit") |
|||
.argv; |
|||
|
|||
const circuit = require(path.resolve(argv.circuit)); |
|||
|
|||
const inputSignals = JSON.parse(fs.readFileSync(argv.input, "utf8")); |
|||
|
|||
try { |
|||
const w = calculateWitness(circuit, inputSignals); |
|||
fs.writeFileSync(argv.output, JSON.stringify(w), "utf8"); |
|||
} catch(err) { |
|||
console.log("ERROR: " + err); |
|||
console.log(err.stack); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1 @@ |
|||
["1","111","222","333","1","1","1","1","0","1","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","1","1","1","1","0","1","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","1","0","1","1","0","0","1","0","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"] |
@ -0,0 +1 @@ |
|||
a[1][2].b[3][4] <== c[5][6].d[7][8] |
@ -0,0 +1,61 @@ |
|||
const path = require("path"); |
|||
const fs = require("fs"); |
|||
const cmd=require("node-cmd"); |
|||
const util = require("util"); |
|||
const assert = require("assert"); |
|||
|
|||
const claimUtils = require("../src/claimUtils.js"); |
|||
|
|||
cmd.get[util.promisify.custom] = (c) => { |
|||
return new Promise((resolve, reject) => { |
|||
cmd.get(c, (err, data, stderr) => { |
|||
if (err) { |
|||
reject(err); |
|||
} else { |
|||
resolve([data, stderr]); |
|||
} |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
const getAsync = util.promisify(cmd.get); |
|||
const mkdir = util.promisify(fs.mkdir); |
|||
const writeFile = util.promisify(fs.writeFile); |
|||
|
|||
describe("command line", () => { |
|||
|
|||
let tmpPath; |
|||
before(async () => { |
|||
tmpPath = path.join(__dirname, "..", "tmp"); |
|||
if (!fs.existsSync(tmpPath)) { |
|||
await mkdir(tmpPath, 0o744); |
|||
} |
|||
process.chdir(tmpPath); |
|||
}); |
|||
|
|||
it("Should create a tree from a claim files", async () => { |
|||
|
|||
let i; |
|||
let claims = []; |
|||
for (i=0; i<100; i++) { |
|||
const b = Buffer.from([ i / 256, i % 256 ]); |
|||
claims[i] = claimUtils.buildClaim("0x01", "0x02", "0x03", b).toString("hex"); |
|||
} |
|||
|
|||
claims = claims.sort(); |
|||
const claimsFile = path.join(tmpPath, "claims100.hex"); |
|||
const dbFile = path.join(tmpPath, "claims100.db"); |
|||
await writeFile(claimsFile, claims.join("\n"), "utf8"); |
|||
|
|||
await getAsync(`${path.join("..", "cli.js")} -d ${dbFile} add ${claimsFile} `); |
|||
|
|||
const data = await getAsync(`${path.join("..", "cli.js")} -d ${dbFile} export`); |
|||
let claims2 = data[0].split("\n"); |
|||
|
|||
claims2 = claims2.filter(function(n){ return n.length>0; }); |
|||
claims2 = claims2.sort(); |
|||
|
|||
assert.equal(claims2.join("\n"), claims.join("\n")); |
|||
|
|||
}).timeout(20000); |
|||
}); |
@ -0,0 +1,2 @@ |
|||
1 * 2 * 3 |
|||
* 4 |
@ -0,0 +1,141 @@ |
|||
const assert = require("assert"); |
|||
|
|||
const StaticMerkle = require("../src/StaticMerkle.js"); |
|||
const MemDB = require("../src/dbMem.js"); |
|||
const hash = require("../src/hashKeccak.js"); |
|||
const buffUtils = require("../src/buffUtils.js"); |
|||
const claimUtils = require("../src/claimUtils.js"); |
|||
|
|||
describe("static merkle", () => { |
|||
before(async () => { |
|||
|
|||
}); |
|||
|
|||
it("Create an empty tring of 0 levels", async () => { |
|||
const dbPrv0 = await MemDB(); |
|||
const SM0 = await StaticMerkle(hash, dbPrv0, 0); |
|||
const empty = SM0.root; |
|||
assert.equal(buffUtils.toHex(empty), "0x0000000000000000000000000000000000000000000000000000000000000000"); |
|||
}); |
|||
|
|||
it("create an empty", async () => { |
|||
const dbPrv = await MemDB(); |
|||
const SM140 = await StaticMerkle(hash, dbPrv, 140); |
|||
const empty = SM140.root; |
|||
assert.equal(buffUtils.toHex(empty), "0x0000000000000000000000000000000000000000000000000000000000000000"); |
|||
}); |
|||
|
|||
it("should add and remove a claim", async() => { |
|||
const dbPrv = await MemDB(); |
|||
const SM140 = await StaticMerkle(hash, dbPrv, 140); |
|||
const empty = SM140.root; |
|||
const claim = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x04"); |
|||
await SM140.addClaim(claim); |
|||
assert.equal(buffUtils.toHex(SM140.root), "0xd3d9ad5e3c0b38c4e3eb411e9e3114b5ed8fb5c4bc69158329feb1a62743cda1"); |
|||
await SM140.removeClaim(claim); |
|||
assert.equal(buffUtils.toHex(SM140.root), buffUtils.toHex(empty)); |
|||
|
|||
assert.equal(SM140.tx.inserts.length, 0); |
|||
|
|||
}); |
|||
|
|||
it("should add two claims in different order and should be the same", async () => { |
|||
const dbPrv_1 = await MemDB(); |
|||
const SM140_1 = await StaticMerkle(hash, dbPrv_1, 140); |
|||
const dbPrv_2 = await MemDB(); |
|||
const SM140_2 = await StaticMerkle(hash, dbPrv_2, 140); |
|||
const empty = SM140_1.root; |
|||
const claim1 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x04"); |
|||
const claim2 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x05"); |
|||
|
|||
await SM140_1.addClaim(claim1); |
|||
await SM140_1.addClaim(claim2); |
|||
|
|||
await SM140_2.addClaim(claim2); |
|||
await SM140_2.addClaim(claim1); |
|||
|
|||
assert.equal(buffUtils.toHex(SM140_1.root), buffUtils.toHex(SM140_2.root)); |
|||
|
|||
await SM140_1.removeClaim(claim1); |
|||
await SM140_1.removeClaim(claim2); |
|||
assert.equal(buffUtils.toHex(SM140_1.root), buffUtils.toHex(empty)); |
|||
|
|||
await SM140_2.removeClaim(claim2); |
|||
await SM140_2.removeClaim(claim1); |
|||
assert.equal(buffUtils.toHex(SM140_2.root), buffUtils.toHex(empty)); |
|||
|
|||
}); |
|||
|
|||
it("should add 10 claims and remove them in different order", async () => { |
|||
const dbPrv = await MemDB(); |
|||
const SM140 = await StaticMerkle(hash, dbPrv, 140); |
|||
const empty = SM140.root; |
|||
const claims = []; |
|||
let i; |
|||
for (i=0; i<10; i++) { |
|||
const b = Buffer.from([ i / 256, i % 256 ]); |
|||
claims[i] = claimUtils.buildClaim("0x01", "0x02", "0x03", b); |
|||
} |
|||
|
|||
for (i=0;i<claims.length; i++) { |
|||
await SM140.addClaim(claims[i]); |
|||
} |
|||
|
|||
assert.equal(buffUtils.toHex(SM140.root), "0xb57c288d5c018c56610a3fb783062c9b199221734c8c5617795b57cbdbd4347f"); |
|||
|
|||
for (i=0;i<claims.length; i++) { |
|||
await SM140.removeClaim(claims[i]); |
|||
} |
|||
|
|||
assert.equal(buffUtils.toHex(SM140.root), buffUtils.toHex(empty)); |
|||
assert.equal(SM140.tx.inserts.length, 0); |
|||
}); |
|||
|
|||
it("Should give the same root when added a repeated claim", async () => { |
|||
const dbPrv = await MemDB(); |
|||
const SM140 = await StaticMerkle(hash, dbPrv, 140); |
|||
const empty = SM140.root; |
|||
const claims = []; |
|||
let i; |
|||
for (i=0; i<100; i++) { |
|||
const b = Buffer.from([ i % 10 ]); |
|||
claims[i] = claimUtils.buildClaim("0x01", "0x02", "0x03", b); |
|||
} |
|||
|
|||
for (i=0;i<claims.length; i++) { |
|||
await SM140.addClaim(claims[i]); |
|||
} |
|||
|
|||
assert.equal(buffUtils.toHex(SM140.root), "0xb57c288d5c018c56610a3fb783062c9b199221734c8c5617795b57cbdbd4347f"); |
|||
|
|||
for (i=0;i<claims.length; i++) { |
|||
await SM140.removeClaim(claims[i]); |
|||
} |
|||
|
|||
assert.equal(buffUtils.toHex(SM140.root), buffUtils.toHex(empty)); |
|||
assert.equal(SM140.tx.inserts.length, 0); |
|||
}).timeout(20000); |
|||
|
|||
it("Should create a merkle proof and verify it ok", async () => { |
|||
const dbPrv = await MemDB(); |
|||
const SM140 = await StaticMerkle(hash, dbPrv, 140); |
|||
const empty = SM140.root; |
|||
const claim1 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x04"); |
|||
const claim2 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x05"); |
|||
|
|||
await SM140.addClaim(claim1); |
|||
await SM140.addClaim(claim2); |
|||
|
|||
const mp = await SM140.getMerkeProof(claim1); |
|||
|
|||
assert.equal(SM140.checkClaim(SM140.root, claim1, mp), true); |
|||
assert.equal(SM140.checkClaim(empty, claim1, mp), false); |
|||
assert.equal(SM140.checkClaim(empty, claim2, mp), false); |
|||
|
|||
const mp1 = await SM140.getMerkeProof(claim1); |
|||
assert.equal(SM140.checkClaim(SM140.root, claim1, mp1), true); |
|||
const mp2 = await SM140.getMerkeProof(claim2); |
|||
assert.equal(SM140.checkClaim(SM140.root, claim2, mp2), true); |
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,45 @@ |
|||
11+12; 13; |
|||
14; 15; |
|||
/* Multi Line |
|||
comment */ |
|||
/*** / * /* **/ |
|||
// Single line comment /* sss */ |
|||
16; 0x1f; 0xAa; |
|||
12; id1; A; B; A+B; |
|||
A*B+A*B+3; |
|||
4/2; |
|||
4/3; |
|||
4/3*3; |
|||
8/2; |
|||
0/2; |
|||
2/1; |
|||
8 % 5; |
|||
-1; +--1; |
|||
(3+4)*(5*2); |
|||
0xFF & 0x12; |
|||
1 << 8; |
|||
-1 >> 257; |
|||
-1 << 257; |
|||
-1 >> 256; |
|||
-1 << 256; |
|||
-1 >> 250; |
|||
-1 << 250; |
|||
33 == 33; |
|||
33 == 34; |
|||
3>3; |
|||
3>=3; |
|||
3<=3; |
|||
3<3; |
|||
3 && 0; |
|||
0 && 3; |
|||
3 && 3; |
|||
0 && 0; |
|||
!3; |
|||
!0; |
|||
!!8; |
|||
2**3; |
|||
(-1)**(-1); |
|||
a[3]; |
|||
a[3][b] + b[4][c][d]; |
|||
func() + func(a) + func(a,b); |
|||
3*4==6+6 && 2+1==3 ? 3+3*2 : (3+2)*6 |
@ -0,0 +1 @@ |
|||
f(1,2) |
@ -0,0 +1,9 @@ |
|||
a+b*c |
|||
(a+b)*c |
|||
var c + a[1].b[2] + c |
|||
f(1,2) |
|||
component f(4) d; |
|||
|
|||
a++ + b++; |
|||
|
|||
--a; |
@ -0,0 +1,5 @@ |
|||
var a; |
|||
var b; |
|||
var c; |
|||
a+b*b[3+a][2]; |
|||
a<<2<=2>>a |
@ -0,0 +1,3 @@ |
|||
a <== b === c |
|||
r = a ? c ? 5 : 6 : b ? 3 : 4 |
|||
c = sqrt(a**2+b**2) |
@ -0,0 +1,8 @@ |
|||
(a + bb) + c; |
|||
include "filename.ext" |
|||
include "secondfile" |
|||
include "therdfile"; |
|||
include "4th file" |
|||
{ |
|||
include "fifthfile" |
|||
} |
@ -0,0 +1,13 @@ |
|||
{ |
|||
3+3 |
|||
4+4 |
|||
5+5 |
|||
} |
|||
6 |
|||
7 |
|||
a <-- 3 |
|||
3 --> a; |
|||
signal input b <== 4; |
|||
4 ==> signal b; |
|||
c === d; |
|||
|
@ -0,0 +1,10 @@ |
|||
signal input b <== 3; |
|||
signal o[44] <-- 2; |
|||
a[1][2].b[3] <== 4 |
|||
function f(a,b) { |
|||
c=a+b; |
|||
} |
|||
|
|||
component b(b1,b2) { |
|||
b1 <== b2[3].pin[4] |
|||
} |
@ -0,0 +1,7 @@ |
|||
if (a) b; else c; |
|||
if (a) { |
|||
1 |
|||
} else { |
|||
2 |
|||
} |
|||
if (1) if(0) 1; else 2; |
@ -0,0 +1,4 @@ |
|||
var a=0; |
|||
for (i=0; i<10; i=i+1) { |
|||
a=a+1; |
|||
} |
@ -0,0 +1,7 @@ |
|||
++a; |
|||
a++; |
|||
b--; |
|||
--b; |
|||
a -- > 0; |
|||
0 < ++ b; |
|||
|
@ -0,0 +1,11 @@ |
|||
a=3 |
|||
a+=3 |
|||
a-=3 |
|||
a*=3 |
|||
a/=3 |
|||
a%=3 |
|||
a>>=3 |
|||
a<<=3 |
|||
a&=3 |
|||
a|=3 |
|||
a^=3 |
@ -0,0 +1,6 @@ |
|||
while (1) { |
|||
a |
|||
} |
|||
do { |
|||
xx; |
|||
} while (1) |
@ -0,0 +1,9 @@ |
|||
function f() { |
|||
return 3; |
|||
} |
|||
|
|||
function ff(a) { |
|||
return 4; |
|||
} |
|||
|
|||
component c = s(a); |
@ -0,0 +1,189 @@ |
|||
const bigInt = require("big-integer"); |
|||
const __P__ = new bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583"); |
|||
const __MASK__ = new bigInt(2).pow(253).minus(1); |
|||
const circuit = {}; |
|||
module.exports = circuit; |
|||
|
|||
circuit.signals={ |
|||
"one": { |
|||
"fullName": "one", |
|||
"value": "1", |
|||
"equivalence": "", |
|||
"direction": "", |
|||
"id": 0 |
|||
}, |
|||
"main.inp": { |
|||
"fullName": "main.inp", |
|||
"direction": "IN", |
|||
"component": "main", |
|||
"equivalence": "", |
|||
"alias": [ |
|||
"main.inp" |
|||
], |
|||
"id": 1 |
|||
}, |
|||
"main.out[0]": { |
|||
"fullName": "main.out[0]", |
|||
"direction": "OUT", |
|||
"component": "main", |
|||
"equivalence": "", |
|||
"alias": [ |
|||
"main.out[0]" |
|||
], |
|||
"id": 2 |
|||
}, |
|||
"main.out[1]": { |
|||
"fullName": "main.out[1]", |
|||
"direction": "OUT", |
|||
"component": "main", |
|||
"equivalence": "", |
|||
"alias": [ |
|||
"main.out[1]" |
|||
], |
|||
"id": 3 |
|||
}, |
|||
"main.out[2]": { |
|||
"fullName": "main.out[2]", |
|||
"direction": "OUT", |
|||
"component": "main", |
|||
"equivalence": "", |
|||
"alias": [ |
|||
"main.out[2]" |
|||
], |
|||
"id": 4 |
|||
} |
|||
}; |
|||
|
|||
circuit.components={ |
|||
"main": { |
|||
"signals": [ |
|||
"main.inp", |
|||
"main.out[0]", |
|||
"main.out[1]", |
|||
"main.out[2]" |
|||
], |
|||
"params": { |
|||
"n": "3" |
|||
}, |
|||
"template": "toBin", |
|||
"inputSignals": 1 |
|||
} |
|||
}; |
|||
|
|||
circuit.signalConstrains=[ |
|||
{ |
|||
"type": "QEQ", |
|||
"a": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.out[0]": "1" |
|||
} |
|||
}, |
|||
"b": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.out[0]": "1", |
|||
"one": "21888242871839275222246405745257275088696311157297823662689037894645226208582" |
|||
} |
|||
}, |
|||
"c": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": {} |
|||
} |
|||
}, |
|||
{ |
|||
"type": "QEQ", |
|||
"a": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.out[1]": "1" |
|||
} |
|||
}, |
|||
"b": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.out[1]": "1", |
|||
"one": "21888242871839275222246405745257275088696311157297823662689037894645226208582" |
|||
} |
|||
}, |
|||
"c": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": {} |
|||
} |
|||
}, |
|||
{ |
|||
"type": "QEQ", |
|||
"a": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.out[2]": "1" |
|||
} |
|||
}, |
|||
"b": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.out[2]": "1", |
|||
"one": "21888242871839275222246405745257275088696311157297823662689037894645226208582" |
|||
} |
|||
}, |
|||
"c": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": {} |
|||
} |
|||
}, |
|||
{ |
|||
"type": "QEQ", |
|||
"a": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": {} |
|||
}, |
|||
"b": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": {} |
|||
}, |
|||
"c": { |
|||
"type": "LINEARCOMBINATION", |
|||
"values": { |
|||
"main.out[0]": "1", |
|||
"main.out[1]": "2", |
|||
"main.out[2]": "4", |
|||
"main.inp": "21888242871839275222246405745257275088696311157297823662689037894645226208582" |
|||
} |
|||
} |
|||
} |
|||
]; |
|||
|
|||
circuit.witnessNames=[ |
|||
[ |
|||
"one" |
|||
], |
|||
[ |
|||
"main.inp" |
|||
], |
|||
[ |
|||
"main.out[0]" |
|||
], |
|||
[ |
|||
"main.out[1]" |
|||
], |
|||
[ |
|||
"main.out[2]" |
|||
] |
|||
]; |
|||
|
|||
{ |
|||
} |
|||
|
|||
circuit.templates = []; |
|||
|
|||
circuit.templates["toBin"] = function(ctx) { |
|||
ctx.setVar("lc1", [], "0"); |
|||
for (ctx.setVar("i", [], "0");bigInt(ctx.getVar("i",[])).lt(ctx.getVar("n",[])) ? 1 : 0;(ctx.setVar("i", [], bigInt(ctx.getVar("i",[])).add("1").mod(__P__))).add(__P__).minus(1).mod(__P__)) |
|||
{ |
|||
ctx.setSignal("out", [ctx.getVar("i",[])], bigInt(bigInt(ctx.getVar("i",[])).greater(256) ? 0 : bigInt(ctx.getSignal("inp", [])).shiftRight(bigInt(ctx.getVar("i",[])).value).and(__MASK__)).and("1").and(__MASK__)); |
|||
ctx.assert(bigInt(bigInt(ctx.getSignal("out", [ctx.getVar("i",[])])).times(bigInt(ctx.getSignal("out", [ctx.getVar("i",[])])).add(__P__).minus("1").mod(__P__)).mod(__P__)).equals("0")); |
|||
ctx.setVar("lc1", [], bigInt(ctx.getVar("lc1",[])).add(bigInt(ctx.getSignal("out", [ctx.getVar("i",[])])).times(bigInt("2").modPow(ctx.getVar("i",[]), __P__)).mod(__P__)).mod(__P__)); |
|||
} |
|||
ctx.assert(bigInt(ctx.getVar("lc1",[])).equals(ctx.getSignal("inp", []))); |
|||
} |
|||
; |
@ -0,0 +1 @@ |
|||
["1","3","1","1","0"] |