mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-07 03:06:42 +01:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80846667ea | ||
|
|
7181c372d9 | ||
|
|
aecc28a79b | ||
|
|
51ff27b9c6 | ||
|
|
6985892f86 | ||
|
|
bacb7afde7 | ||
|
|
d04eff6c0d | ||
|
|
230894921e | ||
|
|
64029e1842 | ||
|
|
700412f23d | ||
|
|
832077fbe9 | ||
|
|
0df0ac712d | ||
|
|
67a35ee400 | ||
|
|
680e3fe139 | ||
|
|
f05c4e1338 | ||
|
|
597deb1eaa | ||
|
|
7a1c606ca6 | ||
|
|
6642d4cf93 | ||
|
|
da0c60a919 | ||
|
|
534efcf355 | ||
|
|
a43154241e | ||
|
|
859c98d2a4 | ||
|
|
8048a5ef7d | ||
|
|
b7a41cda14 | ||
|
|
34049f2fbd |
12
TUTORIAL.md
12
TUTORIAL.md
@@ -156,7 +156,7 @@ snarkjs verify
|
||||
|
||||
This command will use `verification_key.json`, `proof.json` and `public.json` to verify that is valid.
|
||||
|
||||
Here we are veifying that we know a witness that the public inputs and the outputs matches the ones in the `public.json` file.
|
||||
Here we are verifying that we know a witness that the public inputs and the outputs matches the ones in the `public.json` file.
|
||||
|
||||
|
||||
If the proof is ok, you will see `OK` or `INVALID` if not ok.
|
||||
@@ -182,7 +182,7 @@ The verifier contract deployed in the last step has a `view` function called `ve
|
||||
|
||||
This function will return true if the proof and the inputs are valid.
|
||||
|
||||
To facilitiate the call, you can use snarkjs to generate the parameters of the call by typing:
|
||||
To facilitate the call, you can use snarkjs to generate the parameters of the call by typing:
|
||||
|
||||
```sh
|
||||
snarkjs generatecall
|
||||
@@ -192,7 +192,7 @@ Just cut and paste the output to the parameters field of the `verifyProof` metho
|
||||
|
||||
If every thing works ok, this method should return true.
|
||||
|
||||
If you change any bit in the parameters, the result will be veryfiable false.
|
||||
If you change any bit in the parameters, the result will be verifiably false.
|
||||
|
||||
|
||||
## Bonus track
|
||||
@@ -227,19 +227,19 @@ template Multiplier() {
|
||||
component main = Multiplier();
|
||||
```
|
||||
|
||||
A nice thing of circom language is that you can split a <== into two independent acions: <-- and ===
|
||||
A nice thing of the circom language is that you can split a <== into two independent actions: <-- and ===
|
||||
|
||||
The <-- and --> operators assign a value to a signal without creating any constraints.
|
||||
|
||||
The === operator adds a constraint without assigning any value to any signal.
|
||||
|
||||
The circuit has also another problem: the operation works in Zr, so we need to guarantee the multiplication does not overflow. This can be done by binarizing the inputs and checking the ranges, but we will reserve it for future tutorials.
|
||||
The circuit also has another problem: the operation works in Zr, so we need to guarantee the multiplication does not overflow. This can be done by converting the inputs to binary and checking the ranges, but we will reserve it for future tutorials.
|
||||
|
||||
## Where to go from here:
|
||||
|
||||
You may want to read the [README](https://github.com/iden3/circom) to learn more features about circom.
|
||||
|
||||
You can also check a a library with many basic circuits lib binaritzations, comparators, eddsa, hashes, merkle trees etc [here](https://github.com/iden3/circomlib) (Work in progress).
|
||||
You can also check a library with many basic circuits lib binarizations, comparators, eddsa, hashes, merkle trees etc [here](https://github.com/iden3/circomlib) (Work in progress).
|
||||
|
||||
|
||||
Or a exponentiation in the Baby Jub curve [here](https://github.com/iden3/circomlib) (Work in progress).
|
||||
|
||||
44
circuit.json
44
circuit.json
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"mainCode": "{\n}\n",
|
||||
"signalName2Idx": {
|
||||
"one": 0,
|
||||
"main.out": 1
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"name": "main",
|
||||
"params": {},
|
||||
"template": "A",
|
||||
"inputSignals": 0
|
||||
}
|
||||
],
|
||||
"componentName2Idx": {
|
||||
"main": 0
|
||||
},
|
||||
"signals": [
|
||||
{
|
||||
"names": [
|
||||
"one"
|
||||
],
|
||||
"triggerComponents": []
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"main.out"
|
||||
],
|
||||
"triggerComponents": []
|
||||
}
|
||||
],
|
||||
"constraints": [],
|
||||
"templates": {
|
||||
"A": "function(ctx) {\n ctx.setSignal(\"out\", [], \"3\");\n ctx.assert(ctx.getSignal(\"out\", []), \"3\");\n}\n"
|
||||
},
|
||||
"functions": {},
|
||||
"nPrvInputs": 0,
|
||||
"nPubInputs": 0,
|
||||
"nInputs": 0,
|
||||
"nOutputs": 0,
|
||||
"nVars": 1,
|
||||
"nConstants": 1,
|
||||
"nSignals": 2
|
||||
}
|
||||
13
cli.js
13
cli.js
@@ -34,7 +34,16 @@ const argv = require("yargs")
|
||||
.alias("o", "output")
|
||||
.help("h")
|
||||
.alias("h", "help")
|
||||
.alias("v", "verbose")
|
||||
.option("verbose", {
|
||||
alias: "v",
|
||||
type: "boolean",
|
||||
description: "Run with verbose logging"
|
||||
})
|
||||
.option("fast", {
|
||||
alias: "f",
|
||||
type: "boolean",
|
||||
description: "Do not optimize constraints"
|
||||
})
|
||||
.epilogue(`Copyright (C) 2018 0kims association
|
||||
This program comes with ABSOLUTELY NO WARRANTY;
|
||||
This is free software, and you are welcome to redistribute it
|
||||
@@ -56,7 +65,7 @@ if (argv._.length == 0) {
|
||||
const fullFileName = path.resolve(process.cwd(), inputFile);
|
||||
const outName = argv.output ? argv.output : "circuit.json";
|
||||
|
||||
compiler(fullFileName).then( (cir) => {
|
||||
compiler(fullFileName, {reduceConstraints: !argv.fast, verbose: argv.verbose}).then( (cir) => {
|
||||
fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8");
|
||||
process.exit(0);
|
||||
}, (err) => {
|
||||
|
||||
74
package-lock.json
generated
74
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "circom",
|
||||
"version": "0.0.26",
|
||||
"version": "0.0.35",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -119,6 +119,15 @@
|
||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.43.tgz",
|
||||
"integrity": "sha512-9dULc9jsKmXl0Aeunug8wbF+58n+hQoFjqClN7WeZwGLh0XJUWyJJ9Ee+Ep+Ql/J9fRsTVaeThp8MhiCCrY0Jg=="
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -423,10 +432,13 @@
|
||||
}
|
||||
},
|
||||
"eslint-utils": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
|
||||
"integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
|
||||
"dev": true
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
|
||||
"integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
@@ -542,6 +554,12 @@
|
||||
"flat-cache": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true
|
||||
},
|
||||
"find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||
@@ -807,6 +825,18 @@
|
||||
"nomnom": ">= 1.5.x"
|
||||
}
|
||||
},
|
||||
"keccak": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/keccak/-/keccak-2.0.0.tgz",
|
||||
"integrity": "sha512-rKe/lRr0KGhjoz97cwg+oeT1Rj/Y4cjae6glArioUC8JBF9ROGZctwIaaruM7d7naovME4Q8WcQSO908A8qcyQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bindings": "^1.2.1",
|
||||
"inherits": "^2.0.3",
|
||||
"nan": "^2.2.1",
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"lcid": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
|
||||
@@ -841,9 +871,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.11",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"map-age-cleaner": {
|
||||
@@ -920,6 +950,12 @@
|
||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
|
||||
"dev": true
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
|
||||
"dev": true
|
||||
},
|
||||
"natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -1183,6 +1219,12 @@
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
@@ -1229,15 +1271,17 @@
|
||||
}
|
||||
},
|
||||
"snarkjs": {
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.9.tgz",
|
||||
"integrity": "sha512-UMiONT6f86bTB0AyT7bC+QsMgv2wwMk4qz7CYvTK6assojA4poEocJuEc5wl/awHsibQTbX2zNqqnO+IAYMfTA==",
|
||||
"version": "0.1.14",
|
||||
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.14.tgz",
|
||||
"integrity": "sha512-mNsWx5K0ojz73689ZARwqyY62ENvW43movC+WMEHVYsFdcX9lpG+ZjiJGvnQh7LkYg2WY2lFzsXTUZI35TxqeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big-integer": "^1.6.35",
|
||||
"chai": "^4.1.2",
|
||||
"eslint": "^5.3.0",
|
||||
"yargs": "^12.0.2"
|
||||
"big-integer": "^1.6.43",
|
||||
"chai": "^4.2.0",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"eslint": "^5.16.0",
|
||||
"keccak": "^2.0.0",
|
||||
"yargs": "^12.0.5"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "circom",
|
||||
"version": "0.0.26",
|
||||
"version": "0.0.35",
|
||||
"description": "Language to generate logic circuits",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
@@ -38,6 +38,6 @@
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-mocha": "^5.3.0",
|
||||
"jison": "^0.4.18",
|
||||
"snarkjs": "0.1.9"
|
||||
"snarkjs": "0.1.14"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ if { return 'if'; }
|
||||
else { return 'else'; }
|
||||
for { return 'for'; }
|
||||
while { return 'while'; }
|
||||
compute { return 'compute'; }
|
||||
do { return 'do'; }
|
||||
return { return 'return'; }
|
||||
include { return 'include'; }
|
||||
@@ -198,6 +199,10 @@ statment
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| computeStatment
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| returnStatment
|
||||
{
|
||||
$$ = $1;
|
||||
@@ -302,6 +307,14 @@ doWhileStatment
|
||||
}
|
||||
;
|
||||
|
||||
computeStatment
|
||||
: 'compute' statment
|
||||
{
|
||||
$$ = { type: "COMPUTE", body: $2 };
|
||||
setLines($$, @1, @2);
|
||||
}
|
||||
;
|
||||
|
||||
returnStatment
|
||||
: 'return' expression ';'
|
||||
{
|
||||
|
||||
330
parser/jaz.js
330
parser/jaz.js
File diff suppressed because one or more lines are too long
194
src/compiler.js
194
src/compiler.js
@@ -33,7 +33,13 @@ const parser = require("../parser/jaz.js").parser;
|
||||
|
||||
const timeout = ms => new Promise(res => setTimeout(res, ms));
|
||||
|
||||
async function compile(srcFile) {
|
||||
async function compile(srcFile, options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (typeof options.reduceConstraints === "undefined") {
|
||||
options.reduceConstraints = true;
|
||||
}
|
||||
const fullFileName = srcFile;
|
||||
const fullFilePath = path.dirname(fullFileName);
|
||||
|
||||
@@ -59,7 +65,8 @@ async function compile(srcFile) {
|
||||
functions: {},
|
||||
functionParams: {},
|
||||
filePath: fullFilePath,
|
||||
fileName: fullFileName
|
||||
fileName: fullFileName,
|
||||
verbose: options.verbose || false
|
||||
};
|
||||
|
||||
|
||||
@@ -69,14 +76,19 @@ async function compile(srcFile) {
|
||||
throw new Error("A main component must be defined");
|
||||
}
|
||||
|
||||
if (ctx.verbose) console.log("Classify Signals");
|
||||
classifySignals(ctx);
|
||||
reduceConstants(ctx);
|
||||
|
||||
// Repeat while reductions are performed
|
||||
let oldNConstrains = -1;
|
||||
while (ctx.constraints.length != oldNConstrains) {
|
||||
oldNConstrains = ctx.constraints.length;
|
||||
reduceConstrains(ctx);
|
||||
if (ctx.verbose) console.log("Reduce Constraints");
|
||||
reduceConstants(ctx);
|
||||
if (options.reduceConstraints) {
|
||||
|
||||
// Repeat while reductions are performed
|
||||
let oldNConstrains = -1;
|
||||
while (ctx.constraints.length != oldNConstrains) {
|
||||
oldNConstrains = ctx.constraints.length;
|
||||
reduceConstrains(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
generateWitnessNames(ctx);
|
||||
@@ -208,6 +220,7 @@ function generateWitnessNames(ctx) {
|
||||
function reduceConstants(ctx) {
|
||||
const newConstraints = [];
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
if ((ctx.verbose)&&(i%10000 == 0)) console.log("reducing constants: ", i);
|
||||
const c = lc.canonize(ctx, ctx.constraints[i]);
|
||||
if (!lc.isZero(c)) {
|
||||
newConstraints.push(c);
|
||||
@@ -217,66 +230,135 @@ function reduceConstants(ctx) {
|
||||
}
|
||||
|
||||
function reduceConstrains(ctx) {
|
||||
const newConstraints = [];
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
const c = ctx.constraints[i];
|
||||
indexVariables();
|
||||
let possibleConstraints = Object.keys(ctx.constraints);
|
||||
while (possibleConstraints.length>0) {
|
||||
let nextPossibleConstraints = {};
|
||||
for (let i in possibleConstraints) {
|
||||
if ((ctx.verbose)&&(i%10000 == 0)) console.log("reducing constraints: ", i);
|
||||
if (!ctx.constraints[i]) continue;
|
||||
const c = ctx.constraints[i];
|
||||
|
||||
// Swap a and b if b has more variables.
|
||||
if (Object.keys(c.b).length > Object.keys(c.a).length) {
|
||||
const aux = c.a;
|
||||
c.a=c.b;
|
||||
c.b=aux;
|
||||
}
|
||||
// Swap a and b if b has more variables.
|
||||
if (Object.keys(c.b).length > Object.keys(c.a).length) {
|
||||
const aux = c.a;
|
||||
c.a=c.b;
|
||||
c.b=aux;
|
||||
}
|
||||
|
||||
// Mov to C if possible.
|
||||
if (isConstant(c.a)) {
|
||||
const ct = {type: "NUMBER", value: c.a.values["one"]};
|
||||
c.c = lc.add(lc.mul(c.b, ct), c.c);
|
||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
||||
}
|
||||
if (isConstant(c.b)) {
|
||||
const ct = {type: "NUMBER", value: c.b.values["one"]};
|
||||
c.c = lc.add(lc.mul(c.a, ct), c.c);
|
||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
||||
}
|
||||
// Mov to C if possible.
|
||||
if (isConstant(c.a)) {
|
||||
const ct = {type: "NUMBER", value: c.a.values["one"]};
|
||||
c.c = lc.add(lc.mul(c.b, ct), c.c);
|
||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
||||
}
|
||||
if (isConstant(c.b)) {
|
||||
const ct = {type: "NUMBER", value: c.b.values["one"]};
|
||||
c.c = lc.add(lc.mul(c.a, ct), c.c);
|
||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
||||
}
|
||||
|
||||
if (lc.isZero(c.a) || lc.isZero(c.b)) {
|
||||
const isolatedSignal = getFirstInternalSignal(ctx, c.c);
|
||||
if (isolatedSignal) {
|
||||
const isolatedSignalEquivalence = {
|
||||
type: "LINEARCOMBINATION",
|
||||
values: {}
|
||||
};
|
||||
const invCoef = c.c.values[isolatedSignal].modInv(__P__);
|
||||
for (const s in c.c.values) {
|
||||
if (s != isolatedSignal) {
|
||||
const v = __P__.minus(c.c.values[s]).times(invCoef).mod(__P__);
|
||||
if (!v.isZero()) {
|
||||
isolatedSignalEquivalence.values[s] = v;
|
||||
if (lc.isZero(c.a) || lc.isZero(c.b)) {
|
||||
const isolatedSignal = getFirstInternalSignal(ctx, c.c);
|
||||
if (isolatedSignal) {
|
||||
|
||||
let lSignal = ctx.signals[isolatedSignal];
|
||||
while (lSignal.equivalence) {
|
||||
lSignal = ctx.signals[lSignal.equivalence];
|
||||
}
|
||||
|
||||
|
||||
const isolatedSignalEquivalence = {
|
||||
type: "LINEARCOMBINATION",
|
||||
values: {}
|
||||
};
|
||||
const invCoef = c.c.values[isolatedSignal].modInv(__P__);
|
||||
for (const s in c.c.values) {
|
||||
if (s != isolatedSignal) {
|
||||
const v = __P__.minus(c.c.values[s]).times(invCoef).mod(__P__);
|
||||
if (!v.isZero()) {
|
||||
isolatedSignalEquivalence.values[s] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let j=0; j<newConstraints.length; j++) {
|
||||
newConstraints[j] = lc.substitute(newConstraints[j], isolatedSignal, isolatedSignalEquivalence);
|
||||
for (let j in lSignal.inConstraints) {
|
||||
if ((j!=i)&&(ctx.constraints[j])) {
|
||||
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
|
||||
linkSignalsConstraint(j);
|
||||
if (j<i) {
|
||||
nextPossibleConstraints[j] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.constraints[i] = null;
|
||||
|
||||
lSignal.category = "constant";
|
||||
} else {
|
||||
if (lc.isZero(c.c)) ctx.constraints[i] = null;
|
||||
}
|
||||
for (let j=i+1; j<ctx.constraints.length; j++ ) {
|
||||
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
|
||||
}
|
||||
c.a={ type: "LINEARCOMBINATION", values: {} };
|
||||
c.b={ type: "LINEARCOMBINATION", values: {} };
|
||||
c.c={ type: "LINEARCOMBINATION", values: {} };
|
||||
isolatedSignal.category = "constant";
|
||||
}
|
||||
}
|
||||
possibleConstraints = Object.keys(nextPossibleConstraints);
|
||||
}
|
||||
unindexVariables();
|
||||
|
||||
if (!lc.isZero(c)) {
|
||||
newConstraints.push(c);
|
||||
// Pack the constraints
|
||||
let o = 0;
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
if (ctx.constraints[i]) {
|
||||
if (o != i) {
|
||||
ctx.constraints[o] = ctx.constraints[i];
|
||||
}
|
||||
o++;
|
||||
}
|
||||
}
|
||||
ctx.constraints = newConstraints;
|
||||
ctx.constraints.length = o;
|
||||
|
||||
function indexVariables() {
|
||||
for (let i=0; i<ctx.constraints.length; i++) linkSignalsConstraint(i);
|
||||
}
|
||||
|
||||
function linkSignalsConstraint(cidx) {
|
||||
const ct = ctx.constraints[cidx];
|
||||
for (let k in ct.a.values) linkSignal(k, cidx);
|
||||
for (let k in ct.b.values) linkSignal(k, cidx);
|
||||
for (let k in ct.c.values) linkSignal(k, cidx);
|
||||
}
|
||||
|
||||
function unindexVariables() {
|
||||
for (let s in ctx.signals) {
|
||||
let lSignal = ctx.signals[s];
|
||||
while (lSignal.equivalence) {
|
||||
lSignal = ctx.signals[lSignal.equivalence];
|
||||
}
|
||||
if (lSignal.inConstraints) delete lSignal.inConstraints;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function unlinkSignal(signalName, cidx) {
|
||||
let lSignal = ctx.signals[signalName];
|
||||
while (lSignal.equivalence) {
|
||||
lSignal = ctx.signals[lSignal.equivalence];
|
||||
}
|
||||
if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) {
|
||||
delete lSignal.inConstraints[cidx];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
function linkSignal(signalName, cidx) {
|
||||
let lSignal = ctx.signals[signalName];
|
||||
while (lSignal.equivalence) {
|
||||
lSignal = ctx.signals[lSignal.equivalence];
|
||||
}
|
||||
if (!lSignal.inConstraints) lSignal.inConstraints = {};
|
||||
lSignal.inConstraints[cidx] = true;
|
||||
}
|
||||
|
||||
function getFirstInternalSignal(ctx, l) {
|
||||
for (let k in l.values) {
|
||||
|
||||
229
src/exec.js
229
src/exec.js
@@ -131,6 +131,8 @@ function exec(ctx, ast) {
|
||||
return execFunctionCall(ctx, ast);
|
||||
} else if (ast.type == "BLOCK") {
|
||||
return execBlock(ctx, ast);
|
||||
} else if (ast.type == "COMPUTE") {
|
||||
return ;
|
||||
} else if (ast.type == "FOR") {
|
||||
return execFor(ctx, ast);
|
||||
} else if (ast.type == "WHILE") {
|
||||
@@ -179,24 +181,6 @@ function iterateSelectors(ctx, sizes, baseName, fn) {
|
||||
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] = value;
|
||||
} else {
|
||||
setScopeArray(a[sels[0]], sels.slice(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getScope(ctx, name, selectors) {
|
||||
|
||||
@@ -219,11 +203,57 @@ function getScope(ctx, name, selectors) {
|
||||
}
|
||||
|
||||
for (let i=ctx.scopes.length-1; i>=0; i--) {
|
||||
if (ctx.scopes[i][name]) return select(ctx.scopes[i][name], sels);
|
||||
if (ctx.scopes[i][name]) return select(ctx.scopes[i][name].value, sels);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getScopeRef(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, t) {
|
||||
s = s || [];
|
||||
if (s.length == 0) return [v, sels, t];
|
||||
return select(v[s[0]], s.slice(1), t);
|
||||
}
|
||||
|
||||
for (let i=ctx.scopes.length-1; i>=0; i--) {
|
||||
if (ctx.scopes[i][name]) return select(ctx.scopes[i][name].value, sels, ctx.scopes[i][name].type);
|
||||
}
|
||||
return [null, [], ""];
|
||||
}
|
||||
|
||||
|
||||
function setScopeRef(ctx, name, sels, value) {
|
||||
let l = getScopeLevel(ctx, name);
|
||||
if (l==-1) l= ctx.scopes.length-1;
|
||||
|
||||
if (sels.length == 0) {
|
||||
ctx.scopes[l][name].value = value;
|
||||
} else {
|
||||
setScopeArray(ctx.scopes[l][name].value, sels);
|
||||
}
|
||||
|
||||
function setScopeArray(a, sels) {
|
||||
if (sels.length == 1) {
|
||||
a[sels[0]] = value;
|
||||
} else {
|
||||
setScopeArray(a[sels[0]], sels.slice(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getScopeLevel(ctx, name) {
|
||||
for (let i=ctx.scopes.length-1; i>=0; i--) {
|
||||
if (ctx.scopes[i][name]) return i;
|
||||
@@ -247,11 +277,14 @@ function execTemplateDef(ctx, ast) {
|
||||
}
|
||||
scope[ast.name] = {
|
||||
type: "TEMPLATE",
|
||||
params: ast.params,
|
||||
block: ast.block,
|
||||
fileName: ctx.fileName,
|
||||
filePath: ctx.filePath,
|
||||
scopes: copyScope(ctx.scopes)
|
||||
value: {
|
||||
type: "TEMPLATE",
|
||||
params: ast.params,
|
||||
block: ast.block,
|
||||
fileName: ctx.fileName,
|
||||
filePath: ctx.filePath,
|
||||
scopes: copyScope(ctx.scopes)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -264,11 +297,14 @@ function execFunctionDef(ctx, ast) {
|
||||
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)
|
||||
value: {
|
||||
type: "FUNCTION",
|
||||
params: ast.params,
|
||||
block: ast.block,
|
||||
fileName: ctx.fileName,
|
||||
filePath: ctx.filePath,
|
||||
scopes: copyScope(ctx.scopes)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -292,15 +328,18 @@ function execDeclareComponent(ctx, ast) {
|
||||
}
|
||||
|
||||
|
||||
scope[ast.name.name] = iterateSelectors(ctx, sizes, baseName, function(fullName) {
|
||||
scope[ast.name.name] = {
|
||||
type: "COMPONENT",
|
||||
value: iterateSelectors(ctx, sizes, baseName, function(fullName) {
|
||||
|
||||
ctx.components[fullName] = "UNINSTANTIATED";
|
||||
ctx.components[fullName] = "UNINSTANTIATED";
|
||||
|
||||
return {
|
||||
type: "COMPONENT",
|
||||
fullName: fullName
|
||||
};
|
||||
});
|
||||
return {
|
||||
type: "COMPONENT",
|
||||
fullName: fullName
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
return {
|
||||
type: "VARIABLE",
|
||||
@@ -376,7 +415,10 @@ function execInstantiateComponet(ctx, vr, fn) {
|
||||
|
||||
const scope = {};
|
||||
for (let i=0; i< template.params.length; i++) {
|
||||
scope[template.params[i]] = paramValues[i];
|
||||
scope[template.params[i]] = {
|
||||
type: "VARIABLE",
|
||||
value: paramValues[i]
|
||||
};
|
||||
ctx.components[ctx.currentComponent].params[template.params[i]] = extractValue(paramValues[i]);
|
||||
}
|
||||
|
||||
@@ -397,6 +439,12 @@ function execInstantiateComponet(ctx, vr, fn) {
|
||||
|
||||
function execFunctionCall(ctx, ast) {
|
||||
|
||||
if (ast.name == "log") {
|
||||
const v = exec(ctx, ast.params[0]);
|
||||
console.log(v.value.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
const scopeLevel = getScopeLevel(ctx, ast.name);
|
||||
if (scopeLevel == -1) return error(ctx, ast, "Function not defined: " + ast.name);
|
||||
const fnc = getScope(ctx, ast.name);
|
||||
@@ -422,7 +470,10 @@ function execFunctionCall(ctx, ast) {
|
||||
|
||||
const scope = {};
|
||||
for (let i=0; i< fnc.params.length; i++) {
|
||||
scope[fnc.params[i]] = paramValues[i];
|
||||
scope[fnc.params[i]] = {
|
||||
type: "VARIABLE",
|
||||
value: paramValues[i]
|
||||
};
|
||||
}
|
||||
|
||||
ctx.fileName = fnc.fileName;
|
||||
@@ -464,21 +515,24 @@ function execDeclareSignal(ctx, ast) {
|
||||
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" : ""),
|
||||
private: ast.private,
|
||||
component: ctx.currentComponent,
|
||||
equivalence: "",
|
||||
alias: [fullName]
|
||||
};
|
||||
ctx.components[ctx.currentComponent].signals.push(fullName);
|
||||
return {
|
||||
type: "SIGNAL",
|
||||
fullName: fullName,
|
||||
};
|
||||
});
|
||||
scope[ast.name.name] = {
|
||||
type: "SIGNAL",
|
||||
value: iterateSelectors(ctx, sizes, baseName, function(fullName) {
|
||||
ctx.signals[fullName] = {
|
||||
fullName: fullName,
|
||||
direction: ast.declareType == "SIGNALIN" ? "IN" : (ast.declareType == "SIGNALOUT" ? "OUT" : ""),
|
||||
private: ast.private,
|
||||
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,
|
||||
@@ -501,12 +555,15 @@ function execDeclareVariable(ctx, ast) {
|
||||
sizes.push( size.value.toJSNumber() );
|
||||
}
|
||||
|
||||
scope[ast.name.name] = iterateSelectors(ctx, sizes, "", function() {
|
||||
return {
|
||||
type: "NUMBER",
|
||||
value: bigInt(0)
|
||||
};
|
||||
});
|
||||
scope[ast.name.name] = {
|
||||
type: "VARIABLE",
|
||||
value: iterateSelectors(ctx, sizes, "", function() {
|
||||
return {
|
||||
type: "NUMBER",
|
||||
value: bigInt(0)
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
return {
|
||||
type: "VARIABLE",
|
||||
@@ -623,19 +680,20 @@ function execVarAssignement(ctx, ast) {
|
||||
} else {
|
||||
v = ast.values[0];
|
||||
}
|
||||
const num = getScope(ctx, v.name, v.selectors);
|
||||
const [num, sels, typ] = getScopeRef(ctx, v.name, v.selectors);
|
||||
if (ctx.error) return;
|
||||
|
||||
if ((typeof(num) != "object")||(num == null)) return error(ctx, ast, "Variable not defined");
|
||||
|
||||
if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);
|
||||
if (typ == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);
|
||||
if (ctx.error) return;
|
||||
// if (num.type == "SIGNAL") return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops");
|
||||
if ((typ == "SIGNAL")&&(ast.op == "=")) return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops");
|
||||
if ((["NUMBER", "COMPONENT"].indexOf(typ) >= 0 )&&(ast.op != "=")) return error(ctx, ast, `Cannot assign to a var with ${ast.op}. use = op`);
|
||||
|
||||
const res = exec(ctx, ast.values[1]);
|
||||
if (ctx.error) return;
|
||||
|
||||
setScope(ctx, v.name, v.selectors, res);
|
||||
setScopeRef(ctx, v.name, sels, res);
|
||||
|
||||
return v;
|
||||
}
|
||||
@@ -750,7 +808,7 @@ function execAnd(ctx, ast) {
|
||||
if (!a.value || !b.value) return { type: "NUMBER" };
|
||||
return {
|
||||
type: "NUMBER",
|
||||
value: (a.value.neq(0) && a.value.neq(0)) ? bigInt(1) : bigInt(0)
|
||||
value: (a.value.neq(0) && b.value.neq(0)) ? bigInt(1) : bigInt(0)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -764,7 +822,7 @@ function execOr(ctx, ast) {
|
||||
if (!a.value || !b.value) return { type: "NUMBER" };
|
||||
return {
|
||||
type: "NUMBER",
|
||||
value: (a.value.neq(0) || a.value.neq(0)) ? bigInt(1) : bigInt(0)
|
||||
value: (a.value.neq(0) || b.value.neq(0)) ? bigInt(1) : bigInt(0)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -907,13 +965,13 @@ function execMul(ctx, ast) {
|
||||
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] });
|
||||
return execVarAssignement(ctx, { op:"=", 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] });
|
||||
return execVarAssignement(ctx, { op:"=", values: [ast.values[0], res] });
|
||||
}
|
||||
|
||||
function execPlusPlusRight(ctx, ast) {
|
||||
@@ -921,7 +979,7 @@ function execPlusPlusRight(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] });
|
||||
execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
|
||||
return resBefore;
|
||||
}
|
||||
|
||||
@@ -929,7 +987,7 @@ 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] });
|
||||
execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
|
||||
return resAfter;
|
||||
}
|
||||
|
||||
@@ -938,7 +996,7 @@ function execMinusMinusRight(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
|
||||
if (ctx.error) return;
|
||||
execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
|
||||
execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
|
||||
return resBefore;
|
||||
}
|
||||
|
||||
@@ -946,7 +1004,7 @@ function execMinusMinusLeft(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
|
||||
if (ctx.error) return;
|
||||
execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
|
||||
execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
|
||||
return resAfter;
|
||||
}
|
||||
|
||||
@@ -988,7 +1046,12 @@ function execSignalAssign(ctx, ast) {
|
||||
|
||||
let sDest=ctx.signals[dst.fullName];
|
||||
if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.fullName);
|
||||
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
|
||||
|
||||
let isOut = (sDest.component == "main")&&(sDest.direction=="OUT");
|
||||
while (sDest.equivalence) {
|
||||
sDest=ctx.signals[sDest.equivalence];
|
||||
isOut = isOut || ((sDest.component == "main")&&(sDest.direction=="OUT"));
|
||||
}
|
||||
|
||||
if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
|
||||
|
||||
@@ -1016,10 +1079,20 @@ function execSignalAssign(ctx, ast) {
|
||||
|
||||
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;
|
||||
let sSrc = ctx.signals[src.fullName];
|
||||
let isIn = (sSrc.component == "main")&&(sSrc.direction == "IN");
|
||||
while (sSrc.equivalence) {
|
||||
sSrc=ctx.signals[sSrc.equivalence];
|
||||
isIn = isIn || ((sSrc.component == "main")&&(sSrc.direction == "IN"));
|
||||
}
|
||||
|
||||
// Skip if an out is assigned directly to an input.
|
||||
if ((!isIn)||(!isOut)) {
|
||||
sDest.equivalence = src.fullName;
|
||||
sDest.alias = sDest.alias.concat(src.alias);
|
||||
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
|
||||
assignValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (assignValue) {
|
||||
@@ -1038,6 +1111,8 @@ function execSignalAssign(ctx, ast) {
|
||||
}
|
||||
|
||||
function execConstrain(ctx, ast) {
|
||||
ast.fileName = ctx.fileName;
|
||||
ast.filePath = ctx.filePath;
|
||||
const a = exec(ctx, ast.values[0]);
|
||||
if (ctx.error) return;
|
||||
const b = exec(ctx, ast.values[1]);
|
||||
@@ -1050,6 +1125,8 @@ function execConstrain(ctx, ast) {
|
||||
ctx.constraints.push(lc.toQEQ(res));
|
||||
}
|
||||
|
||||
if (ctx.constraints.length % 10000 == 0) console.log("Constraints: " + ctx.constraints.length);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,8 @@ function gen(ctx, ast) {
|
||||
return genFunctionCall(ctx, ast);
|
||||
} else if (ast.type == "BLOCK") {
|
||||
return genBlock(ctx, ast);
|
||||
} else if (ast.type == "COMPUTE") {
|
||||
return genCompute(ctx, ast);
|
||||
} else if (ast.type == "FOR") {
|
||||
return genFor(ctx, ast);
|
||||
} else if (ast.type == "WHILE") {
|
||||
@@ -245,7 +247,7 @@ function genFor(ctx, ast) {
|
||||
const body = gen(ctx, ast.body);
|
||||
if (ctx.error) return;
|
||||
ctx.scopes.pop();
|
||||
return `for (${init};${condition};${step}) { \n${body}\n }\n`;
|
||||
return `for (${init};bigInt(${condition}).neq(bigInt(0));${step}) { \n${body}\n }\n`;
|
||||
}
|
||||
|
||||
function genWhile(ctx, ast) {
|
||||
@@ -253,7 +255,13 @@ function genWhile(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
const body = gen(ctx, ast.body);
|
||||
if (ctx.error) return;
|
||||
return `while (${condition}) {\n${body}\n}\n`;
|
||||
return `while (bigInt(${condition}).neq(bigInt(0))) {\n${body}\n}\n`;
|
||||
}
|
||||
|
||||
function genCompute(ctx, ast) {
|
||||
const body = gen(ctx, ast.body);
|
||||
if (ctx.error) return;
|
||||
return `{\n${body}\n}\n`;
|
||||
}
|
||||
|
||||
function genIf(ctx, ast) {
|
||||
@@ -264,9 +272,9 @@ function genIf(ctx, ast) {
|
||||
if (ast.else) {
|
||||
const elseBody = gen(ctx, ast.else);
|
||||
if (ctx.error) return;
|
||||
return `if (${condition}) {\n${thenBody}\n} else {\n${elseBody}\n}\n`;
|
||||
return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n} else {\n${elseBody}\n}\n`;
|
||||
} else {
|
||||
return `if (${condition}) {\n${thenBody}\n}\n`;
|
||||
return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,11 +422,13 @@ function genConstrain(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
const b = gen(ctx, ast.values[1]);
|
||||
if (ctx.error) return;
|
||||
return `ctx.assert(${a}, ${b})`;
|
||||
const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
|
||||
return `ctx.assert(${a}, ${b}, \"${strErr}\")`;
|
||||
}
|
||||
|
||||
function genSignalAssignConstrain(ctx, ast) {
|
||||
return genVarAssignement(ctx, ast) + ";\n" + genConstrain(ctx, ast);
|
||||
// return genVarAssignement(ctx, ast) + ";\n" + genConstrain(ctx, ast);
|
||||
return genVarAssignement(ctx, ast);
|
||||
}
|
||||
|
||||
function genVarAddAssignement(ctx, ast) {
|
||||
|
||||
@@ -41,7 +41,7 @@ describe("Sum test", () => {
|
||||
|
||||
const witness = circuit.calculateWitness({ "i": 111});
|
||||
assert(witness[0].equals(bigInt(1)));
|
||||
assert(witness[1].equals(bigInt(111)));
|
||||
assert(witness[1].equals(bigInt(111*111)));
|
||||
assert(witness[2].equals(bigInt(111)));
|
||||
});
|
||||
// it("Should assign signal ERROR", async () => {
|
||||
@@ -49,4 +49,19 @@ describe("Sum test", () => {
|
||||
// await compiler(path.join(__dirname, "circuits", "assignsignal.circom"));
|
||||
// }, /Cannot assign to a signal .*/);
|
||||
// });
|
||||
it("Should compile a code with compute", async () => {
|
||||
const cirDef = await compiler(path.join(__dirname, "circuits", "compute.circom"));
|
||||
|
||||
const circuit = new snarkjs.Circuit(cirDef);
|
||||
|
||||
const witness = circuit.calculateWitness({ "x": 6});
|
||||
assert(witness[0].equals(bigInt(1)));
|
||||
assert(witness[1].equals(bigInt(37)));
|
||||
assert(witness[2].equals(bigInt(6)));
|
||||
});
|
||||
it("Should compile a code with compute", async () => {
|
||||
const cirDef = await compiler(path.join(__dirname, "circuits", "inout.circom"));
|
||||
|
||||
assert.equal(cirDef.constraints.length, 1);
|
||||
});
|
||||
});
|
||||
|
||||
17
test/circuits/compute.circom
Normal file
17
test/circuits/compute.circom
Normal file
@@ -0,0 +1,17 @@
|
||||
template X() {
|
||||
signal input x;
|
||||
signal output y;
|
||||
signal x2;
|
||||
signal x3;
|
||||
var a;
|
||||
compute {
|
||||
a = (x*x*x+6)/x;
|
||||
y <-- a;
|
||||
}
|
||||
|
||||
x2 <== x*x;
|
||||
x3 <== x2*x;
|
||||
x*y === x3+6;
|
||||
}
|
||||
|
||||
component main = X();
|
||||
18
test/circuits/inout.circom
Normal file
18
test/circuits/inout.circom
Normal file
@@ -0,0 +1,18 @@
|
||||
template Internal() {
|
||||
signal input in;
|
||||
signal output out;
|
||||
|
||||
out <== in;
|
||||
}
|
||||
|
||||
template InOut() {
|
||||
signal input in;
|
||||
signal output out;
|
||||
|
||||
component internal = Internal();
|
||||
|
||||
internal.in <== in;
|
||||
internal.out ==> out;
|
||||
}
|
||||
|
||||
component main = InOut();
|
||||
@@ -8,7 +8,7 @@ template X() {
|
||||
}
|
||||
|
||||
i === r;
|
||||
out <== r;
|
||||
out <== i*i;
|
||||
}
|
||||
|
||||
component main = X();
|
||||
|
||||
Reference in New Issue
Block a user