Compare commits

...

18 Commits

Author SHA1 Message Date
Jordi Baylina
680e3fe139 0.0.31 2019-08-29 16:26:28 +02:00
Jordi Baylina
f05c4e1338 compute block added 2019-08-29 16:26:19 +02:00
Jordi Baylina
597deb1eaa Merge pull request #31 from Mikerah/patch-1
Typo fixes
2019-06-27 11:40:21 +02:00
Jordi Baylina
7a1c606ca6 0.0.30 2019-06-21 10:43:11 +02:00
Jordi Baylina
6642d4cf93 Fix: include allways reduce constants 2019-06-21 10:42:49 +02:00
Jordi Baylina
da0c60a919 0.0.29 2019-06-16 00:28:32 +02:00
Jordi Baylina
534efcf355 fast mode 2019-06-16 00:27:42 +02:00
Mikerah
a43154241e Typo fixes 2019-06-10 20:41:01 -04:00
Jordi Baylina
859c98d2a4 0.0.28 2019-06-03 07:23:55 +02:00
Jordi Baylina
8048a5ef7d Fix and and or 2019-06-03 07:23:25 +02:00
Jordi Baylina
b7a41cda14 0.0.27 2019-05-11 20:55:54 +02:00
Jordi Baylina
34049f2fbd Conditions to boolean in old versions of node 2019-05-11 20:55:05 +02:00
Jordi Baylina
a602551ee5 0.0.26 2019-05-11 20:40:10 +02:00
Jordi Baylina
4d5760ff67 Merge pull request #24 from karsrhyder/patch-1
Update TUTORIAL.md
2019-05-11 20:38:29 +02:00
Jordi Baylina
4a8bcff3da Merge pull request #30 from kobigurk/master
fix: fixes ^ to do xor
2019-05-11 20:32:49 +02:00
Kobi Gurkan
b8068e8d05 fix: changes ^ to do xor 2019-05-11 19:51:30 +03:00
Jordi Baylina
54092044ae Add video tutorial link 2019-04-12 05:21:20 -07:00
Kars Rhyder
5fccdd6ef1 Update TUTORIAL.md
Some spelling and grammar things
2019-03-04 22:06:37 +01:00
14 changed files with 343 additions and 278 deletions

View File

@@ -11,6 +11,8 @@ In particular, it is designed to work in [zksnarks JavaScript library](https://g
A good starting point [is this tutorial](https://github.com/iden3/circom/blob/master/TUTORIAL.md) A good starting point [is this tutorial](https://github.com/iden3/circom/blob/master/TUTORIAL.md)
Also this [video](https://www.youtube.com/watch?v=-9TJa1hVsKA) is a good starting point.
### First circuit ### First circuit
Creation of a circuit. This is an example of a NAND door: Creation of a circuit. This is an example of a NAND door:

View File

@@ -1,20 +1,18 @@
# circom and snarkjs tutorial # circom and snarkjs tutorial
This tutorial will guide you in creating your first Zero Knowledge zkSnark circuit. It will navegate across the various techniques to write circuits and it will show you how to create proofs and verify them off-chain and on-chain on Ethereum. This tutorial will guide you in creating your first Zero Knowledge zkSnark circuit. It will take you through the various techniques to write circuits, and will show you how to create proofs and verify them off-chain and on-chain on Ethereum.
## 1. Installing the tools ## 1. Installing the tools
### 1.1 Pre-requisites ### 1.1 Pre-requisites
If you don't have it installed yet, you need to install `Node.js` in your laptop. If you don't have it installed yet, you need to install `Node.js`.
Last stable version of `Node.js` (Or 8.12.0) works just fine. But if you install the latest current version `Node.js` (10.12.0) you will see significant performance increase. This is because last versions of node includes Big Integer Libraries nativelly. The `snarkjs` library makes use of this feature if available, and this improves the performance x10 (!).
The last stable version of `Node.js` (or 8.12.0) works just fine, but if you install the latest current version `Node.js` (10.12.0) you will see a significant increase in performance. This is because last versions of node includes Big Integer Libraries nativelly. The `snarkjs` library makes use of this feature if available, and this improves the performance x10 (!).
### 1.2 Install **circom** and **snarkjs** ### 1.2 Install **circom** and **snarkjs**
Just run: Run:
```sh ```sh
npm install -g circom npm install -g circom
@@ -57,7 +55,7 @@ The only thing that the circuit does is forcing the signal `c` to be the value o
After declaring the `Multiplier` template, we instantiate it with a component named`main`. After declaring the `Multiplier` template, we instantiate it with a component named`main`.
Note: When compiling a circuit a component named `main` must always exist. Note: When compiling a circuit, a component named `main` must always exist.
### 2.2 Compile the circuit ### 2.2 Compile the circuit
@@ -111,15 +109,14 @@ The output of the setup will in the form of 2 files: `proving_key.json` and `ver
Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constrains of the circuit. Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constrains of the circuit.
`snarkjs` calculates these for you. You need to provide a file with the inputs and it will execute the circuit and calculate all the intermediate signals and the output. This set of signals is the *witness*. `snarkjs` calculates those for you. You need to provide a file with the inputs and it will execute the circuit and calculate all the intermediate signals and the output. This set of signals is the *witness*.
The zero knowledge proofs prove that you know a set of signals (witness) that match all the constraints but without revealing any of the signals except the public inputs plus the outputs. The zero knowledge proofs prove that you know a set of signals (witness) that match all the constraints, without revealing any of the signals except the public inputs plus the outputs.
For example, Imagine that you want to prove that you are able to factor 33 that means that you know two numbers `a` and `b` that when you multiply them, it results in 33. For example, imagine you want to prove you are able to factor 33. It means that you know two numbers `a` and `b` and when you multiply them, it results in 33.
> Of course you can always use one and the same number as `a` and `b`. We will deal with this problem later. > Of course you can always use one and the same number as `a` and `b`. We will deal with this problem later.
So you want to prove that you know 3 and 11. So you want to prove that you know 3 and 11.
Let's create a file named `input.json` Let's create a file named `input.json`
@@ -128,7 +125,7 @@ Let's create a file named `input.json`
{"a": 3, "b": 11} {"a": 3, "b": 11}
``` ```
And now let's calculate the witness: Now let's calculate the witness:
```sh ```sh
snarkjs calculatewitness snarkjs calculatewitness
@@ -144,7 +141,7 @@ Now that we have the witness generated, we can create the proof.
snarkjs proof snarkjs proof
``` ```
This command will use the `prooving_key.json` and the `witness.json` files by default to generate `proof.json` and `public.json` This command will use the `proving_key.json` and the `witness.json` files by default to generate `proof.json` and `public.json`
The `proof.json` file will contain the actual proof. And the `public.json` file will contain just the values of the public inputs and the outputs. The `proof.json` file will contain the actual proof. And the `public.json` file will contain just the values of the public inputs and the outputs.
@@ -159,11 +156,10 @@ snarkjs verify
This command will use `verification_key.json`, `proof.json` and `public.json` to verify that is valid. 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 an `OK` in the screen or `INVALID` otherwise. If the proof is ok, you will see `OK` or `INVALID` if not ok.
### Generate the solidity verifier ### Generate the solidity verifier
@@ -171,11 +167,11 @@ If the proof is ok, you will see an `OK` in the screen or `INVALID` otherwise.
snarkjs generateverifier snarkjs generateverifier
``` ```
This command will take the `verification_key.json` and generate a solidity code in `verifier.sol` file. This command will take the `verification_key.json` and generate solidity code in `verifier.sol` file.
You can take the code in `verifier.sol` and cut and paste in remix. You can take the code in `verifier.sol` and cut and paste it in remix.
This code contains two contracts: Pairings and Verifier. You just need to deploy the `Verifier` contract. This code contains two contracts: Pairings and Verifier. You only need to deploy the `Verifier` contract.
> You may want to use a test net like Rinkeby, Kovan or Ropsten. You can also use the Javascript VM, but in some browsers, the verification takes long and it may hang the page. > You may want to use a test net like Rinkeby, Kovan or Ropsten. You can also use the Javascript VM, but in some browsers, the verification takes long and it may hang the page.
@@ -186,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. 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 ```sh
snarkjs generatecall snarkjs generatecall
@@ -196,16 +192,16 @@ 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 every thing works ok, this method should return true.
If you just change any bit in the parameters, you can check that the result will be false. If you change any bit in the parameters, the result will be verifiably false.
## Bonus track ## Bonus track
We can fix the circuit to not accept one as any of the values by adding some extra constraints. We can fix the circuit to not accept one as any of the values by adding some extra constraints.
Here the trick is that we use the property that 0 has no inverse. so `(a-1)` should not have an inverse. Here the trick is that we use the property that 0 has no inverse. So `(a-1)` should not have an inverse.
that means that `(a-1)*inv = 1` will be inpossible to match if `a` is one. That means that `(a-1)*inv = 1` will be inpossible to match if `a` is 1.
We just calculate inv by `1/(a-1)` We just calculate inv by `1/(a-1)`
@@ -231,20 +227,19 @@ template Multiplier() {
component main = 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 Just assign a value to a signal without creating any constraints. The <-- and --> operators assign a value to a signal without creating any constraints.
The === operator just adds a constraint without assigning any value to any signal. The === operator adds a constraint without assigning any value to any signal.
The circuit has also another problem and it's that the operation works in Zr, so we need to guarantee too that 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:
## Where to go from here.
You may want to read the [README](https://github.com/iden3/circom) to learn more features about circom. 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). Or a exponentiation in the Baby Jub curve [here](https://github.com/iden3/circomlib) (Work in progress).
@@ -252,14 +247,8 @@ Or a exponentiation in the Baby Jub curve [here](https://github.com/iden3/circom
# Final note # Final note
There is nothing worst for a dev than working with a buggy compiler. This is a very early stage of the compiler, so there are many bugs and lots of works needs to be done. Please have it present if you are doing anything serious with it. There is nothing worse for a dev than working with a buggy compiler. This is a very early stage of the compiler, so there are many bugs and lots of work needs to be done. Please have it present if you are doing anything serious with it.
And please contact us for any isue you have. In general, a github issue with a small piece of code with the bug is very worthy!. And please contact us for any isue you have. In general, a github issue with a small piece of code with the bug is very useful to us.
Enjoy zero knowledge proving! Enjoy zero knowledge proving!

View File

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

3
cli.js
View File

@@ -35,6 +35,7 @@ const argv = require("yargs")
.help("h") .help("h")
.alias("h", "help") .alias("h", "help")
.alias("v", "verbose") .alias("v", "verbose")
.alias("f", "fast")
.epilogue(`Copyright (C) 2018 0kims association .epilogue(`Copyright (C) 2018 0kims association
This program comes with ABSOLUTELY NO WARRANTY; This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
@@ -56,7 +57,7 @@ if (argv._.length == 0) {
const fullFileName = path.resolve(process.cwd(), inputFile); const fullFileName = path.resolve(process.cwd(), inputFile);
const outName = argv.output ? argv.output : "circuit.json"; const outName = argv.output ? argv.output : "circuit.json";
compiler(fullFileName).then( (cir) => { compiler(fullFileName, {reduceConstraints: !argv.fast}).then( (cir) => {
fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8"); fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8");
process.exit(0); process.exit(0);
}, (err) => { }, (err) => {

74
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.0.25", "version": "0.0.31",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -119,6 +119,15 @@
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.43.tgz", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.43.tgz",
"integrity": "sha512-9dULc9jsKmXl0Aeunug8wbF+58n+hQoFjqClN7WeZwGLh0XJUWyJJ9Ee+Ep+Ql/J9fRsTVaeThp8MhiCCrY0Jg==" "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": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -423,10 +432,13 @@
} }
}, },
"eslint-utils": { "eslint-utils": {
"version": "1.3.1", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
"integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
"dev": true "dev": true,
"requires": {
"eslint-visitor-keys": "^1.0.0"
}
}, },
"eslint-visitor-keys": { "eslint-visitor-keys": {
"version": "1.0.0", "version": "1.0.0",
@@ -542,6 +554,12 @@
"flat-cache": "^2.0.1" "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": { "find-up": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
@@ -807,6 +825,18 @@
"nomnom": ">= 1.5.x" "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": { "lcid": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
@@ -841,9 +871,9 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.11", "version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true "dev": true
}, },
"map-age-cleaner": { "map-age-cleaner": {
@@ -920,6 +950,12 @@
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
"dev": true "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": { "natural-compare": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -1183,6 +1219,12 @@
"tslib": "^1.9.0" "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": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -1229,15 +1271,17 @@
} }
}, },
"snarkjs": { "snarkjs": {
"version": "0.1.9", "version": "0.1.14",
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.9.tgz", "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.14.tgz",
"integrity": "sha512-UMiONT6f86bTB0AyT7bC+QsMgv2wwMk4qz7CYvTK6assojA4poEocJuEc5wl/awHsibQTbX2zNqqnO+IAYMfTA==", "integrity": "sha512-mNsWx5K0ojz73689ZARwqyY62ENvW43movC+WMEHVYsFdcX9lpG+ZjiJGvnQh7LkYg2WY2lFzsXTUZI35TxqeA==",
"dev": true, "dev": true,
"requires": { "requires": {
"big-integer": "^1.6.35", "big-integer": "^1.6.43",
"chai": "^4.1.2", "chai": "^4.2.0",
"eslint": "^5.3.0", "escape-string-regexp": "^1.0.5",
"yargs": "^12.0.2" "eslint": "^5.16.0",
"keccak": "^2.0.0",
"yargs": "^12.0.5"
} }
}, },
"source-map": { "source-map": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.0.25", "version": "0.0.31",
"description": "Language to generate logic circuits", "description": "Language to generate logic circuits",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@@ -38,6 +38,6 @@
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-plugin-mocha": "^5.3.0", "eslint-plugin-mocha": "^5.3.0",
"jison": "^0.4.18", "jison": "^0.4.18",
"snarkjs": "0.1.9" "snarkjs": "0.1.14"
} }
} }

View File

@@ -40,6 +40,7 @@ if { return 'if'; }
else { return 'else'; } else { return 'else'; }
for { return 'for'; } for { return 'for'; }
while { return 'while'; } while { return 'while'; }
compute { return 'compute'; }
do { return 'do'; } do { return 'do'; }
return { return 'return'; } return { return 'return'; }
include { return 'include'; } include { return 'include'; }
@@ -198,6 +199,10 @@ statment
{ {
$$ = $1; $$ = $1;
} }
| computeStatment
{
$$ = $1;
}
| returnStatment | returnStatment
{ {
$$ = $1; $$ = $1;
@@ -302,6 +307,14 @@ doWhileStatment
} }
; ;
computeStatment
: 'compute' statment
{
$$ = { type: "COMPUTE", body: $2 };
setLines($$, @1, @2);
}
;
returnStatment returnStatment
: 'return' expression ';' : 'return' expression ';'
{ {
@@ -514,7 +527,7 @@ e12
: e12 '^' e11 : e12 '^' e11
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.or($3.value).and(__MASK__) }; $$ = { type: "NUMBER", value: $1.value.xor($3.value).and(__MASK__) };
} else { } else {
$$ = { type: "OP", op: "^", values: [$1, $3] }; $$ = { type: "OP", op: "^", values: [$1, $3] };
} }

File diff suppressed because one or more lines are too long

View File

@@ -33,7 +33,13 @@ const parser = require("../parser/jaz.js").parser;
const timeout = ms => new Promise(res => setTimeout(res, ms)); const timeout = ms => new Promise(res => setTimeout(res, ms));
async function compile(srcFile) { async function compile(srcFile, options) {
if (!options) {
options = {};
}
if (typeof options.reduceConstraints === "undefined") {
options.reduceConstraints = true;
}
const fullFileName = srcFile; const fullFileName = srcFile;
const fullFilePath = path.dirname(fullFileName); const fullFilePath = path.dirname(fullFileName);
@@ -70,13 +76,16 @@ async function compile(srcFile) {
} }
classifySignals(ctx); classifySignals(ctx);
reduceConstants(ctx);
// Repeat while reductions are performed reduceConstants(ctx);
let oldNConstrains = -1; if (options.reduceConstraints) {
while (ctx.constraints.length != oldNConstrains) {
oldNConstrains = ctx.constraints.length; // Repeat while reductions are performed
reduceConstrains(ctx); let oldNConstrains = -1;
while (ctx.constraints.length != oldNConstrains) {
oldNConstrains = ctx.constraints.length;
reduceConstrains(ctx);
}
} }
generateWitnessNames(ctx); generateWitnessNames(ctx);

View File

@@ -131,6 +131,8 @@ function exec(ctx, ast) {
return execFunctionCall(ctx, ast); return execFunctionCall(ctx, ast);
} else if (ast.type == "BLOCK") { } else if (ast.type == "BLOCK") {
return execBlock(ctx, ast); return execBlock(ctx, ast);
} else if (ast.type == "COMPUTE") {
return ;
} else if (ast.type == "FOR") { } else if (ast.type == "FOR") {
return execFor(ctx, ast); return execFor(ctx, ast);
} else if (ast.type == "WHILE") { } else if (ast.type == "WHILE") {
@@ -397,6 +399,12 @@ function execInstantiateComponet(ctx, vr, fn) {
function execFunctionCall(ctx, ast) { 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); const scopeLevel = getScopeLevel(ctx, ast.name);
if (scopeLevel == -1) return error(ctx, ast, "Function not defined: " + ast.name); if (scopeLevel == -1) return error(ctx, ast, "Function not defined: " + ast.name);
const fnc = getScope(ctx, ast.name); const fnc = getScope(ctx, ast.name);
@@ -750,7 +758,7 @@ function execAnd(ctx, ast) {
if (!a.value || !b.value) return { type: "NUMBER" }; if (!a.value || !b.value) return { type: "NUMBER" };
return { return {
type: "NUMBER", 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 +772,7 @@ function execOr(ctx, ast) {
if (!a.value || !b.value) return { type: "NUMBER" }; if (!a.value || !b.value) return { type: "NUMBER" };
return { return {
type: "NUMBER", 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)
}; };
} }

View File

@@ -116,6 +116,8 @@ function gen(ctx, ast) {
return genFunctionCall(ctx, ast); return genFunctionCall(ctx, ast);
} else if (ast.type == "BLOCK") { } else if (ast.type == "BLOCK") {
return genBlock(ctx, ast); return genBlock(ctx, ast);
} else if (ast.type == "COMPUTE") {
return genCompute(ctx, ast);
} else if (ast.type == "FOR") { } else if (ast.type == "FOR") {
return genFor(ctx, ast); return genFor(ctx, ast);
} else if (ast.type == "WHILE") { } else if (ast.type == "WHILE") {
@@ -245,7 +247,7 @@ function genFor(ctx, ast) {
const body = gen(ctx, ast.body); const body = gen(ctx, ast.body);
if (ctx.error) return; if (ctx.error) return;
ctx.scopes.pop(); 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) { function genWhile(ctx, ast) {
@@ -253,7 +255,13 @@ function genWhile(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
const body = gen(ctx, ast.body); const body = gen(ctx, ast.body);
if (ctx.error) return; if (ctx.error) return;
return `while (${condition}) {\n${body}\n}\n`; return `while (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) { function genIf(ctx, ast) {
@@ -264,9 +272,9 @@ function genIf(ctx, ast) {
if (ast.else) { if (ast.else) {
const elseBody = gen(ctx, ast.else); const elseBody = gen(ctx, ast.else);
if (ctx.error) return; if (ctx.error) return;
return `if (${condition}) {\n${thenBody}\n} else {\n${elseBody}\n}\n`; return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n} else {\n${elseBody}\n}\n`;
} else { } else {
return `if (${condition}) {\n${thenBody}\n}\n`; return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n}\n`;
} }
} }

View File

@@ -41,7 +41,7 @@ describe("Sum test", () => {
const witness = circuit.calculateWitness({ "i": 111}); const witness = circuit.calculateWitness({ "i": 111});
assert(witness[0].equals(bigInt(1))); 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))); assert(witness[2].equals(bigInt(111)));
}); });
// it("Should assign signal ERROR", async () => { // it("Should assign signal ERROR", async () => {
@@ -49,4 +49,14 @@ describe("Sum test", () => {
// await compiler(path.join(__dirname, "circuits", "assignsignal.circom")); // await compiler(path.join(__dirname, "circuits", "assignsignal.circom"));
// }, /Cannot assign to a signal .*/); // }, /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)));
});
}); });

View 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();

View File

@@ -8,7 +8,7 @@ template X() {
} }
i === r; i === r;
out <== r; out <== i*i;
} }
component main = X(); component main = X();