@ -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"] |