mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-06 18:56:40 +01:00
First commit
This commit is contained in:
33
.eslintrc.js
Normal file
33
.eslintrc.js
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
};
|
||||||
63
.gitignore
vendored
Normal file
63
.gitignore
vendored
Normal file
@@ -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
|
||||||
11
circuits/jose.jaz
Normal file
11
circuits/jose.jaz
Normal file
@@ -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();
|
||||||
74
circuits/multiplexer.jaz
Normal file
74
circuits/multiplexer.jaz
Normal file
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
74
circuits/sha256/binsum.jaz
Normal file
74
circuits/sha256/binsum.jaz
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Binary Sum
|
||||||
|
==========
|
||||||
|
|
||||||
|
This component creates a binary sum componet of ops operands and n bits each operand.
|
||||||
|
|
||||||
|
e is Number of carries: Depends on the number of operands in the input.
|
||||||
|
|
||||||
|
Main 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;
|
||||||
|
}
|
||||||
28
circuits/sha256/bitify.jaz
Normal file
28
circuits/sha256/bitify.jaz
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
|
||||||
|
template Num2Bits(n) {
|
||||||
|
signal input in;
|
||||||
|
signal output out[n];
|
||||||
|
var lc1=0;
|
||||||
|
|
||||||
|
for (var i = 0; i<n; i++) {
|
||||||
|
out[i] <-- (in >> i) & 1;
|
||||||
|
out[i] * (out[i] -1 ) === 0;
|
||||||
|
lc1 += out[i] * 2**i;
|
||||||
|
}
|
||||||
|
|
||||||
|
lc1 === in;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template Bits2Num(n) {
|
||||||
|
signal input in[n];
|
||||||
|
signal output out;
|
||||||
|
var lc1=0;
|
||||||
|
|
||||||
|
for (var i = 0; i<n; i++) {
|
||||||
|
lc1 += in[i] * 2**i;
|
||||||
|
}
|
||||||
|
|
||||||
|
lc1 ==> out;
|
||||||
|
}
|
||||||
35
circuits/sha256/constants.jaz
Normal file
35
circuits/sha256/constants.jaz
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
|
||||||
|
template H(x) {
|
||||||
|
signal output out[32];
|
||||||
|
var c = [0x6a09e667,
|
||||||
|
0xbb67ae85,
|
||||||
|
0x3c6ef372,
|
||||||
|
0xa54ff53a,
|
||||||
|
0x510e527f,
|
||||||
|
0x9b05688c,
|
||||||
|
0x1f83d9ab,
|
||||||
|
0x5be0cd19];
|
||||||
|
|
||||||
|
for (var i=0; i<32; i++) {
|
||||||
|
out[i] = (c[x] >> i) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template K(x) {
|
||||||
|
signal output out[32];
|
||||||
|
var c = [
|
||||||
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||||
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||||
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||||
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||||
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||||
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||||
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||||
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i=0; i<32; i++) {
|
||||||
|
out[i] = (c[x] >> i) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
67
circuits/sha256/gates.jaz
Normal file
67
circuits/sha256/gates.jaz
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
circuits/sha256/input_h0.json
Normal file
3
circuits/sha256/input_h0.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"in": "0xd807aa98"
|
||||||
|
}
|
||||||
4
circuits/sha256/input_sum_test.json
Normal file
4
circuits/sha256/input_sum_test.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"a": "111",
|
||||||
|
"b": "222"
|
||||||
|
}
|
||||||
50
circuits/sha256/main.jaz
Normal file
50
circuits/sha256/main.jaz
Normal file
@@ -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();
|
||||||
10
circuits/sha256/rotate.jaz
Normal file
10
circuits/sha256/rotate.jaz
Normal file
@@ -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 ];
|
||||||
|
}
|
||||||
|
}
|
||||||
44
circuits/sha256/sha256_2.jaz
Normal file
44
circuits/sha256/sha256_2.jaz
Normal file
@@ -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;
|
||||||
|
}
|
||||||
145
circuits/sha256/sha256compression.jaz
Normal file
145
circuits/sha256/sha256compression.jaz
Normal file
@@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
25
circuits/sha256/sigma.jaz
Normal file
25
circuits/sha256/sigma.jaz
Normal file
@@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
26
circuits/sha256/sigmaplus.jaz
Normal file
26
circuits/sha256/sigmaplus.jaz
Normal file
@@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
26
circuits/sha256/sum_test.jaz
Normal file
26
circuits/sha256/sum_test.jaz
Normal file
@@ -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
circuits/sha256/t1.jaz
Normal file
0
circuits/sha256/t1.jaz
Normal file
0
circuits/sha256/t2.jaz
Normal file
0
circuits/sha256/t2.jaz
Normal file
20
circuits/tobin.jaz
Normal file
20
circuits/tobin.jaz
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template toBin(n) {
|
||||||
|
signal input inp;
|
||||||
|
signal output out[n];
|
||||||
|
var lc1=0;
|
||||||
|
|
||||||
|
for (var i = 0; i<n; i++) {
|
||||||
|
out[i] <-- (inp >> i) & 1;
|
||||||
|
out[i] * (out[i] -1 ) === 0;
|
||||||
|
lc1 += out[i] * 2**i;
|
||||||
|
}
|
||||||
|
|
||||||
|
lc1 === inp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
component toBin(3) main;
|
||||||
3
input.json
Normal file
3
input.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"inp": "3"
|
||||||
|
}
|
||||||
4
input_jose.json
Normal file
4
input_jose.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"s1": "24",
|
||||||
|
"s2": "1"
|
||||||
|
}
|
||||||
27
inputmx.json
Normal file
27
inputmx.json
Normal file
@@ -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
|
||||||
|
}
|
||||||
154
jose.js
Normal file
154
jose.js
Normal file
@@ -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 = {};
|
||||||
2545
multiplexer.js
Normal file
2545
multiplexer.js
Normal file
File diff suppressed because it is too large
Load Diff
1
outmx.js
Normal file
1
outmx.js
Normal file
@@ -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"]
|
||||||
1232
package-lock.json
generated
Normal file
1232
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
package.json
Normal file
31
package.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
892
parser/jaz.jison
Normal file
892
parser/jaz.jison
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
1
sha256.out
Normal file
1
sha256.out
Normal file
@@ -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"]
|
||||||
209
src/calculateWitness.js
Normal file
209
src/calculateWitness.js
Normal file
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
156
src/circuit_generator.js
Normal file
156
src/circuit_generator.js
Normal file
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
874
src/exec.js
Normal file
874
src/exec.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
479
src/gencode.js
Normal file
479
src/gencode.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
441
src/lcalgebra.js
Normal file
441
src/lcalgebra.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
27
src/rt.js
Normal file
27
src/rt.js
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
5050
sum_test.js
Normal file
5050
sum_test.js
Normal file
File diff suppressed because it is too large
Load Diff
1
sum_test.out
Normal file
1
sum_test.out
Normal file
@@ -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"]
|
||||||
61
test/commandline.js
Normal file
61
test/commandline.js
Normal file
@@ -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);
|
||||||
|
});
|
||||||
2
test/jorge.prg
Normal file
2
test/jorge.prg
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
1 * 2 * 3
|
||||||
|
* 4
|
||||||
141
test/mainTest.js
Normal file
141
test/mainTest.js
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
45
test/test1.jaz
Normal file
45
test/test1.jaz
Normal file
@@ -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
|
||||||
1
test/test10.jaz
Normal file
1
test/test10.jaz
Normal file
@@ -0,0 +1 @@
|
|||||||
|
f(1,2)
|
||||||
9
test/test11.jaz
Normal file
9
test/test11.jaz
Normal file
@@ -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;
|
||||||
5
test/test12.jaz
Normal file
5
test/test12.jaz
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
var a;
|
||||||
|
var b;
|
||||||
|
var c;
|
||||||
|
a+b*b[3+a][2];
|
||||||
|
a<<2<=2>>a
|
||||||
3
test/test13.jaz
Normal file
3
test/test13.jaz
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
a <== b === c
|
||||||
|
r = a ? c ? 5 : 6 : b ? 3 : 4
|
||||||
|
c = sqrt(a**2+b**2)
|
||||||
8
test/test14.jaz
Normal file
8
test/test14.jaz
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
(a + bb) + c;
|
||||||
|
include "filename.ext"
|
||||||
|
include "secondfile"
|
||||||
|
include "therdfile";
|
||||||
|
include "4th file"
|
||||||
|
{
|
||||||
|
include "fifthfile"
|
||||||
|
}
|
||||||
13
test/test2.jaz
Normal file
13
test/test2.jaz
Normal file
@@ -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;
|
||||||
|
|
||||||
10
test/test3.jaz
Normal file
10
test/test3.jaz
Normal file
@@ -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]
|
||||||
|
}
|
||||||
7
test/test4.jaz
Normal file
7
test/test4.jaz
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
if (a) b; else c;
|
||||||
|
if (a) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
if (1) if(0) 1; else 2;
|
||||||
4
test/test5.jaz
Normal file
4
test/test5.jaz
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var a=0;
|
||||||
|
for (i=0; i<10; i=i+1) {
|
||||||
|
a=a+1;
|
||||||
|
}
|
||||||
7
test/test6.jaz
Normal file
7
test/test6.jaz
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
++a;
|
||||||
|
a++;
|
||||||
|
b--;
|
||||||
|
--b;
|
||||||
|
a -- > 0;
|
||||||
|
0 < ++ b;
|
||||||
|
|
||||||
11
test/test7.jaz
Normal file
11
test/test7.jaz
Normal file
@@ -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
|
||||||
6
test/test8.jaz
Normal file
6
test/test8.jaz
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
while (1) {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
xx;
|
||||||
|
} while (1)
|
||||||
9
test/test9.jaz
Normal file
9
test/test9.jaz
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
function f() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ff(a) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
component c = s(a);
|
||||||
189
tobin.js
Normal file
189
tobin.js
Normal file
@@ -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", [])));
|
||||||
|
}
|
||||||
|
;
|
||||||
Reference in New Issue
Block a user