diff --git a/NOTES.md b/NOTES.md
index 4493b4a..467d76e 100644
--- a/NOTES.md
+++ b/NOTES.md
@@ -4,13 +4,15 @@ This keeps track of some development notes.
## Installing cvc5-ff
+If you are installing it Docker, checkout `Dockerfile@base` in `resources/` folder.
+
1. Clone [https://github.com/alex-ozdemir/CVC4/](https://github.com/alex-ozdemir/CVC4/) and check out branch `ff`. It's updated frequently, this note works on `ddcecc5`.
2. Download CoCoALib (0.99800 tested) from [https://cocoa.dima.unige.it/cocoa/](https://cocoa.dima.unige.it/cocoa/). Follow its instruction to install it first.
-3. Go back to `CVC4/build`, run `./configure.sh --cocoa --auto-download`. Make sure you resolve all dependencies mentioned by the output of the script.
+3. Go back to `CVC4/`, run `./configure.sh --cocoa --auto-download`. Make sure you resolve all dependencies mentioned by the output of the script.
4. Apply the patch `CVC4/cmake/deps-utils/CoCoALib-0.99800-trace.patch` to `CoCoALib` (note: you may need to temporarily change `CoCoALib-XXX` to `a`).
5. Follow instructions from CoCoALib to compile and install it again.
6. Clone the latest (not the release, `d2cc42c` tested) version of [https://github.com/SRI-CSL/libpoly.git](https://github.com/SRI-CSL/libpoly.git). Follow its instruction to install it. Note that if your computer already has `poly/` in `/usr/local/include/`, you may need to manually delete it. Then for the cmake argument when installing, go with `cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local`.
-7. Go back to `CVC4/build`, run `./configure.sh --cocoa --auto-download` again. Then `make -j4 install`.
+7. Go back to `CVC4/`, run `./configure.sh --cocoa --auto-download` again. Then go to `CVC4/build/` and do `make -j4 install`.
8. Then `cvc5` should be ready from commandline with `ff` theory support.
## The Circom DSL
diff --git a/README.md b/README.md
index f422228..62b7aa6 100644
--- a/README.md
+++ b/README.md
@@ -4,22 +4,41 @@
Picus
-Picus is a symbolic virtual machine for automated verification tasks on R1CS.
-## Building from Docker
+Picus is an implementation of the $\mathsf{QED}^2$ tool, which checks the uniqueness property (under-constrained signals) of ZKP circuits.
+
+If you are looking for the documentation for the artifact evaluation of $\mathsf{QED}^2$, please switch to the [artifact branch](https://github.com/chyanju/Picus/tree/pldi23-research-artifact).
+
+## Getting Started Guide
+
+This section provides basic instructions on how to test out the tool for the kick-the-tires phase. We provide pre-built docker image, which is recommended.
+
+### Building from Docker (Recommended)
```bash
docker build -t picus:v0 .
-docker run -it --rm picus:v0 bash
+docker run -it --memory=10g picus:v0 bash
```
-## Dependencies (Building from Source)
+> Note: you should adjust the total memory limit (10g) to a suitable value according to your machine configuration. Adding the memory restriction would prevent some benchmarks from jamming docker due to large consumption of the memory. Usually 8g memory is recommended since some benchmarks could be large.
+
+### Building from Source
+
+You can skip this section if you build the tool from Docker.
+
+Building from source is not recommended if you just want to quickly run and check the results. Some dependencies require manual building and configuration, which is system specific. One only needs to make sure the following dependencies are satisfied before the tool / basic testing instructions can be executed.
+
+#### Dependencies
- Racket (8.0+): https://racket-lang.org/
- Rosette (4.0+): https://github.com/emina/rosette
- - `raco pkg install rosette`
+ - `raco pkg install --auto rosette`
- csv-reading: https://www.neilvandyke.org/racket/csv-reading/
- - `raco pkg install csv-reading`
+ - `raco pkg install --auto csv-reading`
+ - graph-lib: [https://pkgs.racket-lang.org/package/graph-lib](https://pkgs.racket-lang.org/package/graph-lib)
+ - `raco pkg install --auto graph`
+ - math-lib: [https://pkgs.racket-lang.org/package/math-lib](https://pkgs.racket-lang.org/package/math-lib)
+ - `raco pkg install --auto math-lib`
- Rust: https://www.rust-lang.org/
- for circom parser
- Node.js: https://nodejs.org/en/
@@ -33,129 +52,143 @@ docker run -it --rm picus:v0 bash
- cvc5-ff: [https://github.com/alex-ozdemir/CVC4/tree/ff](https://github.com/alex-ozdemir/CVC4/tree/ff)
- see installation instructions [here](./NOTES.md#installing-cvc5-ff)
-## Usage
+### Basic Testing Instructions
-> Note: Picus is under development, so there are several experimental versions for the purpose of comparison. The larger the version number, the most recent the version. Ideally you should try to use the most recent version.
-
-> WIP: Lemmas applied in different versions may be different. We are working on a unified interface to it.
-
-### Constraint Preparations
-
-Note: To run the uniqueness checking on benchmarks included (circom files), you'll need to prepare them (compiling to r1cs files) first, by running:
+First change the directory to the repo's root path:
```bash
-./script/prepare-??.sh
+cd Picus/
```
-where `??` corresponds to corresponding benchmark set label.
-
-### V0: Naive Version
-
-This version directly issues the raw constraints to the solver (with some simple optimizations to the constraints to make it more readable by the user).
+Then run the script to compile the basic benchmarks:
```bash
-usage: test-v0-uniqueness.rkt [ ... ]
- is one of
- --r1cs path to target r1cs
- --solver solver to use: z3 | cvc5 (default: z3)
- --timeout timeout for every small query (default: 5000ms)
- --smt show path to generated smt files (default: false)
- --help, -h Show this help
+./scripts/prepare-circomlib.sh
```
-### V1: Naive Slicing Version
+This compiles all the "circomlib-utils" benchmarks, and won't throw any error if the environment is configured successfully.
-This builds on top of v0 version. This version incorporates the slicing features where each time only one key variable's uniqueness property is queried. The core algorithm is located at `picus/algorithms/inc.rkt`.
+Then test some benchmarks, e.g., the `Decoder` benchmark, run:
```bash
-usage: test-v1-uniqueness.rkt [ ... ]
- is one of
- --r1cs path to target r1cs
- --solver solver to use: z3 | cvc5 (default: z3)
- --timeout timeout for every small query (default: 5000ms)
- --smt show path to generated smt files (default: false)
- --help, -h Show this help
+racket ./picus-dpvl-uniqueness.rkt --solver cvc5 --timeout 5000 --weak --r1cs ./benchmarks/circomlib-cff5ab6/Decoder@multiplexer.r1cs
```
-### V2: Propagation & Preserving Version
+A successful run will output logging info ***similar*** to the following (note that actual counter-example could be different due to potential stochastic search strategy in dependant libraries):
-This builds on top of v1 version. This version incorporates a propagation procedure of the uniqueness property between two slicing queries so as to improve scalability. The core algorithm is located at `picus/algorithms/pp.rkt`.
-
-```bash
-usage: test-v2-uniqueness.rkt [ ... ]
- is one of
- --r1cs path to target r1cs
- --solver solver to use: z3 | cvc5 (default: z3)
- --timeout timeout for every small query (default: 5000ms)
- --initlvl initial level of neighboring method: 0 - full nb | 1 | 2 - disable nb (default:0)
- --smt show path to generated smt files (default: false)
- --weak only check weak safety, not strong safety (default: false)
- --get-model produce and print out counter example for every query (default: false)
- --help, -h Show this help
+```
+# r1cs file: ./benchmarks/circomlib-cff5ab6/Decoder@multiplexer.r1cs
+# timeout: 5000
+# solver: cvc5
+# selector: counter
+# precondition: ()
+# propagation: #t
+# smt: #f
+# weak: #t
+# map: #f
+# number of wires: 5
+# number of constraints: 4
+# field size (how many bytes): 32
+# inputs: (0 4).
+# outputs: (1 2 3).
+# targets: #.
+# parsing original r1cs...
+# xlist: (x0 x1 x2 x3 x4).
+# alt-xlist (x0 y1 y2 y3 x4).
+# parsing alternative r1cs...
+# configuring precondition...
+# unique: #.
+# initial known-set #
+# initial unknown-set #
+# refined known-set: #
+# refined unknown-set: #
+ # propagation (linear lemma): none.
+ # propagation (binary01 lemma): none.
+ # propagation (basis2 lemma): none.
+ # propagation (aboz lemma): none.
+ # propagation (aboz lemma): none.
+ # checking: (x1 y1), sat.
+# final unknown set #.
+# weak uniqueness: unsafe.
+# counter-example:
+ #hash((one . 1) (p . 0) (ps1 . 21888242871839275222246405745257275088548364400416034343698204186575808495616) (ps2 . 21888242871839275222246405745257275088548364400416034343698204186575808495615) (ps3 . 21888242871839275222246405745257275088548364400416034343698204186575808495614) (ps4 . 21888242871839275222246405745257275088548364400416034343698204186575808495613) (ps5 . 21888242871839275222246405745257275088548364400416034343698204186575808495612) (x0 . 0) (x1 . 1) (x2 . 0) (x3 . 1) (x4 . 0) (y1 . 0) (y2 . 0) (y3 . 0) (zero . 0)).
```
-### V3: Propagation & Preserving with Neighboring Version
+If you see this, it means the environment that you are operating on is configured successfully.
-This builds on top of v2 version. This version incorporates neighboring checking to narrow down the search scope, which will improve the performance if the ground truth of a circuit is safe. The core algorithm is located at `picus/algorithms/nb.rkt`. Note that the current neighboring version also has propagation & preserving version built inside.
+## Reusability Instructions
+
+### Quick Problem Solving for New Circuits/Benchmarks
+
+We also provide easy API to compile and solve for any new benchmarks created. First you can use the following script to compile arbitrary benchmark:
```bash
-usage: test-v3-uniqueness.rkt [ ... ]
- is one of
- --r1cs path to target r1cs
- --solver solver to use: z3 | cvc5 (default: z3)
- --timeout timeout for every small query (default: 5000ms)
- --initlvl initial level of neighboring method: 0 - full nb | 1 | 2 - disable nb (default:0)
- --smt show path to generated smt files (default: false)
- --weak only check weak safety, not strong safety (default: false)
- --help, -h Show this help
+./picus-compile.sh
```
-## Example Commands
+This will generate a `*.r1cs` file in the same path as your provided `*.circom` file. Then, use the following script to solve for the benchmark:
```bash
-# example test for the r1cs utilities
-racket ./test-read-r1cs.rkt --r1cs ./benchmarks/circomlib-cff5ab6/EscalarMulAny@escalarmulany.r1cs
+./picus-solve.sh
+```
-# check uniqueness using slicing, using cvc5
-# timeout is 3s, output and show path to smt
-racket ./test-v1-uniqueness.rkt --r1cs ./benchmarks/circomlib-cff5ab6/Mux4@mux4.r1cs --timeout 3000 --smt --solver cvc5
+This will automatically invoke the tool and output the result.
-# prepare a set of benchmarks (run from repo root)
-./scripts/prepare-iden3-core.sh
-```
+### More Options and APIs of the Tool
-## Other Commands
+The following lists out all available options for running the tool.
```bash
-# build circom parser
-cd circom-parser
-cargo build
+usage: picus-dpvl-uniqueness.rkt [ ... ]
-# use circom parser
-./circom-parser/target/debug/parser ./examples/test10.circom > ./examples/test10.json
-./circom-parser/target/debug/parser ./benchmarks/ecne/Num2BitsNeg@bitify.circom > ./benchmarks/ecne/Num2BitsNeg@bitify.json
+ is one of
-# simple circom compilation command
-# circom ./test0.circom --r1cs --wasm --sym --c
-circom -o ./examples/ ./examples/test10.circom --r1cs --sym
-circom -o ./benchmarks/ecne/ ./benchmarks/ecne/Num2BitsNeg@bitify.circom --r1cs --sym
+ --r1cs
+ path to target r1cs
+ --timeout
+ timeout for every small query (default: 5000ms)
+ --solver
+ solver to use: z3 | cvc4 | cvc5 (default: z3)
+ --selector
+ selector to use: first | counter (default: counter)
+ --precondition
+ path to precondition json (default: null)
+ --noprop
+ disable propagation (default: false / propagation on)
+ --smt
+ show path to generated smt files (default: false)
+ --weak
+ only check weak safety, not strong safety (default: false)
+ --map
+ map the r1cs signals of model to its circom variable (default: true)
+ --help, -h
+ Show this help
+ --
+ Do not treat any remaining argument as a switch (at this level)
+
+ Multiple single-letter switches can be combined after
+ one `-`. For example, `-h-` is the same as `-h --`.
+```
-# grab Ecne's readable constraints only
-julia --project=. src/gen_benchmark.jl Circom_Functions/benchmarks/bigmod_5_2.r1cs > Circom_Functions/benchmarks/bigmod_5_2.txt
+## Citations
-# calling Ecne
-circom -o ./target/ ./ecne_circomlib_tests/ooo.circom --r1cs --sym --O0
-julia --project=. src/Ecne.jl --r1cs target/ooo.r1cs --name oooo --sym target/ooo.sym
-```
+If you find our work and this tool useful in your research, please consider citing:
-## Resources
-
-- Parsing a circuit into AST: https://circom.party/
-- R1CS Binary Format: https://github.com/iden3/r1csfile/blob/master/doc/r1cs_bin_format.md
- - Wire 0 must be always mapped to label 0 and it's an input forced to value "1" implicitly
-- GF example meaning: https://discourse.julialang.org/t/new-type-definition-galois-field-in-julia-1-x/17123/7
-- Ecne's benchmarks
- - https://github.com/franklynwang/EcneProject/tree/master/ecne_circomlib_tests
-- Ecne's `readR1CS`: https://github.com/franklynwang/EcneProject/blob/master/src/R1CSConstraintSolver.jl#L1626
-- Ecne's `printEquation`: https://github.com/franklynwang/EcneProject/blob/master/src/R1CSConstraintSolver.jl#L424
-- Ecne's r1cs->string: https://github.com/franklynwang/EcneProject/blob/master/src/gen_benchmark.jl
+```
+@ARTICLE{pldi23-picus,
+ title = "Automated Detection of {Under-Constrained} Circuits in
+ {Zero-Knowledge} Proofs",
+ author = "Pailoor, Shankara and Chen, Yanju and Wang, Franklyn and
+ Rodr{\'\i}guez, Clara and Van Geffen, Jacob and Morton, Jason
+ and Chu, Michael and Gu, Brian and Feng, Yu and Dillig, I{\c
+ s}{\i}l",
+ journal = "Proc. ACM Program. Lang.",
+ publisher = "Association for Computing Machinery",
+ volume = 7,
+ number = "PLDI",
+ month = jun,
+ year = 2023,
+ address = "New York, NY, USA",
+ keywords = "SNARKs, program verification, zero-knowledge proofs"
+}
+```
diff --git a/batch-run-picus.sh b/batch-run-picus.sh
deleted file mode 100755
index d92e7d0..0000000
--- a/batch-run-picus.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-# usage: this.sh
-# example: ./batch-run-picus.sh 600 ./logs/test/ ./benchmarks/circomlib-cff5ab6/
-
-otime=$1
-logpath=$2
-targetfolder=$3
-
-mkdir -p ${logpath}
-
-for fp in ${targetfolder}/*.r1cs
-do
- fn=$(basename ${fp})
- bn="${fn%.*}"
- bp="${fp%.*}"
- echo "=================== checking: ${fn} ==================="
- timeout ${otime} racket ./test-v3-uniqueness.rkt --timeout 5000 --solver cvc5 --initlvl 0 --weak --r1cs ${fp} > ${logpath}/${bn}.log 2>&1
-done
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/aliascheck.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/aliascheck.circom
new file mode 100644
index 0000000..ff37978
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/aliascheck.circom
@@ -0,0 +1,32 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "compconstant.circom";
+
+
+template AliasCheck() {
+
+ signal input in[254];
+
+ component compConstant = CompConstant(-1);
+
+ for (var i=0; i<254; i++) in[i] ==> compConstant.in[i];
+
+ compConstant.out === 0;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/babyjub.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/babyjub.circom
new file mode 100644
index 0000000..fbd0bcb
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/babyjub.circom
@@ -0,0 +1,106 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "bitify.circom";
+include "escalarmulfix.circom";
+
+template BabyAdd() {
+ signal input x1;
+ signal input y1;
+ signal input x2;
+ signal input y2;
+ signal output xout;
+ signal output yout;
+
+ signal beta;
+ signal gamma;
+ signal delta;
+ signal tau;
+
+ var a = 168700;
+ var d = 168696;
+
+ beta <== x1*y2;
+ gamma <== y1*x2;
+ delta <== (-a*x1+y1)*(x2 + y2);
+ tau <== beta * gamma;
+
+ xout <-- (beta + gamma) / (1+ d*tau);
+ (1+ d*tau) * xout === (beta + gamma);
+
+ yout <-- (delta + a*beta - gamma) / (1-d*tau);
+ (1-d*tau)*yout === (delta + a*beta - gamma);
+}
+
+template BabyDbl() {
+ signal input x;
+ signal input y;
+ signal output xout;
+ signal output yout;
+
+ component adder = BabyAdd();
+ adder.x1 <== x;
+ adder.y1 <== y;
+ adder.x2 <== x;
+ adder.y2 <== y;
+
+ adder.xout ==> xout;
+ adder.yout ==> yout;
+}
+
+
+template BabyCheck() {
+ signal input x;
+ signal input y;
+
+ signal x2;
+ signal y2;
+
+ var a = 168700;
+ var d = 168696;
+
+ x2 <== x*x;
+ y2 <== y*y;
+
+ a*x2 + y2 === 1 + d*x2*y2;
+}
+
+// Extracts the public key from private key
+template BabyPbk() {
+ signal input in;
+ signal output Ax;
+ signal output Ay;
+
+ var BASE8 = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+
+ component pvkBits = Num2Bits(253);
+ pvkBits.in <== in;
+
+ component mulFix = EscalarMulFix(253, BASE8);
+
+ var i;
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== pvkBits.out[i];
+ }
+ Ax <== mulFix.out[0];
+ Ay <== mulFix.out[1];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/binsum.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/binsum.circom
new file mode 100644
index 0000000..5b72448
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/binsum.circom
@@ -0,0 +1,93 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+
+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 Constraint:
+ 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> k) & 1;
+
+ // Ensure out is binary
+ out[k] * (out[k] - 1) === 0;
+
+ lout += out[k] * 2**k;
+ }
+
+ // Ensure the sum;
+
+ lin === lout;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/bitify.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/bitify.circom
new file mode 100644
index 0000000..d2e753e
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/bitify.circom
@@ -0,0 +1,101 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "./comparators.circom";
+include "./aliascheck.circom";
+
+
+template Num2Bits(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * 2**i;
+ }
+
+ lc1 === in;
+}
+
+template Num2Bits_strict() {
+ signal input in;
+ signal output out[254];
+
+ component aliasCheck = AliasCheck();
+ component n2b = Num2Bits(254);
+ in ==> n2b.in;
+
+ for (var i=0; i<254; i++) {
+ n2b.out[i] ==> out[i];
+ n2b.out[i] ==> aliasCheck.in[i];
+ }
+}
+
+template Bits2Num(n) {
+ signal input in[n];
+ signal output out;
+ var lc1=0;
+
+ for (var i = 0; i out;
+}
+
+template Bits2Num_strict(n) {
+ signal input in[n];
+ signal output out;
+
+ component aliasCheck = AliasCheck();
+ component b2n = Bits2Num(254);
+
+ for (var i=0; i<254; i++) {
+ in[i] ==> b2n.in[i];
+ in[i] ==> aliasCheck.in[i];
+ }
+
+ b2n.out ==> out;
+}
+
+template Num2BitsNeg(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ component isZero;
+
+ isZero = IsZero();
+
+ var neg = n == 0 ? 0 : 2**n - in;
+
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * 2**i;
+ }
+
+ in ==> isZero.in;
+
+
+
+ lc1 + isZero.out * 2**n === 2**n - in;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/comparators.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/comparators.circom
new file mode 100644
index 0000000..db6ac26
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/comparators.circom
@@ -0,0 +1,138 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "./bitify.circom";
+include "./binsum.circom";
+
+template IsZero() {
+ signal input in;
+ signal output out;
+
+ signal inv;
+
+ inv <-- in!=0 ? 1/in : 0;
+
+ out <== -in*inv +1;
+ in*out === 0;
+}
+
+
+template IsEqual() {
+ signal input in[2];
+ signal output out;
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ isz.out ==> out;
+}
+
+template ForceEqualIfEnabled() {
+ signal input enabled;
+ signal input in[2];
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ (1 - isz.out)*enabled === 0;
+}
+
+/*
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template LessThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component num2Bits0;
+ component num2Bits1;
+
+ component adder;
+
+ adder = BinSum(n, 2);
+
+ num2Bits0 = Num2Bits(n);
+ num2Bits1 = Num2BitsNeg(n);
+
+ in[0] ==> num2Bits0.in;
+ in[1] ==> num2Bits1.in;
+
+ var i;
+ for (i=0;i adder.in[0][i];
+ num2Bits1.out[i] ==> adder.in[1][i];
+ }
+
+ adder.out[n-1] ==> out;
+}
+*/
+
+template LessThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component n2b = Num2Bits(n*2+1);
+
+ n2b.in <== in[0]+ (1< out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0];
+ lt.out ==> out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterEqThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0]+1;
+ lt.out ==> out;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/compconstant.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/compconstant.circom
new file mode 100644
index 0000000..0812242
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/compconstant.circom
@@ -0,0 +1,74 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "bitify.circom";
+
+// Returns 1 if in (in binary) > ct
+
+template CompConstant(ct) {
+ signal input in[254];
+ signal output out;
+
+ signal parts[127];
+ signal sout;
+
+ var clsb;
+ var cmsb;
+ var slsb;
+ var smsb;
+
+ var sum=0;
+
+ var b = (1 << 128) -1;
+ var a = 1;
+ var e = 1;
+ var i;
+
+ for (i=0;i<127; i++) {
+ clsb = (ct >> (i*2)) & 1;
+ cmsb = (ct >> (i*2+1)) & 1;
+ slsb = in[i*2];
+ smsb = in[i*2+1];
+
+
+ if ((cmsb==0)&(clsb==0)) {
+ parts[i] <== -b*smsb*slsb + b*smsb + b*slsb;
+ } else if ((cmsb==0)&(clsb==1)) {
+ parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a;
+ } else if ((cmsb==1)&(clsb==0)) {
+ parts[i] <== b*smsb*slsb - a*smsb + a;
+ } else {
+ parts[i] <== -a*smsb*slsb + a;
+ }
+
+ sum = sum + parts[i];
+
+ b = b -e;
+ a = a +e;
+ e = e*2;
+ }
+
+ sout <== sum;
+
+ component num2bits = Num2Bits(135);
+
+ num2bits.in <== sout;
+
+ out <== num2bits.out[127];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/escalarmulfix.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/escalarmulfix.circom
new file mode 100644
index 0000000..54c603b
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/escalarmulfix.circom
@@ -0,0 +1,298 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "mux3.circom";
+include "montgomery.circom";
+include "babyjub.circom";
+
+/*
+ Window of 3 elements, it calculates
+ out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
+ out4 = 4*base
+
+ The result should be compensated.
+ */
+
+/*
+
+ The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
+ First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
+
+ Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
+
+ And Finaly we compute the result: RES = SQ - Q
+
+ As you can see the input of the adders cannot be equal nor zero, except for the last
+ substraction that it's done in montgomery.
+
+ A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
+ is the output of the windows that it's going to be <= 2^246*B
+ */
+template WindowMulFix() {
+ signal input in[3];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== mux.out[1];
+}
+
+
+/*
+ This component does a multiplication of a escalar times a fix base
+ Signals:
+ e: The scalar in bits
+ base: the base point in edwards format
+ out: The result
+ dbl: Point in Edwards to be linked to the next segment.
+ */
+
+template SegmentMulFix(nWindows) {
+ signal input e[nWindows*3];
+ signal input base[2];
+ signal output out[2];
+ signal output dbl[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component adders[nWindows];
+ component cadders[nWindows];
+
+ // In the last step we add an extra doubler so that numbers do not match.
+ component dblLast = MontgomeryDouble();
+
+ for (i=0; i out[0];
+ cAdd.yout ==> out[1];
+
+ windows[nWindows-1].out8[0] ==> dbl[0];
+ windows[nWindows-1].out8[1] ==> dbl[1];
+}
+
+
+/*
+This component multiplies a escalar times a fixed point BASE (twisted edwards format)
+ Signals
+ e: The escalar in binary format
+ out: The output point in twisted edwards
+ */
+template EscalarMulFix(n, BASE) {
+ signal input e[n]; // Input in binary format
+ signal output out[2]; // Point (Twisted format)
+
+ var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
+ var nlastsegment = n - (nsegments-1)*249;
+
+ component segments[nsegments];
+
+ component m2e[nsegments-1];
+ component adders[nsegments-1];
+
+ var s;
+ var i;
+ var nseg;
+ var nWindows;
+
+ for (s=0; s m2e[s-1].in[0];
+ segments[s-1].dbl[1] ==> m2e[s-1].in[1];
+
+ m2e[s-1].out[0] ==> segments[s].base[0];
+ m2e[s-1].out[1] ==> segments[s].base[1];
+
+ if (s==1) {
+ segments[s-1].out[0] ==> adders[s-1].x1;
+ segments[s-1].out[1] ==> adders[s-1].y1;
+ } else {
+ adders[s-2].xout ==> adders[s-1].x1;
+ adders[s-2].yout ==> adders[s-1].y1;
+ }
+ segments[s].out[0] ==> adders[s-1].x2;
+ segments[s].out[1] ==> adders[s-1].y2;
+ }
+ }
+
+ if (nsegments == 1) {
+ segments[0].out[0] ==> out[0];
+ segments[0].out[1] ==> out[1];
+ } else {
+ adders[nsegments-2].xout ==> out[0];
+ adders[nsegments-2].yout ==> out[1];
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/merkleTree.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/merkleTree.circom
new file mode 100644
index 0000000..af3d944
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/merkleTree.circom
@@ -0,0 +1,79 @@
+include "./mimcsponge.circom";
+
+// Computes MiMC(left + right)
+template HashLeftRight(rounds) {
+ signal input left;
+ signal input right;
+
+ signal output hash;
+
+ component hasher = MiMCSponge(2, rounds, 1);
+ hasher.ins[0] <== left;
+ hasher.ins[1] <== right;
+ hasher.k <== 0;
+
+ hash <== hasher.outs[0];
+}
+
+// if pathIndex == 0 returns (left = inputElement, right = pathElement)
+// if pathIndex == 1 returns (left = pathElement, right = inputElement)
+template Selector() {
+ signal input inputElement;
+ signal input pathElement;
+ signal input pathIndex;
+
+ signal output left;
+ signal output right;
+
+ signal leftSelector1;
+ signal leftSelector2;
+ signal rightSelector1;
+ signal rightSelector2;
+
+ pathIndex * (1-pathIndex) === 0;
+
+ leftSelector1 <== (1 - pathIndex) * inputElement;
+ leftSelector2 <== (pathIndex) * pathElement;
+ rightSelector1 <== (pathIndex) * inputElement;
+ rightSelector2 <== (1 - pathIndex) * pathElement;
+
+ left <== leftSelector1 + leftSelector2;
+ right <== rightSelector1 + rightSelector2;
+}
+
+// Verifies that merkle proof is correct for given merkle root and a leaf
+// pathIndex input is an array of 0/1 selectors telling whether given pathElement is on the left or right side of merkle path
+template MerkleTree(levels, rounds) {
+ signal input leaf;
+ signal input root;
+ signal input pathElements[levels];
+ signal input pathIndex[levels];
+
+ // Picus verification output
+ signal output vOut;
+
+ component selectors[levels];
+ component hashers[levels];
+
+ for (var i = 0; i < levels; i++) {
+ selectors[i] = Selector();
+ hashers[i] = HashLeftRight(rounds);
+
+ selectors[i].pathElement <== pathElements[i];
+ selectors[i].pathIndex <== pathIndex[i];
+ }
+
+ selectors[0].inputElement <== leaf;
+ for (var i = 1; i < levels; i++) {
+ hashers[i-1].left <== selectors[i-1].left;
+ hashers[i-1].right <== selectors[i-1].right;
+ selectors[i].inputElement <== hashers[i-1].hash;
+ }
+ hashers[levels-1].left <== selectors[levels-1].left;
+ hashers[levels-1].right <== selectors[levels-1].right;
+
+ root === hashers[levels - 1].hash;
+
+ // vOut <== hashers[levels - 1].hash;
+ vOut <== hashers[0].hash;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/mimcsponge.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/mimcsponge.circom
new file mode 100644
index 0000000..0357b83
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/mimcsponge.circom
@@ -0,0 +1,291 @@
+// implements MiMC-2n/n as hash using a sponge construction.
+// log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110
+// => nRounds should be 220
+template MiMCSponge(nInputs, nRounds, nOutputs) {
+ signal input ins[nInputs];
+ signal input k;
+ signal output outs[nOutputs];
+
+ // S = R||C
+ component S[nInputs + nOutputs - 1];
+
+ for (var i = 0; i < nInputs; i++) {
+ S[i] = MiMCFeistel(nRounds);
+ S[i].k <== k;
+ if (i == 0) {
+ S[i].xL_in <== ins[0];
+ S[i].xR_in <== 0;
+ } else {
+ S[i].xL_in <== S[i-1].xL_out + ins[i];
+ S[i].xR_in <== S[i-1].xR_out;
+ }
+ }
+
+ // outs[0] = S[nInputs - 1].xL_out;
+ outs[0] <-- S[nInputs - 1].xL_out;
+
+ for (var i = 0; i < nOutputs - 1; i++) {
+ S[nInputs + i] = MiMCFeistel(nRounds);
+ S[nInputs + i].k <== k;
+ S[nInputs + i].xL_in <== S[nInputs + i - 1].xL_out;
+ S[nInputs + i].xR_in <== S[nInputs + i - 1].xR_out;
+ outs[i + 1] <== S[nInputs + i].xL_out;
+ }
+}
+
+template MiMCFeistel(nrounds) {
+ signal input xL_in;
+ signal input xR_in;
+ signal input k;
+ signal output xL_out;
+ signal output xR_out;
+
+ var c[220] = [
+ 0,
+ 7120861356467848435263064379192047478074060781135320967663101236819528304084,
+ 5024705281721889198577876690145313457398658950011302225525409148828000436681,
+ 17980351014018068290387269214713820287804403312720763401943303895585469787384,
+ 19886576439381707240399940949310933992335779767309383709787331470398675714258,
+ 1213715278223786725806155661738676903520350859678319590331207960381534602599,
+ 18162138253399958831050545255414688239130588254891200470934232514682584734511,
+ 7667462281466170157858259197976388676420847047604921256361474169980037581876,
+ 7207551498477838452286210989212982851118089401128156132319807392460388436957,
+ 9864183311657946807255900203841777810810224615118629957816193727554621093838,
+ 4798196928559910300796064665904583125427459076060519468052008159779219347957,
+ 17387238494588145257484818061490088963673275521250153686214197573695921400950,
+ 10005334761930299057035055370088813230849810566234116771751925093634136574742,
+ 11897542014760736209670863723231849628230383119798486487899539017466261308762,
+ 16771780563523793011283273687253985566177232886900511371656074413362142152543,
+ 749264854018824809464168489785113337925400687349357088413132714480582918506,
+ 3683645737503705042628598550438395339383572464204988015434959428676652575331,
+ 7556750851783822914673316211129907782679509728346361368978891584375551186255,
+ 20391289379084797414557439284689954098721219201171527383291525676334308303023,
+ 18146517657445423462330854383025300323335289319277199154920964274562014376193,
+ 8080173465267536232534446836148661251987053305394647905212781979099916615292,
+ 10796443006899450245502071131975731672911747129805343722228413358507805531141,
+ 5404287610364961067658660283245291234008692303120470305032076412056764726509,
+ 4623894483395123520243967718315330178025957095502546813929290333264120223168,
+ 16845753148201777192406958674202574751725237939980634861948953189320362207797,
+ 4622170486584704769521001011395820886029808520586507873417553166762370293671,
+ 16688277490485052681847773549197928630624828392248424077804829676011512392564,
+ 11878652861183667748838188993669912629573713271883125458838494308957689090959,
+ 2436445725746972287496138382764643208791713986676129260589667864467010129482,
+ 1888098689545151571063267806606510032698677328923740058080630641742325067877,
+ 148924106504065664829055598316821983869409581623245780505601526786791681102,
+ 18875020877782404439294079398043479420415331640996249745272087358069018086569,
+ 15189693413320228845990326214136820307649565437237093707846682797649429515840,
+ 19669450123472657781282985229369348220906547335081730205028099210442632534079,
+ 5521922218264623411380547905210139511350706092570900075727555783240701821773,
+ 4144769320246558352780591737261172907511489963810975650573703217887429086546,
+ 10097732913112662248360143041019433907849917041759137293018029019134392559350,
+ 1720059427972723034107765345743336447947522473310069975142483982753181038321,
+ 6302388219880227251325608388535181451187131054211388356563634768253301290116,
+ 6745410632962119604799318394592010194450845483518862700079921360015766217097,
+ 10858157235265583624235850660462324469799552996870780238992046963007491306222,
+ 20241898894740093733047052816576694435372877719072347814065227797906130857593,
+ 10165780782761211520836029617746977303303335603838343292431760011576528327409,
+ 2832093654883670345969792724123161241696170611611744759675180839473215203706,
+ 153011722355526826233082383360057587249818749719433916258246100068258954737,
+ 20196970640587451358539129330170636295243141659030208529338914906436009086943,
+ 3180973917010545328313139835982464870638521890385603025657430208141494469656,
+ 17198004293191777441573635123110935015228014028618868252989374962722329283022,
+ 7642160509228669138628515458941659189680509753651629476399516332224325757132,
+ 19346204940546791021518535594447257347218878114049998691060016493806845179755,
+ 11501810868606870391127866188394535330696206817602260610801897042898616817272,
+ 3113973447392053821824427670386252797811804954746053461397972968381571297505,
+ 6545064306297957002139416752334741502722251869537551068239642131448768236585,
+ 5203908808704813498389265425172875593837960384349653691918590736979872578408,
+ 2246692432011290582160062129070762007374502637007107318105405626910313810224,
+ 11760570435432189127645691249600821064883781677693087773459065574359292849137,
+ 5543749482491340532547407723464609328207990784853381797689466144924198391839,
+ 8837549193990558762776520822018694066937602576881497343584903902880277769302,
+ 12855514863299373699594410385788943772765811961581749194183533625311486462501,
+ 5363660674689121676875069134269386492382220935599781121306637800261912519729,
+ 13162342403579303950549728848130828093497701266240457479693991108217307949435,
+ 916941639326869583414469202910306428966657806899788970948781207501251816730,
+ 15618589556584434434009868216186115416835494805174158488636000580759692174228,
+ 8959562060028569701043973060670353733575345393653685776974948916988033453971,
+ 16390754464333401712265575949874369157699293840516802426621216808905079127650,
+ 168282396747788514908709091757591226095443902501365500003618183905496160435,
+ 8327443473179334761744301768309008451162322941906921742120510244986704677004,
+ 17213012626801210615058753489149961717422101711567228037597150941152495100640,
+ 10394369641533736715250242399198097296122982486516256408681925424076248952280,
+ 17784386835392322654196171115293700800825771210400152504776806618892170162248,
+ 16533189939837087893364000390641148516479148564190420358849587959161226782982,
+ 18725396114211370207078434315900726338547621160475533496863298091023511945076,
+ 7132325028834551397904855671244375895110341505383911719294705267624034122405,
+ 148317947440800089795933930720822493695520852448386394775371401743494965187,
+ 19001050671757720352890779127693793630251266879994702723636759889378387053056,
+ 18824274411769830274877839365728651108434404855803844568234862945613766611460,
+ 12771414330193951156383998390424063470766226667986423961689712557338777174205,
+ 11332046574800279729678603488745295198038913503395629790213378101166488244657,
+ 9607550223176946388146938069307456967842408600269548190739947540821716354749,
+ 8756385288462344550200229174435953103162307705310807828651304665320046782583,
+ 176061952957067086877570020242717222844908281373122372938833890096257042779,
+ 12200212977482648306758992405065921724409841940671166017620928947866825250857,
+ 10868453624107875516866146499877130701929063632959660262366632833504750028858,
+ 2016095394399807253596787752134573207202567875457560571095586743878953450738,
+ 21815578223768330433802113452339488275704145896544481092014911825656390567514,
+ 4923772847693564777744725640710197015181591950368494148029046443433103381621,
+ 1813584943682214789802230765734821149202472893379265320098816901270224589984,
+ 10810123816265612772922113403831964815724109728287572256602010709288980656498,
+ 1153669123397255702524721206511185557982017410156956216465120456256288427021,
+ 5007518659266430200134478928344522649876467369278722765097865662497773767152,
+ 2511432546938591792036639990606464315121646668029252285288323664350666551637,
+ 32883284540320451295484135704808083452381176816565850047310272290579727564,
+ 10484856914279112612610993418405543310546746652738541161791501150994088679557,
+ 2026733759645519472558796412979210009170379159866522399881566309631434814953,
+ 14731806221235869882801331463708736361296174006732553130708107037190460654379,
+ 14740327483193277147065845135561988641238516852487657117813536909482068950652,
+ 18787428285295558781869865751953016580493190547148386433580291216673009884554,
+ 3804047064713122820157099453648459188816376755739202017447862327783289895072,
+ 16709604795697901641948603019242067672006293290826991671766611326262532802914,
+ 11061717085931490100602849654034280576915102867237101935487893025907907250695,
+ 2821730726367472966906149684046356272806484545281639696873240305052362149654,
+ 17467794879902895769410571945152708684493991588672014763135370927880883292655,
+ 1571520786233540988201616650622796363168031165456869481368085474420849243232,
+ 10041051776251223165849354194892664881051125330236567356945669006147134614302,
+ 3981753758468103976812813304477670033098707002886030847251581853700311567551,
+ 4365864398105436789177703571412645548020537580493599380018290523813331678900,
+ 2391801327305361293476178683853802679507598622000359948432171562543560193350,
+ 214219368547551689972421167733597094823289857206402800635962137077096090722,
+ 18192064100315141084242006659317257023098826945893371479835220462302399655674,
+ 15487549757142039139328911515400805508248576685795694919457041092150651939253,
+ 10142447197759703415402259672441315777933858467700579946665223821199077641122,
+ 11246573086260753259993971254725613211193686683988426513880826148090811891866,
+ 6574066859860991369704567902211886840188702386542112593710271426704432301235,
+ 11311085442652291634822798307831431035776248927202286895207125867542470350078,
+ 20977948360215259915441258687649465618185769343138135384346964466965010873779,
+ 792781492853909872425531014397300057232399608769451037135936617996830018501,
+ 5027602491523497423798779154966735896562099398367163998686335127580757861872,
+ 14595204575654316237672764823862241845410365278802914304953002937313300553572,
+ 13973538843621261113924259058427434053808430378163734641175100160836376897004,
+ 16395063164993626722686882727042150241125309409717445381854913964674649318585,
+ 8465768840047024550750516678171433288207841931251654898809033371655109266663,
+ 21345603324471810861925019445720576814602636473739003852898308205213912255830,
+ 21171984405852590343970239018692870799717057961108910523876770029017785940991,
+ 10761027113757988230637066281488532903174559953630210849190212601991063767647,
+ 6678298831065390834922566306988418588227382406175769592902974103663687992230,
+ 4993662582188632374202316265508850988596880036291765531885657575099537176757,
+ 18364168158495573675698600238443218434246806358811328083953887470513967121206,
+ 3506345610354615013737144848471391553141006285964325596214723571988011984829,
+ 248732676202643792226973868626360612151424823368345645514532870586234380100,
+ 10090204501612803176317709245679152331057882187411777688746797044706063410969,
+ 21297149835078365363970699581821844234354988617890041296044775371855432973500,
+ 16729368143229828574342820060716366330476985824952922184463387490091156065099,
+ 4467191506765339364971058668792642195242197133011672559453028147641428433293,
+ 8677548159358013363291014307402600830078662555833653517843708051504582990832,
+ 1022951765127126818581466247360193856197472064872288389992480993218645055345,
+ 1888195070251580606973417065636430294417895423429240431595054184472931224452,
+ 4221265384902749246920810956363310125115516771964522748896154428740238579824,
+ 2825393571154632139467378429077438870179957021959813965940638905853993971879,
+ 19171031072692942278056619599721228021635671304612437350119663236604712493093,
+ 10780807212297131186617505517708903709488273075252405602261683478333331220733,
+ 18230936781133176044598070768084230333433368654744509969087239465125979720995,
+ 16901065971871379877929280081392692752968612240624985552337779093292740763381,
+ 146494141603558321291767829522948454429758543710648402457451799015963102253,
+ 2492729278659146790410698334997955258248120870028541691998279257260289595548,
+ 2204224910006646535594933495262085193210692406133533679934843341237521233504,
+ 16062117410185840274616925297332331018523844434907012275592638570193234893570,
+ 5894928453677122829055071981254202951712129328678534592916926069506935491729,
+ 4947482739415078212217504789923078546034438919537985740403824517728200332286,
+ 16143265650645676880461646123844627780378251900510645261875867423498913438066,
+ 397690828254561723549349897112473766901585444153303054845160673059519614409,
+ 11272653598912269895509621181205395118899451234151664604248382803490621227687,
+ 15566927854306879444693061574322104423426072650522411176731130806720753591030,
+ 14222898219492484180162096141564251903058269177856173968147960855133048449557,
+ 16690275395485630428127725067513114066329712673106153451801968992299636791385,
+ 3667030990325966886479548860429670833692690972701471494757671819017808678584,
+ 21280039024501430842616328642522421302481259067470872421086939673482530783142,
+ 15895485136902450169492923978042129726601461603404514670348703312850236146328,
+ 7733050956302327984762132317027414325566202380840692458138724610131603812560,
+ 438123800976401478772659663183448617575635636575786782566035096946820525816,
+ 814913922521637742587885320797606426167962526342166512693085292151314976633,
+ 12368712287081330853637674140264759478736012797026621876924395982504369598764,
+ 2494806857395134874309386694756263421445039103814920780777601708371037591569,
+ 16101132301514338989512946061786320637179843435886825102406248183507106312877,
+ 6252650284989960032925831409804233477770646333900692286731621844532438095656,
+ 9277135875276787021836189566799935097400042171346561246305113339462708861695,
+ 10493603554686607050979497281838644324893776154179810893893660722522945589063,
+ 8673089750662709235894359384294076697329948991010184356091130382437645649279,
+ 9558393272910366944245875920138649617479779893610128634419086981339060613250,
+ 19012287860122586147374214541764572282814469237161122489573881644994964647218,
+ 9783723818270121678386992630754842961728702994964214799008457449989291229500,
+ 15550788416669474113213749561488122552422887538676036667630838378023479382689,
+ 15016165746156232864069722572047169071786333815661109750860165034341572904221,
+ 6506225705710197163670556961299945987488979904603689017479840649664564978574,
+ 10796631184889302076168355684722130903785890709107732067446714470783437829037,
+ 19871836214837460419845806980869387567383718044439891735114283113359312279540,
+ 20871081766843466343749609089986071784031203517506781251203251608363835140622,
+ 5100105771517691442278432864090229416166996183792075307747582375962855820797,
+ 8777887112076272395250620301071581171386440850451972412060638225741125310886,
+ 5300440870136391278944213332144327695659161151625757537632832724102670898756,
+ 1205448543652932944633962232545707633928124666868453915721030884663332604536,
+ 5542499997310181530432302492142574333860449305424174466698068685590909336771,
+ 11028094245762332275225364962905938096659249161369092798505554939952525894293,
+ 19187314764836593118404597958543112407224947638377479622725713735224279297009,
+ 17047263688548829001253658727764731047114098556534482052135734487985276987385,
+ 19914849528178967155534624144358541535306360577227460456855821557421213606310,
+ 2929658084700714257515872921366736697080475676508114973627124569375444665664,
+ 15092262360719700162343163278648422751610766427236295023221516498310468956361,
+ 21578580340755653236050830649990190843552802306886938815497471545814130084980,
+ 1258781501221760320019859066036073675029057285507345332959539295621677296991,
+ 3819598418157732134449049289585680301176983019643974929528867686268702720163,
+ 8653175945487997845203439345797943132543211416447757110963967501177317426221,
+ 6614652990340435611114076169697104582524566019034036680161902142028967568142,
+ 19212515502973904821995111796203064175854996071497099383090983975618035391558,
+ 18664315914479294273286016871365663486061896605232511201418576829062292269769,
+ 11498264615058604317482574216318586415670903094838791165247179252175768794889,
+ 10814026414212439999107945133852431304483604215416531759535467355316227331774,
+ 17566185590731088197064706533119299946752127014428399631467913813769853431107,
+ 14016139747289624978792446847000951708158212463304817001882956166752906714332,
+ 8242601581342441750402731523736202888792436665415852106196418942315563860366,
+ 9244680976345080074252591214216060854998619670381671198295645618515047080988,
+ 12216779172735125538689875667307129262237123728082657485828359100719208190116,
+ 10702811721859145441471328511968332847175733707711670171718794132331147396634,
+ 6479667912792222539919362076122453947926362746906450079329453150607427372979,
+ 15117544653571553820496948522381772148324367479772362833334593000535648316185,
+ 6842203153996907264167856337497139692895299874139131328642472698663046726780,
+ 12732823292801537626009139514048596316076834307941224506504666470961250728055,
+ 6936272626871035740815028148058841877090860312517423346335878088297448888663,
+ 17297554111853491139852678417579991271009602631577069694853813331124433680030,
+ 16641596134749940573104316021365063031319260205559553673368334842484345864859,
+ 7400481189785154329569470986896455371037813715804007747228648863919991399081,
+ 2273205422216987330510475127669563545720586464429614439716564154166712854048,
+ 15162538063742142685306302282127534305212832649282186184583465569986719234456,
+ 5628039096440332922248578319648483863204530861778160259559031331287721255522,
+ 16085392195894691829567913404182676871326863890140775376809129785155092531260,
+ 14227467863135365427954093998621993651369686288941275436795622973781503444257,
+ 18224457394066545825553407391290108485121649197258948320896164404518684305122,
+ 274945154732293792784580363548970818611304339008964723447672490026510689427,
+ 11050822248291117548220126630860474473945266276626263036056336623671308219529,
+ 2119542016932434047340813757208803962484943912710204325088879681995922344971,
+ 0
+ ];
+
+ var t;
+ signal t2[nrounds];
+ signal t4[nrounds];
+ signal xL[nrounds-1];
+ signal xR[nrounds-1];
+
+ for (var i=0; i .
+*/
+
+/*
+ Source: https://en.wikipedia.org/wiki/Montgomery_curve
+
+ 1 + y 1 + y
+ [u, v] = [ ------- , ---------- ]
+ 1 - y (1 - y)x
+
+ */
+
+template Edwards2Montgomery() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- (1 + in[1]) / (1 - in[1]);
+ out[1] <-- out[0] / in[0];
+
+
+ out[0] * (1-in[1]) === (1 + in[1]);
+ out[1] * in[0] === out[0];
+}
+
+/*
+
+ u u - 1
+ [x, y] = [ ---, ------- ]
+ v u + 1
+
+ */
+template Montgomery2Edwards() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- in[0] / in[1];
+ out[1] <-- (in[0] - 1) / (in[0] + 1);
+
+ out[0] * in[1] === in[0];
+ out[1] * (in[0] + 1) === in[0] - 1;
+}
+
+
+/*
+ x2 - x1
+ lamda = ---------
+ y2 - y1
+
+ x3 + A + x1 + x2
+ x3 = B * lamda^2 - A - x1 -x2 => lamda^2 = ------------------
+ B
+
+ y3 = (2*x1 + x2 + A)*lamda - B*lamda^3 - y1 =>
+
+
+ => y3 = lamda * ( 2*x1 + x2 + A - x3 - A - x1 - x2) - y1 =>
+
+ => y3 = lamda * ( x1 - x3 ) - y1
+
+----------
+
+ y2 - y1
+ lamda = ---------
+ x2 - x1
+
+ x3 = B * lamda^2 - A - x1 -x2
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+
+template MontgomeryAdd() {
+ signal input in1[2];
+ signal input in2[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+
+ lamda <-- (in2[1] - in1[1]) / (in2[0] - in1[0]);
+ lamda * (in2[0] - in1[0]) === (in2[1] - in1[1]);
+
+ out[0] <== B*lamda*lamda - A - in1[0] -in2[0];
+ out[1] <== lamda * (in1[0] - out[0]) - in1[1];
+}
+
+/*
+
+ x1_2 = x1*x1
+
+ 3*x1_2 + 2*A*x1 + 1
+ lamda = ---------------------
+ 2*B*y1
+
+ x3 = B * lamda^2 - A - x1 -x1
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+template MontgomeryDouble() {
+ signal input in[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+ signal x1_2;
+
+ x1_2 <== in[0] * in[0];
+
+ lamda <-- (3*x1_2 + 2*A*in[0] + 1 ) / (2*B*in[1]);
+ lamda * (2*B*in[1]) === (3*x1_2 + 2*A*in[0] + 1 );
+
+ out[0] <== B*lamda*lamda - A - 2*in[0];
+ out[1] <== lamda * (in[0] - out[0]) - in[1];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/mux3.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/mux3.circom
new file mode 100644
index 0000000..a3fbc43
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/mux3.circom
@@ -0,0 +1,74 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+template MultiMux3(n) {
+ signal input c[n][8]; // Constants
+ signal input s[3]; // Selector
+ signal output out[n];
+
+ signal a210[n];
+ signal a21[n];
+ signal a20[n];
+ signal a2[n];
+
+ signal a10[n];
+ signal a1[n];
+ signal a0[n];
+ signal a[n];
+
+ // 4 constrains for the intermediary variables
+ signal s10;
+ s10 <== s[1] * s[0];
+
+ for (var i=0; i mux.s[i];
+ }
+
+ mux.out[0] ==> out;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/pedersen.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/pedersen.circom
new file mode 100644
index 0000000..582caba
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/pedersen.circom
@@ -0,0 +1,254 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "montgomery.circom";
+include "mux3.circom";
+include "babyjub.circom";
+
+template Window4() {
+ signal input in[4];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== - mux.out[1]*2*in[3] + mux.out[1]; // Negate y if in[3] is one
+}
+
+
+template Segment(nWindows) {
+ signal input in[nWindows*4];
+ signal input base[2];
+ signal output out[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component doublers1[nWindows-1];
+ component doublers2[nWindows-1];
+ component adders[nWindows-1];
+ for (i=0; i 1) {
+ m2e.in[0] <== adders[nWindows-2].out[0];
+ m2e.in[1] <== adders[nWindows-2].out[1];
+ } else {
+ m2e.in[0] <== windows[0].out[0];
+ m2e.in[1] <== windows[0].out[1];
+ }
+
+ out[0] <== m2e.out[0];
+ out[1] <== m2e.out[1];
+}
+
+template Pedersen(n) {
+ signal input in[n];
+ signal output out[2];
+
+ var BASE[10][2] = [
+ [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
+ [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
+ [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
+ [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
+ [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
+ [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
+ [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
+ [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
+ [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
+ [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
+ ];
+
+ var nSegments = ((n-1)\200)+1;
+
+ component segments[nSegments];
+
+ var i;
+ var j;
+ var nBits;
+ var nWindows;
+ for (i=0; i1) {
+ packPoint.in[0] <== adders[nSegments-2].xout;
+ packPoint.in[1] <== adders[nSegments-2].yout;
+ } else {
+ packPoint.in[0] <== segments[0].out[0];
+ packPoint.in[1] <== segments[0].out[1];
+ }
+
+ out[0] <== packPoint.out[0];
+ out[1] <== packPoint.out[1];
+*/
+
+ if (nSegments>1) {
+ out[0] <== adders[nSegments-2].xout;
+ out[1] <== adders[nSegments-2].yout;
+ } else {
+ out[0] <== segments[0].out[0];
+ out[1] <== segments[0].out[1];
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/min0-tornado-core-ce97895/withdraw.circom b/benchmarks/buggy-mix/min0-tornado-core-ce97895/withdraw.circom
new file mode 100644
index 0000000..1851118
--- /dev/null
+++ b/benchmarks/buggy-mix/min0-tornado-core-ce97895/withdraw.circom
@@ -0,0 +1,57 @@
+include "./bitify.circom";
+include "./pedersen.circom";
+include "./merkleTree.circom";
+
+// computes Pedersen(nullifier + secret)
+template CommitmentHasher() {
+ signal input nullifier;
+ signal input secret;
+
+ signal output commitment;
+ signal output nullifierHash;
+
+ component commitmentHasher = Pedersen(496);
+ component nullifierHasher = Pedersen(248);
+ component nullifierBits = Num2Bits(248);
+ component secretBits = Num2Bits(248);
+ nullifierBits.in <== nullifier;
+ secretBits.in <== secret;
+ for (var i = 0; i < 248; i++) {
+ nullifierHasher.in[i] <== nullifierBits.out[i];
+ commitmentHasher.in[i] <== nullifierBits.out[i];
+ commitmentHasher.in[i + 248] <== secretBits.out[i];
+ }
+
+ commitment <== commitmentHasher.out[0];
+ nullifierHash <== nullifierHasher.out[0];
+}
+
+// Verifies that commitment that corresponds to given secret and nullifier is included in the merkle tree of deposits
+template Withdraw(levels, rounds) {
+ signal input root;
+ signal input nullifierHash;
+ signal input receiver; // not taking part in any computations
+ signal input fee; // not taking part in any computations
+ signal input nullifier;
+ signal input secret;
+ signal input pathElements[levels];
+ signal input pathIndex[levels];
+
+ // simplified by Picus: we just provide the commitment directly
+ signal input hasherCommitment;
+
+ // Picus verification output
+ signal output vOut;
+
+ component tree = MerkleTree(levels, rounds);
+ tree.leaf <== hasherCommitment;
+ tree.root <== root;
+ for (var i = 0; i < levels; i++) {
+ tree.pathElements[i] <== pathElements[i];
+ tree.pathIndex[i] <== pathIndex[i];
+ }
+
+ vOut <== tree.vOut;
+}
+
+component main = Withdraw(2, 2);
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/aliascheck.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/aliascheck.circom
new file mode 100644
index 0000000..ff37978
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/aliascheck.circom
@@ -0,0 +1,32 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "compconstant.circom";
+
+
+template AliasCheck() {
+
+ signal input in[254];
+
+ component compConstant = CompConstant(-1);
+
+ for (var i=0; i<254; i++) in[i] ==> compConstant.in[i];
+
+ compConstant.out === 0;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/babyjub.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/babyjub.circom
new file mode 100644
index 0000000..fbd0bcb
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/babyjub.circom
@@ -0,0 +1,106 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "bitify.circom";
+include "escalarmulfix.circom";
+
+template BabyAdd() {
+ signal input x1;
+ signal input y1;
+ signal input x2;
+ signal input y2;
+ signal output xout;
+ signal output yout;
+
+ signal beta;
+ signal gamma;
+ signal delta;
+ signal tau;
+
+ var a = 168700;
+ var d = 168696;
+
+ beta <== x1*y2;
+ gamma <== y1*x2;
+ delta <== (-a*x1+y1)*(x2 + y2);
+ tau <== beta * gamma;
+
+ xout <-- (beta + gamma) / (1+ d*tau);
+ (1+ d*tau) * xout === (beta + gamma);
+
+ yout <-- (delta + a*beta - gamma) / (1-d*tau);
+ (1-d*tau)*yout === (delta + a*beta - gamma);
+}
+
+template BabyDbl() {
+ signal input x;
+ signal input y;
+ signal output xout;
+ signal output yout;
+
+ component adder = BabyAdd();
+ adder.x1 <== x;
+ adder.y1 <== y;
+ adder.x2 <== x;
+ adder.y2 <== y;
+
+ adder.xout ==> xout;
+ adder.yout ==> yout;
+}
+
+
+template BabyCheck() {
+ signal input x;
+ signal input y;
+
+ signal x2;
+ signal y2;
+
+ var a = 168700;
+ var d = 168696;
+
+ x2 <== x*x;
+ y2 <== y*y;
+
+ a*x2 + y2 === 1 + d*x2*y2;
+}
+
+// Extracts the public key from private key
+template BabyPbk() {
+ signal input in;
+ signal output Ax;
+ signal output Ay;
+
+ var BASE8 = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+
+ component pvkBits = Num2Bits(253);
+ pvkBits.in <== in;
+
+ component mulFix = EscalarMulFix(253, BASE8);
+
+ var i;
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== pvkBits.out[i];
+ }
+ Ax <== mulFix.out[0];
+ Ay <== mulFix.out[1];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/binsum.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/binsum.circom
new file mode 100644
index 0000000..5b72448
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/binsum.circom
@@ -0,0 +1,93 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+
+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 Constraint:
+ 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> k) & 1;
+
+ // Ensure out is binary
+ out[k] * (out[k] - 1) === 0;
+
+ lout += out[k] * 2**k;
+ }
+
+ // Ensure the sum;
+
+ lin === lout;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/bitify.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/bitify.circom
new file mode 100644
index 0000000..d2e753e
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/bitify.circom
@@ -0,0 +1,101 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "./comparators.circom";
+include "./aliascheck.circom";
+
+
+template Num2Bits(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * 2**i;
+ }
+
+ lc1 === in;
+}
+
+template Num2Bits_strict() {
+ signal input in;
+ signal output out[254];
+
+ component aliasCheck = AliasCheck();
+ component n2b = Num2Bits(254);
+ in ==> n2b.in;
+
+ for (var i=0; i<254; i++) {
+ n2b.out[i] ==> out[i];
+ n2b.out[i] ==> aliasCheck.in[i];
+ }
+}
+
+template Bits2Num(n) {
+ signal input in[n];
+ signal output out;
+ var lc1=0;
+
+ for (var i = 0; i out;
+}
+
+template Bits2Num_strict(n) {
+ signal input in[n];
+ signal output out;
+
+ component aliasCheck = AliasCheck();
+ component b2n = Bits2Num(254);
+
+ for (var i=0; i<254; i++) {
+ in[i] ==> b2n.in[i];
+ in[i] ==> aliasCheck.in[i];
+ }
+
+ b2n.out ==> out;
+}
+
+template Num2BitsNeg(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ component isZero;
+
+ isZero = IsZero();
+
+ var neg = n == 0 ? 0 : 2**n - in;
+
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * 2**i;
+ }
+
+ in ==> isZero.in;
+
+
+
+ lc1 + isZero.out * 2**n === 2**n - in;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/comparators.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/comparators.circom
new file mode 100644
index 0000000..db6ac26
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/comparators.circom
@@ -0,0 +1,138 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "./bitify.circom";
+include "./binsum.circom";
+
+template IsZero() {
+ signal input in;
+ signal output out;
+
+ signal inv;
+
+ inv <-- in!=0 ? 1/in : 0;
+
+ out <== -in*inv +1;
+ in*out === 0;
+}
+
+
+template IsEqual() {
+ signal input in[2];
+ signal output out;
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ isz.out ==> out;
+}
+
+template ForceEqualIfEnabled() {
+ signal input enabled;
+ signal input in[2];
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ (1 - isz.out)*enabled === 0;
+}
+
+/*
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template LessThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component num2Bits0;
+ component num2Bits1;
+
+ component adder;
+
+ adder = BinSum(n, 2);
+
+ num2Bits0 = Num2Bits(n);
+ num2Bits1 = Num2BitsNeg(n);
+
+ in[0] ==> num2Bits0.in;
+ in[1] ==> num2Bits1.in;
+
+ var i;
+ for (i=0;i adder.in[0][i];
+ num2Bits1.out[i] ==> adder.in[1][i];
+ }
+
+ adder.out[n-1] ==> out;
+}
+*/
+
+template LessThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component n2b = Num2Bits(n*2+1);
+
+ n2b.in <== in[0]+ (1< out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0];
+ lt.out ==> out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterEqThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0]+1;
+ lt.out ==> out;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/compconstant.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/compconstant.circom
new file mode 100644
index 0000000..0812242
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/compconstant.circom
@@ -0,0 +1,74 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "bitify.circom";
+
+// Returns 1 if in (in binary) > ct
+
+template CompConstant(ct) {
+ signal input in[254];
+ signal output out;
+
+ signal parts[127];
+ signal sout;
+
+ var clsb;
+ var cmsb;
+ var slsb;
+ var smsb;
+
+ var sum=0;
+
+ var b = (1 << 128) -1;
+ var a = 1;
+ var e = 1;
+ var i;
+
+ for (i=0;i<127; i++) {
+ clsb = (ct >> (i*2)) & 1;
+ cmsb = (ct >> (i*2+1)) & 1;
+ slsb = in[i*2];
+ smsb = in[i*2+1];
+
+
+ if ((cmsb==0)&(clsb==0)) {
+ parts[i] <== -b*smsb*slsb + b*smsb + b*slsb;
+ } else if ((cmsb==0)&(clsb==1)) {
+ parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a;
+ } else if ((cmsb==1)&(clsb==0)) {
+ parts[i] <== b*smsb*slsb - a*smsb + a;
+ } else {
+ parts[i] <== -a*smsb*slsb + a;
+ }
+
+ sum = sum + parts[i];
+
+ b = b -e;
+ a = a +e;
+ e = e*2;
+ }
+
+ sout <== sum;
+
+ component num2bits = Num2Bits(135);
+
+ num2bits.in <== sout;
+
+ out <== num2bits.out[127];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/escalarmulfix.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/escalarmulfix.circom
new file mode 100644
index 0000000..54c603b
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/escalarmulfix.circom
@@ -0,0 +1,298 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "mux3.circom";
+include "montgomery.circom";
+include "babyjub.circom";
+
+/*
+ Window of 3 elements, it calculates
+ out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
+ out4 = 4*base
+
+ The result should be compensated.
+ */
+
+/*
+
+ The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
+ First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
+
+ Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
+
+ And Finaly we compute the result: RES = SQ - Q
+
+ As you can see the input of the adders cannot be equal nor zero, except for the last
+ substraction that it's done in montgomery.
+
+ A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
+ is the output of the windows that it's going to be <= 2^246*B
+ */
+template WindowMulFix() {
+ signal input in[3];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== mux.out[1];
+}
+
+
+/*
+ This component does a multiplication of a escalar times a fix base
+ Signals:
+ e: The scalar in bits
+ base: the base point in edwards format
+ out: The result
+ dbl: Point in Edwards to be linked to the next segment.
+ */
+
+template SegmentMulFix(nWindows) {
+ signal input e[nWindows*3];
+ signal input base[2];
+ signal output out[2];
+ signal output dbl[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component adders[nWindows];
+ component cadders[nWindows];
+
+ // In the last step we add an extra doubler so that numbers do not match.
+ component dblLast = MontgomeryDouble();
+
+ for (i=0; i out[0];
+ cAdd.yout ==> out[1];
+
+ windows[nWindows-1].out8[0] ==> dbl[0];
+ windows[nWindows-1].out8[1] ==> dbl[1];
+}
+
+
+/*
+This component multiplies a escalar times a fixed point BASE (twisted edwards format)
+ Signals
+ e: The escalar in binary format
+ out: The output point in twisted edwards
+ */
+template EscalarMulFix(n, BASE) {
+ signal input e[n]; // Input in binary format
+ signal output out[2]; // Point (Twisted format)
+
+ var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
+ var nlastsegment = n - (nsegments-1)*249;
+
+ component segments[nsegments];
+
+ component m2e[nsegments-1];
+ component adders[nsegments-1];
+
+ var s;
+ var i;
+ var nseg;
+ var nWindows;
+
+ for (s=0; s m2e[s-1].in[0];
+ segments[s-1].dbl[1] ==> m2e[s-1].in[1];
+
+ m2e[s-1].out[0] ==> segments[s].base[0];
+ m2e[s-1].out[1] ==> segments[s].base[1];
+
+ if (s==1) {
+ segments[s-1].out[0] ==> adders[s-1].x1;
+ segments[s-1].out[1] ==> adders[s-1].y1;
+ } else {
+ adders[s-2].xout ==> adders[s-1].x1;
+ adders[s-2].yout ==> adders[s-1].y1;
+ }
+ segments[s].out[0] ==> adders[s-1].x2;
+ segments[s].out[1] ==> adders[s-1].y2;
+ }
+ }
+
+ if (nsegments == 1) {
+ segments[0].out[0] ==> out[0];
+ segments[0].out[1] ==> out[1];
+ } else {
+ adders[nsegments-2].xout ==> out[0];
+ adders[nsegments-2].yout ==> out[1];
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/merkleTree.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/merkleTree.circom
new file mode 100644
index 0000000..af3d944
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/merkleTree.circom
@@ -0,0 +1,79 @@
+include "./mimcsponge.circom";
+
+// Computes MiMC(left + right)
+template HashLeftRight(rounds) {
+ signal input left;
+ signal input right;
+
+ signal output hash;
+
+ component hasher = MiMCSponge(2, rounds, 1);
+ hasher.ins[0] <== left;
+ hasher.ins[1] <== right;
+ hasher.k <== 0;
+
+ hash <== hasher.outs[0];
+}
+
+// if pathIndex == 0 returns (left = inputElement, right = pathElement)
+// if pathIndex == 1 returns (left = pathElement, right = inputElement)
+template Selector() {
+ signal input inputElement;
+ signal input pathElement;
+ signal input pathIndex;
+
+ signal output left;
+ signal output right;
+
+ signal leftSelector1;
+ signal leftSelector2;
+ signal rightSelector1;
+ signal rightSelector2;
+
+ pathIndex * (1-pathIndex) === 0;
+
+ leftSelector1 <== (1 - pathIndex) * inputElement;
+ leftSelector2 <== (pathIndex) * pathElement;
+ rightSelector1 <== (pathIndex) * inputElement;
+ rightSelector2 <== (1 - pathIndex) * pathElement;
+
+ left <== leftSelector1 + leftSelector2;
+ right <== rightSelector1 + rightSelector2;
+}
+
+// Verifies that merkle proof is correct for given merkle root and a leaf
+// pathIndex input is an array of 0/1 selectors telling whether given pathElement is on the left or right side of merkle path
+template MerkleTree(levels, rounds) {
+ signal input leaf;
+ signal input root;
+ signal input pathElements[levels];
+ signal input pathIndex[levels];
+
+ // Picus verification output
+ signal output vOut;
+
+ component selectors[levels];
+ component hashers[levels];
+
+ for (var i = 0; i < levels; i++) {
+ selectors[i] = Selector();
+ hashers[i] = HashLeftRight(rounds);
+
+ selectors[i].pathElement <== pathElements[i];
+ selectors[i].pathIndex <== pathIndex[i];
+ }
+
+ selectors[0].inputElement <== leaf;
+ for (var i = 1; i < levels; i++) {
+ hashers[i-1].left <== selectors[i-1].left;
+ hashers[i-1].right <== selectors[i-1].right;
+ selectors[i].inputElement <== hashers[i-1].hash;
+ }
+ hashers[levels-1].left <== selectors[levels-1].left;
+ hashers[levels-1].right <== selectors[levels-1].right;
+
+ root === hashers[levels - 1].hash;
+
+ // vOut <== hashers[levels - 1].hash;
+ vOut <== hashers[0].hash;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/mimcsponge.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/mimcsponge.circom
new file mode 100644
index 0000000..0357b83
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/mimcsponge.circom
@@ -0,0 +1,291 @@
+// implements MiMC-2n/n as hash using a sponge construction.
+// log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110
+// => nRounds should be 220
+template MiMCSponge(nInputs, nRounds, nOutputs) {
+ signal input ins[nInputs];
+ signal input k;
+ signal output outs[nOutputs];
+
+ // S = R||C
+ component S[nInputs + nOutputs - 1];
+
+ for (var i = 0; i < nInputs; i++) {
+ S[i] = MiMCFeistel(nRounds);
+ S[i].k <== k;
+ if (i == 0) {
+ S[i].xL_in <== ins[0];
+ S[i].xR_in <== 0;
+ } else {
+ S[i].xL_in <== S[i-1].xL_out + ins[i];
+ S[i].xR_in <== S[i-1].xR_out;
+ }
+ }
+
+ // outs[0] = S[nInputs - 1].xL_out;
+ outs[0] <-- S[nInputs - 1].xL_out;
+
+ for (var i = 0; i < nOutputs - 1; i++) {
+ S[nInputs + i] = MiMCFeistel(nRounds);
+ S[nInputs + i].k <== k;
+ S[nInputs + i].xL_in <== S[nInputs + i - 1].xL_out;
+ S[nInputs + i].xR_in <== S[nInputs + i - 1].xR_out;
+ outs[i + 1] <== S[nInputs + i].xL_out;
+ }
+}
+
+template MiMCFeistel(nrounds) {
+ signal input xL_in;
+ signal input xR_in;
+ signal input k;
+ signal output xL_out;
+ signal output xR_out;
+
+ var c[220] = [
+ 0,
+ 7120861356467848435263064379192047478074060781135320967663101236819528304084,
+ 5024705281721889198577876690145313457398658950011302225525409148828000436681,
+ 17980351014018068290387269214713820287804403312720763401943303895585469787384,
+ 19886576439381707240399940949310933992335779767309383709787331470398675714258,
+ 1213715278223786725806155661738676903520350859678319590331207960381534602599,
+ 18162138253399958831050545255414688239130588254891200470934232514682584734511,
+ 7667462281466170157858259197976388676420847047604921256361474169980037581876,
+ 7207551498477838452286210989212982851118089401128156132319807392460388436957,
+ 9864183311657946807255900203841777810810224615118629957816193727554621093838,
+ 4798196928559910300796064665904583125427459076060519468052008159779219347957,
+ 17387238494588145257484818061490088963673275521250153686214197573695921400950,
+ 10005334761930299057035055370088813230849810566234116771751925093634136574742,
+ 11897542014760736209670863723231849628230383119798486487899539017466261308762,
+ 16771780563523793011283273687253985566177232886900511371656074413362142152543,
+ 749264854018824809464168489785113337925400687349357088413132714480582918506,
+ 3683645737503705042628598550438395339383572464204988015434959428676652575331,
+ 7556750851783822914673316211129907782679509728346361368978891584375551186255,
+ 20391289379084797414557439284689954098721219201171527383291525676334308303023,
+ 18146517657445423462330854383025300323335289319277199154920964274562014376193,
+ 8080173465267536232534446836148661251987053305394647905212781979099916615292,
+ 10796443006899450245502071131975731672911747129805343722228413358507805531141,
+ 5404287610364961067658660283245291234008692303120470305032076412056764726509,
+ 4623894483395123520243967718315330178025957095502546813929290333264120223168,
+ 16845753148201777192406958674202574751725237939980634861948953189320362207797,
+ 4622170486584704769521001011395820886029808520586507873417553166762370293671,
+ 16688277490485052681847773549197928630624828392248424077804829676011512392564,
+ 11878652861183667748838188993669912629573713271883125458838494308957689090959,
+ 2436445725746972287496138382764643208791713986676129260589667864467010129482,
+ 1888098689545151571063267806606510032698677328923740058080630641742325067877,
+ 148924106504065664829055598316821983869409581623245780505601526786791681102,
+ 18875020877782404439294079398043479420415331640996249745272087358069018086569,
+ 15189693413320228845990326214136820307649565437237093707846682797649429515840,
+ 19669450123472657781282985229369348220906547335081730205028099210442632534079,
+ 5521922218264623411380547905210139511350706092570900075727555783240701821773,
+ 4144769320246558352780591737261172907511489963810975650573703217887429086546,
+ 10097732913112662248360143041019433907849917041759137293018029019134392559350,
+ 1720059427972723034107765345743336447947522473310069975142483982753181038321,
+ 6302388219880227251325608388535181451187131054211388356563634768253301290116,
+ 6745410632962119604799318394592010194450845483518862700079921360015766217097,
+ 10858157235265583624235850660462324469799552996870780238992046963007491306222,
+ 20241898894740093733047052816576694435372877719072347814065227797906130857593,
+ 10165780782761211520836029617746977303303335603838343292431760011576528327409,
+ 2832093654883670345969792724123161241696170611611744759675180839473215203706,
+ 153011722355526826233082383360057587249818749719433916258246100068258954737,
+ 20196970640587451358539129330170636295243141659030208529338914906436009086943,
+ 3180973917010545328313139835982464870638521890385603025657430208141494469656,
+ 17198004293191777441573635123110935015228014028618868252989374962722329283022,
+ 7642160509228669138628515458941659189680509753651629476399516332224325757132,
+ 19346204940546791021518535594447257347218878114049998691060016493806845179755,
+ 11501810868606870391127866188394535330696206817602260610801897042898616817272,
+ 3113973447392053821824427670386252797811804954746053461397972968381571297505,
+ 6545064306297957002139416752334741502722251869537551068239642131448768236585,
+ 5203908808704813498389265425172875593837960384349653691918590736979872578408,
+ 2246692432011290582160062129070762007374502637007107318105405626910313810224,
+ 11760570435432189127645691249600821064883781677693087773459065574359292849137,
+ 5543749482491340532547407723464609328207990784853381797689466144924198391839,
+ 8837549193990558762776520822018694066937602576881497343584903902880277769302,
+ 12855514863299373699594410385788943772765811961581749194183533625311486462501,
+ 5363660674689121676875069134269386492382220935599781121306637800261912519729,
+ 13162342403579303950549728848130828093497701266240457479693991108217307949435,
+ 916941639326869583414469202910306428966657806899788970948781207501251816730,
+ 15618589556584434434009868216186115416835494805174158488636000580759692174228,
+ 8959562060028569701043973060670353733575345393653685776974948916988033453971,
+ 16390754464333401712265575949874369157699293840516802426621216808905079127650,
+ 168282396747788514908709091757591226095443902501365500003618183905496160435,
+ 8327443473179334761744301768309008451162322941906921742120510244986704677004,
+ 17213012626801210615058753489149961717422101711567228037597150941152495100640,
+ 10394369641533736715250242399198097296122982486516256408681925424076248952280,
+ 17784386835392322654196171115293700800825771210400152504776806618892170162248,
+ 16533189939837087893364000390641148516479148564190420358849587959161226782982,
+ 18725396114211370207078434315900726338547621160475533496863298091023511945076,
+ 7132325028834551397904855671244375895110341505383911719294705267624034122405,
+ 148317947440800089795933930720822493695520852448386394775371401743494965187,
+ 19001050671757720352890779127693793630251266879994702723636759889378387053056,
+ 18824274411769830274877839365728651108434404855803844568234862945613766611460,
+ 12771414330193951156383998390424063470766226667986423961689712557338777174205,
+ 11332046574800279729678603488745295198038913503395629790213378101166488244657,
+ 9607550223176946388146938069307456967842408600269548190739947540821716354749,
+ 8756385288462344550200229174435953103162307705310807828651304665320046782583,
+ 176061952957067086877570020242717222844908281373122372938833890096257042779,
+ 12200212977482648306758992405065921724409841940671166017620928947866825250857,
+ 10868453624107875516866146499877130701929063632959660262366632833504750028858,
+ 2016095394399807253596787752134573207202567875457560571095586743878953450738,
+ 21815578223768330433802113452339488275704145896544481092014911825656390567514,
+ 4923772847693564777744725640710197015181591950368494148029046443433103381621,
+ 1813584943682214789802230765734821149202472893379265320098816901270224589984,
+ 10810123816265612772922113403831964815724109728287572256602010709288980656498,
+ 1153669123397255702524721206511185557982017410156956216465120456256288427021,
+ 5007518659266430200134478928344522649876467369278722765097865662497773767152,
+ 2511432546938591792036639990606464315121646668029252285288323664350666551637,
+ 32883284540320451295484135704808083452381176816565850047310272290579727564,
+ 10484856914279112612610993418405543310546746652738541161791501150994088679557,
+ 2026733759645519472558796412979210009170379159866522399881566309631434814953,
+ 14731806221235869882801331463708736361296174006732553130708107037190460654379,
+ 14740327483193277147065845135561988641238516852487657117813536909482068950652,
+ 18787428285295558781869865751953016580493190547148386433580291216673009884554,
+ 3804047064713122820157099453648459188816376755739202017447862327783289895072,
+ 16709604795697901641948603019242067672006293290826991671766611326262532802914,
+ 11061717085931490100602849654034280576915102867237101935487893025907907250695,
+ 2821730726367472966906149684046356272806484545281639696873240305052362149654,
+ 17467794879902895769410571945152708684493991588672014763135370927880883292655,
+ 1571520786233540988201616650622796363168031165456869481368085474420849243232,
+ 10041051776251223165849354194892664881051125330236567356945669006147134614302,
+ 3981753758468103976812813304477670033098707002886030847251581853700311567551,
+ 4365864398105436789177703571412645548020537580493599380018290523813331678900,
+ 2391801327305361293476178683853802679507598622000359948432171562543560193350,
+ 214219368547551689972421167733597094823289857206402800635962137077096090722,
+ 18192064100315141084242006659317257023098826945893371479835220462302399655674,
+ 15487549757142039139328911515400805508248576685795694919457041092150651939253,
+ 10142447197759703415402259672441315777933858467700579946665223821199077641122,
+ 11246573086260753259993971254725613211193686683988426513880826148090811891866,
+ 6574066859860991369704567902211886840188702386542112593710271426704432301235,
+ 11311085442652291634822798307831431035776248927202286895207125867542470350078,
+ 20977948360215259915441258687649465618185769343138135384346964466965010873779,
+ 792781492853909872425531014397300057232399608769451037135936617996830018501,
+ 5027602491523497423798779154966735896562099398367163998686335127580757861872,
+ 14595204575654316237672764823862241845410365278802914304953002937313300553572,
+ 13973538843621261113924259058427434053808430378163734641175100160836376897004,
+ 16395063164993626722686882727042150241125309409717445381854913964674649318585,
+ 8465768840047024550750516678171433288207841931251654898809033371655109266663,
+ 21345603324471810861925019445720576814602636473739003852898308205213912255830,
+ 21171984405852590343970239018692870799717057961108910523876770029017785940991,
+ 10761027113757988230637066281488532903174559953630210849190212601991063767647,
+ 6678298831065390834922566306988418588227382406175769592902974103663687992230,
+ 4993662582188632374202316265508850988596880036291765531885657575099537176757,
+ 18364168158495573675698600238443218434246806358811328083953887470513967121206,
+ 3506345610354615013737144848471391553141006285964325596214723571988011984829,
+ 248732676202643792226973868626360612151424823368345645514532870586234380100,
+ 10090204501612803176317709245679152331057882187411777688746797044706063410969,
+ 21297149835078365363970699581821844234354988617890041296044775371855432973500,
+ 16729368143229828574342820060716366330476985824952922184463387490091156065099,
+ 4467191506765339364971058668792642195242197133011672559453028147641428433293,
+ 8677548159358013363291014307402600830078662555833653517843708051504582990832,
+ 1022951765127126818581466247360193856197472064872288389992480993218645055345,
+ 1888195070251580606973417065636430294417895423429240431595054184472931224452,
+ 4221265384902749246920810956363310125115516771964522748896154428740238579824,
+ 2825393571154632139467378429077438870179957021959813965940638905853993971879,
+ 19171031072692942278056619599721228021635671304612437350119663236604712493093,
+ 10780807212297131186617505517708903709488273075252405602261683478333331220733,
+ 18230936781133176044598070768084230333433368654744509969087239465125979720995,
+ 16901065971871379877929280081392692752968612240624985552337779093292740763381,
+ 146494141603558321291767829522948454429758543710648402457451799015963102253,
+ 2492729278659146790410698334997955258248120870028541691998279257260289595548,
+ 2204224910006646535594933495262085193210692406133533679934843341237521233504,
+ 16062117410185840274616925297332331018523844434907012275592638570193234893570,
+ 5894928453677122829055071981254202951712129328678534592916926069506935491729,
+ 4947482739415078212217504789923078546034438919537985740403824517728200332286,
+ 16143265650645676880461646123844627780378251900510645261875867423498913438066,
+ 397690828254561723549349897112473766901585444153303054845160673059519614409,
+ 11272653598912269895509621181205395118899451234151664604248382803490621227687,
+ 15566927854306879444693061574322104423426072650522411176731130806720753591030,
+ 14222898219492484180162096141564251903058269177856173968147960855133048449557,
+ 16690275395485630428127725067513114066329712673106153451801968992299636791385,
+ 3667030990325966886479548860429670833692690972701471494757671819017808678584,
+ 21280039024501430842616328642522421302481259067470872421086939673482530783142,
+ 15895485136902450169492923978042129726601461603404514670348703312850236146328,
+ 7733050956302327984762132317027414325566202380840692458138724610131603812560,
+ 438123800976401478772659663183448617575635636575786782566035096946820525816,
+ 814913922521637742587885320797606426167962526342166512693085292151314976633,
+ 12368712287081330853637674140264759478736012797026621876924395982504369598764,
+ 2494806857395134874309386694756263421445039103814920780777601708371037591569,
+ 16101132301514338989512946061786320637179843435886825102406248183507106312877,
+ 6252650284989960032925831409804233477770646333900692286731621844532438095656,
+ 9277135875276787021836189566799935097400042171346561246305113339462708861695,
+ 10493603554686607050979497281838644324893776154179810893893660722522945589063,
+ 8673089750662709235894359384294076697329948991010184356091130382437645649279,
+ 9558393272910366944245875920138649617479779893610128634419086981339060613250,
+ 19012287860122586147374214541764572282814469237161122489573881644994964647218,
+ 9783723818270121678386992630754842961728702994964214799008457449989291229500,
+ 15550788416669474113213749561488122552422887538676036667630838378023479382689,
+ 15016165746156232864069722572047169071786333815661109750860165034341572904221,
+ 6506225705710197163670556961299945987488979904603689017479840649664564978574,
+ 10796631184889302076168355684722130903785890709107732067446714470783437829037,
+ 19871836214837460419845806980869387567383718044439891735114283113359312279540,
+ 20871081766843466343749609089986071784031203517506781251203251608363835140622,
+ 5100105771517691442278432864090229416166996183792075307747582375962855820797,
+ 8777887112076272395250620301071581171386440850451972412060638225741125310886,
+ 5300440870136391278944213332144327695659161151625757537632832724102670898756,
+ 1205448543652932944633962232545707633928124666868453915721030884663332604536,
+ 5542499997310181530432302492142574333860449305424174466698068685590909336771,
+ 11028094245762332275225364962905938096659249161369092798505554939952525894293,
+ 19187314764836593118404597958543112407224947638377479622725713735224279297009,
+ 17047263688548829001253658727764731047114098556534482052135734487985276987385,
+ 19914849528178967155534624144358541535306360577227460456855821557421213606310,
+ 2929658084700714257515872921366736697080475676508114973627124569375444665664,
+ 15092262360719700162343163278648422751610766427236295023221516498310468956361,
+ 21578580340755653236050830649990190843552802306886938815497471545814130084980,
+ 1258781501221760320019859066036073675029057285507345332959539295621677296991,
+ 3819598418157732134449049289585680301176983019643974929528867686268702720163,
+ 8653175945487997845203439345797943132543211416447757110963967501177317426221,
+ 6614652990340435611114076169697104582524566019034036680161902142028967568142,
+ 19212515502973904821995111796203064175854996071497099383090983975618035391558,
+ 18664315914479294273286016871365663486061896605232511201418576829062292269769,
+ 11498264615058604317482574216318586415670903094838791165247179252175768794889,
+ 10814026414212439999107945133852431304483604215416531759535467355316227331774,
+ 17566185590731088197064706533119299946752127014428399631467913813769853431107,
+ 14016139747289624978792446847000951708158212463304817001882956166752906714332,
+ 8242601581342441750402731523736202888792436665415852106196418942315563860366,
+ 9244680976345080074252591214216060854998619670381671198295645618515047080988,
+ 12216779172735125538689875667307129262237123728082657485828359100719208190116,
+ 10702811721859145441471328511968332847175733707711670171718794132331147396634,
+ 6479667912792222539919362076122453947926362746906450079329453150607427372979,
+ 15117544653571553820496948522381772148324367479772362833334593000535648316185,
+ 6842203153996907264167856337497139692895299874139131328642472698663046726780,
+ 12732823292801537626009139514048596316076834307941224506504666470961250728055,
+ 6936272626871035740815028148058841877090860312517423346335878088297448888663,
+ 17297554111853491139852678417579991271009602631577069694853813331124433680030,
+ 16641596134749940573104316021365063031319260205559553673368334842484345864859,
+ 7400481189785154329569470986896455371037813715804007747228648863919991399081,
+ 2273205422216987330510475127669563545720586464429614439716564154166712854048,
+ 15162538063742142685306302282127534305212832649282186184583465569986719234456,
+ 5628039096440332922248578319648483863204530861778160259559031331287721255522,
+ 16085392195894691829567913404182676871326863890140775376809129785155092531260,
+ 14227467863135365427954093998621993651369686288941275436795622973781503444257,
+ 18224457394066545825553407391290108485121649197258948320896164404518684305122,
+ 274945154732293792784580363548970818611304339008964723447672490026510689427,
+ 11050822248291117548220126630860474473945266276626263036056336623671308219529,
+ 2119542016932434047340813757208803962484943912710204325088879681995922344971,
+ 0
+ ];
+
+ var t;
+ signal t2[nrounds];
+ signal t4[nrounds];
+ signal xL[nrounds-1];
+ signal xR[nrounds-1];
+
+ for (var i=0; i .
+*/
+
+/*
+ Source: https://en.wikipedia.org/wiki/Montgomery_curve
+
+ 1 + y 1 + y
+ [u, v] = [ ------- , ---------- ]
+ 1 - y (1 - y)x
+
+ */
+
+template Edwards2Montgomery() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- (1 + in[1]) / (1 - in[1]);
+ out[1] <-- out[0] / in[0];
+
+
+ out[0] * (1-in[1]) === (1 + in[1]);
+ out[1] * in[0] === out[0];
+}
+
+/*
+
+ u u - 1
+ [x, y] = [ ---, ------- ]
+ v u + 1
+
+ */
+template Montgomery2Edwards() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- in[0] / in[1];
+ out[1] <-- (in[0] - 1) / (in[0] + 1);
+
+ out[0] * in[1] === in[0];
+ out[1] * (in[0] + 1) === in[0] - 1;
+}
+
+
+/*
+ x2 - x1
+ lamda = ---------
+ y2 - y1
+
+ x3 + A + x1 + x2
+ x3 = B * lamda^2 - A - x1 -x2 => lamda^2 = ------------------
+ B
+
+ y3 = (2*x1 + x2 + A)*lamda - B*lamda^3 - y1 =>
+
+
+ => y3 = lamda * ( 2*x1 + x2 + A - x3 - A - x1 - x2) - y1 =>
+
+ => y3 = lamda * ( x1 - x3 ) - y1
+
+----------
+
+ y2 - y1
+ lamda = ---------
+ x2 - x1
+
+ x3 = B * lamda^2 - A - x1 -x2
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+
+template MontgomeryAdd() {
+ signal input in1[2];
+ signal input in2[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+
+ lamda <-- (in2[1] - in1[1]) / (in2[0] - in1[0]);
+ lamda * (in2[0] - in1[0]) === (in2[1] - in1[1]);
+
+ out[0] <== B*lamda*lamda - A - in1[0] -in2[0];
+ out[1] <== lamda * (in1[0] - out[0]) - in1[1];
+}
+
+/*
+
+ x1_2 = x1*x1
+
+ 3*x1_2 + 2*A*x1 + 1
+ lamda = ---------------------
+ 2*B*y1
+
+ x3 = B * lamda^2 - A - x1 -x1
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+template MontgomeryDouble() {
+ signal input in[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+ signal x1_2;
+
+ x1_2 <== in[0] * in[0];
+
+ lamda <-- (3*x1_2 + 2*A*in[0] + 1 ) / (2*B*in[1]);
+ lamda * (2*B*in[1]) === (3*x1_2 + 2*A*in[0] + 1 );
+
+ out[0] <== B*lamda*lamda - A - 2*in[0];
+ out[1] <== lamda * (in[0] - out[0]) - in[1];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/mux3.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/mux3.circom
new file mode 100644
index 0000000..a3fbc43
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/mux3.circom
@@ -0,0 +1,74 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+template MultiMux3(n) {
+ signal input c[n][8]; // Constants
+ signal input s[3]; // Selector
+ signal output out[n];
+
+ signal a210[n];
+ signal a21[n];
+ signal a20[n];
+ signal a2[n];
+
+ signal a10[n];
+ signal a1[n];
+ signal a0[n];
+ signal a[n];
+
+ // 4 constrains for the intermediary variables
+ signal s10;
+ s10 <== s[1] * s[0];
+
+ for (var i=0; i mux.s[i];
+ }
+
+ mux.out[0] ==> out;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/pedersen.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/pedersen.circom
new file mode 100644
index 0000000..582caba
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/pedersen.circom
@@ -0,0 +1,254 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "montgomery.circom";
+include "mux3.circom";
+include "babyjub.circom";
+
+template Window4() {
+ signal input in[4];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== - mux.out[1]*2*in[3] + mux.out[1]; // Negate y if in[3] is one
+}
+
+
+template Segment(nWindows) {
+ signal input in[nWindows*4];
+ signal input base[2];
+ signal output out[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component doublers1[nWindows-1];
+ component doublers2[nWindows-1];
+ component adders[nWindows-1];
+ for (i=0; i 1) {
+ m2e.in[0] <== adders[nWindows-2].out[0];
+ m2e.in[1] <== adders[nWindows-2].out[1];
+ } else {
+ m2e.in[0] <== windows[0].out[0];
+ m2e.in[1] <== windows[0].out[1];
+ }
+
+ out[0] <== m2e.out[0];
+ out[1] <== m2e.out[1];
+}
+
+template Pedersen(n) {
+ signal input in[n];
+ signal output out[2];
+
+ var BASE[10][2] = [
+ [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
+ [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
+ [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
+ [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
+ [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
+ [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
+ [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
+ [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
+ [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
+ [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
+ ];
+
+ var nSegments = ((n-1)\200)+1;
+
+ component segments[nSegments];
+
+ var i;
+ var j;
+ var nBits;
+ var nWindows;
+ for (i=0; i1) {
+ packPoint.in[0] <== adders[nSegments-2].xout;
+ packPoint.in[1] <== adders[nSegments-2].yout;
+ } else {
+ packPoint.in[0] <== segments[0].out[0];
+ packPoint.in[1] <== segments[0].out[1];
+ }
+
+ out[0] <== packPoint.out[0];
+ out[1] <== packPoint.out[1];
+*/
+
+ if (nSegments>1) {
+ out[0] <== adders[nSegments-2].xout;
+ out[1] <== adders[nSegments-2].yout;
+ } else {
+ out[0] <== segments[0].out[0];
+ out[1] <== segments[0].out[1];
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/re-tornado-core-ce97895/withdraw.circom b/benchmarks/buggy-mix/re-tornado-core-ce97895/withdraw.circom
new file mode 100644
index 0000000..a8da75d
--- /dev/null
+++ b/benchmarks/buggy-mix/re-tornado-core-ce97895/withdraw.circom
@@ -0,0 +1,66 @@
+include "./bitify.circom";
+include "./pedersen.circom";
+include "./merkleTree.circom";
+
+// computes Pedersen(nullifier + secret)
+template CommitmentHasher() {
+ signal input nullifier;
+ signal input secret;
+
+ signal output commitment;
+ signal output nullifierHash;
+
+ component commitmentHasher = Pedersen(496);
+ component nullifierHasher = Pedersen(248);
+ component nullifierBits = Num2Bits(248);
+ component secretBits = Num2Bits(248);
+ nullifierBits.in <== nullifier;
+ secretBits.in <== secret;
+ for (var i = 0; i < 248; i++) {
+ nullifierHasher.in[i] <== nullifierBits.out[i];
+ commitmentHasher.in[i] <== nullifierBits.out[i];
+ commitmentHasher.in[i + 248] <== secretBits.out[i];
+ }
+
+ commitment <== commitmentHasher.out[0];
+ nullifierHash <== nullifierHasher.out[0];
+}
+
+// Verifies that commitment that corresponds to given secret and nullifier is included in the merkle tree of deposits
+template Withdraw(levels, rounds) {
+ signal input root;
+ signal input nullifierHash;
+ signal input receiver; // not taking part in any computations
+ signal input fee; // not taking part in any computations
+ signal input nullifier;
+ signal input secret;
+ signal input pathElements[levels];
+ signal input pathIndex[levels];
+
+ // Picus verification output
+ signal output vOut;
+
+ component hasher = CommitmentHasher();
+ hasher.nullifier <== nullifier;
+ hasher.secret <== secret;
+
+ nullifierHash === hasher.nullifierHash;
+
+ component tree = MerkleTree(levels, rounds);
+ tree.leaf <== hasher.commitment;
+ tree.root <== root;
+ for (var i = 0; i < levels; i++) {
+ tree.pathElements[i] <== pathElements[i];
+ tree.pathIndex[i] <== pathIndex[i];
+ }
+
+ // Add hidden signal to make sure that tampering with receiver or fee will invalidate the snark proof
+ // Most likely it is not required, but it's better to stay on the safe side and it only takes 1 constraint
+ // Multiplication is used to prevent optimizer from removing this constraint
+ signal unused;
+ unused <== receiver * fee;
+
+ vOut <== tree.vOut;
+}
+
+component main = Withdraw(16, 220);
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/aliascheck.circom b/benchmarks/buggy-mix/tornado-core-ce97895/aliascheck.circom
new file mode 100644
index 0000000..ff37978
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/aliascheck.circom
@@ -0,0 +1,32 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "compconstant.circom";
+
+
+template AliasCheck() {
+
+ signal input in[254];
+
+ component compConstant = CompConstant(-1);
+
+ for (var i=0; i<254; i++) in[i] ==> compConstant.in[i];
+
+ compConstant.out === 0;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/babyjub.circom b/benchmarks/buggy-mix/tornado-core-ce97895/babyjub.circom
new file mode 100644
index 0000000..fbd0bcb
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/babyjub.circom
@@ -0,0 +1,106 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "bitify.circom";
+include "escalarmulfix.circom";
+
+template BabyAdd() {
+ signal input x1;
+ signal input y1;
+ signal input x2;
+ signal input y2;
+ signal output xout;
+ signal output yout;
+
+ signal beta;
+ signal gamma;
+ signal delta;
+ signal tau;
+
+ var a = 168700;
+ var d = 168696;
+
+ beta <== x1*y2;
+ gamma <== y1*x2;
+ delta <== (-a*x1+y1)*(x2 + y2);
+ tau <== beta * gamma;
+
+ xout <-- (beta + gamma) / (1+ d*tau);
+ (1+ d*tau) * xout === (beta + gamma);
+
+ yout <-- (delta + a*beta - gamma) / (1-d*tau);
+ (1-d*tau)*yout === (delta + a*beta - gamma);
+}
+
+template BabyDbl() {
+ signal input x;
+ signal input y;
+ signal output xout;
+ signal output yout;
+
+ component adder = BabyAdd();
+ adder.x1 <== x;
+ adder.y1 <== y;
+ adder.x2 <== x;
+ adder.y2 <== y;
+
+ adder.xout ==> xout;
+ adder.yout ==> yout;
+}
+
+
+template BabyCheck() {
+ signal input x;
+ signal input y;
+
+ signal x2;
+ signal y2;
+
+ var a = 168700;
+ var d = 168696;
+
+ x2 <== x*x;
+ y2 <== y*y;
+
+ a*x2 + y2 === 1 + d*x2*y2;
+}
+
+// Extracts the public key from private key
+template BabyPbk() {
+ signal input in;
+ signal output Ax;
+ signal output Ay;
+
+ var BASE8 = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+
+ component pvkBits = Num2Bits(253);
+ pvkBits.in <== in;
+
+ component mulFix = EscalarMulFix(253, BASE8);
+
+ var i;
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== pvkBits.out[i];
+ }
+ Ax <== mulFix.out[0];
+ Ay <== mulFix.out[1];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/binsum.circom b/benchmarks/buggy-mix/tornado-core-ce97895/binsum.circom
new file mode 100644
index 0000000..5b72448
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/binsum.circom
@@ -0,0 +1,93 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+
+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 Constraint:
+ 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> k) & 1;
+
+ // Ensure out is binary
+ out[k] * (out[k] - 1) === 0;
+
+ lout += out[k] * 2**k;
+ }
+
+ // Ensure the sum;
+
+ lin === lout;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/bitify.circom b/benchmarks/buggy-mix/tornado-core-ce97895/bitify.circom
new file mode 100644
index 0000000..d2e753e
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/bitify.circom
@@ -0,0 +1,101 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "./comparators.circom";
+include "./aliascheck.circom";
+
+
+template Num2Bits(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * 2**i;
+ }
+
+ lc1 === in;
+}
+
+template Num2Bits_strict() {
+ signal input in;
+ signal output out[254];
+
+ component aliasCheck = AliasCheck();
+ component n2b = Num2Bits(254);
+ in ==> n2b.in;
+
+ for (var i=0; i<254; i++) {
+ n2b.out[i] ==> out[i];
+ n2b.out[i] ==> aliasCheck.in[i];
+ }
+}
+
+template Bits2Num(n) {
+ signal input in[n];
+ signal output out;
+ var lc1=0;
+
+ for (var i = 0; i out;
+}
+
+template Bits2Num_strict(n) {
+ signal input in[n];
+ signal output out;
+
+ component aliasCheck = AliasCheck();
+ component b2n = Bits2Num(254);
+
+ for (var i=0; i<254; i++) {
+ in[i] ==> b2n.in[i];
+ in[i] ==> aliasCheck.in[i];
+ }
+
+ b2n.out ==> out;
+}
+
+template Num2BitsNeg(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ component isZero;
+
+ isZero = IsZero();
+
+ var neg = n == 0 ? 0 : 2**n - in;
+
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * 2**i;
+ }
+
+ in ==> isZero.in;
+
+
+
+ lc1 + isZero.out * 2**n === 2**n - in;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/comparators.circom b/benchmarks/buggy-mix/tornado-core-ce97895/comparators.circom
new file mode 100644
index 0000000..db6ac26
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/comparators.circom
@@ -0,0 +1,138 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "./bitify.circom";
+include "./binsum.circom";
+
+template IsZero() {
+ signal input in;
+ signal output out;
+
+ signal inv;
+
+ inv <-- in!=0 ? 1/in : 0;
+
+ out <== -in*inv +1;
+ in*out === 0;
+}
+
+
+template IsEqual() {
+ signal input in[2];
+ signal output out;
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ isz.out ==> out;
+}
+
+template ForceEqualIfEnabled() {
+ signal input enabled;
+ signal input in[2];
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ (1 - isz.out)*enabled === 0;
+}
+
+/*
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template LessThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component num2Bits0;
+ component num2Bits1;
+
+ component adder;
+
+ adder = BinSum(n, 2);
+
+ num2Bits0 = Num2Bits(n);
+ num2Bits1 = Num2BitsNeg(n);
+
+ in[0] ==> num2Bits0.in;
+ in[1] ==> num2Bits1.in;
+
+ var i;
+ for (i=0;i adder.in[0][i];
+ num2Bits1.out[i] ==> adder.in[1][i];
+ }
+
+ adder.out[n-1] ==> out;
+}
+*/
+
+template LessThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component n2b = Num2Bits(n*2+1);
+
+ n2b.in <== in[0]+ (1< out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0];
+ lt.out ==> out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterEqThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0]+1;
+ lt.out ==> out;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/compconstant.circom b/benchmarks/buggy-mix/tornado-core-ce97895/compconstant.circom
new file mode 100644
index 0000000..0812242
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/compconstant.circom
@@ -0,0 +1,74 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "bitify.circom";
+
+// Returns 1 if in (in binary) > ct
+
+template CompConstant(ct) {
+ signal input in[254];
+ signal output out;
+
+ signal parts[127];
+ signal sout;
+
+ var clsb;
+ var cmsb;
+ var slsb;
+ var smsb;
+
+ var sum=0;
+
+ var b = (1 << 128) -1;
+ var a = 1;
+ var e = 1;
+ var i;
+
+ for (i=0;i<127; i++) {
+ clsb = (ct >> (i*2)) & 1;
+ cmsb = (ct >> (i*2+1)) & 1;
+ slsb = in[i*2];
+ smsb = in[i*2+1];
+
+
+ if ((cmsb==0)&(clsb==0)) {
+ parts[i] <== -b*smsb*slsb + b*smsb + b*slsb;
+ } else if ((cmsb==0)&(clsb==1)) {
+ parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a;
+ } else if ((cmsb==1)&(clsb==0)) {
+ parts[i] <== b*smsb*slsb - a*smsb + a;
+ } else {
+ parts[i] <== -a*smsb*slsb + a;
+ }
+
+ sum = sum + parts[i];
+
+ b = b -e;
+ a = a +e;
+ e = e*2;
+ }
+
+ sout <== sum;
+
+ component num2bits = Num2Bits(135);
+
+ num2bits.in <== sout;
+
+ out <== num2bits.out[127];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/escalarmulfix.circom b/benchmarks/buggy-mix/tornado-core-ce97895/escalarmulfix.circom
new file mode 100644
index 0000000..54c603b
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/escalarmulfix.circom
@@ -0,0 +1,298 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "mux3.circom";
+include "montgomery.circom";
+include "babyjub.circom";
+
+/*
+ Window of 3 elements, it calculates
+ out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
+ out4 = 4*base
+
+ The result should be compensated.
+ */
+
+/*
+
+ The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
+ First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
+
+ Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
+
+ And Finaly we compute the result: RES = SQ - Q
+
+ As you can see the input of the adders cannot be equal nor zero, except for the last
+ substraction that it's done in montgomery.
+
+ A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
+ is the output of the windows that it's going to be <= 2^246*B
+ */
+template WindowMulFix() {
+ signal input in[3];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== mux.out[1];
+}
+
+
+/*
+ This component does a multiplication of a escalar times a fix base
+ Signals:
+ e: The scalar in bits
+ base: the base point in edwards format
+ out: The result
+ dbl: Point in Edwards to be linked to the next segment.
+ */
+
+template SegmentMulFix(nWindows) {
+ signal input e[nWindows*3];
+ signal input base[2];
+ signal output out[2];
+ signal output dbl[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component adders[nWindows];
+ component cadders[nWindows];
+
+ // In the last step we add an extra doubler so that numbers do not match.
+ component dblLast = MontgomeryDouble();
+
+ for (i=0; i out[0];
+ cAdd.yout ==> out[1];
+
+ windows[nWindows-1].out8[0] ==> dbl[0];
+ windows[nWindows-1].out8[1] ==> dbl[1];
+}
+
+
+/*
+This component multiplies a escalar times a fixed point BASE (twisted edwards format)
+ Signals
+ e: The escalar in binary format
+ out: The output point in twisted edwards
+ */
+template EscalarMulFix(n, BASE) {
+ signal input e[n]; // Input in binary format
+ signal output out[2]; // Point (Twisted format)
+
+ var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
+ var nlastsegment = n - (nsegments-1)*249;
+
+ component segments[nsegments];
+
+ component m2e[nsegments-1];
+ component adders[nsegments-1];
+
+ var s;
+ var i;
+ var nseg;
+ var nWindows;
+
+ for (s=0; s m2e[s-1].in[0];
+ segments[s-1].dbl[1] ==> m2e[s-1].in[1];
+
+ m2e[s-1].out[0] ==> segments[s].base[0];
+ m2e[s-1].out[1] ==> segments[s].base[1];
+
+ if (s==1) {
+ segments[s-1].out[0] ==> adders[s-1].x1;
+ segments[s-1].out[1] ==> adders[s-1].y1;
+ } else {
+ adders[s-2].xout ==> adders[s-1].x1;
+ adders[s-2].yout ==> adders[s-1].y1;
+ }
+ segments[s].out[0] ==> adders[s-1].x2;
+ segments[s].out[1] ==> adders[s-1].y2;
+ }
+ }
+
+ if (nsegments == 1) {
+ segments[0].out[0] ==> out[0];
+ segments[0].out[1] ==> out[1];
+ } else {
+ adders[nsegments-2].xout ==> out[0];
+ adders[nsegments-2].yout ==> out[1];
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/merkleTree.circom b/benchmarks/buggy-mix/tornado-core-ce97895/merkleTree.circom
new file mode 100644
index 0000000..11e4c62
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/merkleTree.circom
@@ -0,0 +1,73 @@
+include "./mimcsponge.circom";
+
+// Computes MiMC(left + right)
+template HashLeftRight(rounds) {
+ signal input left;
+ signal input right;
+
+ signal output hash;
+
+ component hasher = MiMCSponge(2, rounds, 1);
+ hasher.ins[0] <== left;
+ hasher.ins[1] <== right;
+ hasher.k <== 0;
+
+ hash <== hasher.outs[0];
+}
+
+// if pathIndex == 0 returns (left = inputElement, right = pathElement)
+// if pathIndex == 1 returns (left = pathElement, right = inputElement)
+template Selector() {
+ signal input inputElement;
+ signal input pathElement;
+ signal input pathIndex;
+
+ signal output left;
+ signal output right;
+
+ signal leftSelector1;
+ signal leftSelector2;
+ signal rightSelector1;
+ signal rightSelector2;
+
+ pathIndex * (1-pathIndex) === 0;
+
+ leftSelector1 <== (1 - pathIndex) * inputElement;
+ leftSelector2 <== (pathIndex) * pathElement;
+ rightSelector1 <== (pathIndex) * inputElement;
+ rightSelector2 <== (1 - pathIndex) * pathElement;
+
+ left <== leftSelector1 + leftSelector2;
+ right <== rightSelector1 + rightSelector2;
+}
+
+// Verifies that merkle proof is correct for given merkle root and a leaf
+// pathIndex input is an array of 0/1 selectors telling whether given pathElement is on the left or right side of merkle path
+template MerkleTree(levels, rounds) {
+ signal input leaf;
+ signal input root;
+ signal input pathElements[levels];
+ signal input pathIndex[levels];
+
+ component selectors[levels];
+ component hashers[levels];
+
+ for (var i = 0; i < levels; i++) {
+ selectors[i] = Selector();
+ hashers[i] = HashLeftRight(rounds);
+
+ selectors[i].pathElement <== pathElements[i];
+ selectors[i].pathIndex <== pathIndex[i];
+ }
+
+ selectors[0].inputElement <== leaf;
+ for (var i = 1; i < levels; i++) {
+ hashers[i-1].left <== selectors[i-1].left;
+ hashers[i-1].right <== selectors[i-1].right;
+ selectors[i].inputElement <== hashers[i-1].hash;
+ }
+ hashers[levels-1].left <== selectors[levels-1].left;
+ hashers[levels-1].right <== selectors[levels-1].right;
+
+ root === hashers[levels - 1].hash;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/mimcsponge.circom b/benchmarks/buggy-mix/tornado-core-ce97895/mimcsponge.circom
new file mode 100644
index 0000000..0357b83
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/mimcsponge.circom
@@ -0,0 +1,291 @@
+// implements MiMC-2n/n as hash using a sponge construction.
+// log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110
+// => nRounds should be 220
+template MiMCSponge(nInputs, nRounds, nOutputs) {
+ signal input ins[nInputs];
+ signal input k;
+ signal output outs[nOutputs];
+
+ // S = R||C
+ component S[nInputs + nOutputs - 1];
+
+ for (var i = 0; i < nInputs; i++) {
+ S[i] = MiMCFeistel(nRounds);
+ S[i].k <== k;
+ if (i == 0) {
+ S[i].xL_in <== ins[0];
+ S[i].xR_in <== 0;
+ } else {
+ S[i].xL_in <== S[i-1].xL_out + ins[i];
+ S[i].xR_in <== S[i-1].xR_out;
+ }
+ }
+
+ // outs[0] = S[nInputs - 1].xL_out;
+ outs[0] <-- S[nInputs - 1].xL_out;
+
+ for (var i = 0; i < nOutputs - 1; i++) {
+ S[nInputs + i] = MiMCFeistel(nRounds);
+ S[nInputs + i].k <== k;
+ S[nInputs + i].xL_in <== S[nInputs + i - 1].xL_out;
+ S[nInputs + i].xR_in <== S[nInputs + i - 1].xR_out;
+ outs[i + 1] <== S[nInputs + i].xL_out;
+ }
+}
+
+template MiMCFeistel(nrounds) {
+ signal input xL_in;
+ signal input xR_in;
+ signal input k;
+ signal output xL_out;
+ signal output xR_out;
+
+ var c[220] = [
+ 0,
+ 7120861356467848435263064379192047478074060781135320967663101236819528304084,
+ 5024705281721889198577876690145313457398658950011302225525409148828000436681,
+ 17980351014018068290387269214713820287804403312720763401943303895585469787384,
+ 19886576439381707240399940949310933992335779767309383709787331470398675714258,
+ 1213715278223786725806155661738676903520350859678319590331207960381534602599,
+ 18162138253399958831050545255414688239130588254891200470934232514682584734511,
+ 7667462281466170157858259197976388676420847047604921256361474169980037581876,
+ 7207551498477838452286210989212982851118089401128156132319807392460388436957,
+ 9864183311657946807255900203841777810810224615118629957816193727554621093838,
+ 4798196928559910300796064665904583125427459076060519468052008159779219347957,
+ 17387238494588145257484818061490088963673275521250153686214197573695921400950,
+ 10005334761930299057035055370088813230849810566234116771751925093634136574742,
+ 11897542014760736209670863723231849628230383119798486487899539017466261308762,
+ 16771780563523793011283273687253985566177232886900511371656074413362142152543,
+ 749264854018824809464168489785113337925400687349357088413132714480582918506,
+ 3683645737503705042628598550438395339383572464204988015434959428676652575331,
+ 7556750851783822914673316211129907782679509728346361368978891584375551186255,
+ 20391289379084797414557439284689954098721219201171527383291525676334308303023,
+ 18146517657445423462330854383025300323335289319277199154920964274562014376193,
+ 8080173465267536232534446836148661251987053305394647905212781979099916615292,
+ 10796443006899450245502071131975731672911747129805343722228413358507805531141,
+ 5404287610364961067658660283245291234008692303120470305032076412056764726509,
+ 4623894483395123520243967718315330178025957095502546813929290333264120223168,
+ 16845753148201777192406958674202574751725237939980634861948953189320362207797,
+ 4622170486584704769521001011395820886029808520586507873417553166762370293671,
+ 16688277490485052681847773549197928630624828392248424077804829676011512392564,
+ 11878652861183667748838188993669912629573713271883125458838494308957689090959,
+ 2436445725746972287496138382764643208791713986676129260589667864467010129482,
+ 1888098689545151571063267806606510032698677328923740058080630641742325067877,
+ 148924106504065664829055598316821983869409581623245780505601526786791681102,
+ 18875020877782404439294079398043479420415331640996249745272087358069018086569,
+ 15189693413320228845990326214136820307649565437237093707846682797649429515840,
+ 19669450123472657781282985229369348220906547335081730205028099210442632534079,
+ 5521922218264623411380547905210139511350706092570900075727555783240701821773,
+ 4144769320246558352780591737261172907511489963810975650573703217887429086546,
+ 10097732913112662248360143041019433907849917041759137293018029019134392559350,
+ 1720059427972723034107765345743336447947522473310069975142483982753181038321,
+ 6302388219880227251325608388535181451187131054211388356563634768253301290116,
+ 6745410632962119604799318394592010194450845483518862700079921360015766217097,
+ 10858157235265583624235850660462324469799552996870780238992046963007491306222,
+ 20241898894740093733047052816576694435372877719072347814065227797906130857593,
+ 10165780782761211520836029617746977303303335603838343292431760011576528327409,
+ 2832093654883670345969792724123161241696170611611744759675180839473215203706,
+ 153011722355526826233082383360057587249818749719433916258246100068258954737,
+ 20196970640587451358539129330170636295243141659030208529338914906436009086943,
+ 3180973917010545328313139835982464870638521890385603025657430208141494469656,
+ 17198004293191777441573635123110935015228014028618868252989374962722329283022,
+ 7642160509228669138628515458941659189680509753651629476399516332224325757132,
+ 19346204940546791021518535594447257347218878114049998691060016493806845179755,
+ 11501810868606870391127866188394535330696206817602260610801897042898616817272,
+ 3113973447392053821824427670386252797811804954746053461397972968381571297505,
+ 6545064306297957002139416752334741502722251869537551068239642131448768236585,
+ 5203908808704813498389265425172875593837960384349653691918590736979872578408,
+ 2246692432011290582160062129070762007374502637007107318105405626910313810224,
+ 11760570435432189127645691249600821064883781677693087773459065574359292849137,
+ 5543749482491340532547407723464609328207990784853381797689466144924198391839,
+ 8837549193990558762776520822018694066937602576881497343584903902880277769302,
+ 12855514863299373699594410385788943772765811961581749194183533625311486462501,
+ 5363660674689121676875069134269386492382220935599781121306637800261912519729,
+ 13162342403579303950549728848130828093497701266240457479693991108217307949435,
+ 916941639326869583414469202910306428966657806899788970948781207501251816730,
+ 15618589556584434434009868216186115416835494805174158488636000580759692174228,
+ 8959562060028569701043973060670353733575345393653685776974948916988033453971,
+ 16390754464333401712265575949874369157699293840516802426621216808905079127650,
+ 168282396747788514908709091757591226095443902501365500003618183905496160435,
+ 8327443473179334761744301768309008451162322941906921742120510244986704677004,
+ 17213012626801210615058753489149961717422101711567228037597150941152495100640,
+ 10394369641533736715250242399198097296122982486516256408681925424076248952280,
+ 17784386835392322654196171115293700800825771210400152504776806618892170162248,
+ 16533189939837087893364000390641148516479148564190420358849587959161226782982,
+ 18725396114211370207078434315900726338547621160475533496863298091023511945076,
+ 7132325028834551397904855671244375895110341505383911719294705267624034122405,
+ 148317947440800089795933930720822493695520852448386394775371401743494965187,
+ 19001050671757720352890779127693793630251266879994702723636759889378387053056,
+ 18824274411769830274877839365728651108434404855803844568234862945613766611460,
+ 12771414330193951156383998390424063470766226667986423961689712557338777174205,
+ 11332046574800279729678603488745295198038913503395629790213378101166488244657,
+ 9607550223176946388146938069307456967842408600269548190739947540821716354749,
+ 8756385288462344550200229174435953103162307705310807828651304665320046782583,
+ 176061952957067086877570020242717222844908281373122372938833890096257042779,
+ 12200212977482648306758992405065921724409841940671166017620928947866825250857,
+ 10868453624107875516866146499877130701929063632959660262366632833504750028858,
+ 2016095394399807253596787752134573207202567875457560571095586743878953450738,
+ 21815578223768330433802113452339488275704145896544481092014911825656390567514,
+ 4923772847693564777744725640710197015181591950368494148029046443433103381621,
+ 1813584943682214789802230765734821149202472893379265320098816901270224589984,
+ 10810123816265612772922113403831964815724109728287572256602010709288980656498,
+ 1153669123397255702524721206511185557982017410156956216465120456256288427021,
+ 5007518659266430200134478928344522649876467369278722765097865662497773767152,
+ 2511432546938591792036639990606464315121646668029252285288323664350666551637,
+ 32883284540320451295484135704808083452381176816565850047310272290579727564,
+ 10484856914279112612610993418405543310546746652738541161791501150994088679557,
+ 2026733759645519472558796412979210009170379159866522399881566309631434814953,
+ 14731806221235869882801331463708736361296174006732553130708107037190460654379,
+ 14740327483193277147065845135561988641238516852487657117813536909482068950652,
+ 18787428285295558781869865751953016580493190547148386433580291216673009884554,
+ 3804047064713122820157099453648459188816376755739202017447862327783289895072,
+ 16709604795697901641948603019242067672006293290826991671766611326262532802914,
+ 11061717085931490100602849654034280576915102867237101935487893025907907250695,
+ 2821730726367472966906149684046356272806484545281639696873240305052362149654,
+ 17467794879902895769410571945152708684493991588672014763135370927880883292655,
+ 1571520786233540988201616650622796363168031165456869481368085474420849243232,
+ 10041051776251223165849354194892664881051125330236567356945669006147134614302,
+ 3981753758468103976812813304477670033098707002886030847251581853700311567551,
+ 4365864398105436789177703571412645548020537580493599380018290523813331678900,
+ 2391801327305361293476178683853802679507598622000359948432171562543560193350,
+ 214219368547551689972421167733597094823289857206402800635962137077096090722,
+ 18192064100315141084242006659317257023098826945893371479835220462302399655674,
+ 15487549757142039139328911515400805508248576685795694919457041092150651939253,
+ 10142447197759703415402259672441315777933858467700579946665223821199077641122,
+ 11246573086260753259993971254725613211193686683988426513880826148090811891866,
+ 6574066859860991369704567902211886840188702386542112593710271426704432301235,
+ 11311085442652291634822798307831431035776248927202286895207125867542470350078,
+ 20977948360215259915441258687649465618185769343138135384346964466965010873779,
+ 792781492853909872425531014397300057232399608769451037135936617996830018501,
+ 5027602491523497423798779154966735896562099398367163998686335127580757861872,
+ 14595204575654316237672764823862241845410365278802914304953002937313300553572,
+ 13973538843621261113924259058427434053808430378163734641175100160836376897004,
+ 16395063164993626722686882727042150241125309409717445381854913964674649318585,
+ 8465768840047024550750516678171433288207841931251654898809033371655109266663,
+ 21345603324471810861925019445720576814602636473739003852898308205213912255830,
+ 21171984405852590343970239018692870799717057961108910523876770029017785940991,
+ 10761027113757988230637066281488532903174559953630210849190212601991063767647,
+ 6678298831065390834922566306988418588227382406175769592902974103663687992230,
+ 4993662582188632374202316265508850988596880036291765531885657575099537176757,
+ 18364168158495573675698600238443218434246806358811328083953887470513967121206,
+ 3506345610354615013737144848471391553141006285964325596214723571988011984829,
+ 248732676202643792226973868626360612151424823368345645514532870586234380100,
+ 10090204501612803176317709245679152331057882187411777688746797044706063410969,
+ 21297149835078365363970699581821844234354988617890041296044775371855432973500,
+ 16729368143229828574342820060716366330476985824952922184463387490091156065099,
+ 4467191506765339364971058668792642195242197133011672559453028147641428433293,
+ 8677548159358013363291014307402600830078662555833653517843708051504582990832,
+ 1022951765127126818581466247360193856197472064872288389992480993218645055345,
+ 1888195070251580606973417065636430294417895423429240431595054184472931224452,
+ 4221265384902749246920810956363310125115516771964522748896154428740238579824,
+ 2825393571154632139467378429077438870179957021959813965940638905853993971879,
+ 19171031072692942278056619599721228021635671304612437350119663236604712493093,
+ 10780807212297131186617505517708903709488273075252405602261683478333331220733,
+ 18230936781133176044598070768084230333433368654744509969087239465125979720995,
+ 16901065971871379877929280081392692752968612240624985552337779093292740763381,
+ 146494141603558321291767829522948454429758543710648402457451799015963102253,
+ 2492729278659146790410698334997955258248120870028541691998279257260289595548,
+ 2204224910006646535594933495262085193210692406133533679934843341237521233504,
+ 16062117410185840274616925297332331018523844434907012275592638570193234893570,
+ 5894928453677122829055071981254202951712129328678534592916926069506935491729,
+ 4947482739415078212217504789923078546034438919537985740403824517728200332286,
+ 16143265650645676880461646123844627780378251900510645261875867423498913438066,
+ 397690828254561723549349897112473766901585444153303054845160673059519614409,
+ 11272653598912269895509621181205395118899451234151664604248382803490621227687,
+ 15566927854306879444693061574322104423426072650522411176731130806720753591030,
+ 14222898219492484180162096141564251903058269177856173968147960855133048449557,
+ 16690275395485630428127725067513114066329712673106153451801968992299636791385,
+ 3667030990325966886479548860429670833692690972701471494757671819017808678584,
+ 21280039024501430842616328642522421302481259067470872421086939673482530783142,
+ 15895485136902450169492923978042129726601461603404514670348703312850236146328,
+ 7733050956302327984762132317027414325566202380840692458138724610131603812560,
+ 438123800976401478772659663183448617575635636575786782566035096946820525816,
+ 814913922521637742587885320797606426167962526342166512693085292151314976633,
+ 12368712287081330853637674140264759478736012797026621876924395982504369598764,
+ 2494806857395134874309386694756263421445039103814920780777601708371037591569,
+ 16101132301514338989512946061786320637179843435886825102406248183507106312877,
+ 6252650284989960032925831409804233477770646333900692286731621844532438095656,
+ 9277135875276787021836189566799935097400042171346561246305113339462708861695,
+ 10493603554686607050979497281838644324893776154179810893893660722522945589063,
+ 8673089750662709235894359384294076697329948991010184356091130382437645649279,
+ 9558393272910366944245875920138649617479779893610128634419086981339060613250,
+ 19012287860122586147374214541764572282814469237161122489573881644994964647218,
+ 9783723818270121678386992630754842961728702994964214799008457449989291229500,
+ 15550788416669474113213749561488122552422887538676036667630838378023479382689,
+ 15016165746156232864069722572047169071786333815661109750860165034341572904221,
+ 6506225705710197163670556961299945987488979904603689017479840649664564978574,
+ 10796631184889302076168355684722130903785890709107732067446714470783437829037,
+ 19871836214837460419845806980869387567383718044439891735114283113359312279540,
+ 20871081766843466343749609089986071784031203517506781251203251608363835140622,
+ 5100105771517691442278432864090229416166996183792075307747582375962855820797,
+ 8777887112076272395250620301071581171386440850451972412060638225741125310886,
+ 5300440870136391278944213332144327695659161151625757537632832724102670898756,
+ 1205448543652932944633962232545707633928124666868453915721030884663332604536,
+ 5542499997310181530432302492142574333860449305424174466698068685590909336771,
+ 11028094245762332275225364962905938096659249161369092798505554939952525894293,
+ 19187314764836593118404597958543112407224947638377479622725713735224279297009,
+ 17047263688548829001253658727764731047114098556534482052135734487985276987385,
+ 19914849528178967155534624144358541535306360577227460456855821557421213606310,
+ 2929658084700714257515872921366736697080475676508114973627124569375444665664,
+ 15092262360719700162343163278648422751610766427236295023221516498310468956361,
+ 21578580340755653236050830649990190843552802306886938815497471545814130084980,
+ 1258781501221760320019859066036073675029057285507345332959539295621677296991,
+ 3819598418157732134449049289585680301176983019643974929528867686268702720163,
+ 8653175945487997845203439345797943132543211416447757110963967501177317426221,
+ 6614652990340435611114076169697104582524566019034036680161902142028967568142,
+ 19212515502973904821995111796203064175854996071497099383090983975618035391558,
+ 18664315914479294273286016871365663486061896605232511201418576829062292269769,
+ 11498264615058604317482574216318586415670903094838791165247179252175768794889,
+ 10814026414212439999107945133852431304483604215416531759535467355316227331774,
+ 17566185590731088197064706533119299946752127014428399631467913813769853431107,
+ 14016139747289624978792446847000951708158212463304817001882956166752906714332,
+ 8242601581342441750402731523736202888792436665415852106196418942315563860366,
+ 9244680976345080074252591214216060854998619670381671198295645618515047080988,
+ 12216779172735125538689875667307129262237123728082657485828359100719208190116,
+ 10702811721859145441471328511968332847175733707711670171718794132331147396634,
+ 6479667912792222539919362076122453947926362746906450079329453150607427372979,
+ 15117544653571553820496948522381772148324367479772362833334593000535648316185,
+ 6842203153996907264167856337497139692895299874139131328642472698663046726780,
+ 12732823292801537626009139514048596316076834307941224506504666470961250728055,
+ 6936272626871035740815028148058841877090860312517423346335878088297448888663,
+ 17297554111853491139852678417579991271009602631577069694853813331124433680030,
+ 16641596134749940573104316021365063031319260205559553673368334842484345864859,
+ 7400481189785154329569470986896455371037813715804007747228648863919991399081,
+ 2273205422216987330510475127669563545720586464429614439716564154166712854048,
+ 15162538063742142685306302282127534305212832649282186184583465569986719234456,
+ 5628039096440332922248578319648483863204530861778160259559031331287721255522,
+ 16085392195894691829567913404182676871326863890140775376809129785155092531260,
+ 14227467863135365427954093998621993651369686288941275436795622973781503444257,
+ 18224457394066545825553407391290108485121649197258948320896164404518684305122,
+ 274945154732293792784580363548970818611304339008964723447672490026510689427,
+ 11050822248291117548220126630860474473945266276626263036056336623671308219529,
+ 2119542016932434047340813757208803962484943912710204325088879681995922344971,
+ 0
+ ];
+
+ var t;
+ signal t2[nrounds];
+ signal t4[nrounds];
+ signal xL[nrounds-1];
+ signal xR[nrounds-1];
+
+ for (var i=0; i .
+*/
+
+/*
+ Source: https://en.wikipedia.org/wiki/Montgomery_curve
+
+ 1 + y 1 + y
+ [u, v] = [ ------- , ---------- ]
+ 1 - y (1 - y)x
+
+ */
+
+template Edwards2Montgomery() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- (1 + in[1]) / (1 - in[1]);
+ out[1] <-- out[0] / in[0];
+
+
+ out[0] * (1-in[1]) === (1 + in[1]);
+ out[1] * in[0] === out[0];
+}
+
+/*
+
+ u u - 1
+ [x, y] = [ ---, ------- ]
+ v u + 1
+
+ */
+template Montgomery2Edwards() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- in[0] / in[1];
+ out[1] <-- (in[0] - 1) / (in[0] + 1);
+
+ out[0] * in[1] === in[0];
+ out[1] * (in[0] + 1) === in[0] - 1;
+}
+
+
+/*
+ x2 - x1
+ lamda = ---------
+ y2 - y1
+
+ x3 + A + x1 + x2
+ x3 = B * lamda^2 - A - x1 -x2 => lamda^2 = ------------------
+ B
+
+ y3 = (2*x1 + x2 + A)*lamda - B*lamda^3 - y1 =>
+
+
+ => y3 = lamda * ( 2*x1 + x2 + A - x3 - A - x1 - x2) - y1 =>
+
+ => y3 = lamda * ( x1 - x3 ) - y1
+
+----------
+
+ y2 - y1
+ lamda = ---------
+ x2 - x1
+
+ x3 = B * lamda^2 - A - x1 -x2
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+
+template MontgomeryAdd() {
+ signal input in1[2];
+ signal input in2[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+
+ lamda <-- (in2[1] - in1[1]) / (in2[0] - in1[0]);
+ lamda * (in2[0] - in1[0]) === (in2[1] - in1[1]);
+
+ out[0] <== B*lamda*lamda - A - in1[0] -in2[0];
+ out[1] <== lamda * (in1[0] - out[0]) - in1[1];
+}
+
+/*
+
+ x1_2 = x1*x1
+
+ 3*x1_2 + 2*A*x1 + 1
+ lamda = ---------------------
+ 2*B*y1
+
+ x3 = B * lamda^2 - A - x1 -x1
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+template MontgomeryDouble() {
+ signal input in[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+ signal x1_2;
+
+ x1_2 <== in[0] * in[0];
+
+ lamda <-- (3*x1_2 + 2*A*in[0] + 1 ) / (2*B*in[1]);
+ lamda * (2*B*in[1]) === (3*x1_2 + 2*A*in[0] + 1 );
+
+ out[0] <== B*lamda*lamda - A - 2*in[0];
+ out[1] <== lamda * (in[0] - out[0]) - in[1];
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/mux3.circom b/benchmarks/buggy-mix/tornado-core-ce97895/mux3.circom
new file mode 100644
index 0000000..a3fbc43
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/mux3.circom
@@ -0,0 +1,74 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+template MultiMux3(n) {
+ signal input c[n][8]; // Constants
+ signal input s[3]; // Selector
+ signal output out[n];
+
+ signal a210[n];
+ signal a21[n];
+ signal a20[n];
+ signal a2[n];
+
+ signal a10[n];
+ signal a1[n];
+ signal a0[n];
+ signal a[n];
+
+ // 4 constrains for the intermediary variables
+ signal s10;
+ s10 <== s[1] * s[0];
+
+ for (var i=0; i mux.s[i];
+ }
+
+ mux.out[0] ==> out;
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/pedersen.circom b/benchmarks/buggy-mix/tornado-core-ce97895/pedersen.circom
new file mode 100644
index 0000000..582caba
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/pedersen.circom
@@ -0,0 +1,254 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+include "montgomery.circom";
+include "mux3.circom";
+include "babyjub.circom";
+
+template Window4() {
+ signal input in[4];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== - mux.out[1]*2*in[3] + mux.out[1]; // Negate y if in[3] is one
+}
+
+
+template Segment(nWindows) {
+ signal input in[nWindows*4];
+ signal input base[2];
+ signal output out[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component doublers1[nWindows-1];
+ component doublers2[nWindows-1];
+ component adders[nWindows-1];
+ for (i=0; i 1) {
+ m2e.in[0] <== adders[nWindows-2].out[0];
+ m2e.in[1] <== adders[nWindows-2].out[1];
+ } else {
+ m2e.in[0] <== windows[0].out[0];
+ m2e.in[1] <== windows[0].out[1];
+ }
+
+ out[0] <== m2e.out[0];
+ out[1] <== m2e.out[1];
+}
+
+template Pedersen(n) {
+ signal input in[n];
+ signal output out[2];
+
+ var BASE[10][2] = [
+ [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
+ [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
+ [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
+ [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
+ [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
+ [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
+ [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
+ [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
+ [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
+ [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
+ ];
+
+ var nSegments = ((n-1)\200)+1;
+
+ component segments[nSegments];
+
+ var i;
+ var j;
+ var nBits;
+ var nWindows;
+ for (i=0; i1) {
+ packPoint.in[0] <== adders[nSegments-2].xout;
+ packPoint.in[1] <== adders[nSegments-2].yout;
+ } else {
+ packPoint.in[0] <== segments[0].out[0];
+ packPoint.in[1] <== segments[0].out[1];
+ }
+
+ out[0] <== packPoint.out[0];
+ out[1] <== packPoint.out[1];
+*/
+
+ if (nSegments>1) {
+ out[0] <== adders[nSegments-2].xout;
+ out[1] <== adders[nSegments-2].yout;
+ } else {
+ out[0] <== segments[0].out[0];
+ out[1] <== segments[0].out[1];
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/buggy-mix/tornado-core-ce97895/withdraw.circom b/benchmarks/buggy-mix/tornado-core-ce97895/withdraw.circom
new file mode 100644
index 0000000..5b7c14a
--- /dev/null
+++ b/benchmarks/buggy-mix/tornado-core-ce97895/withdraw.circom
@@ -0,0 +1,61 @@
+include "./bitify.circom";
+include "./pedersen.circom";
+include "./merkleTree.circom";
+
+// computes Pedersen(nullifier + secret)
+template CommitmentHasher() {
+ signal input nullifier;
+ signal input secret;
+
+ signal output commitment;
+ signal output nullifierHash;
+
+ component commitmentHasher = Pedersen(496);
+ component nullifierHasher = Pedersen(248);
+ component nullifierBits = Num2Bits(248);
+ component secretBits = Num2Bits(248);
+ nullifierBits.in <== nullifier;
+ secretBits.in <== secret;
+ for (var i = 0; i < 248; i++) {
+ nullifierHasher.in[i] <== nullifierBits.out[i];
+ commitmentHasher.in[i] <== nullifierBits.out[i];
+ commitmentHasher.in[i + 248] <== secretBits.out[i];
+ }
+
+ commitment <== commitmentHasher.out[0];
+ nullifierHash <== nullifierHasher.out[0];
+}
+
+// Verifies that commitment that corresponds to given secret and nullifier is included in the merkle tree of deposits
+template Withdraw(levels, rounds) {
+ signal input root;
+ signal input nullifierHash;
+ signal input receiver; // not taking part in any computations
+ signal input fee; // not taking part in any computations
+ signal input nullifier;
+ signal input secret;
+ signal input pathElements[levels];
+ signal input pathIndex[levels];
+
+ component hasher = CommitmentHasher();
+ hasher.nullifier <== nullifier;
+ hasher.secret <== secret;
+
+ nullifierHash === hasher.nullifierHash;
+
+ component tree = MerkleTree(levels, rounds);
+ tree.leaf <== hasher.commitment;
+ tree.root <== root;
+ for (var i = 0; i < levels; i++) {
+ tree.pathElements[i] <== pathElements[i];
+ tree.pathIndex[i] <== pathIndex[i];
+ }
+
+ // Add hidden signal to make sure that tampering with receiver or fee will invalidate the snark proof
+ // Most likely it is not required, but it's better to stay on the safe side and it only takes 1 constraint
+ // Multiplication is used to prevent optimizer from removing this constraint
+ signal unused;
+ unused <== receiver * fee;
+}
+
+component main = Withdraw(16, 220);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/BigAdd_1_2.circom b/benchmarks/circom-pairing-ext-743d761/BigAdd_1_2.circom
new file mode 100644
index 0000000..21f28eb
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/BigAdd_1_2.circom
@@ -0,0 +1,6 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+// k>2
+component main = BigAdd(1,2);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/BigAdd_251_2.circom b/benchmarks/circom-pairing-ext-743d761/BigAdd_251_2.circom
new file mode 100644
index 0000000..7ae7482
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/BigAdd_251_2.circom
@@ -0,0 +1,6 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+// k>=2, n<=251
+component main = BigAdd(251,2);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/BigIsEqual_16.circom b/benchmarks/circom-pairing-ext-743d761/BigIsEqual_16.circom
new file mode 100644
index 0000000..06bee72
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/BigIsEqual_16.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = BigIsEqual(16);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/BigIsZero_16.circom b/benchmarks/circom-pairing-ext-743d761/BigIsZero_16.circom
new file mode 100644
index 0000000..13940c2
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/BigIsZero_16.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = BigIsZero(16);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/BigMultShortLong_126_16_0.circom b/benchmarks/circom-pairing-ext-743d761/BigMultShortLong_126_16_0.circom
new file mode 100644
index 0000000..0cf310d
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/BigMultShortLong_126_16_0.circom
@@ -0,0 +1,6 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+// k>=2, n<=251
+component main = BigMultShortLong(126,16,0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/BigMultShortLong_1_1_0.circom b/benchmarks/circom-pairing-ext-743d761/BigMultShortLong_1_1_0.circom
new file mode 100644
index 0000000..7d537be
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/BigMultShortLong_1_1_0.circom
@@ -0,0 +1,6 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+// k>=2, n<=251
+component main = BigMultShortLong(1,1,0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/FpMultiply_1_1_2.circom b/benchmarks/circom-pairing-ext-743d761/FpMultiply_1_1_2.circom
new file mode 100644
index 0000000..b7908ec
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/FpMultiply_1_1_2.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/fp.circom";
+
+component main {public [a,b]} = FpMultiply(4, 3, [1, 1, 1]);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModProd_0.circom b/benchmarks/circom-pairing-ext-743d761/ModProd_0.circom
new file mode 100644
index 0000000..e2b082e
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModProd_0.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModProd(0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModProd_126.circom b/benchmarks/circom-pairing-ext-743d761/ModProd_126.circom
new file mode 100644
index 0000000..9c2b4fa
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModProd_126.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModProd(126);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModProd_16.circom b/benchmarks/circom-pairing-ext-743d761/ModProd_16.circom
new file mode 100644
index 0000000..52dcfd0
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModProd_16.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModProd(16);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSubThree_0.circom b/benchmarks/circom-pairing-ext-743d761/ModSubThree_0.circom
new file mode 100644
index 0000000..68767a4
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSubThree_0.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSubThree(0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSubThree_251.circom b/benchmarks/circom-pairing-ext-743d761/ModSubThree_251.circom
new file mode 100644
index 0000000..65d4fbd
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSubThree_251.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSubThree(251);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSub_0.circom b/benchmarks/circom-pairing-ext-743d761/ModSub_0.circom
new file mode 100644
index 0000000..c181698
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSub_0.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSub(0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSub_252.circom b/benchmarks/circom-pairing-ext-743d761/ModSub_252.circom
new file mode 100644
index 0000000..3d7a1e6
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSub_252.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSub(252);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSumFour_0.circom b/benchmarks/circom-pairing-ext-743d761/ModSumFour_0.circom
new file mode 100644
index 0000000..b0b29d1
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSumFour_0.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSumFour(0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSumFour_251.circom b/benchmarks/circom-pairing-ext-743d761/ModSumFour_251.circom
new file mode 100644
index 0000000..2399e14
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSumFour_251.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSumFour(251);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSumThree_0.circom b/benchmarks/circom-pairing-ext-743d761/ModSumThree_0.circom
new file mode 100644
index 0000000..97444da
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSumThree_0.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSumThree(0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSumThree_251.circom b/benchmarks/circom-pairing-ext-743d761/ModSumThree_251.circom
new file mode 100644
index 0000000..d66280b
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSumThree_251.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSumThree(251);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSum_0.circom b/benchmarks/circom-pairing-ext-743d761/ModSum_0.circom
new file mode 100644
index 0000000..879b466
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSum_0.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSum(0);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/ModSum_252.circom b/benchmarks/circom-pairing-ext-743d761/ModSum_252.circom
new file mode 100644
index 0000000..7b96be0
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/ModSum_252.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.2;
+
+include "../libs/circom-pairing-743d761/bigint.circom";
+
+component main = ModSum(252);
\ No newline at end of file
diff --git a/benchmarks/circom-pairing-ext-743d761/test-Split.circom b/benchmarks/circom-pairing-ext-743d761/test-Split.circom
new file mode 100644
index 0000000..538589f
--- /dev/null
+++ b/benchmarks/circom-pairing-ext-743d761/test-Split.circom
@@ -0,0 +1,17 @@
+pragma circom 2.0.2;
+
+// include "../libs/circom-pairing-743d761/bigint.circom";
+
+template Split(n, m) {
+ assert(n <= 126);
+ signal input in;
+ signal output small;
+ signal output big;
+
+ small <-- in % (1 << n);
+ big <-- in \ (1 << n);
+
+ in === small + big * (1 << n);
+}
+
+component main = Split(8,254);
\ No newline at end of file
diff --git a/benchmarks/libs/circom-pairing-743d761/fp.circom b/benchmarks/libs/circom-pairing-743d761/fp.circom
index bf2a51e..e0db410 100644
--- a/benchmarks/libs/circom-pairing-743d761/fp.circom
+++ b/benchmarks/libs/circom-pairing-743d761/fp.circom
@@ -2,6 +2,7 @@ pragma circom 2.0.3;
include "bigint.circom";
include "bigint_func.circom";
+include "field_elements_func.circom";
// a[i], b[i] in 0... 2**n-1
// represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k)
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/README.md b/benchmarks/libs/pre-circomlib-cff5ab6/README.md
new file mode 100644
index 0000000..40a833e
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/README.md
@@ -0,0 +1,830 @@
+# CircomLib/Circuits
+
+## Description
+
+- This folder contains circuit templates for standard operations and many cryptographic primitives.
+- Below you can find specifications of each function. In the representation of elements, there are three tyes:
+ - Binary
+ - String
+ - Field element (the field is specified in each case. We consider 2 possible fields: Fp and Fr, where p... and r... .)
+
+## Table of Contents
+
+[TOC]
+
+## Jordi
+
+* compconstant - Returns 1 if `in` (expanded to binary array) > `ct`
+* aliascheck - check if `in` (expanded to binary array) oveflowed its 254 bits (<= -1)
+* babyjub - twisted Edwards curve 168700.x^2 + y^2 = 1 + 168696.x^2.y^2
+ * BabyAdd - (`xout`,`yout`) = (`x1`,`y1`) + (`x2`,`y2`)
+ * BabyDbl - (`xout`,`yout`) = 2*(`x`,`y`)
+ * BabyCheck - check that (`x`,`y`) is on the curve
+* binsub - binary subtraction
+* gates - logical gates
+* mimc - SNARK-friendly hash Minimal Multiplicative Complexity.
+ * https://eprint.iacr.org/2016/492.pdf
+ * zcash/zcash#2233
+* smt - Sparse Merkle Tree
+ * https://ethresear.ch/t/optimizing-sparse-merkle-trees/3751
+* montgomery https://en.wikipedia.org/wiki/Montgomery_curve
+
+## Circuits
+
+### sha256
+
+Folder containing the implementation of sha256 hash circuit.
+
+### smt
+
+Folder containing the circuit implementation of Sparse Merkle Trees.
+
+### aliascheck
+
+- `AliasCheck()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### babyjub
+
+Arithmetic on [Baby Jubjub elliptic curve](https://github.com/barryWhiteHat/baby_jubjub) in twisted Edwards form. (TODO: Expose here the characteristics of the curve?)
+
+
+- `BabyAdd()`
+
+ - DESCRIPTION
+
+ It adds two points on the Baby Jubjub curve. More specifically, given two points P1 = (`x1`, `y1`) and P2 = (`x2`, `y2`) it returns a point P3 = (`xout`, `yout`) such that
+
+ (`xout`, `yout`) = (`x1`,`y1`) + (`x2`,`y2`)
+ = ((`x1y2`+`y1x2`)/(1+`dx1x2y1y2`)),(`y1y2`-`ax1x2`)/(1-`dx1x2y1y2`))
+
+ - SCHEMA
+ ```
+ var a var d
+ | |
+ | |
+ ______v_________v_______
+ input x1 ----> | |
+ input y1 ----> | BabyAdd() | ----> output xout
+ input x2 ----> | | ----> output yout
+ input y2 ----> |________________________|
+ ```
+
+ - INPUTS
+
+ | Input | Representation | Description | |
+ | ------------- | ------------- | ------------- | ------------- |
+ | `x1` | Bigint | Field element of Fp | First coordinate of a point (x1, y1) on E. |
+ | `y1` | Bigint | Field element of Fp | Second coordinate of a point (x1, y1) on E. |
+ | `x2` | Bigint | Field element of Fp | First coordinate of a point (x2, y2) on E. |
+ | `y2` | Bigint | Field element of Fp | Second coordinate of a point (x2, y2) on E. |
+
+ Requirement: at least `x1`!=`x2` or `y1`!=`y2`.
+
+ - OUTPUT
+
+ | Input | Representation | Description | |
+ | ------------- | ------------- | ------------- | ------------- |
+ | `xout` | Bigint | Field element of Fp | First coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). |
+ | `yout` | Bigint | Field element of Fp | Second coordinate of the addition point (xout, yout) = (x1, y1) + (x2, y2). |
+
+ - BENCHMARKS (constraints)
+
+ - EXAMPLE
+
+- `BabyDbl()`
+ - DESCRIPTION : doubles a point (`xout`,`yout`) = 2*(`x`,`y`).
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `BabyCheck()`
+
+ - DESCRIPTION : checks if a given point is in the curve.
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `BabyPbk()`
+
+ - DESCRIPTION: : given a private key, it returns the associated public key.
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+
+### binsub
+
+- `BinSub(n)`
+
+ - DESCRIPTION: binary substraction.
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### binsum
+
+- `nbits(a)`
+
+ - DESCRIPTION : binary sum.
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `BinSum(n, ops)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### bitify
+
+- `Num2Bits()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Num2Bits_strict()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Bits2Num()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Bits2Num_strict()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Num2BitsNeg()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### comparators
+
+- `IsZero() `
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `IsEqual()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `ForceEqualIfEnabled()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `LessThan()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `GreaterThan()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `GreaterEqThan()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### compconstant
+
+- `CompConstant(ct)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### eddsa
+
+Edwards Digital Signature Algorithm in Baby Jubjbub (link a eddsa)
+
+- `EdDSAVerifier(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### eddsamimc
+
+- `EdDSAMiMCVerifier()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### eddsamimcsponge
+
+- `EdDSAMiMCSpongeVerifier()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### eddsaposeidon
+
+- `EdDSAPoseidonVerifier()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### escalarmul
+
+- `EscalarMulWindow(base, k)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `EscalarMul(n, base)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### escalarmulany
+
+- `Multiplexor2()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `BitElementMulAny()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `SegmentMulAny(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `EscalarMulAny(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### escalarmulfix
+
+- `WindowMulFix()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `SegmentMulFix(nWindows)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `EscalarMulFix(n, BASE)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### escalarmulw4table
+
+- `pointAdd`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `EscalarMulW4Table`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### gates
+
+- `XOR`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `AND`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `OR`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `NOT`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `NAND`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `NOR`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `MultiAND`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### mimc
+
+Implementation of MiMC-7 hash in Fp being... (link to description of the hash)
+
+- `MiMC7(nrounds)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `MultiMiMC7(nInputs, nRounds)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### mimcsponge
+
+- `MiMCSponge(nInputs, nRounds, nOutputs)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `MiMCFeistel(nrounds)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### montgomery
+
+- `Edwards2Montgomery()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Montgomery2Edwards()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `MontgomeryAdd()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `MontgomeryDouble()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### multiplexer
+
+- `log2(a)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `EscalarProduct(w)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Decoder(w)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Multiplexer(wIn, nIn)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### mux1
+
+- `MultiMux1(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Mux1()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### mux2
+
+- `MultiMux2(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Mux2()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### mux3
+
+- `MultiMux3(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Mux3()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### mux4
+
+- `MultiMux4(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Mux4()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### pedersen_old
+
+Old version of the Pedersen hash (do not use any
+more?).
+
+### pedersen
+
+- `Window4()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Segment(nWindows)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Pedersen(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### pointbits
+
+- `sqrt(n)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Bits2Point()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Bits2Point_Strict()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Point2Bits`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Point2Bits_Strict`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### poseidon
+
+Implementation of Poseidon hash function (LINK)
+
+- `Sigma()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Ark(t, C, r)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Mix(t, M)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+- `Poseidon(nInputs)`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### sign
+
+- `Sign()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
+
+### switcher
+
+- `Switcher()`
+
+ - DESCRIPTION
+ - SCHEMA
+ - INPUT
+ - OUTPUT
+ - BENCHMARKS
+ - EXAMPLE
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/aliascheck.circom b/benchmarks/libs/pre-circomlib-cff5ab6/aliascheck.circom
new file mode 100644
index 0000000..1c5a5f8
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/aliascheck.circom
@@ -0,0 +1,33 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "compconstant.circom";
+
+
+template AliasCheck() {
+
+ signal input in[254];
+
+ component compConstant = CompConstant(-1);
+
+ for (var i=0; i<254; i++) in[i] ==> compConstant.in[i];
+
+ compConstant.out === 0;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/babyjub.circom b/benchmarks/libs/pre-circomlib-cff5ab6/babyjub.circom
new file mode 100644
index 0000000..5565cf9
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/babyjub.circom
@@ -0,0 +1,122 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "bitify.circom";
+include "escalarmulfix.circom";
+
+// added by Picus
+include "comparators.circom";
+
+template BabyAdd() {
+ signal input x1;
+ signal input y1;
+ signal input x2;
+ signal input y2;
+ signal output xout;
+ signal output yout;
+
+ signal beta;
+ signal gamma;
+ signal delta;
+ signal tau;
+
+ var a = 168700;
+ var d = 168696;
+
+ beta <== x1*y2;
+ gamma <== y1*x2;
+ delta <== (-a*x1+y1)*(x2 + y2);
+ tau <== beta * gamma;
+
+ // added by Picus
+ // tau != 1
+ component c0 = IsEqual();
+ c0.in[0] <== tau;
+ c0.in[1] <== 1;
+ c0.out === 0;
+ // tau != -1
+ component c1 = IsEqual();
+ c1.in[0] <== tau;
+ c1.in[1] <== -1;
+ c1.out === 0;
+
+ xout <-- (beta + gamma) / (1+ d*tau);
+ (1+ d*tau) * xout === (beta + gamma);
+
+ yout <-- (delta + a*beta - gamma) / (1-d*tau);
+ (1-d*tau)*yout === (delta + a*beta - gamma);
+}
+
+template BabyDbl() {
+ signal input x;
+ signal input y;
+ signal output xout;
+ signal output yout;
+
+ component adder = BabyAdd();
+ adder.x1 <== x;
+ adder.y1 <== y;
+ adder.x2 <== x;
+ adder.y2 <== y;
+
+ adder.xout ==> xout;
+ adder.yout ==> yout;
+}
+
+
+template BabyCheck() {
+ signal input x;
+ signal input y;
+
+ signal x2;
+ signal y2;
+
+ var a = 168700;
+ var d = 168696;
+
+ x2 <== x*x;
+ y2 <== y*y;
+
+ a*x2 + y2 === 1 + d*x2*y2;
+}
+
+// Extracts the public key from private key
+template BabyPbk() {
+ signal input in;
+ signal output Ax;
+ signal output Ay;
+
+ var BASE8[2] = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+
+ component pvkBits = Num2Bits(253);
+ pvkBits.in <== in;
+
+ component mulFix = EscalarMulFix(253, BASE8);
+
+ var i;
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== pvkBits.out[i];
+ }
+ Ax <== mulFix.out[0];
+ Ay <== mulFix.out[1];
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/binsub.circom b/benchmarks/libs/pre-circomlib-cff5ab6/binsub.circom
new file mode 100644
index 0000000..a20fbf8
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/binsub.circom
@@ -0,0 +1,74 @@
+ /*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+This component creates a binary substraction.
+
+
+Main Constraint:
+ (in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1)) +
+ + 2^n
+ - (in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1))
+ ===
+ out[0] * 2^0 + out[1] * 2^1 + + out[n-1] *2^(n-1) + aux
+
+
+ out[0] * (out[0] - 1) === 0
+ out[1] * (out[0] - 1) === 0
+ .
+ .
+ .
+ out[n-1] * (out[n-1] - 1) === 0
+ aux * (aux-1) == 0
+
+*/
+pragma circom 2.0.0;
+
+template BinSub(n) {
+ signal input in[2][n];
+ signal output out[n];
+
+ signal aux;
+
+ var lin = 2**n;
+ var lout = 0;
+
+ var i;
+
+ for (i=0; i> i) & 1;
+
+ // Ensure out is binary
+ out[i] * (out[i] - 1) === 0;
+
+ lout = lout + out[i]*(2**i);
+ }
+
+ aux <-- (lin >> n) & 1;
+ aux*(aux-1) === 0;
+ lout = lout + aux*(2**n);
+
+ // Ensure the sum;
+ lin === lout;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/binsum.circom b/benchmarks/libs/pre-circomlib-cff5ab6/binsum.circom
new file mode 100644
index 0000000..28c7fcc
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/binsum.circom
@@ -0,0 +1,101 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+
+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 Constraint:
+ 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.
+ */
+ pragma circom 2.0.0;
+
+function nbits(a) {
+ var n = 1;
+ var r = 0;
+ while (n-1> k) & 1;
+
+ // Ensure out is binary
+ out[k] * (out[k] - 1) === 0;
+
+ lout += out[k] * e2;
+
+ e2 = e2+e2;
+ }
+
+ // Ensure the sum;
+
+ lin === lout;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/bitify.circom b/benchmarks/libs/pre-circomlib-cff5ab6/bitify.circom
new file mode 100644
index 0000000..bfdd4e8
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/bitify.circom
@@ -0,0 +1,106 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "comparators.circom";
+include "aliascheck.circom";
+
+
+template Num2Bits(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ var e2=1;
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * e2;
+ e2 = e2+e2;
+ }
+
+ lc1 === in;
+}
+
+template Num2Bits_strict() {
+ signal input in;
+ signal output out[254];
+
+ component aliasCheck = AliasCheck();
+ component n2b = Num2Bits(254);
+ in ==> n2b.in;
+
+ for (var i=0; i<254; i++) {
+ n2b.out[i] ==> out[i];
+ n2b.out[i] ==> aliasCheck.in[i];
+ }
+}
+
+template Bits2Num(n) {
+ signal input in[n];
+ signal output out;
+ var lc1=0;
+
+ var e2 = 1;
+ for (var i = 0; i out;
+}
+
+template Bits2Num_strict() {
+ signal input in[254];
+ signal output out;
+
+ component aliasCheck = AliasCheck();
+ component b2n = Bits2Num(254);
+
+ for (var i=0; i<254; i++) {
+ in[i] ==> b2n.in[i];
+ in[i] ==> aliasCheck.in[i];
+ }
+
+ b2n.out ==> out;
+}
+
+template Num2BitsNeg(n) {
+ signal input in;
+ signal output out[n];
+ var lc1=0;
+
+ component isZero;
+
+ isZero = IsZero();
+
+ var neg = n == 0 ? 0 : 2**n - in;
+
+ for (var i = 0; i> i) & 1;
+ out[i] * (out[i] -1 ) === 0;
+ lc1 += out[i] * 2**i;
+ }
+
+ in ==> isZero.in;
+
+
+
+ lc1 + isZero.out * 2**n === 2**n - in;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/comparators.circom b/benchmarks/libs/pre-circomlib-cff5ab6/comparators.circom
new file mode 100644
index 0000000..bfed032
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/comparators.circom
@@ -0,0 +1,141 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "bitify.circom";
+include "binsum.circom";
+
+template IsZero() {
+ signal input in;
+ signal output out;
+
+ signal inv;
+
+ inv <-- in!=0 ? 1/in : 0;
+
+ out <== -in*inv +1;
+ in*out === 0;
+}
+
+
+template IsEqual() {
+ signal input in[2];
+ signal output out;
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ isz.out ==> out;
+}
+
+template ForceEqualIfEnabled() {
+ signal input enabled;
+ signal input in[2];
+
+ component isz = IsZero();
+
+ in[1] - in[0] ==> isz.in;
+
+ (1 - isz.out)*enabled === 0;
+}
+
+/*
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template LessThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component num2Bits0;
+ component num2Bits1;
+
+ component adder;
+
+ adder = BinSum(n, 2);
+
+ num2Bits0 = Num2Bits(n);
+ num2Bits1 = Num2BitsNeg(n);
+
+ in[0] ==> num2Bits0.in;
+ in[1] ==> num2Bits1.in;
+
+ var i;
+ for (i=0;i adder.in[0][i];
+ num2Bits1.out[i] ==> adder.in[1][i];
+ }
+
+ adder.out[n-1] ==> out;
+}
+*/
+
+template LessThan(n) {
+ assert(n <= 252);
+ signal input in[2];
+ signal output out;
+
+ component n2b = Num2Bits(n+1);
+
+ n2b.in <== in[0]+ (1< out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0];
+ lt.out ==> out;
+}
+
+// N is the number of bits the input have.
+// The MSF is the sign bit.
+template GreaterEqThan(n) {
+ signal input in[2];
+ signal output out;
+
+ component lt = LessThan(n);
+
+ lt.in[0] <== in[1];
+ lt.in[1] <== in[0]+1;
+ lt.out ==> out;
+}
+
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/compconstant.circom b/benchmarks/libs/pre-circomlib-cff5ab6/compconstant.circom
new file mode 100644
index 0000000..1bca83a
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/compconstant.circom
@@ -0,0 +1,74 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "bitify.circom";
+
+// Returns 1 if in (in binary) > ct
+
+template CompConstant(ct) {
+ signal input in[254];
+ signal output out;
+
+ signal parts[127];
+ signal sout;
+
+ var clsb;
+ var cmsb;
+ var slsb;
+ var smsb;
+
+ var sum=0;
+
+ var b = (1 << 128) -1;
+ var a = 1;
+ var e = 1;
+ var i;
+
+ for (i=0;i<127; i++) {
+ clsb = (ct >> (i*2)) & 1;
+ cmsb = (ct >> (i*2+1)) & 1;
+ slsb = in[i*2];
+ smsb = in[i*2+1];
+
+ if ((cmsb==0)&&(clsb==0)) {
+ parts[i] <== -b*smsb*slsb + b*smsb + b*slsb;
+ } else if ((cmsb==0)&&(clsb==1)) {
+ parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a;
+ } else if ((cmsb==1)&&(clsb==0)) {
+ parts[i] <== b*smsb*slsb - a*smsb + a;
+ } else {
+ parts[i] <== -a*smsb*slsb + a;
+ }
+
+ sum = sum + parts[i];
+
+ b = b -e;
+ a = a +e;
+ e = e*2;
+ }
+
+ sout <== sum;
+
+ component num2bits = Num2Bits(135);
+
+ num2bits.in <== sout;
+
+ out <== num2bits.out[127];
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/eddsa.circom b/benchmarks/libs/pre-circomlib-cff5ab6/eddsa.circom
new file mode 100644
index 0000000..04b5f87
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/eddsa.circom
@@ -0,0 +1,139 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "compconstant.circom";
+include "pointbits.circom";
+include "pedersen.circom";
+include "escalarmulany.circom";
+include "escalarmulfix.circom";
+
+template EdDSAVerifier(n) {
+ signal input msg[n];
+
+ signal input A[256];
+ signal input R8[256];
+ signal input S[256];
+
+ signal Ax;
+ signal Ay;
+
+ signal R8x;
+ signal R8y;
+
+ var i;
+
+// Ensure S compConstant.in[i];
+ }
+ compConstant.out === 0;
+ S[254] === 0;
+ S[255] === 0;
+
+// Convert A to Field elements (And verify A)
+
+ component bits2pointA = Bits2Point_Strict();
+
+ for (i=0; i<256; i++) {
+ bits2pointA.in[i] <== A[i];
+ }
+ Ax <== bits2pointA.out[0];
+ Ay <== bits2pointA.out[1];
+
+// Convert R8 to Field elements (And verify R8)
+
+ component bits2pointR8 = Bits2Point_Strict();
+
+ for (i=0; i<256; i++) {
+ bits2pointR8.in[i] <== R8[i];
+ }
+ R8x <== bits2pointR8.out[0];
+ R8y <== bits2pointR8.out[1];
+
+// Calculate the h = H(R,A, msg)
+
+ component hash = Pedersen(512+n);
+
+ for (i=0; i<256; i++) {
+ hash.in[i] <== R8[i];
+ hash.in[256+i] <== A[i];
+ }
+ for (i=0; i .
+*/
+pragma circom 2.0.0;
+
+include "compconstant.circom";
+include "pointbits.circom";
+include "mimc.circom";
+include "bitify.circom";
+include "escalarmulany.circom";
+include "escalarmulfix.circom";
+
+template EdDSAMiMCVerifier() {
+ signal input enabled;
+ signal input Ax;
+ signal input Ay;
+
+ signal input S;
+ signal input R8x;
+ signal input R8y;
+
+ signal input M;
+
+ var i;
+
+// Ensure S compConstant.in[i];
+ }
+ compConstant.in[253] <== 0;
+ compConstant.out === 0;
+
+// Calculate the h = H(R,A, msg)
+
+ component hash = MultiMiMC7(5, 91);
+ hash.in[0] <== R8x;
+ hash.in[1] <== R8y;
+ hash.in[2] <== Ax;
+ hash.in[3] <== Ay;
+ hash.in[4] <== M;
+ hash.k <== 0;
+
+ component h2bits = Num2Bits_strict();
+ h2bits.in <== hash.out;
+
+// Calculate second part of the right side: right2 = h*8*A
+
+ // Multiply by 8 by adding it 3 times. This also ensure that the result is in
+ // the subgroup.
+ component dbl1 = BabyDbl();
+ dbl1.x <== Ax;
+ dbl1.y <== Ay;
+ component dbl2 = BabyDbl();
+ dbl2.x <== dbl1.xout;
+ dbl2.y <== dbl1.yout;
+ component dbl3 = BabyDbl();
+ dbl3.x <== dbl2.xout;
+ dbl3.y <== dbl2.yout;
+
+ // We check that A is not zero.
+ component isZero = IsZero();
+ isZero.in <== dbl3.x;
+ isZero.out === 0;
+
+ component mulAny = EscalarMulAny(254);
+ for (i=0; i<254; i++) {
+ mulAny.e[i] <== h2bits.out[i];
+ }
+ mulAny.p[0] <== dbl3.xout;
+ mulAny.p[1] <== dbl3.yout;
+
+
+// Compute the right side: right = R8 + right2
+
+ component addRight = BabyAdd();
+ addRight.x1 <== R8x;
+ addRight.y1 <== R8y;
+ addRight.x2 <== mulAny.out[0];
+ addRight.y2 <== mulAny.out[1];
+
+// Calculate left side of equation left = S*B8
+
+ var BASE8[2] = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+ component mulFix = EscalarMulFix(253, BASE8);
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== snum2bits.out[i];
+ }
+
+// Do the comparation left == right if enabled;
+
+ component eqCheckX = ForceEqualIfEnabled();
+ eqCheckX.enabled <== enabled;
+ eqCheckX.in[0] <== mulFix.out[0];
+ eqCheckX.in[1] <== addRight.xout;
+
+ component eqCheckY = ForceEqualIfEnabled();
+ eqCheckY.enabled <== enabled;
+ eqCheckY.in[0] <== mulFix.out[1];
+ eqCheckY.in[1] <== addRight.yout;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/eddsamimcsponge.circom b/benchmarks/libs/pre-circomlib-cff5ab6/eddsamimcsponge.circom
new file mode 100644
index 0000000..3267c45
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/eddsamimcsponge.circom
@@ -0,0 +1,124 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "compconstant.circom";
+include "pointbits.circom";
+include "mimcsponge.circom";
+include "bitify.circom";
+include "escalarmulany.circom";
+include "escalarmulfix.circom";
+
+template EdDSAMiMCSpongeVerifier() {
+ signal input enabled;
+ signal input Ax;
+ signal input Ay;
+
+ signal input S;
+ signal input R8x;
+ signal input R8y;
+
+ signal input M;
+
+ var i;
+
+// Ensure S compConstant.in[i];
+ }
+ compConstant.in[253] <== 0;
+ compConstant.out === 0;
+
+// Calculate the h = H(R,A, msg)
+
+ component hash = MiMCSponge(5, 220, 1);
+ hash.ins[0] <== R8x;
+ hash.ins[1] <== R8y;
+ hash.ins[2] <== Ax;
+ hash.ins[3] <== Ay;
+ hash.ins[4] <== M;
+ hash.k <== 0;
+
+ component h2bits = Num2Bits_strict();
+ h2bits.in <== hash.outs[0];
+
+// Calculate second part of the right side: right2 = h*8*A
+
+ // Multiply by 8 by adding it 3 times. This also ensure that the result is in
+ // the subgroup.
+ component dbl1 = BabyDbl();
+ dbl1.x <== Ax;
+ dbl1.y <== Ay;
+ component dbl2 = BabyDbl();
+ dbl2.x <== dbl1.xout;
+ dbl2.y <== dbl1.yout;
+ component dbl3 = BabyDbl();
+ dbl3.x <== dbl2.xout;
+ dbl3.y <== dbl2.yout;
+
+ // We check that A is not zero.
+ component isZero = IsZero();
+ isZero.in <== dbl3.x;
+ isZero.out === 0;
+
+ component mulAny = EscalarMulAny(254);
+ for (i=0; i<254; i++) {
+ mulAny.e[i] <== h2bits.out[i];
+ }
+ mulAny.p[0] <== dbl3.xout;
+ mulAny.p[1] <== dbl3.yout;
+
+
+// Compute the right side: right = R8 + right2
+
+ component addRight = BabyAdd();
+ addRight.x1 <== R8x;
+ addRight.y1 <== R8y;
+ addRight.x2 <== mulAny.out[0];
+ addRight.y2 <== mulAny.out[1];
+
+// Calculate left side of equation left = S*B8
+
+ var BASE8[2] = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+ component mulFix = EscalarMulFix(253, BASE8);
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== snum2bits.out[i];
+ }
+
+// Do the comparation left == right if enabled;
+
+ component eqCheckX = ForceEqualIfEnabled();
+ eqCheckX.enabled <== enabled;
+ eqCheckX.in[0] <== mulFix.out[0];
+ eqCheckX.in[1] <== addRight.xout;
+
+ component eqCheckY = ForceEqualIfEnabled();
+ eqCheckY.enabled <== enabled;
+ eqCheckY.in[0] <== mulFix.out[1];
+ eqCheckY.in[1] <== addRight.yout;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/eddsaposeidon.circom b/benchmarks/libs/pre-circomlib-cff5ab6/eddsaposeidon.circom
new file mode 100644
index 0000000..1fce1f3
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/eddsaposeidon.circom
@@ -0,0 +1,123 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "compconstant.circom";
+include "poseidon.circom";
+include "bitify.circom";
+include "escalarmulany.circom";
+include "escalarmulfix.circom";
+
+template EdDSAPoseidonVerifier() {
+ signal input enabled;
+ signal input Ax;
+ signal input Ay;
+
+ signal input S;
+ signal input R8x;
+ signal input R8y;
+
+ signal input M;
+
+ var i;
+
+// Ensure S compConstant.in[i];
+ }
+ compConstant.in[253] <== 0;
+ compConstant.out*enabled === 0;
+
+// Calculate the h = H(R,A, msg)
+
+ component hash = Poseidon(5);
+
+ hash.inputs[0] <== R8x;
+ hash.inputs[1] <== R8y;
+ hash.inputs[2] <== Ax;
+ hash.inputs[3] <== Ay;
+ hash.inputs[4] <== M;
+
+ component h2bits = Num2Bits_strict();
+ h2bits.in <== hash.out;
+
+// Calculate second part of the right side: right2 = h*8*A
+
+ // Multiply by 8 by adding it 3 times. This also ensure that the result is in
+ // the subgroup.
+ component dbl1 = BabyDbl();
+ dbl1.x <== Ax;
+ dbl1.y <== Ay;
+ component dbl2 = BabyDbl();
+ dbl2.x <== dbl1.xout;
+ dbl2.y <== dbl1.yout;
+ component dbl3 = BabyDbl();
+ dbl3.x <== dbl2.xout;
+ dbl3.y <== dbl2.yout;
+
+ // We check that A is not zero.
+ component isZero = IsZero();
+ isZero.in <== dbl3.x;
+ isZero.out*enabled === 0;
+
+ component mulAny = EscalarMulAny(254);
+ for (i=0; i<254; i++) {
+ mulAny.e[i] <== h2bits.out[i];
+ }
+ mulAny.p[0] <== dbl3.xout;
+ mulAny.p[1] <== dbl3.yout;
+
+
+// Compute the right side: right = R8 + right2
+
+ component addRight = BabyAdd();
+ addRight.x1 <== R8x;
+ addRight.y1 <== R8y;
+ addRight.x2 <== mulAny.out[0];
+ addRight.y2 <== mulAny.out[1];
+
+// Calculate left side of equation left = S*B8
+
+ var BASE8[2] = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+ component mulFix = EscalarMulFix(253, BASE8);
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== snum2bits.out[i];
+ }
+
+// Do the comparation left == right if enabled;
+
+ component eqCheckX = ForceEqualIfEnabled();
+ eqCheckX.enabled <== enabled;
+ eqCheckX.in[0] <== mulFix.out[0];
+ eqCheckX.in[1] <== addRight.xout;
+
+ component eqCheckY = ForceEqualIfEnabled();
+ eqCheckY.enabled <== enabled;
+ eqCheckY.in[0] <== mulFix.out[1];
+ eqCheckY.in[1] <== addRight.yout;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/escalarmul.circom b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmul.circom
new file mode 100644
index 0000000..809d995
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmul.circom
@@ -0,0 +1,166 @@
+ /*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+
+ ┏━━━━━━━━━━━┓
+ ┃ ┃
+ ┃ ┃
+ (inx, iny) ══════════════════════════════════════════▶┃ EC Point ┃
+ ┃ ╠═▶ (outx, outy)
+ ╔══▶┃ Adder ┃
+ ║ ┃ ┃
+ ║ ┃ ┃
+ ║ ┃ ┃
+ ┏━━━━━━━━━━━┓ ┏━━━━━━━━━━━━┓ ║ ┗━━━━━━━━━━━┛
+ ┃ ┃ ┃ ┃ ║
+ ┃ ┃ ┃ ┃ ║
+ ┃ ╠═══(p0x,p0y)═══▶┃ ┃ ║
+ ┃ ╠═══(p1x,p1y)═══▶┃ ┃ ║
+ ┃ ╠═══(p2x,p2y)═══▶┃ ┃ ║
+ ┃ ╠═══(p3x,p3y)═══▶┃ ┃ ║
+ ┃ ╠═══(p4x,p4y)═══▶┃ ┃ ║
+ ┃ ╠═══(p5x,p5y)═══▶┃ ┃ ║
+ ┃ ╠═══(p6x,p6y)═══▶┃ ┃ ║
+ ┃ Constant ╠═══(p7x,p7y)═══▶┃ ┃ ║
+ ┃ Points ┃ ┃ Mux4 ╠══╝
+ ┃ ╠═══(p8x,p8y)═══▶┃ ┃
+ ┃ ╠═══(p9x,p9y)═══▶┃ ┃
+ ┃ ╠══(p10x,p10y)══▶┃ ┃
+ ┃ ╠══(p11x,p11y)══▶┃ ┃
+ ┃ ╠══(p12x,p12y)══▶┃ ┃
+ ┃ ╠══(p13x,p13y)══▶┃ ┃
+ ┃ ╠══(p14x,p14y)══▶┃ ┃
+ ┃ ╠══(p15x,p15y)══▶┃ ┃
+ ┃ ┃ ┃ ┃
+ ┃ ┃ ┃ ┃
+ ┗━━━━━━━━━━━┛ ┗━━━━━━━━━━━━┛
+ ▲ ▲ ▲ ▲
+ │ │ │ │
+ s0 ─────────────────────────────────┘ │ │ │
+ s1 ────────────────────────────────────┘ │ │
+ s2 ───────────────────────────────────────┘ │
+ s3 ──────────────────────────────────────────┘
+
+
+ */
+pragma circom 2.0.0;
+
+include "mux4.circom";
+include "escalarmulw4table.circom";
+include "babyjub.circom";
+
+template EscalarMulWindow(base, k) {
+
+ signal input in[2];
+ signal input sel[4];
+ signal output out[2];
+
+ var table[16][2];
+ component mux;
+ component adder;
+
+ var i;
+
+ table = EscalarMulW4Table(base, k);
+ mux = MultiMux4(2);
+ adder = BabyAdd();
+
+ for (i=0; i<4; i++) {
+ sel[i] ==> mux.s[i];
+ }
+
+ for (i=0; i<16; i++) {
+ mux.c[0][i] <== table[i][0];
+ mux.c[1][i] <== table[i][1];
+ }
+
+ in[0] ==> adder.x1;
+ in[1] ==> adder.y1;
+
+ mux.out[0] ==> adder.x2;
+ mux.out[1] ==> adder.y2;
+
+ adder.xout ==> out[0];
+ adder.yout ==> out[1];
+}
+
+/*
+
+
+ ┏━━━━━━━━━┓ ┏━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━┓
+ ┃ ┃ ┃ ┃ ┃ ┃
+ inp ════▶┃Window(0)┃═════▶┃Window(1)┃════════ . . . . ═════════▶┃ Window(nBlocks-1) ┃═════▶ out
+ ┃ ┃ ┃ ┃ ┃ ┃
+ ┗━━━━━━━━━┛ ┗━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━┛
+ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
+ in[0]─────────┘ │ │ │ │ │ │ │ │ │ │ │
+ in[1]───────────┘ │ │ │ │ │ │ │ │ │ │
+ in[2]─────────────┘ │ │ │ │ │ │ │ 0 0
+ in[3]───────────────┘ │ │ │ │ │ │
+ in[4]──────────────────────────┘ │ │ │ │ │
+ in[5]────────────────────────────┘ │ │ │ │
+ in[6]──────────────────────────────┘ │ │ │
+ in[7]────────────────────────────────┘ │ │
+ . │ │
+ . │ │
+ in[n-2]─────────────────────────────────────────────────────────────────────┘ │
+ in[n-1]───────────────────────────────────────────────────────────────────────┘
+
+ */
+
+template EscalarMul(n, base) {
+ signal input in[n];
+ signal input inp[2]; // Point input to be added
+ signal output out[2];
+
+ var nBlocks = ((n-1)>>2)+1;
+ var i;
+ var j;
+
+ component windows[nBlocks];
+
+ // Construct the windows
+ for (i=0; i= n) {
+ windows[i].sel[j] <== 0;
+ } else {
+ windows[i].sel[j] <== in[i*4+j];
+ }
+ }
+ }
+
+ // Start with generator
+ windows[0].in[0] <== inp[0];
+ windows[0].in[1] <== inp[1];
+
+ for(i=0; i windows[i+1].in[0];
+ windows[i].out[1] ==> windows[i+1].in[1];
+ }
+
+ windows[nBlocks-1].out[0] ==> out[0];
+ windows[nBlocks-1].out[1] ==> out[1];
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulany.circom b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulany.circom
new file mode 100644
index 0000000..f07fe7d
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulany.circom
@@ -0,0 +1,197 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "montgomery.circom";
+include "babyjub.circom";
+include "comparators.circom";
+
+template Multiplexor2() {
+ signal input sel;
+ signal input in[2][2];
+ signal output out[2];
+
+ out[0] <== (in[1][0] - in[0][0])*sel + in[0][0];
+ out[1] <== (in[1][1] - in[0][1])*sel + in[0][1];
+}
+
+template BitElementMulAny() {
+ signal input sel;
+ signal input dblIn[2];
+ signal input addIn[2];
+ signal output dblOut[2];
+ signal output addOut[2];
+
+ component doubler = MontgomeryDouble();
+ component adder = MontgomeryAdd();
+ component selector = Multiplexor2();
+
+
+ sel ==> selector.sel;
+
+ dblIn[0] ==> doubler.in[0];
+ dblIn[1] ==> doubler.in[1];
+ doubler.out[0] ==> adder.in1[0];
+ doubler.out[1] ==> adder.in1[1];
+ addIn[0] ==> adder.in2[0];
+ addIn[1] ==> adder.in2[1];
+ addIn[0] ==> selector.in[0][0];
+ addIn[1] ==> selector.in[0][1];
+ adder.out[0] ==> selector.in[1][0];
+ adder.out[1] ==> selector.in[1][1];
+
+ doubler.out[0] ==> dblOut[0];
+ doubler.out[1] ==> dblOut[1];
+ selector.out[0] ==> addOut[0];
+ selector.out[1] ==> addOut[1];
+}
+
+// p is montgomery point
+// n must be <= 248
+// returns out in twisted edwards
+// Double is in montgomery to be linked;
+
+template SegmentMulAny(n) {
+ signal input e[n];
+ signal input p[2];
+ signal output out[2];
+ signal output dbl[2];
+
+ component bits[n-1];
+
+ component e2m = Edwards2Montgomery();
+
+ p[0] ==> e2m.in[0];
+ p[1] ==> e2m.in[1];
+
+ var i;
+
+ bits[0] = BitElementMulAny();
+ e2m.out[0] ==> bits[0].dblIn[0];
+ e2m.out[1] ==> bits[0].dblIn[1];
+ e2m.out[0] ==> bits[0].addIn[0];
+ e2m.out[1] ==> bits[0].addIn[1];
+ e[1] ==> bits[0].sel;
+
+ for (i=1; i bits[i].dblIn[0];
+ bits[i-1].dblOut[1] ==> bits[i].dblIn[1];
+ bits[i-1].addOut[0] ==> bits[i].addIn[0];
+ bits[i-1].addOut[1] ==> bits[i].addIn[1];
+ e[i+1] ==> bits[i].sel;
+ }
+
+ bits[n-2].dblOut[0] ==> dbl[0];
+ bits[n-2].dblOut[1] ==> dbl[1];
+
+ component m2e = Montgomery2Edwards();
+
+ bits[n-2].addOut[0] ==> m2e.in[0];
+ bits[n-2].addOut[1] ==> m2e.in[1];
+
+ component eadder = BabyAdd();
+
+ m2e.out[0] ==> eadder.x1;
+ m2e.out[1] ==> eadder.y1;
+ -p[0] ==> eadder.x2;
+ p[1] ==> eadder.y2;
+
+ component lastSel = Multiplexor2();
+
+ e[0] ==> lastSel.sel;
+ eadder.xout ==> lastSel.in[0][0];
+ eadder.yout ==> lastSel.in[0][1];
+ m2e.out[0] ==> lastSel.in[1][0];
+ m2e.out[1] ==> lastSel.in[1][1];
+
+ lastSel.out[0] ==> out[0];
+ lastSel.out[1] ==> out[1];
+}
+
+// This function assumes that p is in the subgroup and it is different to 0
+
+template EscalarMulAny(n) {
+ signal input e[n]; // Input in binary format
+ signal input p[2]; // Point (Twisted format)
+ signal output out[2]; // Point (Twisted format)
+
+ var nsegments = (n-1)\148 +1;
+ var nlastsegment = n - (nsegments-1)*148;
+
+ component segments[nsegments];
+ component doublers[nsegments-1];
+ component m2e[nsegments-1];
+ component adders[nsegments-1];
+ component zeropoint = IsZero();
+ zeropoint.in <== p[0];
+
+ var s;
+ var i;
+ var nseg;
+
+ for (s=0; s segments[s].e[i];
+ }
+
+ if (s==0) {
+ // force G8 point if input point is zero
+ segments[s].p[0] <== p[0] + (5299619240641551281634865583518297030282874472190772894086521144482721001553 - p[0])*zeropoint.out;
+ segments[s].p[1] <== p[1] + (16950150798460657717958625567821834550301663161624707787222815936182638968203 - p[1])*zeropoint.out;
+ } else {
+ doublers[s-1] = MontgomeryDouble();
+ m2e[s-1] = Montgomery2Edwards();
+ adders[s-1] = BabyAdd();
+
+ segments[s-1].dbl[0] ==> doublers[s-1].in[0];
+ segments[s-1].dbl[1] ==> doublers[s-1].in[1];
+
+ doublers[s-1].out[0] ==> m2e[s-1].in[0];
+ doublers[s-1].out[1] ==> m2e[s-1].in[1];
+
+ m2e[s-1].out[0] ==> segments[s].p[0];
+ m2e[s-1].out[1] ==> segments[s].p[1];
+
+ if (s==1) {
+ segments[s-1].out[0] ==> adders[s-1].x1;
+ segments[s-1].out[1] ==> adders[s-1].y1;
+ } else {
+ adders[s-2].xout ==> adders[s-1].x1;
+ adders[s-2].yout ==> adders[s-1].y1;
+ }
+ segments[s].out[0] ==> adders[s-1].x2;
+ segments[s].out[1] ==> adders[s-1].y2;
+ }
+ }
+
+ if (nsegments == 1) {
+ segments[0].out[0]*(1-zeropoint.out) ==> out[0];
+ segments[0].out[1]+(1-segments[0].out[1])*zeropoint.out ==> out[1];
+ } else {
+ adders[nsegments-2].xout*(1-zeropoint.out) ==> out[0];
+ adders[nsegments-2].yout+(1-adders[nsegments-2].yout)*zeropoint.out ==> out[1];
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulfix.circom b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulfix.circom
new file mode 100644
index 0000000..4669d36
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulfix.circom
@@ -0,0 +1,299 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "mux3.circom";
+include "montgomery.circom";
+include "babyjub.circom";
+
+/*
+ Window of 3 elements, it calculates
+ out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
+ out4 = 4*base
+
+ The result should be compensated.
+ */
+
+/*
+
+ The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
+ First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
+
+ Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
+
+ And Finaly we compute the result: RES = SQ - Q
+
+ As you can see the input of the adders cannot be equal nor zero, except for the last
+ substraction that it's done in montgomery.
+
+ A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
+ is the output of the windows that it's going to be <= 2^246*B
+ */
+template WindowMulFix() {
+ signal input in[3];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== mux.out[1];
+}
+
+
+/*
+ This component does a multiplication of a escalar times a fix base
+ Signals:
+ e: The scalar in bits
+ base: the base point in edwards format
+ out: The result
+ dbl: Point in Edwards to be linked to the next segment.
+ */
+
+template SegmentMulFix(nWindows) {
+ signal input e[nWindows*3];
+ signal input base[2];
+ signal output out[2];
+ signal output dbl[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component adders[nWindows];
+ component cadders[nWindows];
+
+ // In the last step we add an extra doubler so that numbers do not match.
+ component dblLast = MontgomeryDouble();
+
+ for (i=0; i out[0];
+ cAdd.yout ==> out[1];
+
+ windows[nWindows-1].out8[0] ==> dbl[0];
+ windows[nWindows-1].out8[1] ==> dbl[1];
+}
+
+
+/*
+This component multiplies a escalar times a fixed point BASE (twisted edwards format)
+ Signals
+ e: The escalar in binary format
+ out: The output point in twisted edwards
+ */
+template EscalarMulFix(n, BASE) {
+ signal input e[n]; // Input in binary format
+ signal output out[2]; // Point (Twisted format)
+
+ var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
+ var nlastsegment = n - (nsegments-1)*249;
+
+ component segments[nsegments];
+
+ component m2e[nsegments-1];
+ component adders[nsegments-1];
+
+ var s;
+ var i;
+ var nseg;
+ var nWindows;
+
+ for (s=0; s m2e[s-1].in[0];
+ segments[s-1].dbl[1] ==> m2e[s-1].in[1];
+
+ m2e[s-1].out[0] ==> segments[s].base[0];
+ m2e[s-1].out[1] ==> segments[s].base[1];
+
+ if (s==1) {
+ segments[s-1].out[0] ==> adders[s-1].x1;
+ segments[s-1].out[1] ==> adders[s-1].y1;
+ } else {
+ adders[s-2].xout ==> adders[s-1].x1;
+ adders[s-2].yout ==> adders[s-1].y1;
+ }
+ segments[s].out[0] ==> adders[s-1].x2;
+ segments[s].out[1] ==> adders[s-1].y2;
+ }
+ }
+
+ if (nsegments == 1) {
+ segments[0].out[0] ==> out[0];
+ segments[0].out[1] ==> out[1];
+ } else {
+ adders[nsegments-2].xout ==> out[0];
+ adders[nsegments-2].yout ==> out[1];
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulw4table.circom b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulw4table.circom
new file mode 100644
index 0000000..25c095a
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/escalarmulw4table.circom
@@ -0,0 +1,52 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+function pointAdd(x1,y1,x2,y2) {
+ var a = 168700;
+ var d = 168696;
+
+ var res[2];
+ res[0] = (x1*y2 + y1*x2) / (1 + d*x1*x2*y1*y2);
+ res[1] = (y1*y2 - a*x1*x2) / (1 - d*x1*x2*y1*y2);
+ return res;
+}
+
+function EscalarMulW4Table(base, k) {
+ var out[16][2];
+
+ var i;
+ var p[2];
+
+ var dbl[2] = base;
+
+ for (i=0; i .
+*/
+pragma circom 2.0.0;
+
+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 MultiAND(n) {
+ signal input in[n];
+ signal output out;
+ component and1;
+ component and2;
+ component ands[2];
+ if (n==1) {
+ out <== in[0];
+ } else if (n==2) {
+ and1 = AND();
+ and1.a <== in[0];
+ and1.b <== in[1];
+ out <== and1.out;
+ } else {
+ and2 = AND();
+ var n1 = n\2;
+ var n2 = n-n\2;
+ ands[0] = MultiAND(n1);
+ ands[1] = MultiAND(n2);
+ var i;
+ for (i=0; i .
+*/
+pragma circom 2.0.0;
+
+template MiMC7(nrounds) {
+ signal input x_in;
+ signal input k;
+ signal output out;
+
+ var c[91] = [
+ 0,
+ 20888961410941983456478427210666206549300505294776164667214940546594746570981,
+ 15265126113435022738560151911929040668591755459209400716467504685752745317193,
+ 8334177627492981984476504167502758309043212251641796197711684499645635709656,
+ 1374324219480165500871639364801692115397519265181803854177629327624133579404,
+ 11442588683664344394633565859260176446561886575962616332903193988751292992472,
+ 2558901189096558760448896669327086721003508630712968559048179091037845349145,
+ 11189978595292752354820141775598510151189959177917284797737745690127318076389,
+ 3262966573163560839685415914157855077211340576201936620532175028036746741754,
+ 17029914891543225301403832095880481731551830725367286980611178737703889171730,
+ 4614037031668406927330683909387957156531244689520944789503628527855167665518,
+ 19647356996769918391113967168615123299113119185942498194367262335168397100658,
+ 5040699236106090655289931820723926657076483236860546282406111821875672148900,
+ 2632385916954580941368956176626336146806721642583847728103570779270161510514,
+ 17691411851977575435597871505860208507285462834710151833948561098560743654671,
+ 11482807709115676646560379017491661435505951727793345550942389701970904563183,
+ 8360838254132998143349158726141014535383109403565779450210746881879715734773,
+ 12663821244032248511491386323242575231591777785787269938928497649288048289525,
+ 3067001377342968891237590775929219083706800062321980129409398033259904188058,
+ 8536471869378957766675292398190944925664113548202769136103887479787957959589,
+ 19825444354178182240559170937204690272111734703605805530888940813160705385792,
+ 16703465144013840124940690347975638755097486902749048533167980887413919317592,
+ 13061236261277650370863439564453267964462486225679643020432589226741411380501,
+ 10864774797625152707517901967943775867717907803542223029967000416969007792571,
+ 10035653564014594269791753415727486340557376923045841607746250017541686319774,
+ 3446968588058668564420958894889124905706353937375068998436129414772610003289,
+ 4653317306466493184743870159523234588955994456998076243468148492375236846006,
+ 8486711143589723036499933521576871883500223198263343024003617825616410932026,
+ 250710584458582618659378487568129931785810765264752039738223488321597070280,
+ 2104159799604932521291371026105311735948154964200596636974609406977292675173,
+ 16313562605837709339799839901240652934758303521543693857533755376563489378839,
+ 6032365105133504724925793806318578936233045029919447519826248813478479197288,
+ 14025118133847866722315446277964222215118620050302054655768867040006542798474,
+ 7400123822125662712777833064081316757896757785777291653271747396958201309118,
+ 1744432620323851751204287974553233986555641872755053103823939564833813704825,
+ 8316378125659383262515151597439205374263247719876250938893842106722210729522,
+ 6739722627047123650704294650168547689199576889424317598327664349670094847386,
+ 21211457866117465531949733809706514799713333930924902519246949506964470524162,
+ 13718112532745211817410303291774369209520657938741992779396229864894885156527,
+ 5264534817993325015357427094323255342713527811596856940387954546330728068658,
+ 18884137497114307927425084003812022333609937761793387700010402412840002189451,
+ 5148596049900083984813839872929010525572543381981952060869301611018636120248,
+ 19799686398774806587970184652860783461860993790013219899147141137827718662674,
+ 19240878651604412704364448729659032944342952609050243268894572835672205984837,
+ 10546185249390392695582524554167530669949955276893453512788278945742408153192,
+ 5507959600969845538113649209272736011390582494851145043668969080335346810411,
+ 18177751737739153338153217698774510185696788019377850245260475034576050820091,
+ 19603444733183990109492724100282114612026332366576932662794133334264283907557,
+ 10548274686824425401349248282213580046351514091431715597441736281987273193140,
+ 1823201861560942974198127384034483127920205835821334101215923769688644479957,
+ 11867589662193422187545516240823411225342068709600734253659804646934346124945,
+ 18718569356736340558616379408444812528964066420519677106145092918482774343613,
+ 10530777752259630125564678480897857853807637120039176813174150229243735996839,
+ 20486583726592018813337145844457018474256372770211860618687961310422228379031,
+ 12690713110714036569415168795200156516217175005650145422920562694422306200486,
+ 17386427286863519095301372413760745749282643730629659997153085139065756667205,
+ 2216432659854733047132347621569505613620980842043977268828076165669557467682,
+ 6309765381643925252238633914530877025934201680691496500372265330505506717193,
+ 20806323192073945401862788605803131761175139076694468214027227878952047793390,
+ 4037040458505567977365391535756875199663510397600316887746139396052445718861,
+ 19948974083684238245321361840704327952464170097132407924861169241740046562673,
+ 845322671528508199439318170916419179535949348988022948153107378280175750024,
+ 16222384601744433420585982239113457177459602187868460608565289920306145389382,
+ 10232118865851112229330353999139005145127746617219324244541194256766741433339,
+ 6699067738555349409504843460654299019000594109597429103342076743347235369120,
+ 6220784880752427143725783746407285094967584864656399181815603544365010379208,
+ 6129250029437675212264306655559561251995722990149771051304736001195288083309,
+ 10773245783118750721454994239248013870822765715268323522295722350908043393604,
+ 4490242021765793917495398271905043433053432245571325177153467194570741607167,
+ 19596995117319480189066041930051006586888908165330319666010398892494684778526,
+ 837850695495734270707668553360118467905109360511302468085569220634750561083,
+ 11803922811376367215191737026157445294481406304781326649717082177394185903907,
+ 10201298324909697255105265958780781450978049256931478989759448189112393506592,
+ 13564695482314888817576351063608519127702411536552857463682060761575100923924,
+ 9262808208636973454201420823766139682381973240743541030659775288508921362724,
+ 173271062536305557219323722062711383294158572562695717740068656098441040230,
+ 18120430890549410286417591505529104700901943324772175772035648111937818237369,
+ 20484495168135072493552514219686101965206843697794133766912991150184337935627,
+ 19155651295705203459475805213866664350848604323501251939850063308319753686505,
+ 11971299749478202793661982361798418342615500543489781306376058267926437157297,
+ 18285310723116790056148596536349375622245669010373674803854111592441823052978,
+ 7069216248902547653615508023941692395371990416048967468982099270925308100727,
+ 6465151453746412132599596984628739550147379072443683076388208843341824127379,
+ 16143532858389170960690347742477978826830511669766530042104134302796355145785,
+ 19362583304414853660976404410208489566967618125972377176980367224623492419647,
+ 1702213613534733786921602839210290505213503664731919006932367875629005980493,
+ 10781825404476535814285389902565833897646945212027592373510689209734812292327,
+ 4212716923652881254737947578600828255798948993302968210248673545442808456151,
+ 7594017890037021425366623750593200398174488805473151513558919864633711506220,
+ 18979889247746272055963929241596362599320706910852082477600815822482192194401,
+ 13602139229813231349386885113156901793661719180900395818909719758150455500533
+ ];
+
+ var t;
+ signal t2[nrounds];
+ signal t4[nrounds];
+ signal t6[nrounds];
+ signal t7[nrounds-1];
+
+ for (var i=0; i nRounds should be 220
+template MiMCSponge(nInputs, nRounds, nOutputs) {
+ signal input ins[nInputs];
+ signal input k;
+ signal output outs[nOutputs];
+
+ var i;
+
+ // S = R||C
+ component S[nInputs + nOutputs - 1];
+
+ for (i = 0; i < nInputs; i++) {
+ S[i] = MiMCFeistel(nRounds);
+ S[i].k <== k;
+ if (i == 0) {
+ S[i].xL_in <== ins[0];
+ S[i].xR_in <== 0;
+ } else {
+ S[i].xL_in <== S[i-1].xL_out + ins[i];
+ S[i].xR_in <== S[i-1].xR_out;
+ }
+ }
+
+ outs[0] <== S[nInputs - 1].xL_out;
+
+ for (i = 0; i < nOutputs - 1; i++) {
+ S[nInputs + i] = MiMCFeistel(nRounds);
+ S[nInputs + i].k <== k;
+ S[nInputs + i].xL_in <== S[nInputs + i - 1].xL_out;
+ S[nInputs + i].xR_in <== S[nInputs + i - 1].xR_out;
+ outs[i + 1] <== S[nInputs + i].xL_out;
+ }
+}
+
+template MiMCFeistel(nrounds) {
+ signal input xL_in;
+ signal input xR_in;
+ signal input k;
+ signal output xL_out;
+ signal output xR_out;
+
+ // doesn't contain the first and last round constants, which are always zero
+ var c_partial[218] = [
+ 7120861356467848435263064379192047478074060781135320967663101236819528304084,
+ 5024705281721889198577876690145313457398658950011302225525409148828000436681,
+ 17980351014018068290387269214713820287804403312720763401943303895585469787384,
+ 19886576439381707240399940949310933992335779767309383709787331470398675714258,
+ 1213715278223786725806155661738676903520350859678319590331207960381534602599,
+ 18162138253399958831050545255414688239130588254891200470934232514682584734511,
+ 7667462281466170157858259197976388676420847047604921256361474169980037581876,
+ 7207551498477838452286210989212982851118089401128156132319807392460388436957,
+ 9864183311657946807255900203841777810810224615118629957816193727554621093838,
+ 4798196928559910300796064665904583125427459076060519468052008159779219347957,
+ 17387238494588145257484818061490088963673275521250153686214197573695921400950,
+ 10005334761930299057035055370088813230849810566234116771751925093634136574742,
+ 11897542014760736209670863723231849628230383119798486487899539017466261308762,
+ 16771780563523793011283273687253985566177232886900511371656074413362142152543,
+ 749264854018824809464168489785113337925400687349357088413132714480582918506,
+ 3683645737503705042628598550438395339383572464204988015434959428676652575331,
+ 7556750851783822914673316211129907782679509728346361368978891584375551186255,
+ 20391289379084797414557439284689954098721219201171527383291525676334308303023,
+ 18146517657445423462330854383025300323335289319277199154920964274562014376193,
+ 8080173465267536232534446836148661251987053305394647905212781979099916615292,
+ 10796443006899450245502071131975731672911747129805343722228413358507805531141,
+ 5404287610364961067658660283245291234008692303120470305032076412056764726509,
+ 4623894483395123520243967718315330178025957095502546813929290333264120223168,
+ 16845753148201777192406958674202574751725237939980634861948953189320362207797,
+ 4622170486584704769521001011395820886029808520586507873417553166762370293671,
+ 16688277490485052681847773549197928630624828392248424077804829676011512392564,
+ 11878652861183667748838188993669912629573713271883125458838494308957689090959,
+ 2436445725746972287496138382764643208791713986676129260589667864467010129482,
+ 1888098689545151571063267806606510032698677328923740058080630641742325067877,
+ 148924106504065664829055598316821983869409581623245780505601526786791681102,
+ 18875020877782404439294079398043479420415331640996249745272087358069018086569,
+ 15189693413320228845990326214136820307649565437237093707846682797649429515840,
+ 19669450123472657781282985229369348220906547335081730205028099210442632534079,
+ 5521922218264623411380547905210139511350706092570900075727555783240701821773,
+ 4144769320246558352780591737261172907511489963810975650573703217887429086546,
+ 10097732913112662248360143041019433907849917041759137293018029019134392559350,
+ 1720059427972723034107765345743336447947522473310069975142483982753181038321,
+ 6302388219880227251325608388535181451187131054211388356563634768253301290116,
+ 6745410632962119604799318394592010194450845483518862700079921360015766217097,
+ 10858157235265583624235850660462324469799552996870780238992046963007491306222,
+ 20241898894740093733047052816576694435372877719072347814065227797906130857593,
+ 10165780782761211520836029617746977303303335603838343292431760011576528327409,
+ 2832093654883670345969792724123161241696170611611744759675180839473215203706,
+ 153011722355526826233082383360057587249818749719433916258246100068258954737,
+ 20196970640587451358539129330170636295243141659030208529338914906436009086943,
+ 3180973917010545328313139835982464870638521890385603025657430208141494469656,
+ 17198004293191777441573635123110935015228014028618868252989374962722329283022,
+ 7642160509228669138628515458941659189680509753651629476399516332224325757132,
+ 19346204940546791021518535594447257347218878114049998691060016493806845179755,
+ 11501810868606870391127866188394535330696206817602260610801897042898616817272,
+ 3113973447392053821824427670386252797811804954746053461397972968381571297505,
+ 6545064306297957002139416752334741502722251869537551068239642131448768236585,
+ 5203908808704813498389265425172875593837960384349653691918590736979872578408,
+ 2246692432011290582160062129070762007374502637007107318105405626910313810224,
+ 11760570435432189127645691249600821064883781677693087773459065574359292849137,
+ 5543749482491340532547407723464609328207990784853381797689466144924198391839,
+ 8837549193990558762776520822018694066937602576881497343584903902880277769302,
+ 12855514863299373699594410385788943772765811961581749194183533625311486462501,
+ 5363660674689121676875069134269386492382220935599781121306637800261912519729,
+ 13162342403579303950549728848130828093497701266240457479693991108217307949435,
+ 916941639326869583414469202910306428966657806899788970948781207501251816730,
+ 15618589556584434434009868216186115416835494805174158488636000580759692174228,
+ 8959562060028569701043973060670353733575345393653685776974948916988033453971,
+ 16390754464333401712265575949874369157699293840516802426621216808905079127650,
+ 168282396747788514908709091757591226095443902501365500003618183905496160435,
+ 8327443473179334761744301768309008451162322941906921742120510244986704677004,
+ 17213012626801210615058753489149961717422101711567228037597150941152495100640,
+ 10394369641533736715250242399198097296122982486516256408681925424076248952280,
+ 17784386835392322654196171115293700800825771210400152504776806618892170162248,
+ 16533189939837087893364000390641148516479148564190420358849587959161226782982,
+ 18725396114211370207078434315900726338547621160475533496863298091023511945076,
+ 7132325028834551397904855671244375895110341505383911719294705267624034122405,
+ 148317947440800089795933930720822493695520852448386394775371401743494965187,
+ 19001050671757720352890779127693793630251266879994702723636759889378387053056,
+ 18824274411769830274877839365728651108434404855803844568234862945613766611460,
+ 12771414330193951156383998390424063470766226667986423961689712557338777174205,
+ 11332046574800279729678603488745295198038913503395629790213378101166488244657,
+ 9607550223176946388146938069307456967842408600269548190739947540821716354749,
+ 8756385288462344550200229174435953103162307705310807828651304665320046782583,
+ 176061952957067086877570020242717222844908281373122372938833890096257042779,
+ 12200212977482648306758992405065921724409841940671166017620928947866825250857,
+ 10868453624107875516866146499877130701929063632959660262366632833504750028858,
+ 2016095394399807253596787752134573207202567875457560571095586743878953450738,
+ 21815578223768330433802113452339488275704145896544481092014911825656390567514,
+ 4923772847693564777744725640710197015181591950368494148029046443433103381621,
+ 1813584943682214789802230765734821149202472893379265320098816901270224589984,
+ 10810123816265612772922113403831964815724109728287572256602010709288980656498,
+ 1153669123397255702524721206511185557982017410156956216465120456256288427021,
+ 5007518659266430200134478928344522649876467369278722765097865662497773767152,
+ 2511432546938591792036639990606464315121646668029252285288323664350666551637,
+ 32883284540320451295484135704808083452381176816565850047310272290579727564,
+ 10484856914279112612610993418405543310546746652738541161791501150994088679557,
+ 2026733759645519472558796412979210009170379159866522399881566309631434814953,
+ 14731806221235869882801331463708736361296174006732553130708107037190460654379,
+ 14740327483193277147065845135561988641238516852487657117813536909482068950652,
+ 18787428285295558781869865751953016580493190547148386433580291216673009884554,
+ 3804047064713122820157099453648459188816376755739202017447862327783289895072,
+ 16709604795697901641948603019242067672006293290826991671766611326262532802914,
+ 11061717085931490100602849654034280576915102867237101935487893025907907250695,
+ 2821730726367472966906149684046356272806484545281639696873240305052362149654,
+ 17467794879902895769410571945152708684493991588672014763135370927880883292655,
+ 1571520786233540988201616650622796363168031165456869481368085474420849243232,
+ 10041051776251223165849354194892664881051125330236567356945669006147134614302,
+ 3981753758468103976812813304477670033098707002886030847251581853700311567551,
+ 4365864398105436789177703571412645548020537580493599380018290523813331678900,
+ 2391801327305361293476178683853802679507598622000359948432171562543560193350,
+ 214219368547551689972421167733597094823289857206402800635962137077096090722,
+ 18192064100315141084242006659317257023098826945893371479835220462302399655674,
+ 15487549757142039139328911515400805508248576685795694919457041092150651939253,
+ 10142447197759703415402259672441315777933858467700579946665223821199077641122,
+ 11246573086260753259993971254725613211193686683988426513880826148090811891866,
+ 6574066859860991369704567902211886840188702386542112593710271426704432301235,
+ 11311085442652291634822798307831431035776248927202286895207125867542470350078,
+ 20977948360215259915441258687649465618185769343138135384346964466965010873779,
+ 792781492853909872425531014397300057232399608769451037135936617996830018501,
+ 5027602491523497423798779154966735896562099398367163998686335127580757861872,
+ 14595204575654316237672764823862241845410365278802914304953002937313300553572,
+ 13973538843621261113924259058427434053808430378163734641175100160836376897004,
+ 16395063164993626722686882727042150241125309409717445381854913964674649318585,
+ 8465768840047024550750516678171433288207841931251654898809033371655109266663,
+ 21345603324471810861925019445720576814602636473739003852898308205213912255830,
+ 21171984405852590343970239018692870799717057961108910523876770029017785940991,
+ 10761027113757988230637066281488532903174559953630210849190212601991063767647,
+ 6678298831065390834922566306988418588227382406175769592902974103663687992230,
+ 4993662582188632374202316265508850988596880036291765531885657575099537176757,
+ 18364168158495573675698600238443218434246806358811328083953887470513967121206,
+ 3506345610354615013737144848471391553141006285964325596214723571988011984829,
+ 248732676202643792226973868626360612151424823368345645514532870586234380100,
+ 10090204501612803176317709245679152331057882187411777688746797044706063410969,
+ 21297149835078365363970699581821844234354988617890041296044775371855432973500,
+ 16729368143229828574342820060716366330476985824952922184463387490091156065099,
+ 4467191506765339364971058668792642195242197133011672559453028147641428433293,
+ 8677548159358013363291014307402600830078662555833653517843708051504582990832,
+ 1022951765127126818581466247360193856197472064872288389992480993218645055345,
+ 1888195070251580606973417065636430294417895423429240431595054184472931224452,
+ 4221265384902749246920810956363310125115516771964522748896154428740238579824,
+ 2825393571154632139467378429077438870179957021959813965940638905853993971879,
+ 19171031072692942278056619599721228021635671304612437350119663236604712493093,
+ 10780807212297131186617505517708903709488273075252405602261683478333331220733,
+ 18230936781133176044598070768084230333433368654744509969087239465125979720995,
+ 16901065971871379877929280081392692752968612240624985552337779093292740763381,
+ 146494141603558321291767829522948454429758543710648402457451799015963102253,
+ 2492729278659146790410698334997955258248120870028541691998279257260289595548,
+ 2204224910006646535594933495262085193210692406133533679934843341237521233504,
+ 16062117410185840274616925297332331018523844434907012275592638570193234893570,
+ 5894928453677122829055071981254202951712129328678534592916926069506935491729,
+ 4947482739415078212217504789923078546034438919537985740403824517728200332286,
+ 16143265650645676880461646123844627780378251900510645261875867423498913438066,
+ 397690828254561723549349897112473766901585444153303054845160673059519614409,
+ 11272653598912269895509621181205395118899451234151664604248382803490621227687,
+ 15566927854306879444693061574322104423426072650522411176731130806720753591030,
+ 14222898219492484180162096141564251903058269177856173968147960855133048449557,
+ 16690275395485630428127725067513114066329712673106153451801968992299636791385,
+ 3667030990325966886479548860429670833692690972701471494757671819017808678584,
+ 21280039024501430842616328642522421302481259067470872421086939673482530783142,
+ 15895485136902450169492923978042129726601461603404514670348703312850236146328,
+ 7733050956302327984762132317027414325566202380840692458138724610131603812560,
+ 438123800976401478772659663183448617575635636575786782566035096946820525816,
+ 814913922521637742587885320797606426167962526342166512693085292151314976633,
+ 12368712287081330853637674140264759478736012797026621876924395982504369598764,
+ 2494806857395134874309386694756263421445039103814920780777601708371037591569,
+ 16101132301514338989512946061786320637179843435886825102406248183507106312877,
+ 6252650284989960032925831409804233477770646333900692286731621844532438095656,
+ 9277135875276787021836189566799935097400042171346561246305113339462708861695,
+ 10493603554686607050979497281838644324893776154179810893893660722522945589063,
+ 8673089750662709235894359384294076697329948991010184356091130382437645649279,
+ 9558393272910366944245875920138649617479779893610128634419086981339060613250,
+ 19012287860122586147374214541764572282814469237161122489573881644994964647218,
+ 9783723818270121678386992630754842961728702994964214799008457449989291229500,
+ 15550788416669474113213749561488122552422887538676036667630838378023479382689,
+ 15016165746156232864069722572047169071786333815661109750860165034341572904221,
+ 6506225705710197163670556961299945987488979904603689017479840649664564978574,
+ 10796631184889302076168355684722130903785890709107732067446714470783437829037,
+ 19871836214837460419845806980869387567383718044439891735114283113359312279540,
+ 20871081766843466343749609089986071784031203517506781251203251608363835140622,
+ 5100105771517691442278432864090229416166996183792075307747582375962855820797,
+ 8777887112076272395250620301071581171386440850451972412060638225741125310886,
+ 5300440870136391278944213332144327695659161151625757537632832724102670898756,
+ 1205448543652932944633962232545707633928124666868453915721030884663332604536,
+ 5542499997310181530432302492142574333860449305424174466698068685590909336771,
+ 11028094245762332275225364962905938096659249161369092798505554939952525894293,
+ 19187314764836593118404597958543112407224947638377479622725713735224279297009,
+ 17047263688548829001253658727764731047114098556534482052135734487985276987385,
+ 19914849528178967155534624144358541535306360577227460456855821557421213606310,
+ 2929658084700714257515872921366736697080475676508114973627124569375444665664,
+ 15092262360719700162343163278648422751610766427236295023221516498310468956361,
+ 21578580340755653236050830649990190843552802306886938815497471545814130084980,
+ 1258781501221760320019859066036073675029057285507345332959539295621677296991,
+ 3819598418157732134449049289585680301176983019643974929528867686268702720163,
+ 8653175945487997845203439345797943132543211416447757110963967501177317426221,
+ 6614652990340435611114076169697104582524566019034036680161902142028967568142,
+ 19212515502973904821995111796203064175854996071497099383090983975618035391558,
+ 18664315914479294273286016871365663486061896605232511201418576829062292269769,
+ 11498264615058604317482574216318586415670903094838791165247179252175768794889,
+ 10814026414212439999107945133852431304483604215416531759535467355316227331774,
+ 17566185590731088197064706533119299946752127014428399631467913813769853431107,
+ 14016139747289624978792446847000951708158212463304817001882956166752906714332,
+ 8242601581342441750402731523736202888792436665415852106196418942315563860366,
+ 9244680976345080074252591214216060854998619670381671198295645618515047080988,
+ 12216779172735125538689875667307129262237123728082657485828359100719208190116,
+ 10702811721859145441471328511968332847175733707711670171718794132331147396634,
+ 6479667912792222539919362076122453947926362746906450079329453150607427372979,
+ 15117544653571553820496948522381772148324367479772362833334593000535648316185,
+ 6842203153996907264167856337497139692895299874139131328642472698663046726780,
+ 12732823292801537626009139514048596316076834307941224506504666470961250728055,
+ 6936272626871035740815028148058841877090860312517423346335878088297448888663,
+ 17297554111853491139852678417579991271009602631577069694853813331124433680030,
+ 16641596134749940573104316021365063031319260205559553673368334842484345864859,
+ 7400481189785154329569470986896455371037813715804007747228648863919991399081,
+ 2273205422216987330510475127669563545720586464429614439716564154166712854048,
+ 15162538063742142685306302282127534305212832649282186184583465569986719234456,
+ 5628039096440332922248578319648483863204530861778160259559031331287721255522,
+ 16085392195894691829567913404182676871326863890140775376809129785155092531260,
+ 14227467863135365427954093998621993651369686288941275436795622973781503444257,
+ 18224457394066545825553407391290108485121649197258948320896164404518684305122,
+ 274945154732293792784580363548970818611304339008964723447672490026510689427,
+ 11050822248291117548220126630860474473945266276626263036056336623671308219529,
+ 2119542016932434047340813757208803962484943912710204325088879681995922344971
+ ];
+
+ var t;
+ signal t2[nrounds];
+ signal t4[nrounds];
+ signal xL[nrounds-1];
+ signal xR[nrounds-1];
+
+ var c;
+ for (var i=0; i .
+*/
+
+/*
+ Source: https://en.wikipedia.org/wiki/Montgomery_curve
+
+ 1 + y 1 + y
+ [u, v] = [ ------- , ---------- ]
+ 1 - y (1 - y)x
+
+ */
+pragma circom 2.0.0;
+
+// add by Picus
+include "comparators.circom";
+
+template Edwards2Montgomery() {
+ signal input in[2];
+ signal output out[2];
+
+ // added by Picus
+ // in[0] != 0
+ component c0 = IsEqual();
+ c0.in[0] <== in[0];
+ c0.in[1] <== 0;
+ c0.out === 0;
+ // in[1] != 1
+ component c1 = IsEqual();
+ c1.in[0] <== in[1];
+ c1.in[1] <== 1;
+ c1.out === 0;
+
+ out[0] <-- (1 + in[1]) / (1 - in[1]);
+ out[1] <-- out[0] / in[0];
+
+
+ out[0] * (1-in[1]) === (1 + in[1]);
+ out[1] * in[0] === out[0];
+}
+
+/*
+
+ u u - 1
+ [x, y] = [ ---, ------- ]
+ v u + 1
+
+ */
+template Montgomery2Edwards() {
+ signal input in[2];
+ signal output out[2];
+
+ // added by Picus
+ // in[1] != 0
+ component c0 = IsEqual();
+ c0.in[0] <== in[1];
+ c0.in[1] <== 0;
+ c0.out === 0;
+ // in[0] != -1
+ component c1 = IsEqual();
+ c1.in[0] <== in[0];
+ c1.in[1] <== -1;
+ c1.out === 0;
+
+ out[0] <-- in[0] / in[1];
+ out[1] <-- (in[0] - 1) / (in[0] + 1);
+
+ out[0] * in[1] === in[0];
+ out[1] * (in[0] + 1) === in[0] - 1;
+}
+
+
+/*
+ x2 - x1
+ lamda = ---------
+ y2 - y1
+
+ x3 + A + x1 + x2
+ x3 = B * lamda^2 - A - x1 -x2 => lamda^2 = ------------------
+ B
+
+ y3 = (2*x1 + x2 + A)*lamda - B*lamda^3 - y1 =>
+
+
+ => y3 = lamda * ( 2*x1 + x2 + A - x3 - A - x1 - x2) - y1 =>
+
+ => y3 = lamda * ( x1 - x3 ) - y1
+
+----------
+
+ y2 - y1
+ lamda = ---------
+ x2 - x1
+
+ x3 = B * lamda^2 - A - x1 -x2
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+
+template MontgomeryAdd() {
+ signal input in1[2];
+ signal input in2[2];
+ signal output out[2];
+
+ // added by Picus
+ // in2[0] != in1[0]
+ component c0 = IsEqual();
+ c0.in[0] <== in2[0];
+ c0.in[1] <== in1[0];
+ c0.out === 0;
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+
+ lamda <-- (in2[1] - in1[1]) / (in2[0] - in1[0]);
+ lamda * (in2[0] - in1[0]) === (in2[1] - in1[1]);
+
+ out[0] <== B*lamda*lamda - A - in1[0] -in2[0];
+ out[1] <== lamda * (in1[0] - out[0]) - in1[1];
+}
+
+/*
+
+ x1_2 = x1*x1
+
+ 3*x1_2 + 2*A*x1 + 1
+ lamda = ---------------------
+ 2*B*y1
+
+ x3 = B * lamda^2 - A - x1 -x1
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+template MontgomeryDouble() {
+ signal input in[2];
+ signal output out[2];
+
+ // added by Picus
+ // in[1] != 0
+ component c0 = IsEqual();
+ c0.in[0] <== in[1];
+ c0.in[1] <== 0;
+ c0.out === 0;
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+ signal x1_2;
+
+ x1_2 <== in[0] * in[0];
+
+ lamda <-- (3*x1_2 + 2*A*in[0] + 1 ) / (2*B*in[1]);
+ lamda * (2*B*in[1]) === (3*x1_2 + 2*A*in[0] + 1 );
+
+ out[0] <== B*lamda*lamda - A - 2*in[0];
+ out[1] <== lamda * (in[0] - out[0]) - in[1];
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/multiplexer.circom b/benchmarks/libs/pre-circomlib-cff5ab6/multiplexer.circom
new file mode 100644
index 0000000..848e31e
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/multiplexer.circom
@@ -0,0 +1,115 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+// --> Assignation without constraint
+// <-- Assignation without constraint
+// === Constraint
+// <== Assignation with constraint
+// ==> Assignation with constraint
+// 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 success;
+ success * (success -1) === 0;
+}
+
+
+template Multiplexer(wIn, nIn) {
+ signal input inp[nIn][wIn];
+ signal input sel;
+ signal output out[wIn];
+ component dec = Decoder(nIn);
+ component ep[wIn];
+
+ for (var k=0; k dec.inp;
+ for (var j=0; j ep[j].in1[k];
+ dec.out[k] ==> ep[j].in2[k];
+ }
+ ep[j].out ==> out[j];
+ }
+ dec.success === 1;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/mux1.circom b/benchmarks/libs/pre-circomlib-cff5ab6/mux1.circom
new file mode 100644
index 0000000..444cb84
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/mux1.circom
@@ -0,0 +1,48 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+template MultiMux1(n) {
+ signal input c[n][2]; // Constants
+ signal input s; // Selector
+ signal output out[n];
+
+ for (var i=0; i mux.s;
+
+ mux.out[0] ==> out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/mux2.circom b/benchmarks/libs/pre-circomlib-cff5ab6/mux2.circom
new file mode 100644
index 0000000..557539b
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/mux2.circom
@@ -0,0 +1,63 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+template MultiMux2(n) {
+ signal input c[n][4]; // Constants
+ signal input s[2]; // Selector
+ signal output out[n];
+
+ signal a10[n];
+ signal a1[n];
+ signal a0[n];
+ signal a[n];
+
+ signal s10;
+ s10 <== s[1] * s[0];
+
+ for (var i=0; i mux.s[i];
+ }
+
+ mux.out[0] ==> out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/mux3.circom b/benchmarks/libs/pre-circomlib-cff5ab6/mux3.circom
new file mode 100644
index 0000000..4be5f7c
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/mux3.circom
@@ -0,0 +1,75 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+template MultiMux3(n) {
+ signal input c[n][8]; // Constants
+ signal input s[3]; // Selector
+ signal output out[n];
+
+ signal a210[n];
+ signal a21[n];
+ signal a20[n];
+ signal a2[n];
+
+ signal a10[n];
+ signal a1[n];
+ signal a0[n];
+ signal a[n];
+
+ // 4 constrains for the intermediary variables
+ signal s10;
+ s10 <== s[1] * s[0];
+
+ for (var i=0; i mux.s[i];
+ }
+
+ mux.out[0] ==> out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/mux4.circom b/benchmarks/libs/pre-circomlib-cff5ab6/mux4.circom
new file mode 100644
index 0000000..01e98bc
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/mux4.circom
@@ -0,0 +1,119 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+template MultiMux4(n) {
+ signal input c[n][16]; // Constants
+ signal input s[4]; // Selector
+ signal output out[n];
+
+ signal a3210[n];
+ signal a321[n];
+ signal a320[n];
+ signal a310[n];
+ signal a32[n];
+ signal a31[n];
+ signal a30[n];
+ signal a3[n];
+
+ signal a210[n];
+ signal a21[n];
+ signal a20[n];
+ signal a10[n];
+ signal a2[n];
+ signal a1[n];
+ signal a0[n];
+ signal a[n];
+
+ // 4 constrains for the intermediary variables
+ signal s10;
+ s10 <== s[1] * s[0];
+ signal s20;
+ s20 <== s[2] * s[0];
+ signal s21;
+ s21 <== s[2] * s[1];
+ signal s210;
+ s210 <== s21 * s[0];
+
+
+ for (var i=0; i mux.s[i];
+ }
+
+ mux.out[0] ==> out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/pedersen.circom b/benchmarks/libs/pre-circomlib-cff5ab6/pedersen.circom
new file mode 100644
index 0000000..a29f486
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/pedersen.circom
@@ -0,0 +1,257 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "montgomery.circom";
+include "mux3.circom";
+include "babyjub.circom";
+
+template Window4() {
+ signal input in[4];
+ signal input base[2];
+ signal output out[2];
+ signal output out8[2]; // Returns 8*Base (To be linked)
+
+ component mux = MultiMux3(2);
+
+ mux.s[0] <== in[0];
+ mux.s[1] <== in[1];
+ mux.s[2] <== in[2];
+
+ component dbl2 = MontgomeryDouble();
+ component adr3 = MontgomeryAdd();
+ component adr4 = MontgomeryAdd();
+ component adr5 = MontgomeryAdd();
+ component adr6 = MontgomeryAdd();
+ component adr7 = MontgomeryAdd();
+ component adr8 = MontgomeryAdd();
+
+// in[0] -> 1*BASE
+
+ mux.c[0][0] <== base[0];
+ mux.c[1][0] <== base[1];
+
+// in[1] -> 2*BASE
+ dbl2.in[0] <== base[0];
+ dbl2.in[1] <== base[1];
+ mux.c[0][1] <== dbl2.out[0];
+ mux.c[1][1] <== dbl2.out[1];
+
+// in[2] -> 3*BASE
+ adr3.in1[0] <== base[0];
+ adr3.in1[1] <== base[1];
+ adr3.in2[0] <== dbl2.out[0];
+ adr3.in2[1] <== dbl2.out[1];
+ mux.c[0][2] <== adr3.out[0];
+ mux.c[1][2] <== adr3.out[1];
+
+// in[3] -> 4*BASE
+ adr4.in1[0] <== base[0];
+ adr4.in1[1] <== base[1];
+ adr4.in2[0] <== adr3.out[0];
+ adr4.in2[1] <== adr3.out[1];
+ mux.c[0][3] <== adr4.out[0];
+ mux.c[1][3] <== adr4.out[1];
+
+// in[4] -> 5*BASE
+ adr5.in1[0] <== base[0];
+ adr5.in1[1] <== base[1];
+ adr5.in2[0] <== adr4.out[0];
+ adr5.in2[1] <== adr4.out[1];
+ mux.c[0][4] <== adr5.out[0];
+ mux.c[1][4] <== adr5.out[1];
+
+// in[5] -> 6*BASE
+ adr6.in1[0] <== base[0];
+ adr6.in1[1] <== base[1];
+ adr6.in2[0] <== adr5.out[0];
+ adr6.in2[1] <== adr5.out[1];
+ mux.c[0][5] <== adr6.out[0];
+ mux.c[1][5] <== adr6.out[1];
+
+// in[6] -> 7*BASE
+ adr7.in1[0] <== base[0];
+ adr7.in1[1] <== base[1];
+ adr7.in2[0] <== adr6.out[0];
+ adr7.in2[1] <== adr6.out[1];
+ mux.c[0][6] <== adr7.out[0];
+ mux.c[1][6] <== adr7.out[1];
+
+// in[7] -> 8*BASE
+ adr8.in1[0] <== base[0];
+ adr8.in1[1] <== base[1];
+ adr8.in2[0] <== adr7.out[0];
+ adr8.in2[1] <== adr7.out[1];
+ mux.c[0][7] <== adr8.out[0];
+ mux.c[1][7] <== adr8.out[1];
+
+ out8[0] <== adr8.out[0];
+ out8[1] <== adr8.out[1];
+
+ out[0] <== mux.out[0];
+ out[1] <== - mux.out[1]*2*in[3] + mux.out[1]; // Negate y if in[3] is one
+}
+
+
+template Segment(nWindows) {
+ signal input in[nWindows*4];
+ signal input base[2];
+ signal output out[2];
+
+ var i;
+ var j;
+
+ // Convert the base to montgomery
+
+ component e2m = Edwards2Montgomery();
+ e2m.in[0] <== base[0];
+ e2m.in[1] <== base[1];
+
+ component windows[nWindows];
+ component doublers1[nWindows-1];
+ component doublers2[nWindows-1];
+ component adders[nWindows-1];
+ for (i=0; i 1) {
+ m2e.in[0] <== adders[nWindows-2].out[0];
+ m2e.in[1] <== adders[nWindows-2].out[1];
+ } else {
+ m2e.in[0] <== windows[0].out[0];
+ m2e.in[1] <== windows[0].out[1];
+ }
+
+ out[0] <== m2e.out[0];
+ out[1] <== m2e.out[1];
+}
+
+template Pedersen(n) {
+ signal input in[n];
+ signal output out[2];
+
+ var BASE[10][2] = [
+ [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
+ [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
+ [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
+ [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
+ [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
+ [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
+ [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
+ [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
+ [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
+ [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
+
+ ];
+
+ var nSegments = ((n-1)\200)+1;
+
+ component segments[nSegments];
+
+ var i;
+ var j;
+ var nBits;
+ var nWindows;
+ for (i=0; i1) {
+ packPoint.in[0] <== adders[nSegments-2].xout;
+ packPoint.in[1] <== adders[nSegments-2].yout;
+ } else {
+ packPoint.in[0] <== segments[0].out[0];
+ packPoint.in[1] <== segments[0].out[1];
+ }
+
+ out[0] <== packPoint.out[0];
+ out[1] <== packPoint.out[1];
+*/
+
+ if (nSegments>1) {
+ out[0] <== adders[nSegments-2].xout;
+ out[1] <== adders[nSegments-2].yout;
+ } else {
+ out[0] <== segments[0].out[0];
+ out[1] <== segments[0].out[1];
+ }
+}
+
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/pedersen_old.circom b/benchmarks/libs/pre-circomlib-cff5ab6/pedersen_old.circom
new file mode 100644
index 0000000..c338e44
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/pedersen_old.circom
@@ -0,0 +1,68 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "escalarmul.circom";
+
+template Pedersen(n) {
+ signal input in[n];
+ signal output out[2];
+
+ var nexps = ((n-1) \ 250) + 1;
+ var nlastbits = n - (nexps-1)*250;
+
+ component escalarMuls[nexps];
+
+ var PBASE[10][2] = [
+ [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
+ [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
+ [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
+ [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
+ [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
+ [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
+ [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
+ [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
+ [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
+ [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
+
+ ];
+
+ var i;
+ var j;
+ var nexpbits;
+ for (i=0; i out[0];
+ escalarMuls[nexps-1].out[1] ==> out[1];
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/pointbits.circom b/benchmarks/libs/pre-circomlib-cff5ab6/pointbits.circom
new file mode 100644
index 0000000..fa6007d
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/pointbits.circom
@@ -0,0 +1,164 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "bitify.circom";
+include "aliascheck.circom";
+include "compconstant.circom";
+include "babyjub.circom";
+
+
+function sqrt(n) {
+
+ if (n == 0) {
+ return 0;
+ }
+
+ // Test that have solution
+ var res = n ** ((-1) >> 1);
+// if (res!=1) assert(false, "SQRT does not exists");
+ if (res!=1) return 0;
+
+ var m = 28;
+ var c = 19103219067921713944291392827692070036145651957329286315305642004821462161904;
+ var t = n ** 81540058820840996586704275553141814055101440848469862132140264610111;
+ var r = n ** ((81540058820840996586704275553141814055101440848469862132140264610111+1)>>1);
+ var sq;
+ var i;
+ var b;
+ var j;
+
+ while ((r != 0)&&(t != 1)) {
+ sq = t*t;
+ i = 1;
+ while (sq!=1) {
+ i++;
+ sq = sq*sq;
+ }
+
+ // b = c ^ m-i-1
+ b = c;
+ for (j=0; j< m-i-1; j ++) b = b*b;
+
+ m = i;
+ c = b*b;
+ t = t*c;
+ r = r*b;
+ }
+
+ if (r < 0 ) {
+ r = -r;
+ }
+
+ return r;
+}
+
+
+template Bits2Point() {
+ signal input in[256];
+ signal output out[2];
+}
+
+template Bits2Point_Strict() {
+ signal input in[256];
+ signal output out[2];
+
+ var i;
+
+ // Check aliasing
+ component aliasCheckY = AliasCheck();
+ for (i=0; i<254; i++) {
+ aliasCheckY.in[i] <== in[i];
+ }
+ in[254] === 0;
+
+ component b2nY = Bits2Num(254);
+ for (i=0; i<254; i++) {
+ b2nY.in[i] <== in[i];
+ }
+
+ out[1] <== b2nY.out;
+
+ var a = 168700;
+ var d = 168696;
+
+ var y2 = out[1] * out[1];
+
+ var x = sqrt( (1-y2)/(a - d*y2) );
+
+ if (in[255] == 1) x = -x;
+
+ out[0] <-- x;
+
+ component babyCheck = BabyCheck();
+ babyCheck.x <== out[0];
+ babyCheck.y <== out[1];
+
+ component n2bX = Num2Bits(254);
+ n2bX.in <== out[0];
+ component aliasCheckX = AliasCheck();
+ for (i=0; i<254; i++) {
+ aliasCheckX.in[i] <== n2bX.out[i];
+ }
+
+ component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808);
+ for (i=0; i<254; i++) {
+ signCalc.in[i] <== n2bX.out[i];
+ }
+
+ signCalc.out === in[255];
+}
+
+
+template Point2Bits() {
+ signal input in[2];
+ signal output out[256];
+
+
+}
+
+template Point2Bits_Strict() {
+ signal input in[2];
+ signal output out[256];
+
+ var i;
+
+ component n2bX = Num2Bits(254);
+ n2bX.in <== in[0];
+ component n2bY = Num2Bits(254);
+ n2bY.in <== in[1];
+
+ component aliasCheckX = AliasCheck();
+ component aliasCheckY = AliasCheck();
+ for (i=0; i<254; i++) {
+ aliasCheckX.in[i] <== n2bX.out[i];
+ aliasCheckY.in[i] <== n2bY.out[i];
+ }
+
+ component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808);
+ for (i=0; i<254; i++) {
+ signCalc.in[i] <== n2bX.out[i];
+ }
+
+ for (i=0; i<254; i++) {
+ out[i] <== n2bY.out[i];
+ }
+ out[254] <== 0;
+ out[255] <== signCalc.out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/poseidon.circom b/benchmarks/libs/pre-circomlib-cff5ab6/poseidon.circom
new file mode 100644
index 0000000..2ab28b6
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/poseidon.circom
@@ -0,0 +1,193 @@
+pragma circom 2.0.0;
+
+include "./poseidon_constants.circom";
+
+template Sigma() {
+ signal input in;
+ signal output out;
+
+ signal in2;
+ signal in4;
+
+ in2 <== in*in;
+ in4 <== in2*in2;
+
+ out <== in4*in;
+}
+
+template Ark(t, C, r) {
+ signal input in[t];
+ signal output out[t];
+
+ for (var i=0; i0) {
+ ark[0].in[j] <== inputs[j-1];
+ } else {
+ ark[0].in[j] <== 0;
+ }
+ }
+
+ for (var r = 0; r < nRoundsF\2-1; r++) {
+ for (var j=0; j0) {
+ ark[i].in[j] <== inputs[j-1];
+ } else {
+ ark[i].in[j] <== 0;
+ }
+ } else {
+ ark[i].in[j] <== mix[i-1].out[j];
+ }
+ }
+
+ if (i < nRoundsF/2 || i >= nRoundsP + nRoundsF/2) {
+ k = i < nRoundsF/2 ? i : i - nRoundsP;
+ mix[i] = Mix(t, M);
+ for (var j=0; j .
+*/
+
+/* Ch
+
+000 0
+001 1
+010 0
+011 1
+100 0
+101 0
+110 1
+111 1
+
+out = a&b ^ (!a)&c =>
+
+out = a*(b-c) + c
+
+*/
+pragma circom 2.0.0;
+
+template Ch_t(n) {
+ signal input a[n];
+ signal input b[n];
+ signal input c[n];
+ signal output out[n];
+
+ for (var k=0; k .
+*/
+pragma circom 2.0.0;
+
+template H(x) {
+ signal output out[32];
+ var c[8] = [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[64] = [
+ 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;
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/main.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/main.circom
new file mode 100644
index 0000000..88d69d6
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/main.circom
@@ -0,0 +1,35 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "sha256_2.circom";
+
+template Main() {
+ signal input a;
+ signal input b;
+ signal output out;
+
+ component sha256_2 = Sha256_2();
+
+ sha256_2.a <== a;
+ sha256_2.b <== a;
+ out <== sha256_2.out;
+}
+
+component main = Main();
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/maj.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/maj.circom
new file mode 100644
index 0000000..1c0940c
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/maj.circom
@@ -0,0 +1,45 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/* Maj function for sha256
+
+out = a&b ^ a&c ^ b&c =>
+
+out = a*b + a*c + b*c - 2*a*b*c =>
+
+out = a*( b + c - 2*b*c ) + b*c =>
+
+mid = b*c
+out = a*( b + c - 2*mid ) + mid
+
+*/
+pragma circom 2.0.0;
+
+template Maj_t(n) {
+ signal input a[n];
+ signal input b[n];
+ signal input c[n];
+ signal output out[n];
+ signal mid[n];
+
+ for (var k=0; k .
+*/
+pragma circom 2.0.0;
+
+template RotR(n, r) {
+ signal input in[n];
+ signal output out[n];
+
+ for (var i=0; i> k)&1;
+ }
+
+ component ha0 = H(0);
+ component hb0 = H(1);
+ component hc0 = H(2);
+ component hd0 = H(3);
+ component he0 = H(4);
+ component hf0 = H(5);
+ component hg0 = H(6);
+ component hh0 = H(7);
+
+ component sha256compression[nBlocks];
+
+ for (i=0; i .
+*/
+pragma circom 2.0.0;
+
+include "constants.circom";
+include "sha256compression.circom";
+include "../bitify.circom";
+
+template Sha256_2() {
+ signal input a;
+ signal input b;
+ signal output out;
+
+ var i;
+ var k;
+
+ component bits2num = Bits2Num(216);
+ component num2bits[2];
+
+ num2bits[0] = Num2Bits(216);
+ num2bits[1] = Num2Bits(216);
+
+ num2bits[0].in <== a;
+ num2bits[1].in <== b;
+
+
+ component sha256compression = Sha256compression() ;
+
+ component ha0 = H(0);
+ component hb0 = H(1);
+ component hc0 = H(2);
+ component hd0 = H(3);
+ component he0 = H(4);
+ component hf0 = H(5);
+ component hg0 = H(6);
+ component hh0 = H(7);
+
+ for (k=0; k<32; k++ ) {
+ sha256compression.hin[0*32+k] <== ha0.out[k];
+ sha256compression.hin[1*32+k] <== hb0.out[k];
+ sha256compression.hin[2*32+k] <== hc0.out[k];
+ sha256compression.hin[3*32+k] <== hd0.out[k];
+ sha256compression.hin[4*32+k] <== he0.out[k];
+ sha256compression.hin[5*32+k] <== hf0.out[k];
+ sha256compression.hin[6*32+k] <== hg0.out[k];
+ sha256compression.hin[7*32+k] <== hh0.out[k];
+ }
+
+ for (i=0; i<216; i++) {
+ sha256compression.inp[i] <== num2bits[0].out[215-i];
+ sha256compression.inp[i+216] <== num2bits[1].out[215-i];
+ }
+
+ sha256compression.inp[432] <== 1;
+
+ for (i=433; i<503; i++) {
+ sha256compression.inp[i] <== 0;
+ }
+
+ sha256compression.inp[503] <== 1;
+ sha256compression.inp[504] <== 1;
+ sha256compression.inp[505] <== 0;
+ sha256compression.inp[506] <== 1;
+ sha256compression.inp[507] <== 1;
+ sha256compression.inp[508] <== 0;
+ sha256compression.inp[509] <== 0;
+ sha256compression.inp[510] <== 0;
+ sha256compression.inp[511] <== 0;
+
+ for (i=0; i<216; i++) {
+ bits2num.in[i] <== sha256compression.out[255-i];
+ }
+
+ out <== bits2num.out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sha256compression.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sha256compression.circom
new file mode 100644
index 0000000..98f7c98
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sha256compression.circom
@@ -0,0 +1,166 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "constants.circom";
+include "t1.circom";
+include "t2.circom";
+include "../binsum.circom";
+include "sigmaplus.circom";
+include "sha256compression_function.circom";
+
+
+template Sha256compression() {
+ signal input hin[256];
+ signal input inp[512];
+ signal output out[256];
+ signal a[65][32];
+ signal b[65][32];
+ signal c[65][32];
+ signal d[65][32];
+ signal e[65][32];
+ signal f[65][32];
+ signal g[65][32];
+ signal h[65][32];
+ signal w[64][32];
+
+
+ var outCalc[256] = sha256compression(hin, inp);
+
+ var i;
+ for (i=0; i<256; i++) out[i] <-- outCalc[i];
+
+ component sigmaPlus[48];
+ for (i=0; i<48; i++) sigmaPlus[i] = SigmaPlus();
+
+ component ct_k[64];
+ for (i=0; i<64; i++) ct_k[i] = K(i);
+
+ component t1[64];
+ for (i=0; i<64; i++) t1[i] = T1();
+
+ component t2[64];
+ for (i=0; i<64; i++) t2[i] = T2();
+
+ component suma[64];
+ for (i=0; i<64; i++) suma[i] = BinSum(32, 2);
+
+ component sume[64];
+ for (i=0; i<64; i++) sume[i] = BinSum(32, 2);
+
+ component fsum[8];
+ for (i=0; i<8; i++) fsum[i] = BinSum(32, 2);
+
+ var k;
+ var t;
+
+ for (t=0; t<64; t++) {
+ if (t<16) {
+ for (k=0; k<32; k++) {
+ w[t][k] <== inp[t*32+31-k];
+ }
+ } else {
+ for (k=0; k<32; k++) {
+ sigmaPlus[t-16].in2[k] <== w[t-2][k];
+ sigmaPlus[t-16].in7[k] <== w[t-7][k];
+ sigmaPlus[t-16].in15[k] <== w[t-15][k];
+ sigmaPlus[t-16].in16[k] <== w[t-16][k];
+ }
+
+ for (k=0; k<32; k++) {
+ w[t][k] <== sigmaPlus[t-16].out[k];
+ }
+ }
+ }
+
+ for (k=0; k<32; k++ ) {
+ a[0][k] <== hin[k];
+ b[0][k] <== hin[32*1 + k];
+ c[0][k] <== hin[32*2 + k];
+ d[0][k] <== hin[32*3 + k];
+ e[0][k] <== hin[32*4 + k];
+ f[0][k] <== hin[32*5 + k];
+ g[0][k] <== hin[32*6 + k];
+ h[0][k] <== hin[32*7 + k];
+ }
+
+ for (t = 0; t<64; t++) {
+ for (k=0; k<32; k++) {
+ t1[t].h[k] <== h[t][k];
+ t1[t].e[k] <== e[t][k];
+ t1[t].f[k] <== f[t][k];
+ t1[t].g[k] <== g[t][k];
+ t1[t].k[k] <== ct_k[t].out[k];
+ t1[t].w[k] <== w[t][k];
+
+ t2[t].a[k] <== a[t][k];
+ t2[t].b[k] <== b[t][k];
+ t2[t].c[k] <== c[t][k];
+ }
+
+ for (k=0; k<32; k++) {
+ sume[t].in[0][k] <== d[t][k];
+ sume[t].in[1][k] <== t1[t].out[k];
+
+ suma[t].in[0][k] <== t1[t].out[k];
+ suma[t].in[1][k] <== t2[t].out[k];
+ }
+
+ for (k=0; k<32; k++) {
+ h[t+1][k] <== g[t][k];
+ g[t+1][k] <== f[t][k];
+ f[t+1][k] <== e[t][k];
+ e[t+1][k] <== sume[t].out[k];
+ d[t+1][k] <== c[t][k];
+ c[t+1][k] <== b[t][k];
+ b[t+1][k] <== a[t][k];
+ a[t+1][k] <== suma[t].out[k];
+ }
+ }
+
+ for (k=0; k<32; k++) {
+ fsum[0].in[0][k] <== hin[32*0+k];
+ fsum[0].in[1][k] <== a[64][k];
+ fsum[1].in[0][k] <== hin[32*1+k];
+ fsum[1].in[1][k] <== b[64][k];
+ fsum[2].in[0][k] <== hin[32*2+k];
+ fsum[2].in[1][k] <== c[64][k];
+ fsum[3].in[0][k] <== hin[32*3+k];
+ fsum[3].in[1][k] <== d[64][k];
+ fsum[4].in[0][k] <== hin[32*4+k];
+ fsum[4].in[1][k] <== e[64][k];
+ fsum[5].in[0][k] <== hin[32*5+k];
+ fsum[5].in[1][k] <== f[64][k];
+ fsum[6].in[0][k] <== hin[32*6+k];
+ fsum[6].in[1][k] <== g[64][k];
+ fsum[7].in[0][k] <== hin[32*7+k];
+ fsum[7].in[1][k] <== h[64][k];
+ }
+
+ for (k=0; k<32; k++) {
+ out[31-k] === fsum[0].out[k];
+ out[32+31-k] === fsum[1].out[k];
+ out[64+31-k] === fsum[2].out[k];
+ out[96+31-k] === fsum[3].out[k];
+ out[128+31-k] === fsum[4].out[k];
+ out[160+31-k] === fsum[5].out[k];
+ out[192+31-k] === fsum[6].out[k];
+ out[224+31-k] === fsum[7].out[k];
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sha256compression_function.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sha256compression_function.circom
new file mode 100644
index 0000000..9f8d5b8
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sha256compression_function.circom
@@ -0,0 +1,112 @@
+// signal input hin[256];
+// signal input inp[512];
+// signal output out[256];
+pragma circom 2.0.0;
+
+function rrot(x, n) {
+ return ((x >> n) | (x << (32-n))) & 0xFFFFFFFF;
+}
+
+function bsigma0(x) {
+ return rrot(x,2) ^ rrot(x,13) ^ rrot(x,22);
+}
+
+function bsigma1(x) {
+ return rrot(x,6) ^ rrot(x,11) ^ rrot(x,25);
+}
+
+function ssigma0(x) {
+ return rrot(x,7) ^ rrot(x,18) ^ (x >> 3);
+}
+
+function ssigma1(x) {
+ return rrot(x,17) ^ rrot(x,19) ^ (x >> 10);
+}
+
+function Maj(x, y, z) {
+ return (x&y) ^ (x&z) ^ (y&z);
+}
+
+function Ch(x, y, z) {
+ return (x & y) ^ ((0xFFFFFFFF ^x) & z);
+}
+
+function sha256K(i) {
+ var k[64] = [
+ 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
+ ];
+ return k[i];
+}
+
+function sha256compression(hin, inp) {
+ var H[8];
+ var a;
+ var b;
+ var c;
+ var d;
+ var e;
+ var f;
+ var g;
+ var h;
+ var out[256];
+ for (var i=0; i<8; i++) {
+ H[i] = 0;
+ for (var j=0; j<32; j++) {
+ H[i] += hin[i*32+j] << j;
+ }
+ }
+ a=H[0];
+ b=H[1];
+ c=H[2];
+ d=H[3];
+ e=H[4];
+ f=H[5];
+ g=H[6];
+ h=H[7];
+ var w[64];
+ var T1;
+ var T2;
+ for (var i=0; i<64; i++) {
+ if (i<16) {
+ w[i]=0;
+ for (var j=0; j<32; j++) {
+ w[i] += inp[i*32+31-j]<> j) & 1;
+ }
+ }
+ return out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/shift.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/shift.circom
new file mode 100644
index 0000000..317cd32
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/shift.circom
@@ -0,0 +1,33 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+template ShR(n, r) {
+ signal input in[n];
+ signal output out[n];
+
+ for (var i=0; i= n) {
+ out[i] <== 0;
+ } else {
+ out[i] <== in[ i+r ];
+ }
+ }
+}
+
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sigma.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sigma.circom
new file mode 100644
index 0000000..bcb0b80
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sigma.circom
@@ -0,0 +1,77 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "xor3.circom";
+include "rotate.circom";
+include "shift.circom";
+
+template SmallSigma(ra, rb, rc) {
+ signal input in[32];
+ signal output out[32];
+ var k;
+
+ component rota = RotR(32, ra);
+ component rotb = RotR(32, rb);
+ component shrc = ShR(32, rc);
+
+ for (k=0; k<32; k++) {
+ rota.in[k] <== in[k];
+ rotb.in[k] <== in[k];
+ shrc.in[k] <== in[k];
+ }
+
+ component xor3 = Xor3(32);
+ for (k=0; k<32; k++) {
+ xor3.a[k] <== rota.out[k];
+ xor3.b[k] <== rotb.out[k];
+ xor3.c[k] <== shrc.out[k];
+ }
+
+ for (k=0; k<32; k++) {
+ out[k] <== xor3.out[k];
+ }
+}
+
+template BigSigma(ra, rb, rc) {
+ signal input in[32];
+ signal output out[32];
+ var k;
+
+ component rota = RotR(32, ra);
+ component rotb = RotR(32, rb);
+ component rotc = RotR(32, rc);
+ for (k=0; k<32; k++) {
+ rota.in[k] <== in[k];
+ rotb.in[k] <== in[k];
+ rotc.in[k] <== in[k];
+ }
+
+ component xor3 = Xor3(32);
+
+ for (k=0; k<32; k++) {
+ xor3.a[k] <== rota.out[k];
+ xor3.b[k] <== rotb.out[k];
+ xor3.c[k] <== rotc.out[k];
+ }
+
+ for (k=0; k<32; k++) {
+ out[k] <== xor3.out[k];
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sigmaplus.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sigmaplus.circom
new file mode 100644
index 0000000..35e3300
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/sigmaplus.circom
@@ -0,0 +1,50 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "../binsum.circom";
+include "sigma.circom";
+
+template SigmaPlus() {
+ signal input in2[32];
+ signal input in7[32];
+ signal input in15[32];
+ signal input in16[32];
+ signal output out[32];
+ var k;
+
+ component sigma1 = SmallSigma(17,19,10);
+ component sigma0 = SmallSigma(7, 18, 3);
+ for (k=0; k<32; k++) {
+ sigma1.in[k] <== in2[k];
+ sigma0.in[k] <== in15[k];
+ }
+
+ component sum = BinSum(32, 4);
+ for (k=0; k<32; 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];
+ }
+
+ for (k=0; k<32; k++) {
+ out[k] <== sum.out[k];
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/t1.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/t1.circom
new file mode 100644
index 0000000..e606772
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/t1.circom
@@ -0,0 +1,58 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "../binsum.circom";
+include "sigma.circom";
+include "ch.circom";
+
+template T1() {
+ signal input h[32];
+ signal input e[32];
+ signal input f[32];
+ signal input g[32];
+ signal input k[32];
+ signal input w[32];
+ signal output out[32];
+
+ var ki;
+
+ component ch = Ch_t(32);
+ component bigsigma1 = BigSigma(6, 11, 25);
+
+ for (ki=0; ki<32; ki++) {
+ bigsigma1.in[ki] <== e[ki];
+ ch.a[ki] <== e[ki];
+ ch.b[ki] <== f[ki];
+ ch.c[ki] <== g[ki];
+ }
+
+ component sum = BinSum(32, 5);
+ for (ki=0; ki<32; ki++) {
+ sum.in[0][ki] <== h[ki];
+ sum.in[1][ki] <== bigsigma1.out[ki];
+ sum.in[2][ki] <== ch.out[ki];
+ sum.in[3][ki] <== k[ki];
+ sum.in[4][ki] <== w[ki];
+ }
+
+ for (ki=0; ki<32; ki++) {
+ out[ki] <== sum.out[ki];
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/t2.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/t2.circom
new file mode 100644
index 0000000..5a83d59
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/t2.circom
@@ -0,0 +1,51 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "../binsum.circom";
+include "sigma.circom";
+include "maj.circom";
+
+template T2() {
+ signal input a[32];
+ signal input b[32];
+ signal input c[32];
+ signal output out[32];
+ var k;
+
+ component bigsigma0 = BigSigma(2, 13, 22);
+ component maj = Maj_t(32);
+ for (k=0; k<32; k++) {
+ bigsigma0.in[k] <== a[k];
+ maj.a[k] <== a[k];
+ maj.b[k] <== b[k];
+ maj.c[k] <== c[k];
+ }
+
+ component sum = BinSum(32, 2);
+
+ for (k=0; k<32; k++) {
+ sum.in[0][k] <== bigsigma0.out[k];
+ sum.in[1][k] <== maj.out[k];
+ }
+
+ for (k=0; k<32; k++) {
+ out[k] <== sum.out[k];
+ }
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/sha256/xor3.circom b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/xor3.circom
new file mode 100644
index 0000000..9c21e4e
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/sha256/xor3.circom
@@ -0,0 +1,45 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/* Xor3 function for sha256
+
+out = a ^ b ^ c =>
+
+out = a+b+c - 2*a*b - 2*a*c - 2*b*c + 4*a*b*c =>
+
+out = a*( 1 - 2*b - 2*c + 4*b*c ) + b + c - 2*b*c =>
+
+mid = b*c
+out = a*( 1 - 2*b -2*c + 4*mid ) + b + c - 2 * mid
+
+*/
+pragma circom 2.0.0;
+
+template Xor3(n) {
+ signal input a[n];
+ signal input b[n];
+ signal input c[n];
+ signal output out[n];
+ signal mid[n];
+
+ for (var k=0; k .
+*/
+pragma circom 2.0.0;
+
+include "compconstant.circom";
+
+template Sign() {
+ signal input in[254];
+ signal output sign;
+
+ component comp = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808);
+
+ var i;
+
+ for (i=0; i<254; i++) {
+ comp.in[i] <== in[i];
+ }
+
+ sign <== comp.out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/smt/smthash_mimc.circom b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smthash_mimc.circom
new file mode 100644
index 0000000..272e527
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smthash_mimc.circom
@@ -0,0 +1,58 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "../mimc.circom";
+
+
+/*
+ Hash1 = H(1 | key | value)
+ */
+
+template SMTHash1() {
+ signal input key;
+ signal input value;
+ signal output out;
+
+ component h = MultiMiMC7(2, 91); // Constant
+ h.in[0] <== key;
+ h.in[1] <== value;
+ h.k <== 1;
+
+ out <== h.out;
+}
+
+/*
+ This component is used to create the 2 nodes.
+
+ Hash2 = H(Hl | Hr)
+ */
+
+template SMTHash2() {
+ signal input L;
+ signal input R;
+ signal output out;
+
+ component h = MultiMiMC7(2, 91); // Constant
+ h.in[0] <== L;
+ h.in[1] <== R;
+ h.k <== 0;
+
+ out <== h.out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/smt/smthash_poseidon.circom b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smthash_poseidon.circom
new file mode 100644
index 0000000..aa6b8b3
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smthash_poseidon.circom
@@ -0,0 +1,57 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+pragma circom 2.0.0;
+
+include "../poseidon.circom";
+
+
+/*
+ Hash1 = H(1 | key | value)
+ */
+
+template SMTHash1() {
+ signal input key;
+ signal input value;
+ signal output out;
+
+ component h = Poseidon(3); // Constant
+ h.inputs[0] <== key;
+ h.inputs[1] <== value;
+ h.inputs[2] <== 1;
+
+ out <== h.out;
+}
+
+/*
+ This component is used to create the 2 nodes.
+
+ Hash2 = H(Hl | Hr)
+ */
+
+template SMTHash2() {
+ signal input L;
+ signal input R;
+ signal output out;
+
+ component h = Poseidon(2); // Constant
+ h.inputs[0] <== L;
+ h.inputs[1] <== R;
+
+ out <== h.out;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtlevins.circom b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtlevins.circom
new file mode 100644
index 0000000..a03ae50
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtlevins.circom
@@ -0,0 +1,103 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+
+This component finds the level where the oldInsert is done.
+The rules are:
+
+levIns[i] == 1 if its level and all the child levels have a sibling of 0 and
+the parent level has a sibling != 0. Considere that the root level always has
+a parent with a sibling != 0.
+
+
+ ┌──────────────┐
+ │ │
+ │ │───▶ levIns[0] <== (1-done[i])
+ │ │
+ └──────────────┘
+ ▲
+ │
+ │
+ done[0]
+
+
+
+ done[i-1] <== levIns[i] + done[i]
+ ▲
+ │
+ │
+ ┌───────────┐ ┌──────────────┐
+ │ │ │ │
+ sibling[i-1]───▶│IsZero[i-1]│─▶│ │───▶ levIns[i] <== (1-done[i])*(1-isZero[i-1].out)
+ │ │ │ │
+ └───────────┘ └──────────────┘
+ ▲
+ │
+ │
+ done[i]
+
+
+
+ done[n-2] <== levIns[n-1]
+ ▲
+ │
+ │
+ ┌───────────┐ ┌──────────────┐
+ │ │ │ │
+ sibling[n-2]───▶│IsZero[n-2]│─▶│ │────▶ levIns[n-1] <== (1-isZero[n-2].out)
+ │ │ │ │
+ └───────────┘ └──────────────┘
+
+ ┌───────────┐
+ │ │
+ sibling[n-1]───▶│IsZero[n-1]│────▶ === 0
+ │ │
+ └───────────┘
+
+ */
+ pragma circom 2.0.0;
+
+template SMTLevIns(nLevels) {
+ signal input enabled;
+ signal input siblings[nLevels];
+ signal output levIns[nLevels];
+ signal done[nLevels-1]; // Indicates if the insLevel has aready been detected.
+
+ var i;
+
+ component isZero[nLevels];
+
+ for (i=0; i0; i--) {
+ levIns[i] <== (1-done[i])*(1-isZero[i-1].out);
+ done[i-1] <== levIns[i] + done[i];
+ }
+
+ levIns[0] <== (1-done[0]);
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtprocessor.circom b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtprocessor.circom
new file mode 100644
index 0000000..b75f17c
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtprocessor.circom
@@ -0,0 +1,261 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/***************************************************************************************************
+
+SMTProcessor: Sparse Merkle Tree processor is a component to verify an insert/update/delete elements
+into the Sparse Merkle tree.
+
+
+Insert to an empty leaf
+=======================
+
+ STATE OLD STATE NEW STATE
+ ===== ========= =========
+
+ oldRoot newRoot
+ ▲ ▲
+ │ │
+ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
+ top │Sibling├────▶┃ Hash ┃◀─┐ │Sibling├────▶┃ Hash ┃◀─┐
+ └───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
+ │ │
+ │ │
+ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐
+ top ┌─────▶┃ Hash ┃◀──┤Sibling│ ┌─────▶┃ Hash ┃◀──┤Sibling│
+ │ ┗━━━━━━━┛ └───────┘ │ ┗━━━━━━━┛ └───────┘
+ │ │
+ │ │
+ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
+ top │Sibling├──▶┃ Hash ┃◀─────┐ │Sibling├──▶┃ Hash ┃◀─────┐
+ └───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
+ │ │
+ │ │
+ ┌────┴────┐ ┌────┴────┐
+ old0 │ 0 │ │New1Leaf │
+ └─────────┘ └─────────┘
+
+
+ ┏━━━━━━━┓ ┏━━━━━━━┓
+ na ┃ Hash ┃ ┃ Hash ┃
+ ┗━━━━━━━┛ ┗━━━━━━━┛
+
+
+ ┏━━━━━━━┓ ┏━━━━━━━┓
+ na ┃ Hash ┃ ┃ Hash ┃
+ ┗━━━━━━━┛ ┗━━━━━━━┛
+
+
+
+Insert to a used leaf.
+=====================
+
+ STATE OLD STATE NEW STATE
+ ===== ========= =========
+
+
+ oldRoot newRoot
+ ▲ ▲
+ │ │
+ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
+ top │Sibling├────▶┃ Hash ┃◀─┐ │Sibling├────▶┃ Hash ┃◀─┐
+ └───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
+ │ │
+ │ │
+ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐
+ top ┌─────▶┃ Hash ┃◀──┤Sibling│ ┌─────▶┃ Hash ┃◀──┤Sibling│
+ │ ┗━━━━━━━┛ └───────┘ │ ┗━━━━━━━┛ └───────┘
+ │ │
+ │ │
+ ┌───────┐ ┏━━━┻━━━┓ ┌───────┐ ┏━━━┻━━━┓
+ top │Sibling├──▶┃ Hash ┃◀─────┐ │Sibling├──▶┃ Hash ┃◀─────┐
+ └───────┘ ┗━━━━━━━┛ │ └───────┘ ┗━━━━━━━┛ │
+ │ │
+ │ │
+ ┌────┴────┐ ┏━━━┻━━━┓ ┌───────┐
+ bot │Old1Leaf │ ┌─────▶┃ Hash ┃◀──┼─ 0 │
+ └─────────┘ │ ┗━━━━━━━┛ └───────┘
+ │
+ │
+ ┏━━━━━━━┓ ┌───────┐ ┏━━━┻━━━┓
+ bot ┃ Hash ┃ │ 0 ─┼──▶┃ Hash ┃◀─────┐
+ ┗━━━━━━━┛ └───────┘ ┗━━━━━━━┛ │
+ │
+ │
+ ┏━━━━━━━┓ ┏━━━┻━━━┓ ┌───────┐
+ bot ┃ Hash ┃ ┌─────▶┃ Hash ┃◀──│ 0 │
+ ┗━━━━━━━┛ │ ┗━━━━━━━┛ └───────┘
+ │
+ │
+ ┏━━━━━━━┓ ┌─────────┐ ┏━━━┻━━━┓ ┌─────────┐
+ new1 ┃ Hash ┃ │Old1Leaf ├──▶┃ Hash ┃◀──│New1Leaf │
+ ┗━━━━━━━┛ └─────────┘ ┗━━━━━━━┛ └─────────┘
+
+
+ ┏━━━━━━━┓ ┏━━━━━━━┓
+ na ┃ Hash ┃ ┃ Hash ┃
+ ┗━━━━━━━┛ ┗━━━━━━━┛
+
+
+ ┏━━━━━━━┓ ┏━━━━━━━┓
+ na ┃ Hash ┃ ┃ Hash ┃
+ ┗━━━━━━━┛ ┗━━━━━━━┛
+
+
+Fnction
+fnc[0] fnc[1]
+0 0 NOP
+0 1 UPDATE
+1 0 INSERT
+1 1 DELETE
+
+
+***************************************************************************************************/
+pragma circom 2.0.0;
+
+include "../gates.circom";
+include "../bitify.circom";
+include "../comparators.circom";
+include "../switcher.circom";
+include "smtlevins.circom";
+include "smtprocessorlevel.circom";
+include "smtprocessorsm.circom";
+include "smthash_poseidon.circom";
+
+template SMTProcessor(nLevels) {
+ signal input oldRoot;
+ signal output newRoot;
+ signal input siblings[nLevels];
+ signal input oldKey;
+ signal input oldValue;
+ signal input isOld0;
+ signal input newKey;
+ signal input newValue;
+ signal input fnc[2];
+
+ signal enabled;
+
+ var i;
+
+ enabled <== fnc[0] + fnc[1] - fnc[0]*fnc[1];
+
+ component hash1Old = SMTHash1();
+ hash1Old.key <== oldKey;
+ hash1Old.value <== oldValue;
+
+ component hash1New = SMTHash1();
+ hash1New.key <== newKey;
+ hash1New.value <== newValue;
+
+ component n2bOld = Num2Bits_strict();
+ component n2bNew = Num2Bits_strict();
+
+ n2bOld.in <== oldKey;
+ n2bNew.in <== newKey;
+
+ component smtLevIns = SMTLevIns(nLevels);
+ for (i=0; i .
+*/
+
+/******
+
+SMTProcessorLevel
+
+This circuit has 2 hash
+
+Outputs according to the state.
+
+State oldRoot newRoot
+===== ======= =======
+top H'(oldChild, sibling) H'(newChild, sibling)
+old0 0 new1leaf
+bot old1leaf H'(newChild, 0)
+new1 old1leaf H'(new1leaf, old1leaf)
+na 0 0
+
+upd old1leaf new1leaf
+
+H' is the Hash function with the inputs shifted acordingly.
+
+*****/
+pragma circom 2.0.0;
+
+
+template SMTProcessorLevel() {
+ signal input st_top;
+ signal input st_old0;
+ signal input st_bot;
+ signal input st_new1;
+ signal input st_na;
+ signal input st_upd;
+
+ signal output oldRoot;
+ signal output newRoot;
+ signal input sibling;
+ signal input old1leaf;
+ signal input new1leaf;
+ signal input newlrbit;
+ signal input oldChild;
+ signal input newChild;
+
+ signal aux[4];
+
+ component oldProofHash = SMTHash2();
+ component newProofHash = SMTHash2();
+
+ component oldSwitcher = Switcher();
+ component newSwitcher = Switcher();
+
+ // Old side
+
+ oldSwitcher.L <== oldChild;
+ oldSwitcher.R <== sibling;
+
+ oldSwitcher.sel <== newlrbit;
+ oldProofHash.L <== oldSwitcher.outL;
+ oldProofHash.R <== oldSwitcher.outR;
+
+ aux[0] <== old1leaf * (st_bot + st_new1 + st_upd);
+ oldRoot <== aux[0] + oldProofHash.out * st_top;
+
+ // New side
+
+ aux[1] <== newChild * ( st_top + st_bot);
+ newSwitcher.L <== aux[1] + new1leaf*st_new1;
+
+ aux[2] <== sibling*st_top;
+ newSwitcher.R <== aux[2] + old1leaf*st_new1;
+
+ newSwitcher.sel <== newlrbit;
+ newProofHash.L <== newSwitcher.outL;
+ newProofHash.R <== newSwitcher.outR;
+
+ aux[3] <== newProofHash.out * (st_top + st_bot + st_new1);
+ newRoot <== aux[3] + new1leaf * (st_old0 + st_upd);
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtprocessorsm.circom b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtprocessorsm.circom
new file mode 100644
index 0000000..e40356f
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtprocessorsm.circom
@@ -0,0 +1,165 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/***************************************************************************************************
+Each level on a SMTProcessor has a state.
+
+The state of the level depends on the state of te botom level and on `xor` and
+`is0` signals.
+
+`isOldLev` 1 when is the level where oldLeaf is.
+
+`xor` signal is 0 if the index bit at the current level is the same in the old
+and the new index, and 1 if it is different.
+
+`is0` signal, is 1 if we are inserting/deleting in an empty leaf and 0 if we
+are inserting/deleting in a leaf that contains an element.
+
+The states are:
+
+top: While the index bits of the old and new insex in the top level is the same, whe are in the top state.
+old0: When the we reach insert level, we go to old0 state
+if `is0`=1.
+btn: Once in insert level and `is0` =0 we go to btn or new1 level if xor=1
+new1: This level is reached when xor=1. Here is where we insert/delete the hash of the
+old and the new trees with just one element.
+na: Not appliable. After processing it, we go to the na level.
+
+
+Fnction
+fnc[0] fnc[1]
+0 0 NOP
+0 1 UPDATE
+1 0 INSERT
+1 1 DELETE
+
+
+ ###########
+ # #
+ ┌────────────────────────────▶# upd #─────────────────────┐
+ │ ## ## │
+ │ ######### │
+ levIns=1 │ │
+ fnc[0]=0 │ │ any
+ │ │
+ │ │
+ │ │
+ │ ########### │
+ │ levIns=1 # # │
+ levIns=0 │ is0=1 ┌────────────▶# old0 #────────┐ │ any
+ ┌─────┐ │ fnc[0]=1│ ## ## │ │ ┌──────┐
+ │ │ │ │ ######### │ any │ │ │
+ │ ▼ │ │ │ ▼ ▼ │
+ │ ########### │ │ ########### │
+ │ # # ────────────┘ └────────▶# #│
+ └──# top # # na #
+ ## ## ───────────────────┐ levIns=1 ┌──▶## ##
+ ######### │ is0=0 │ #########
+ │ │ fnc[0]=1 │
+ │ │ xor=1 ########### │ any
+ │ └──────────────────▶# # │
+ │ # new1 #──┘
+ │ ## ##
+ └────────────────────────────────┐ #########
+ levIns=1 │ ▲
+ is0=0 │ ┌─────┘
+ fnc[0]=1 │ ###########│ xor=1
+ xor=0 │ # #
+ ▼# btn #
+ ## ##
+ #########◀───────┐
+ │ │
+ │ │
+ └────────────┘
+ xor=0
+
+***************************************************************************************************/
+pragma circom 2.0.0;
+
+template SMTProcessorSM() {
+ signal input xor;
+ signal input is0;
+ signal input levIns;
+ signal input fnc[2];
+
+ signal input prev_top;
+ signal input prev_old0;
+ signal input prev_bot;
+ signal input prev_new1;
+ signal input prev_na;
+ signal input prev_upd;
+
+ signal output st_top;
+ signal output st_old0;
+ signal output st_bot;
+ signal output st_new1;
+ signal output st_na;
+ signal output st_upd;
+
+ signal aux1;
+ signal aux2;
+
+ aux1 <== prev_top * levIns;
+ aux2 <== aux1*fnc[0]; // prev_top * levIns * fnc[0]
+
+ // st_top = prev_top*(1-levIns)
+ // = + prev_top
+ // - prev_top * levIns = aux1
+
+ st_top <== prev_top - aux1;
+
+ // st_old0 = prev_top * levIns * is0 * fnc[0]
+ // = + prev_top * levIns * is0 * fnc[0] = aux2 * is0
+
+ st_old0 <== aux2 * is0; // prev_top * levIns * is0 * fnc[0]
+
+ // st_new1 = prev_top * levIns * (1-is0)*fnc[0] * xor + prev_bot*xor =
+ // = + prev_top * levIns * fnc[0] * xor = aux2 * xor
+ // - prev_top * levIns * is0 * fnc[0] * xor = st_old0 * xor
+ // + prev_bot * xor = prev_bot * xor
+
+ st_new1 <== (aux2 - st_old0 + prev_bot)*xor;
+
+
+ // st_bot = prev_top * levIns * (1-is0)*fnc[0] * (1-xor) + prev_bot*(1-xor);
+ // = + prev_top * levIns * fnc[0]
+ // - prev_top * levIns * is0 * fnc[0]
+ // - prev_top * levIns * fnc[0] * xor
+ // + prev_top * levIns * is0 * fnc[0] * xor
+ // + prev_bot
+ // - prev_bot * xor
+
+ st_bot <== (1-xor) * (aux2 - st_old0 + prev_bot);
+
+
+ // st_upd = prev_top * (1-fnc[0]) *levIns;
+ // = + prev_top * levIns
+ // - prev_top * levIns * fnc[0]
+
+ st_upd <== aux1 - aux2;
+
+ // st_na = prev_new1 + prev_old0 + prev_na + prev_upd;
+ // = + prev_new1
+ // + prev_old0
+ // + prev_na
+ // + prev_upd
+
+ st_na <== prev_new1 + prev_old0 + prev_na + prev_upd;
+
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtverifier.circom b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtverifier.circom
new file mode 100644
index 0000000..152eba3
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtverifier.circom
@@ -0,0 +1,138 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+
+SMTVerifier is a component to verify inclusion/exclusion of an element in the tree
+
+
+fnc: 0 -> VERIFY INCLUSION
+ 1 -> VERIFY NOT INCLUSION
+
+ */
+ pragma circom 2.0.0;
+
+
+include "../gates.circom";
+include "../bitify.circom";
+include "../comparators.circom";
+include "../switcher.circom";
+include "smtlevins.circom";
+include "smtverifierlevel.circom";
+include "smtverifiersm.circom";
+include "smthash_poseidon.circom";
+
+template SMTVerifier(nLevels) {
+ signal input enabled;
+ signal input root;
+ signal input siblings[nLevels];
+ signal input oldKey;
+ signal input oldValue;
+ signal input isOld0;
+ signal input key;
+ signal input value;
+ signal input fnc;
+
+ var i;
+
+ component hash1Old = SMTHash1();
+ hash1Old.key <== oldKey;
+ hash1Old.value <== oldValue;
+
+ component hash1New = SMTHash1();
+ hash1New.key <== key;
+ hash1New.value <== value;
+
+ component n2bOld = Num2Bits_strict();
+ component n2bNew = Num2Bits_strict();
+
+ n2bOld.in <== oldKey;
+ n2bNew.in <== key;
+
+ component smtLevIns = SMTLevIns(nLevels);
+ for (i=0; i .
+*/
+
+/******
+
+SMTVerifierLevel
+
+This circuit has 1 hash
+
+Outputs according to the state.
+
+State root
+===== =======
+top H'(child, sibling)
+i0 0
+iold old1leaf
+inew new1leaf
+na 0
+
+H' is the Hash function with the inputs shifted acordingly.
+
+*****/
+pragma circom 2.0.0;
+
+template SMTVerifierLevel() {
+ signal input st_top;
+ signal input st_i0;
+ signal input st_iold;
+ signal input st_inew;
+ signal input st_na;
+
+ signal output root;
+ signal input sibling;
+ signal input old1leaf;
+ signal input new1leaf;
+ signal input lrbit;
+ signal input child;
+
+ signal aux[2];
+
+ component proofHash = SMTHash2();
+ component switcher = Switcher();
+
+ switcher.L <== child;
+ switcher.R <== sibling;
+
+ switcher.sel <== lrbit;
+ proofHash.L <== switcher.outL;
+ proofHash.R <== switcher.outR;
+
+ aux[0] <== proofHash.out * st_top;
+ aux[1] <== old1leaf*st_iold;
+
+ root <== aux[0] + aux[1] + new1leaf*st_inew;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtverifiersm.circom b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtverifiersm.circom
new file mode 100644
index 0000000..63d2c41
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/smt/smtverifiersm.circom
@@ -0,0 +1,106 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+Each level in the SMTVerifier has a state.
+
+This is the state machine.
+
+The signals are
+
+levIns: 1 if we are in the level where the insertion should happen
+xor: 1 if the bitKey of the old and new keys are different in this level
+is0: Input that indicates that the oldKey is 0
+fnc: 0 -> VERIFY INCLUSION
+ 1 -> VERIFY NOT INCLUSION
+
+err state is not a state itself. It's a lack of state.
+
+The end of the last level will have to be `na`
+
+ levIns=0 any
+ ┌────┐ ┌────┐
+ │ │ │ │
+ │ ▼ levIns=1 ▼ │
+ │ ########### is0=1 ########### ########### │
+ │ # # fnc=1 # # any # # │
+ └──# top # ─────────────────────▶# i0 #───────────────▶# na #──┘
+ ## ## ──────────┐ ## ## ┌───────▶## ##
+ ########─────────────┐│ ######### │┌────────▶#########
+ ││ levIns=1 ││
+ ││ is0=0 ########### ││
+ ││ fnc=1 # # any│
+ │└──────────▶ # iold #────────┘│
+ │ ## ## │
+ │ ######### │
+ │ │
+ │ levIns=1 ########### │
+ │ fnc=0 # # any
+ └────────────▶# inew #─────────┘
+ ## ##
+ #########
+
+ */
+ pragma circom 2.0.0;
+
+
+template SMTVerifierSM() {
+ signal input is0;
+ signal input levIns;
+ signal input fnc;
+
+ signal input prev_top;
+ signal input prev_i0;
+ signal input prev_iold;
+ signal input prev_inew;
+ signal input prev_na;
+
+ signal output st_top;
+ signal output st_i0;
+ signal output st_iold;
+ signal output st_inew;
+ signal output st_na;
+
+ signal prev_top_lev_ins;
+ signal prev_top_lev_ins_fnc;
+
+ prev_top_lev_ins <== prev_top * levIns;
+ prev_top_lev_ins_fnc <== prev_top_lev_ins*fnc; // prev_top * levIns * fnc
+
+ // st_top = prev_top * (1-levIns)
+ // = + prev_top
+ // - prev_top * levIns
+ st_top <== prev_top - prev_top_lev_ins;
+
+ // st_inew = prev_top * levIns * (1-fnc)
+ // = + prev_top * levIns
+ // - prev_top * levIns * fnc
+ st_inew <== prev_top_lev_ins - prev_top_lev_ins_fnc;
+
+ // st_iold = prev_top * levIns * (1-is0)*fnc
+ // = + prev_top * levIns * fnc
+ // - prev_top * levIns * fnc * is0
+ st_iold <== prev_top_lev_ins_fnc * (1 - is0);
+
+ // st_i0 = prev_top * levIns * is0
+ // = + prev_top * levIns * is0
+ st_i0 <== prev_top_lev_ins * is0;
+
+ st_na <== prev_na + prev_inew + prev_iold + prev_i0;
+}
diff --git a/benchmarks/libs/pre-circomlib-cff5ab6/switcher.circom b/benchmarks/libs/pre-circomlib-cff5ab6/switcher.circom
new file mode 100644
index 0000000..e2e19a6
--- /dev/null
+++ b/benchmarks/libs/pre-circomlib-cff5ab6/switcher.circom
@@ -0,0 +1,42 @@
+/*
+ Copyright 2018 0KIMS association.
+
+ This file is part of circom (Zero Knowledge Circuit Compiler).
+
+ circom is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ circom is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with circom. If not, see .
+*/
+
+/*
+ Assume sel is binary.
+
+ If sel == 0 then outL = L and outR=R
+ If sel == 1 then outL = R and outR=L
+
+ */
+
+pragma circom 2.0.0;
+
+template Switcher() {
+ signal input sel;
+ signal input L;
+ signal input R;
+ signal output outL;
+ signal output outR;
+
+ signal aux;
+
+ aux <== (R-L)*sel; // We create aux in order to have only one multiplication
+ outL <== aux + L;
+ outR <== -aux + R;
+}
diff --git a/benchmarks/motivating/VDBuggy.circom b/benchmarks/motivating/VDBuggy.circom
new file mode 100644
index 0000000..468d4b9
--- /dev/null
+++ b/benchmarks/motivating/VDBuggy.circom
@@ -0,0 +1,39 @@
+pragma circom 2.0.0;
+include "../libs/circomlib-cff5ab6/gates.circom";
+include "../libs/circomlib-cff5ab6/comparators.circom";
+
+template Decoder(w) {
+ signal input inp;
+ signal output out[w];
+ signal output success;
+ var lc=0;
+
+ for (var i=0; i success;
+ success * (success -1) === 0;
+}
+
+template ValidateDecoding(w) {
+ signal input x;
+ signal input arr[w];
+ signal output success;
+
+ component multiAnd = MultiAND(w);
+ component decoder = Decoder(w);
+ component checkEq[w];
+ decoder.inp <== x;
+ for (var i=0; i out[i];
+ lc = lc + out[i];
+ }
+ lc ==> success;
+}
+
+template ValidateDecoding(w) {
+ signal input x;
+ signal input arr[w];
+ signal output success;
+
+ component multiAnd = MultiAND(w);
+ component decoder = Decoder(w);
+ component checkEq[w];
+ decoder.inp <== x;
+ for (var i=0; inumber p-timeout))
+ ]
+ [("--solver") p-solver "solver to use: z3 | cvc4 | cvc5 (default: z3)"
+ (cond
+ [(set-member? (set "z3" "cvc5" "cvc4") p-solver) (set! arg-solver p-solver)]
+ [else (tokamak:exit "solver needs to be either z3 or cvc5")]
+ )
+ ]
+ [("--selector") p-selector "selector to use: first | counter (default: counter)"
+ (set! arg-selector p-selector)
+ ]
+ [("--precondition") p-precondition "path to precondition json (default: null)"
+ (set! arg-precondition p-precondition)
+ ]
+ [("--noprop") "disable propagation (default: false / propagation on)"
+ (set! arg-prop #f)
+ ]
+ [("--smt") "show path to generated smt files (default: false)"
+ (set! arg-smt #t)
+ ]
+ [("--weak") "only check weak safety, not strong safety (default: false)"
+ (set! arg-weak #t)
+ ]
+)
+(printf "# r1cs file: ~a\n" arg-r1cs)
+(printf "# timeout: ~a\n" arg-timeout)
+(printf "# solver: ~a\n" arg-solver)
+(printf "# selector: ~a\n" arg-selector)
+(printf "# precondition: ~a\n" arg-precondition)
+(printf "# propagation: ~a\n" arg-prop)
+(printf "# smt: ~a\n" arg-smt)
+(printf "# weak: ~a\n" arg-weak)
+
+; =================================================
+; ======== resolve solver specific methods ========
+; =================================================
+(define state-smt-path (solver:state-smt-path arg-solver))
+(define solve (solver:solve arg-solver))
+(define parse-r1cs (solver:parse-r1cs arg-solver))
+(define expand-r1cs (solver:expand-r1cs arg-solver))
+(define normalize-r1cs (solver:normalize-r1cs arg-solver))
+(define optimize-r1cs-p0 (solver:optimize-r1cs-p0 arg-solver))
+(define optimize-r1cs-p1 (solver:optimize-r1cs-p1 arg-solver))
+(define interpret-r1cs (solver:interpret-r1cs arg-solver))
+
+; ==================================
+; ======== main preparation ========
+; ==================================
+(define r0 (r1cs:read-r1cs arg-r1cs))
+(define nwires (r1cs:get-nwires r0))
+(define mconstraints (r1cs:get-mconstraints r0))
+(printf "# number of wires: ~a\n" nwires)
+(printf "# number of constraints: ~a\n" mconstraints)
+(printf "# field size (how many bytes): ~a\n" (r1cs:get-field-size r0))
+
+; categorize signals
+(define input-list (r1cs:r1cs-inputs r0))
+(define input-set (list->set input-list))
+(define output-list (r1cs:r1cs-outputs r0))
+(define output-set (list->set output-list))
+(define target-set (if arg-weak (list->set output-list) (list->set (range nwires))))
+(printf "# inputs: ~a.\n" input-list)
+(printf "# outputs: ~a.\n" output-list)
+(printf "# targets: ~a.\n" target-set)
+
+; parse original r1cs
+(printf "# parsing original r1cs...\n")
+(define-values (xlist opts defs cnsts) (parse-r1cs r0 null)) ; interpret the constraint system
+(printf "# xlist: ~a.\n" xlist)
+; parse alternative r1cs
+(define alt-xlist (for/list ([i (range nwires)])
+ (if (not (utils:contains? input-list i))
+ (format "y~a" i)
+ (list-ref xlist i)
+ )
+))
+(printf "# alt-xlist ~a.\n" alt-xlist)
+(printf "# parsing alternative r1cs...\n")
+(define-values (_ __ alt-defs alt-cnsts) (parse-r1cs r0 alt-xlist))
+
+(printf "# configuring precondition...\n")
+(define-values (unique-set precondition) (if (null? arg-precondition)
+ (values (list->set (list)) null)
+ ; read!
+ (pre:read-precondition arg-precondition)
+))
+(printf "# unique: ~a.\n" unique-set)
+
+; ============================
+; ======== main solve ========
+; ============================
+; a full picus constraint pass is:
+; raw
+; | parse-r1cs
+; v
+; cnsts
+; | optimize-r1cs-p0
+; v
+; p0cnsts
+; | expand-r1cs
+; v
+; expcnsts
+; | normalize-r1cs
+; v
+; nrmcnsts
+; | optimize-r1cs-p1
+; v
+; p1cnsts
+; | (downstream queries)
+; ...
+(define path-sym (string-replace arg-r1cs ".r1cs" ".sym"))
+(define-values (res res-ks res-us res-info) (cex:apply-algorithm
+ r0 nwires mconstraints
+ input-set output-set target-set
+ xlist opts defs cnsts
+ alt-xlist alt-defs alt-cnsts
+ unique-set precondition ; prior knowledge row
+ arg-selector arg-prop arg-timeout arg-smt path-sym
+ solve state-smt-path interpret-r1cs
+ parse-r1cs optimize-r1cs-p0 expand-r1cs normalize-r1cs optimize-r1cs-p1
+))
+(printf "# final unknown set ~a.\n" res-us)
+(if arg-weak
+ (printf "# weak uniqueness: ~a.\n" res)
+ (printf "# strong uniqueness: ~a.\n" res)
+)
+(when (equal? 'unsafe res)
+ (printf "# counter-example:\n ~a.\n" res-info))
\ No newline at end of file
diff --git a/picus-compile.sh b/picus-compile.sh
new file mode 100755
index 0000000..a1e4e67
--- /dev/null
+++ b/picus-compile.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# usage:
+# picus-compile.sh
+
+fp=$1
+fd="$(dirname "${fp}")"
+fn="$(basename "${fp}")"
+bn="${fn%.*}"
+
+# echo "# preparing: ${fp}"
+circom -o ${fd} ${fp} --r1cs --sym --O0 > /dev/null 2>&1
diff --git a/picus-dpvl-uniqueness.rkt b/picus-dpvl-uniqueness.rkt
new file mode 100644
index 0000000..fc4f6b8
--- /dev/null
+++ b/picus-dpvl-uniqueness.rkt
@@ -0,0 +1,173 @@
+#lang racket
+; common require
+(require json racket/engine
+ (prefix-in tokamak: "./picus/tokamak.rkt")
+ (prefix-in utils: "./picus/utils.rkt")
+ (prefix-in config: "./picus/config.rkt")
+ (prefix-in solver: "./picus/solver.rkt")
+ (prefix-in r1cs: "./picus/r1cs/r1cs-grammar.rkt")
+ (prefix-in dpvl: "./picus/algorithms/dpvl.rkt")
+ (prefix-in pre: "./picus/precondition.rkt")
+)
+
+; =====================================
+; ======== commandline parsing ========
+; =====================================
+; parse command line arguments
+(define arg-r1cs null)
+(define arg-timeout 5000)
+(define arg-solver "z3")
+(define arg-selector "counter")
+(define arg-precondition null)
+(define arg-prop #t)
+(define arg-slv #t)
+(define arg-smt #f)
+(define arg-weak #f)
+(define arg-map #f)
+(command-line
+ #:once-each
+ [("--r1cs") p-r1cs "path to target r1cs"
+ (begin
+ (set! arg-r1cs p-r1cs)
+ (when (not (string-suffix? arg-r1cs ".r1cs"))
+ (tokamak:exit "file needs to be *.r1cs")
+ )
+ )
+ ]
+ [("--timeout") p-timeout "timeout for every small query (default: 5000ms)"
+ (set! arg-timeout (string->number p-timeout))
+ ]
+ [("--solver") p-solver "solver to use: z3 | cvc4 | cvc5 (default: z3)"
+ (cond
+ [(set-member? (set "z3" "cvc5" "cvc4") p-solver) (set! arg-solver p-solver)]
+ [else (tokamak:exit "solver needs to be either z3 or cvc5")]
+ )
+ ]
+ [("--selector") p-selector "selector to use: first | counter (default: counter)"
+ (set! arg-selector p-selector)
+ ]
+ [("--precondition") p-precondition "path to precondition json (default: null)"
+ (set! arg-precondition p-precondition)
+ ]
+ [("--noprop") "disable propagation (default: false / propagation on)"
+ (set! arg-prop #f)
+ ]
+ [("--nosolve") "disable solver phase (default: false / solver on)"
+ (set! arg-slv #f)
+ ]
+ [("--smt") "show path to generated smt files (default: false)"
+ (set! arg-smt #t)
+ ]
+ [("--weak") "only check weak safety, not strong safety (default: false)"
+ (set! arg-weak #t)
+ ]
+ [("--map") "map the r1cs signals of model to its circom variable (default: true)"
+ (set! arg-map #t)
+ ]
+)
+(printf "# r1cs file: ~a\n" arg-r1cs)
+(printf "# timeout: ~a\n" arg-timeout)
+(printf "# solver: ~a\n" arg-solver)
+(printf "# selector: ~a\n" arg-selector)
+(printf "# precondition: ~a\n" arg-precondition)
+(printf "# propagation on: ~a\n" arg-prop)
+(printf "# solver on: ~a\n" arg-slv)
+(printf "# smt: ~a\n" arg-smt)
+(printf "# weak: ~a\n" arg-weak)
+(printf "# map: ~a\n" arg-map)
+
+; =================================================
+; ======== resolve solver specific methods ========
+; =================================================
+(define state-smt-path (solver:state-smt-path arg-solver))
+(define solve (solver:solve arg-solver))
+(define parse-r1cs (solver:parse-r1cs arg-solver))
+(define expand-r1cs (solver:expand-r1cs arg-solver))
+(define normalize-r1cs (solver:normalize-r1cs arg-solver))
+(define optimize-r1cs-p0 (solver:optimize-r1cs-p0 arg-solver))
+(define optimize-r1cs-p1 (solver:optimize-r1cs-p1 arg-solver))
+(define interpret-r1cs (solver:interpret-r1cs arg-solver))
+
+; ==================================
+; ======== main preparation ========
+; ==================================
+(define r0 (r1cs:read-r1cs arg-r1cs))
+(define nwires (r1cs:get-nwires r0))
+(define mconstraints (r1cs:get-mconstraints r0))
+(printf "# number of wires: ~a\n" nwires)
+(printf "# number of constraints: ~a\n" mconstraints)
+(printf "# field size (how many bytes): ~a\n" (r1cs:get-field-size r0))
+
+; categorize signals
+(define input-list (r1cs:r1cs-inputs r0))
+(define input-set (list->set input-list))
+(define output-list (r1cs:r1cs-outputs r0))
+(define output-set (list->set output-list))
+(define target-set (if arg-weak (list->set output-list) (list->set (range nwires))))
+(printf "# inputs: ~a.\n" input-list)
+(printf "# outputs: ~a.\n" output-list)
+(printf "# targets: ~a.\n" target-set)
+
+; parse original r1cs
+(printf "# parsing original r1cs...\n")
+(define-values (xlist opts defs cnsts) (parse-r1cs r0 null)) ; interpret the constraint system
+(printf "# xlist: ~a.\n" xlist)
+; parse alternative r1cs
+(define alt-xlist (for/list ([i (range nwires)])
+ (if (not (utils:contains? input-list i))
+ (format "y~a" i)
+ (list-ref xlist i)
+ )
+))
+(printf "# alt-xlist ~a.\n" alt-xlist)
+(printf "# parsing alternative r1cs...\n")
+(define-values (_ __ alt-defs alt-cnsts) (parse-r1cs r0 alt-xlist))
+
+(printf "# configuring precondition...\n")
+(define-values (unique-set precondition) (if (null? arg-precondition)
+ (values (list->set (list)) null)
+ ; read!
+ (pre:read-precondition arg-precondition)
+))
+(printf "# unique: ~a.\n" unique-set)
+
+; ============================
+; ======== main solve ========
+; ============================
+; a full picus constraint pass is:
+; raw
+; | parse-r1cs
+; v
+; cnsts
+; | optimize-r1cs-p0
+; v
+; p0cnsts
+; | expand-r1cs
+; v
+; expcnsts
+; | normalize-r1cs
+; v
+; nrmcnsts
+; | optimize-r1cs-p1
+; v
+; p1cnsts
+; | (downstream queries)
+; ...
+(define path-sym (string-replace arg-r1cs ".r1cs" ".sym"))
+(define-values (res res-ks res-us res-info) (dpvl:apply-algorithm
+ r0 nwires mconstraints
+ input-set output-set target-set
+ xlist opts defs cnsts
+ alt-xlist alt-defs alt-cnsts
+ unique-set precondition ; prior knowledge row
+ arg-selector arg-prop arg-slv arg-timeout arg-smt arg-map path-sym
+ solve state-smt-path interpret-r1cs
+ parse-r1cs optimize-r1cs-p0 expand-r1cs normalize-r1cs optimize-r1cs-p1
+))
+(printf "# final unknown set ~a.\n" res-us)
+(if arg-weak
+ (printf "# weak uniqueness: ~a.\n" res)
+ (printf "# strong uniqueness: ~a.\n" res)
+)
+(when (equal? 'unsafe res)
+ (printf "# counter-example:\n ~a.\n" res-info))
\ No newline at end of file
diff --git a/test-read-r1cs.rkt b/picus-read-r1cs.rkt
similarity index 94%
rename from test-read-r1cs.rkt
rename to picus-read-r1cs.rkt
index ad17c61..647ce5d 100644
--- a/test-read-r1cs.rkt
+++ b/picus-read-r1cs.rkt
@@ -2,7 +2,7 @@
(require
(prefix-in tokamak: "./picus/tokamak.rkt")
(prefix-in utils: "./picus/utils.rkt")
- (prefix-in r1cs: "./picus/r1cs-grammar.rkt")
+ (prefix-in r1cs: "./picus/r1cs/r1cs-grammar.rkt")
)
; parse command line arguments
diff --git a/picus-solve.sh b/picus-solve.sh
new file mode 100755
index 0000000..fca2e56
--- /dev/null
+++ b/picus-solve.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# usage:
+# picus-solve.sh
+
+fp=$1
+fd="$(dirname "${fp}")"
+fn="$(basename "${fp}")"
+bn="${fn%.*}"
+
+otime=600
+solver=cvc5
+
+echo "# solving: ${fp}"
+timeout ${otime} racket ./picus-dpvl-uniqueness.rkt --timeout 5000 --solver ${solver} --weak --r1cs ${fp} --map
\ No newline at end of file
diff --git a/picus/algorithms/cex.rkt b/picus/algorithms/cex.rkt
new file mode 100644
index 0000000..27e45e2
--- /dev/null
+++ b/picus/algorithms/cex.rkt
@@ -0,0 +1,143 @@
+#lang racket
+; this implements the decide & propagate verification loop algorithm
+(require graph
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
+ (prefix-in cg: "./constraint-graph.rkt")
+ (prefix-in dpvl: "./dpvl.rkt")
+)
+(provide (rename-out
+ [apply-algorithm apply-algorithm]
+))
+
+; convert a (partial) model to r1cs constraints (assignment assertions)
+(define (model2cnsts arg-model)
+ ; direct return
+ (r1cs:rcmds (for/list ([key (hash-keys arg-model)])
+ (r1cs:rassert (r1cs:req
+ (r1cs:rvar key)
+ (r1cs:rint (hash-ref arg-model key))
+ ))
+ ))
+)
+
+(define (apply-algorithm
+ r0 nwires mconstraints
+ input-set output-set target-set
+ xlist opts defs cnsts
+ alt-xlist alt-defs alt-cnsts
+ unique-set precondition
+ arg-selector arg-prop arg-timeout arg-smt path-sym
+ solve state-smt-path interpret-r1cs
+ parse-r1cs optimize-r1cs-p0 expand-r1cs normalize-r1cs optimize-r1cs-p1
+ )
+
+ (define cg0 (cg:compute-constraint-graph r0 cnsts path-sym))
+ (define g0 (cg:cgraph-g cg0))
+ (define edge2cid (cg:cgraph-e2c cg0))
+ (define sid2order (cg:cgraph-s2o cg0))
+ (define sid2scope (cg:cgraph-s2s cg0))
+ (define order2scope (cg:cgraph-o2s cg0))
+ (define norders (vector-length order2scope))
+
+ (define partial-model (make-hash))
+
+ (when (not (equal? (set "main") (vector-ref order2scope (- norders 1))))
+ (tokamak:exit "tha last scope is not main"))
+
+ ; exclude the main scope in iteration
+ (for ([i (range (- norders 1))])
+ (define iscope (vector-ref order2scope i)) ; current scope
+ (define nscope (vector-ref order2scope (+ 1 i))) ; next scope, last scope is natually main
+ (printf "===========================================\n")
+ (printf "# i=~a, scope=~a\n" i iscope)
+ (printf "===========================================\n")
+ ; get connecting pairs
+ (define icps (cg:get-connecting-pairs cg0 iscope))
+ ; extract connected signals (outside scope) from connecting pairs
+ (define icsigs (list->set (for/list ([p icps]) (cdr p))))
+ ; extract subgraph with extra connected signals
+ (define isubcg (cg:get-scoped-subgraph cg0 iscope icsigs))
+ (define isubg0 (cg:cgraph-g isubcg))
+ ; (printf "# subgraph:\n~a\n" (graphviz isubg0))
+
+ ; decide local targets (main targets + signals connecting to next scope)
+ ; which is also local target signals
+ ; (fixme) probably need to check whether signal is already in partial model
+ (define global-tsigs (list->set (filter
+ (lambda (x) (and
+ (equal? (set "main") (vector-ref sid2scope x)))
+ (set-member? target-set x)
+ )
+ (set->list icsigs)
+ )))
+ (printf "# global-tsigs ~a\n" global-tsigs)
+ (define local-tsigs (list->set (filter
+ (lambda (x) (equal? nscope (vector-ref sid2scope x)))
+ (set->list icsigs)
+ )))
+ (printf "# local-tsigs ~a\n" local-tsigs)
+ (define query-tsigs (if (set-empty? global-tsigs)
+ ; no global target signals connected to this scope, use local one
+ local-tsigs
+ ; there's global target signals, use global
+ ; (fixme) this is not entirely correct
+ global-tsigs
+ ))
+ (printf "# init query-tsigs ~a\n" query-tsigs)
+ ; removed query signals that are already in the partial model
+ (set! query-tsigs (list->set (filter
+ (lambda (x) (not (hash-has-key? partial-model (format "x~a" x))))
+ (set->list query-tsigs)
+ )))
+ (printf "# refined query-tsigs ~a\n" query-tsigs)
+ ; all signals in the subgraph
+ (define local-sigs (list->set (get-vertices isubg0)))
+ (printf "# local-sigs ~a\n" local-sigs)
+ ; all constraint ids in the subgraph
+ (define local-cids (sort (remove-duplicates (flatten (for/list ([e (get-edges isubg0)])
+ (set->list (hash-ref edge2cid (list->set e)))
+ ))) <))
+ (printf "# local-cids ~a\n" local-cids)
+
+ (define icnsts (r1cs:rcmds (for/list ([cid local-cids]) (r1cs:rcmds-ref cnsts cid))))
+ (define ialt-cnsts (r1cs:rcmds (for/list ([cid local-cids]) (r1cs:rcmds-ref alt-cnsts cid))))
+
+ (printf "# start solving...\n")
+ (define-values (res res-ks res-us res-info) (dpvl:apply-algorithm
+ r0 nwires mconstraints
+ input-set output-set query-tsigs
+ xlist opts defs icnsts
+ alt-xlist alt-defs ialt-cnsts
+ unique-set precondition ; prior knowledge row
+ arg-selector arg-prop #t arg-timeout arg-smt #f path-sym
+ solve state-smt-path interpret-r1cs
+ parse-r1cs optimize-r1cs-p0 expand-r1cs normalize-r1cs optimize-r1cs-p1
+ #:extcnsts (model2cnsts partial-model)
+ #:skip-query? (equal? i 2) ; (debug)
+ ))
+
+ ; no counter-example can be found within time limit, exit directly
+ (when (not (equal? 'unsafe res))
+ (tokamak:exit "# query returns: ~a, cannot continue counter-example generation" res))
+
+ ; there's a counter-example, store partial model
+ (define str-ids (remove-duplicates (append
+ (for/list ([sid local-sigs]) (list-ref xlist sid))
+ (for/list ([sid local-sigs]) (list-ref alt-xlist sid))
+ )))
+ (printf "# str-ids: ~a\n" str-ids)
+ (for ([sid str-ids])
+ (hash-set! partial-model sid (hash-ref res-info sid))
+ )
+
+ (printf "# end solving.\n")
+ ; (todo) if success, need to update exclude-scopes
+ )
+
+ ; return
+ (values 'unsafe null null partial-model)
+
+)
\ No newline at end of file
diff --git a/picus/algorithms/cex0.rkt b/picus/algorithms/cex0.rkt
new file mode 100644
index 0000000..96b1abe
--- /dev/null
+++ b/picus/algorithms/cex0.rkt
@@ -0,0 +1,114 @@
+#lang racket
+; this implements the decide & propagate verification loop algorithm
+(require graph
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
+ (prefix-in cg: "./constraint-graph.rkt")
+ (prefix-in dpvl: "./dpvl.rkt")
+)
+(provide (rename-out
+ [apply-algorithm apply-algorithm]
+))
+
+; convert a (partial) model to r1cs constraints (assignment assertions)
+(define (model2cnsts arg-model)
+ ; direct return
+ (r1cs:rcmds (for/list ([key (hash-keys arg-model)])
+ (r1cs:rassert (r1cs:req
+ (r1cs:rvar key)
+ (r1cs:rint (hash-ref arg-model key))
+ ))
+ ))
+)
+
+(define (apply-algorithm
+ r0 nwires mconstraints
+ input-set output-set target-set
+ xlist opts defs cnsts
+ alt-xlist alt-defs alt-cnsts
+ unique-set precondition
+ arg-selector arg-prop arg-timeout arg-smt path-sym
+ solve state-smt-path interpret-r1cs
+ parse-r1cs optimize-r1cs-p0 expand-r1cs normalize-r1cs optimize-r1cs-p1
+ )
+
+ (define cg0 (cg:compute-constraint-graph r0 cnsts path-sym))
+ (define g0 (cg:cgraph-g cg0))
+ (define edge2cid (cg:cgraph-e2c cg0))
+ (define sid2order (cg:cgraph-s2o cg0))
+ (define sid2scope (cg:cgraph-s2s cg0))
+ (define order2scope (cg:cgraph-o2s cg0))
+
+ (define n-orders (vector-length order2scope))
+ ; (printf "# order2scope: ~a\n" order2scope)
+ ; extra set to consider when extracting subgraph
+ (define extra-set (set-union input-set output-set))
+ (define exclude-scopes (set (set "main"))) ; starts with main scope
+ (define partial-model (make-hash))
+
+ (when (not (equal? (set "main") (vector-ref order2scope (- n-orders 1))))
+ (tokamak:exit "tha last scope is not main"))
+
+ (for ([i (range (- n-orders 1))])
+ (define i-scope (vector-ref order2scope i))
+ (printf "===========================================\n")
+ (printf "# i=~a, scope=~a\n" i i-scope)
+ (printf "===========================================\n")
+ (define i-subcg (cg:get-scoped-subgraph cg0 i-scope extra-set #:touching? #t))
+ (define i-subg0 (cg:cgraph-g i-subcg))
+ ; (printf "# subgraph:\n~a\n" (graphviz (cg:cgraph-g i-subcg)))
+ ; construct new scoped arguments
+ ; (fixme) for now, we only get a subset of the following and do not change others:
+ ; - target-set
+ ; - cnsts
+ ; - alt-cnsts
+
+ ; all signal ids in the current subgraph
+ (define i-sids (list->set (get-vertices i-subg0)))
+ ; extract local output signals (signals that connect to other scopes)
+ (define lo-sids (cg:get-connecting-signals cg0 i-scope #:exclude-scopes exclude-scopes))
+ ; (printf "# i-sids: ~a\n" i-sids)
+ (define i-target-set (set-union lo-sids (set-intersect target-set i-sids)))
+ (printf "# i-target-set: ~a\n" i-target-set)
+ (define i-cids (sort (remove-duplicates (flatten (for/list ([e (get-edges i-subg0)])
+ (set->list (hash-ref edge2cid (list->set e)))
+ ))) <))
+ (define i-cnsts (r1cs:rcmds (for/list ([cid i-cids]) (r1cs:rcmds-ref cnsts cid))))
+ (define i-alt-cnsts (r1cs:rcmds (for/list ([cid i-cids]) (r1cs:rcmds-ref alt-cnsts cid))))
+ (printf "# i-cids: ~a\n" i-cids)
+
+ (printf "# start solving...\n")
+ (define-values (res res-ks res-us res-info) (dpvl:apply-algorithm
+ r0 nwires mconstraints
+ input-set output-set i-target-set
+ xlist opts defs i-cnsts
+ alt-xlist alt-defs i-alt-cnsts
+ unique-set precondition ; prior knowledge row
+ arg-selector arg-prop arg-timeout arg-smt path-sym
+ solve state-smt-path interpret-r1cs
+ parse-r1cs optimize-r1cs-p0 expand-r1cs normalize-r1cs optimize-r1cs-p1
+ #:extcnsts (model2cnsts partial-model)
+ ))
+
+ ; no counter-example can be found within time limit, exit directly
+ (when (not (equal? 'unsafe res))
+ (tokamak:exit "# query returns: ~a, cannot continue counter-example generation" res))
+
+ ; there's a counter-example, store partial model
+ (define str-ids (remove-duplicates (append
+ (for/list ([sid i-sids]) (list-ref xlist sid))
+ (for/list ([sid i-sids]) (list-ref alt-xlist sid))
+ )))
+ (printf "# str-ids: ~a\n" str-ids)
+ (for ([sid str-ids])
+ (hash-set! partial-model sid (hash-ref res-info sid))
+ )
+
+ (printf "# end solving.\n")
+
+ ; (todo) if success, need to update exclude-scopes
+ )
+
+)
\ No newline at end of file
diff --git a/picus/algorithms/clara-nb.rkt b/picus/algorithms/clara-nb.rkt
deleted file mode 100644
index 1f0ccab..0000000
--- a/picus/algorithms/clara-nb.rkt
+++ /dev/null
@@ -1,777 +0,0 @@
-#lang rosette
-; this implements the propagation & preserving algorithm with base lemma
-(require
- (prefix-in tokamak: "../tokamak.rkt")
- (prefix-in utils: "../utils.rkt")
- (prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
-)
-(provide (rename-out
- [apply-nb apply-nb]
-))
-
-(define (is-rint-zero x)
- (if (r1cs:rint? x)
- (if (= 0 (r1cs:rint-v x))
- #t
- #f
- )
- #f
- )
-)
-
-(define (is-rint-one x)
- (if (r1cs:rint? x)
- (if (= 1 (r1cs:rint-v x))
- #t
- #f
- )
- #f
- )
-)
-
-(define (contains-rint-zero l)
- (if (null? l)
- #f
- (let ([x (car l)])
- (if (r1cs:rint? x)
- (if (= 0 (r1cs:rint-v x))
- #t
- (contains-rint-zero (cdr l))
- )
- (contains-rint-zero (cdr l))
- )
- )
- )
-)
-
-(define (get-single-coefficient v)
- (match v
- [(r1cs:rint v) (list v "x0")]
- [(r1cs:rvar v) (list 1 v)]
- [(r1cs:rmul vs)
- (define l1 (get-single-coefficient (car vs)))
- (define l2 (get-single-coefficient (car (cdr vs))))
- (list (* (list-ref l1 0) (list-ref l2 0)) (list-ref l2 1))
- ]
- [else (tokamak:exit "not supported for single coefficient ~a" v)]
- )
-)
-
-(define (get-list-coefficients vs)
- (for/list ([v vs])
- (get-single-coefficient v)
- )
-)
-
-(define (check-base base sorted_coefs)
- (if (= (length sorted_coefs) 1)
- #t
- (if (= (modulo (* base (car sorted_coefs)) config:p) (car (cdr sorted_coefs)))
- (check-base base (cdr sorted_coefs))
- #f
- )
- )
-)
-
-(define (is-base-representation coefs-vars)
- (define sorted-coefs-vars (sort coefs-vars (lambda (x y) (< (list-ref x 0) (list-ref y 0)))))
-
- (define sorted-coefs
- (for/list ([v sorted-coefs-vars])
- (list-ref v 0)
- )
- )
-
- (define sorted-vars
- (for/list ([v sorted-coefs-vars])
- (string->number (substring (list-ref v 1) 1))
- )
- )
-
- (define pot_base (/ (car (cdr sorted-coefs)) (car sorted-coefs)))
- (if (> pot_base 1)
- (if (utils:contains? sorted-vars 0)
- (values #f 1 '())
- (values (check-base pot_base (cdr sorted-coefs)) pot_base sorted-vars)
- )
- (values #f 1 '())
- )
-)
-
-(define (get-potential-inits vs)
- (filter
- (lambda (v) (and
- (= 2 (length v))
- (or (= 1 (list-ref v 0)) (= (- config:p 1) (list-ref v 0))))
- )
- vs
- )
-)
-
-(define (generate-base-constraints vs)
- (define coefs (get-list-coefficients vs))
- (define potential-inits (get-potential-inits coefs))
- (define new-cnst '())
- (for ([init potential-inits])
- (define pos-coefs
- (filter
- (lambda (x) (not (string=? (car (cdr x)) (car (cdr init)))))
- (for/list ([elem coefs])
- (list
- (if (= (car init) 1)
- (- config:p (car elem))
- (car elem)
- )
- (car (cdr elem))
- )
- )
- )
- )
- (define-values (is-base base vars) (is-base-representation pos-coefs))
- (cond
- [is-base (set! new-cnst (cons (list base vars (string->number (substring (list-ref init 1) 1))) new-cnst))]
- )
- )
-
- new-cnst
-)
-
-(define (get-base-representations arg-r1cs)
- ;(printf "Studying ~a\n" arg-r1cs)
- (match arg-r1cs
-
- ; command level
- ; probably the original block
- [(r1cs:rcmds vs)
- (define new-reps (for/list ([v vs]) (get-base-representations v)))
- (foldl append (list) new-reps)
- ]
-
- [(r1cs:rassert v)(get-base-representations v)]
-
- ; sub-command level
- [(r1cs:req lhs rhs)
- (cond
- [(is-rint-zero lhs)
- (match rhs
- [(r1cs:radd vs)
- ; apply lemma
- (if (> (length vs) 2)
- (generate-base-constraints vs)
- '()
- )
- ;(printf "New cons: ~a\n" cnsts)
- ]
- [else '()]
- )
- ]
- [(is-rint-zero rhs)
- (match lhs
- [(r1cs:radd vs)
- ; apply lemma
- (if (> (length vs) 2)
- (generate-base-constraints vs)
- '()
- )
- ]
- [else '()]
- )
- ]
- [else '()]
- )
-
- ]
-
-
-
- [(r1cs:rneq lhs rhs) (list)]
- [(r1cs:rleq lhs rhs) (list)]
- [(r1cs:rlt lhs rhs) (list)]
- [(r1cs:rgeq lhs rhs) (list)]
- [(r1cs:rgt lhs rhs) (list)]
- [(r1cs:rraw v) (list)]
- [(r1cs:rlogic v) (list)]
- [(r1cs:rdef v t) (list)]
- [(r1cs:rassert v) (list)]
- [(r1cs:rcmt v) (list)]
- [(r1cs:rsolve ) (list)]
-
- [(r1cs:rand vs)
- (define new-reps (for/list ([v vs]) (get-base-representations v)))
- (foldl append (list) new-reps)
- ]
- [(r1cs:ror vs)
- (list )
- ]
- [(r1cs:rstr v) (list )]
-
- [else (tokamak:exit "not supported for base representation: ~a" arg-r1cs)]
- )
-)
-
-(define (rebuild-addition vs)
- (r1cs:radd
- (for/list ([v vs])
- (r1cs:rmul (list
- (r1cs:rint (list-ref v 0))
- (r1cs:rvar (list-ref v 1))
- ))
- )
- )
-)
-
-(define (belongs-to-base-field s base)
- (r1cs:req
- (r1cs:rmul(for/list [(pos (range base))]
- (r1cs:radd (list (r1cs:rint (- config:p pos)) (r1cs:rvar s)))
- ))
- (r1cs:rint 0)
- )
-)
-
-(define (generate-base-representations-constraints list-base-1 list-base-2)
-
- (define new-conds (for/list ([i (range (length list-base-1))])
- (define info-base-1 (list-ref list-base-1 i))
- (define base-1 (list-ref info-base-1 0))
- (define bounded-vars-1 (list-ref info-base-1 1))
- (define right-side-1 (list-ref info-base-1 2))
-
- (define info-base-2 (list-ref list-base-2 i))
- (define base-2 (list-ref info-base-2 0))
- (define bounded-vars-2 (list-ref info-base-2 1))
- (define right-side-2 (list-ref info-base-2 2))
-
- (assert (= base-1 base-2))
-
- (define base-assertions-1
- (r1cs:rand
- (for/list ([x bounded-vars-1])
- (belongs-to-base-field x base-1)
- )
- )
- )
- (define base-assertions-2
- (r1cs:rand
- (for/list ([x bounded-vars-2])
- (belongs-to-base-field x base-1)
- )
- )
- )
- (define eq-assertion
- (r1cs:req
- (rebuild-addition right-side-1)
- (rebuild-addition right-side-2)
- )
- )
- (define impl-conditions
- (r1cs:rand (list base-assertions-1 base-assertions-2 eq-assertion))
- )
-
- (define impl-postconditions
- (r1cs:rand
- (for/list ([i (range (length bounded-vars-2))])
- (r1cs:req
- (r1cs:rvar (list-ref bounded-vars-1 i))
- (r1cs:rvar (list-ref bounded-vars-2 i))
- )
- )
- )
- )
- (r1cs:rassert (r1cs:rimp impl-conditions impl-postconditions))
-
- ))
- (r1cs:rcmds new-conds)
-)
-
-(define (compute-bounded-signals arg-r1cs)
- (define constraints (r1cs:get-constraints arg-r1cs))
- (define mconstraints (r1cs:get-mconstraints arg-r1cs))
- (define bounds (for/list ([cnst mconstraints])
- (r1cs:extract-bounded-signals (list-ref constraints cnst))
- ))
- (filter
- (lambda (x) (not (= (list-ref x 0) 0)))
- bounds
- )
-)
-
-(define (get-subset-cmds cmd l-values)
- (match cmd
- [(r1cs:rcmds vs)
- (r1cs:rcmds (for/list ([v l-values]) (list-ref vs v)))
- ]
- [else (tokamak:exit "error: not a list command ~a" cmd)]
- )
-)
-
-; ==============================================================================================
-; ======== Propagation & Preserving with Neighboring Algorithm (Clara's Implementation) ========
-; ==============================================================================================
-; (note) for convenience this moves the entire context
-; because the original version is deeply merged into main context with
-; closures, global variables etc. that are hard to detach
-(define (apply-nb
- r0 nwires mconstraints input-list output-list
- xlist original-definitions original-cnsts
- xlist0 alternative-definitions alternative-cnsts
- arg-weak arg-timeout arg-smt arg-initlvl
- solver:get-theory solver:solve solver:state-smt-path parser:parse-r1cs optimizer:optimize rint:interpret-r1cs
- )
-
- ; state variable of whether the current round has unknown/timeout queries
- ; need to reset to #f at each new round
- (define round-has-unknown null)
-
- (printf "# computing mappings...\n")
- ; parse signal2constraints and constraints2signals
- (define signal2constraints (r1cs:compute-signal2constraints r0))
- (printf "# map from signal to constraints: ~a\n" signal2constraints)
- (define constraint2signals (r1cs:compute-constraint2signals r0))
- (printf "# map from constraints to signals: ~a\n" constraint2signals)
- (define constraint2solvablesignals (r1cs:compute-constraint2solvablesignals r0))
- (printf "# map from constraints to solvable signals: ~a\n" constraint2solvablesignals)
-
- (define optimized-original-cnsts ((optimizer:optimize) original-cnsts))
- (define optimized-alternative-cnsts ((optimizer:optimize) alternative-cnsts))
-
- ; to generate the constraints checking for base-representations
- (define base-representations (get-base-representations optimized-original-cnsts))
- (printf "# Base representations: ~a.\n" base-representations)
-
- ; to obtain the bounds for checking the base representations -> can be used by the solver
- (define bounded-signals (compute-bounded-signals r0))
- (printf "Bounded signals: ~a\n" bounded-signals)
-
- ;;; function to check if the bounds of a base representation are satisfied
- (define (is-valid-base-representation base elems bounds)
- (define are-valid-elems
- (for/list ([elem elems])
- (define-values (is-bounded bound) (utils:get-elem-map bounds elem))
- (match is-bounded
- [#f #f]
- [else
- (< bound base)
- ]
- )
- )
- )
- (foldl (lambda (x y) (and x y)) #t are-valid-elems)
- )
-
- ;;; base representations where the bounds are verified
- ;;; in case the right side is unique, the elements at the left side is too
- (define valid-base-representations
- (filter
- (lambda (base-representation) (is-valid-base-representation
- (list-ref base-representation 0)
- (list-ref base-representation 1)
- bounded-signals
- ))
- base-representations
- )
- )
- (printf "Valid Base Representations ~a\n" valid-base-representations)
-
- (define base2activation-signal
- (for/list ([base valid-base-representations])
- (list-ref base 2)
- )
- )
-
- (define base2propagation-signals
- (for/list ([base valid-base-representations])
- (filter
- (lambda (x) (not (utils:contains? input-list x)))
- (list-ref base 1)
- )
- )
- )
-
- (printf "Base2Activation ~a\n" base2activation-signal)
- (printf "Base2Propagation ~a\n" base2propagation-signals)
-
- (define partial-cmds (r1cs:append-rcmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "================================"))
- (r1cs:rcmt (r1cs:rstr "======== original block ========"))
- (r1cs:rcmt (r1cs:rstr "================================"))
- ))
- original-definitions
- original-cnsts
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "==================================="))
- (r1cs:rcmt (r1cs:rstr "======== alternative block ========"))
- (r1cs:rcmt (r1cs:rstr "==================================="))
- ))
- alternative-definitions
- alternative-cnsts
- ))
-
- ; keep track of index of xlist (not xlist0 since that's incomplete)
- (define known-list (filter
- (lambda (x) (! (null? x)))
- (for/list ([i (range nwires)])
- (if (utils:contains? xlist0 (list-ref xlist i))
- i
- null
- )
- )
- ))
- (define unknown-list (filter
- (lambda (x) (! (null? x)))
- (for/list ([i (range nwires)])
- (if (utils:contains? xlist0 (list-ref xlist i))
- null
- i
- )
- )
- ))
- (printf "# initial known-list: ~a\n" known-list)
- (printf "# initial unknown-list: ~a\n" unknown-list)
-
- ; initialize unknown sets for each constraint
- (define initial-constraint2ukn
- (for/list ([i mconstraints])
- (filter
- (lambda (signal) (
- utils:contains?
- unknown-list
- signal
- ))
- (list-ref constraint2signals i)
- )
- )
- )
- (printf "# initial constraints2ukn ~a\n" initial-constraint2ukn)
-
- ; compute the level-1 neighbors of the signals
- ; (not taking into account as neighbors the known signals)
- (define (compute-signal2neighborconstraints signal known)
- (foldl
- (lambda (x y)
- (set-union y (foldl (lambda (x1 y1) (
- set-union y1 (if (utils:contains? known-list x1) '() (list-ref signal2constraints x1))))
- '()
- (list-ref constraint2signals x)
- ) )
- )
- (list-ref signal2constraints signal)
- (list-ref signal2constraints signal)
- )
- )
-
- ; generate a smt file containing the constraints of the set s
- (define (partial-cmds-list list-c)
- (r1cs:append-rcmds
- (r1cs:rcmds
- (list (r1cs:rassert (r1cs:req
- (r1cs:rint 1) (r1cs:rvar (format "~a" (list-ref xlist 0)))
- )))
- )
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "================================"))
- (r1cs:rcmt (r1cs:rstr "======== original block ========"))
- (r1cs:rcmt (r1cs:rstr "================================"))
- ))
- original-definitions
- (get-subset-cmds original-cnsts list-c)
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "==================================="))
- (r1cs:rcmt (r1cs:rstr "======== alternative block ========"))
- (r1cs:rcmt (r1cs:rstr "==================================="))
- ))
- alternative-definitions
- (get-subset-cmds alternative-cnsts list-c)
-
- )
- )
-
- ;;; to generate the cluster of constraints of a signal depending on the level
- (define (partial-cmds-signal-level0 s)
- (partial-cmds-list (list-ref signal2constraints s))
- )
-
- (define (partial-cmds-signal-level1 s)
- (partial-cmds-list (compute-signal2neighborconstraints s input-list))
- )
-
- (define (partial-cmds-signal-level1known s known)
- (partial-cmds-list (compute-signal2neighborconstraints s known))
- )
-
-
- ; applies the base checking to the different bases: in case the activation
- ; is unique then all the propagation signals are unique
- (define (apply-basis-lemma known unknown constraint2ukn used-basis)
- (printf "# ==== new round of applying lemmas ===\n")
- (define pot-easy '())
- (for ([index (range (length base2activation-signal))])
- (define pot-activation (list-ref base2activation-signal index))
- (cond
- [(and (not (utils:contains? used-basis index)) (utils:contains? known pot-activation))
- (for ([pro-signal (list-ref base2propagation-signals index)])
- (printf "# Verified uniqueness of signal ~a via unique basis reasoning\n" pro-signal)
- (set! known (cons pro-signal known))
- (set! unknown (remove pro-signal unknown))
- (for ([pot-cnst (list-ref signal2constraints pro-signal)])
- (define new-value (remove pro-signal (list-ref constraint2ukn pot-cnst)))
- (set! constraint2ukn (list-set constraint2ukn pot-cnst new-value))
- )
- (set! pot-easy (append (list-ref signal2constraints pro-signal) pot-easy))
- )
- (set! used-basis (cons index used-basis))
- ]
- )
- )
-
- (values known unknown constraint2ukn pot-easy used-basis)
- )
-
- ;;; applies the propagation phase
- (define (apply-propagation known unknown constraint2ukn pot-easy)
- (printf "# ==== new round of propagation ===\n")
- (for ([cnst pot-easy])
- (define ukn-set (list-ref constraint2ukn cnst))
- (set!-values (known unknown constraint2ukn) (cond
- [(= (length ukn-set) 1)
- (define only-signal (car ukn-set))
- (cond
- [(utils:contains? (list-ref constraint2solvablesignals cnst) only-signal)
- (printf "# Verified uniqueness of signal ~a via constraint ~a\n" only-signal cnst)
- (set! known (cons only-signal known))
- (set! unknown (remove only-signal unknown))
- (for ([pot-cnst (list-ref signal2constraints only-signal)])
- (define new-value (remove only-signal (list-ref constraint2ukn pot-cnst)))
- (set! constraint2ukn (list-set constraint2ukn pot-cnst new-value))
- )
- (apply-propagation known unknown constraint2ukn (list-ref signal2constraints only-signal))
- ]
- [else (values known unknown constraint2ukn)]
- )
- ]
- [else (values known unknown constraint2ukn)]
- ))
- )
- (values known unknown constraint2ukn)
- )
-
-
- ;;; Functions related with the heuristics
- (define (get-bounded-signals constraints2ukn)
- (define bounded-constraints
- (filter
- (lambda (x)
- (= (length (list-ref constraints2ukn x)) 1)
- )
- (range mconstraints)
- )
- )
- (define bounded-signals
- (for/list ([cnst bounded-constraints])
- (car (list-ref constraints2ukn cnst))
- )
- )
- (values bounded-constraints bounded-signals)
- )
-
- (define (get-order-promising-signals constraint2ukn ukn triedAndFailed)
- ;(printf "constraint2ukn: ~a\n" constraint2ukn)
- (define-values (bounded-constraints bounded-signals) (get-bounded-signals constraint2ukn))
- ;(printf "Bounded signals: ~a\n" bounded-signals)
- ;(printf "Bounded constraints: ~a\n" bounded-constraints)
- (define constraint2UnUkn
- (for/list ([index mconstraints])
- (cond
- [(utils:contains? bounded-constraints index) -2]
- [else
- (define nUkn (length (list-ref constraint2ukn index)))
- (define nBoundedUkn (length
- (filter
- (lambda (x) (utils:contains? bounded-signals x))
- (list-ref constraint2ukn index)
- )
- ))
- (define nKnown (- (length (list-ref constraint2signals index)) (length (list-ref constraint2ukn index))))
- ;(printf "Known ~a Bounded ~a Ukn ~a\n" nKnown nBoundedUkn nUkn)
- (+ (* 0.1 nKnown) (* 0.5 nBoundedUkn) (- nUkn))
- ]
- )
-
- )
- )
- ;(printf "Constraint to points ~a\n" constraint2UnUkn)
- (define signal2totalPoints
- (for/list ([signal ukn])
- (define total-known
- (foldl
- (lambda (y x)(max x (list-ref constraint2UnUkn y)))
- -1000
- (list-ref signal2constraints signal)
- )
- )
- (define already-tried (utils:contains? triedAndFailed signal))
- (if already-tried
- (list signal (- total-known 100))
- (list signal total-known)
- )
- )
- )
- ;(printf "Signal to points ~a\n" signal2totalPoints)
- (define order-signal-val (
- sort signal2totalPoints (lambda (x y) (> (list-ref x 1) (list-ref y 1))))
- )
- (for/list ([value order-signal-val])
- (list-ref value 0)
- )
- )
-
-
- ;;; function that applies a complete iteration of the algorithm
- (define (apply-complete-iteration known unknown constraint2ukn pot-easy0 used-basis0 tried-and-failed)
- (define-values (kn0 ukn0 c2ukn0)
- (apply-propagation known unknown constraint2ukn pot-easy0)
- )
-
- (define-values (kn ukn c2ukn pot-easy used-basis)
- (apply-basis-lemma kn0 ukn0 c2ukn0 used-basis0)
- )
-
- (cond
- [(null? pot-easy)
- (cond
- [(and arg-weak (utils:empty_inter? ukn output-list))
- null
- ]
- [else
- (define promising-signals-ordered (get-order-promising-signals c2ukn ukn tried-and-failed))
- (printf "# ==== new round of SMT solvers ===\n")
- (set! round-has-unknown #f)
- (define-values (signal-smt new-failures) (try-solve-smt promising-signals-ordered kn tried-and-failed))
- (cond
- [(>= signal-smt 0)
- (set! kn (cons signal-smt kn))
- (set! ukn (remove signal-smt ukn))
- (for ([pot-cnst (list-ref signal2constraints signal-smt)])
- (define new-value (remove signal-smt (list-ref c2ukn pot-cnst)))
- (set! c2ukn (list-set c2ukn pot-cnst new-value))
- )
- (if (null? ukn)
- null
- (if arg-weak
- (if (utils:empty_inter? ukn output-list)
- ukn
- (apply-complete-iteration kn ukn c2ukn (list-ref signal2constraints signal-smt) used-basis new-failures)
- )
- (apply-complete-iteration kn ukn c2ukn (list-ref signal2constraints signal-smt) used-basis new-failures)
- )
- )
- ]
- [else ukn]
- )
- ]
- )
- ]
- [ else
- (apply-complete-iteration kn ukn c2ukn pot-easy used-basis tried-and-failed)
- ]
- )
- )
-
- ;;; function that applies the smt phase of the algorithm
- (define (try-solve-smt promising-signals-ordered known tried-and-failed)
- (cond
- [(null? promising-signals-ordered) (values -1 '())]
- [else
- (cond
- [(try-solve-smt-single-signal (car promising-signals-ordered) known arg-initlvl)
- (values (car promising-signals-ordered) tried-and-failed)
- ]
- [else
- (set! tried-and-failed (cons (car promising-signals-ordered) tried-and-failed))
- (try-solve-smt (cdr promising-signals-ordered) known tried-and-failed)
- ]
- )
-
- ]
- )
- )
-
- ;;; function that tries to verify the uniqueness of signal s, assuming that the signals in known are unique
- ;;; level indicates the cluster of constraints that it sends to the SMT solver
- (define (try-solve-smt-single-signal signal known level)
- (printf " # checking: (~a ~a)@Lv.~a, " (list-ref xlist signal) (list-ref xlist0 signal) level)
- (define known-cmds (r1cs:rcmds (for/list ([j known])
- (r1cs:rassert (r1cs:req (r1cs:rvar (list-ref xlist j)) (r1cs:rvar (list-ref xlist0 j))))
- )))
- (define partial-cmds-level
- (cond
- [(= level 0) (partial-cmds-signal-level0 signal)]
- [(= level 1) (partial-cmds-signal-level1 signal)]
- [(= level 2) partial-cmds]
- )
- )
- (define final-cmds (r1cs:append-rcmds
- (r1cs:rcmds (list (r1cs:rlogic (r1cs:rstr (solver:get-theory)))))
- partial-cmds-level
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "============================="))
- (r1cs:rcmt (r1cs:rstr "======== known block ========"))
- (r1cs:rcmt (r1cs:rstr "============================="))
- ))
- known-cmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "============================="))
- (r1cs:rcmt (r1cs:rstr "======== query block ========"))
- (r1cs:rcmt (r1cs:rstr "============================="))
- ))
- (r1cs:rcmds (list
- (r1cs:rassert (r1cs:rneq (r1cs:rvar (list-ref xlist signal)) (r1cs:rvar (list-ref xlist0 signal))))
- (r1cs:rsolve )
- ))
- ))
- ; perform optimization
- (define optimized-cmds ((optimizer:optimize) final-cmds))
- (define final-str (string-join ((rint:interpret-r1cs) optimized-cmds) "\n"))
- (define res ((solver:solve) final-str arg-timeout #:output-smt? #f))
- (when arg-smt
- (printf " # smt path: ~a\n" (solver:state-smt-path)))
- (cond
- [(equal? 'unsat (car res))
- (printf "verified.\n")
- #t
- ]
- [(equal? 'sat (car res))
- (cond
- [(< level 2)
- (printf "sat\n")
- (try-solve-smt-single-signal signal known (+ level 1))
- ]
- [ else
- (printf "sat\n")
- #f
- ]
- )
-
- ]
- [else
- (cond
- [(< level 2)
- (printf "skip\n")
- (try-solve-smt-single-signal signal known (+ level 1))
- ]
- [ else
- (printf "skip\n")
- (set! round-has-unknown #t)
- #f
- ]
- )
- ]
- )
- )
-
- (define res-ul (apply-complete-iteration known-list unknown-list initial-constraint2ukn (range mconstraints) '() '()))
- ; return
- (values res-ul round-has-unknown)
-)
\ No newline at end of file
diff --git a/picus/algorithms/clara-pp.rkt b/picus/algorithms/clara-pp.rkt
deleted file mode 100644
index 819a099..0000000
--- a/picus/algorithms/clara-pp.rkt
+++ /dev/null
@@ -1,706 +0,0 @@
-#lang rosette
-; this implements the propagation & preserving algorithm with base lemma
-(require
- (prefix-in tokamak: "../tokamak.rkt")
- (prefix-in utils: "../utils.rkt")
- (prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
-)
-(provide (rename-out
- [apply-pp apply-pp]
-))
-
-(define (is-rint-zero x)
- (if (r1cs:rint? x)
- (if (= 0 (r1cs:rint-v x))
- #t
- #f
- )
- #f
- )
-)
-
-(define (is-rint-one x)
- (if (r1cs:rint? x)
- (if (= 1 (r1cs:rint-v x))
- #t
- #f
- )
- #f
- )
-)
-
-(define (contains-rint-zero l)
- (if (null? l)
- #f
- (let ([x (car l)])
- (if (r1cs:rint? x)
- (if (= 0 (r1cs:rint-v x))
- #t
- (contains-rint-zero (cdr l))
- )
- (contains-rint-zero (cdr l))
- )
- )
- )
-)
-
-(define (get-single-coefficient v)
- (match v
- [(r1cs:rint v) (list v "x0")]
- [(r1cs:rvar v) (list 1 v)]
- [(r1cs:rmul vs)
- (define l1 (get-single-coefficient (car vs)))
- (define l2 (get-single-coefficient (car (cdr vs))))
- (list (* (list-ref l1 0) (list-ref l2 0)) (list-ref l2 1))
- ]
- [else (tokamak:exit "not supported for single coefficient ~a" v)]
- )
-)
-
-(define (get-list-coefficients vs)
- (for/list ([v vs])
- (get-single-coefficient v)
- )
-)
-
-(define (check-base base sorted_coefs)
- (if (= (length sorted_coefs) 1)
- #t
- (if (= (modulo (* base (car sorted_coefs)) config:p) (car (cdr sorted_coefs)))
- (check-base base (cdr sorted_coefs))
- #f
- )
- )
-)
-
-(define (is-base-representation coefs-vars)
- (define sorted-coefs-vars (sort coefs-vars (lambda (x y) (< (list-ref x 0) (list-ref y 0)))))
-
- (define sorted-coefs
- (for/list ([v sorted-coefs-vars])
- (list-ref v 0)
- )
- )
-
- (define sorted-vars
- (for/list ([v sorted-coefs-vars])
- (string->number (substring (list-ref v 1) 1))
- )
- )
-
- (define pot_base (/ (car (cdr sorted-coefs)) (car sorted-coefs)))
- (if (> pot_base 1)
- (if (utils:contains? sorted-vars 0)
- (values #f 1 '())
- (values (check-base pot_base (cdr sorted-coefs)) pot_base sorted-vars)
- )
- (values #f 1 '())
- )
-)
-
-(define (get-potential-inits vs)
- (filter
- (lambda (v) (and
- (= 2 (length v))
- (or (= 1 (list-ref v 0)) (= (- config:p 1) (list-ref v 0))))
- )
- vs
- )
-)
-
-(define (generate-base-constraints vs)
- (define coefs (get-list-coefficients vs))
- (define potential-inits (get-potential-inits coefs))
- (define new-cnst '())
- (for ([init potential-inits])
- (define pos-coefs
- (filter
- (lambda (x) (not (string=? (car (cdr x)) (car (cdr init)))))
- (for/list ([elem coefs])
- (list
- (if (= (car init) 1)
- (- config:p (car elem))
- (car elem)
- )
- (car (cdr elem))
- )
- )
- )
- )
- (define-values (is-base base vars) (is-base-representation pos-coefs))
- (cond
- [is-base (set! new-cnst (cons (list base vars (string->number (substring (list-ref init 1) 1))) new-cnst))]
- )
- )
-
- new-cnst
-)
-
-(define (get-base-representations arg-r1cs)
- ;(printf "Studying ~a\n" arg-r1cs)
- (match arg-r1cs
-
- ; command level
- ; probably the original block
- [(r1cs:rcmds vs)
- (define new-reps (for/list ([v vs]) (get-base-representations v)))
- (foldl append (list) new-reps)
- ]
-
- [(r1cs:rassert v)(get-base-representations v)]
-
- ; sub-command level
- [(r1cs:req lhs rhs)
- (cond
- [(is-rint-zero lhs)
- (match rhs
- [(r1cs:radd vs)
- ; apply lemma
- (if (> (length vs) 2)
- (generate-base-constraints vs)
- '()
- )
- ;(printf "New cons: ~a\n" cnsts)
- ]
- [else '()]
- )
- ]
- [(is-rint-zero rhs)
- (match lhs
- [(r1cs:radd vs)
- ; apply lemma
- (if (> (length vs) 2)
- (generate-base-constraints vs)
- '()
- )
- ]
- [else '()]
- )
- ]
- [else '()]
- )
-
- ]
-
-
-
- [(r1cs:rneq lhs rhs) (list)]
- [(r1cs:rleq lhs rhs) (list)]
- [(r1cs:rlt lhs rhs) (list)]
- [(r1cs:rgeq lhs rhs) (list)]
- [(r1cs:rgt lhs rhs) (list)]
- [(r1cs:rraw v) (list)]
- [(r1cs:rlogic v) (list)]
- [(r1cs:rdef v t) (list)]
- [(r1cs:rassert v) (list)]
- [(r1cs:rcmt v) (list)]
- [(r1cs:rsolve ) (list)]
-
- [(r1cs:rand vs)
- (define new-reps (for/list ([v vs]) (get-base-representations v)))
- (foldl append (list) new-reps)
- ]
- [(r1cs:ror vs)
- (list )
- ]
- [(r1cs:rstr v) (list )]
-
- [else (tokamak:exit "not supported for base representation: ~a" arg-r1cs)]
- )
-)
-
-(define (rebuild-addition vs)
- (r1cs:radd
- (for/list ([v vs])
- (r1cs:rmul (list
- (r1cs:rint (list-ref v 0))
- (r1cs:rvar (list-ref v 1))
- ))
- )
- )
-)
-
-(define (belongs-to-base-field s base)
- (r1cs:req
- (r1cs:rmul(for/list [(pos (range base))]
- (r1cs:radd (list (r1cs:rint (- config:p pos)) (r1cs:rvar s)))
- ))
- (r1cs:rint 0)
- )
-)
-
-(define (generate-base-representations-constraints list-base-1 list-base-2)
-
- (define new-conds (for/list ([i (range (length list-base-1))])
- (define info-base-1 (list-ref list-base-1 i))
- (define base-1 (list-ref info-base-1 0))
- (define bounded-vars-1 (list-ref info-base-1 1))
- (define right-side-1 (list-ref info-base-1 2))
-
- (define info-base-2 (list-ref list-base-2 i))
- (define base-2 (list-ref info-base-2 0))
- (define bounded-vars-2 (list-ref info-base-2 1))
- (define right-side-2 (list-ref info-base-2 2))
-
- (assert (= base-1 base-2))
-
- (define base-assertions-1
- (r1cs:rand
- (for/list ([x bounded-vars-1])
- (belongs-to-base-field x base-1)
- )
- )
- )
- (define base-assertions-2
- (r1cs:rand
- (for/list ([x bounded-vars-2])
- (belongs-to-base-field x base-1)
- )
- )
- )
- (define eq-assertion
- (r1cs:req
- (rebuild-addition right-side-1)
- (rebuild-addition right-side-2)
- )
- )
- (define impl-conditions
- (r1cs:rand (list base-assertions-1 base-assertions-2 eq-assertion))
- )
-
- (define impl-postconditions
- (r1cs:rand
- (for/list ([i (range (length bounded-vars-2))])
- (r1cs:req
- (r1cs:rvar (list-ref bounded-vars-1 i))
- (r1cs:rvar (list-ref bounded-vars-2 i))
- )
- )
- )
- )
- (r1cs:rassert (r1cs:rimp impl-conditions impl-postconditions))
-
- ))
- (r1cs:rcmds new-conds)
-)
-
-(define (compute-bounded-signals arg-r1cs)
- (define constraints (r1cs:get-constraints arg-r1cs))
- (define mconstraints (r1cs:get-mconstraints arg-r1cs))
- (define bounds (for/list ([cnst mconstraints])
- (r1cs:extract-bounded-signals (list-ref constraints cnst))
- ))
- (filter
- (lambda (x) (not (= (list-ref x 0) 0)))
- bounds
- )
-)
-
-; =============================================================================
-; ======== Propagation & Preserving Algorithm (Clara's Implementation) ========
-; =============================================================================
-; (note) for convenience this moves the entire context
-; because the original version is deeply merged into main context with
-; closures, global variables etc. that are hard to detach
-(define (apply-pp
- r0 nwires mconstraints input-list output-list
- xlist original-definitions original-cnsts
- xlist0 alternative-definitions alternative-cnsts
- arg-weak arg-timeout arg-smt arg-model
- solver:get-theory solver:solve solver:state-smt-path parser:parse-r1cs optimizer:optimize rint:interpret-r1cs
- )
-
- ; state variable of whether the current round has unknown/timeout queries
- ; need to reset to #f at each new round
- (define round-has-unknown null)
-
- ; parse signal2constraints and constraints2signals
- (define signal2constraints (r1cs:compute-signal2constraints r0))
- (define constraint2signals (r1cs:compute-constraint2signals r0))
- (define constraint2solvablesignals (r1cs:compute-constraint2solvablesignals r0))
- (printf "# map from signal to constraints: ~a\n" signal2constraints)
- (printf "# map from constraints to signals: ~a\n" constraint2signals)
- (printf "# map from constraints to solvable signals: ~a\n" constraint2solvablesignals)
-
- (define optimized-original-cnsts ((optimizer:optimize) original-cnsts))
- (define optimized-alternative-cnsts ((optimizer:optimize) alternative-cnsts))
-
- ; to generate the constraints checking for base-representations
- (define base-representations (get-base-representations optimized-original-cnsts))
- (printf "# Base representations: ~a.\n" base-representations)
-
- ; to obtain the bounds for checking the base representations -> can be used by the solver
- (define bounded-signals (compute-bounded-signals r0))
- (printf "Bounded signals: ~a\n" bounded-signals)
-
- ;;; function to check if the bounds of a base representation are satisfied
- (define (is-valid-base-representation base elems bounds)
- (define are-valid-elems
- (for/list ([elem elems])
- (define-values (is-bounded bound) (utils:get-elem-map bounds elem))
- (match is-bounded
- [#f #f]
- [else
- (< bound base)
- ]
- )
- )
- )
- (foldl (lambda (x y) (and x y)) #t are-valid-elems)
- )
-
- ;;; base representations where the bounds are verified
- ;;; in case the right side is unique, the elements at the left side is too
- (define valid-base-representations
- (filter
- (lambda (base-representation) (is-valid-base-representation
- (list-ref base-representation 0)
- (list-ref base-representation 1)
- bounded-signals
- ))
- base-representations
- )
- )
- (printf "Valid Base Representations ~a\n" valid-base-representations)
-
- (define base2activation-signal
- (for/list ([base valid-base-representations])
- (list-ref base 2)
- )
- )
-
- (define base2propagation-signals
- (for/list ([base valid-base-representations])
- (filter
- (lambda (x) (not (utils:contains? input-list x)))
- (list-ref base 1)
- )
- )
- )
-
- (printf "Base2Activation ~a\n" base2activation-signal)
- (printf "Base2Propagation ~a\n" base2propagation-signals)
-
- (define partial-cmds (r1cs:append-rcmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "================================"))
- (r1cs:rcmt (r1cs:rstr "======== original block ========"))
- (r1cs:rcmt (r1cs:rstr "================================"))
- ))
- original-definitions
- original-cnsts
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "==================================="))
- (r1cs:rcmt (r1cs:rstr "======== alternative block ========"))
- (r1cs:rcmt (r1cs:rstr "==================================="))
- ))
- alternative-definitions
- alternative-cnsts
- ))
-
- ; keep track of index of xlist (not xlist0 since that's incomplete)
- (define known-list (filter
- (lambda (x) (! (null? x)))
- (for/list ([i (range nwires)])
- (if (utils:contains? xlist0 (list-ref xlist i))
- i
- null
- )
- )
- ))
- (define unknown-list (filter
- (lambda (x) (! (null? x)))
- (for/list ([i (range nwires)])
- (if (utils:contains? xlist0 (list-ref xlist i))
- null
- i
- )
- )
- ))
- (printf "# initial known-list: ~a\n" known-list)
- (printf "# initial unknown-list: ~a\n" unknown-list)
-
- ; initialize unknown sets for each constraint
- (define initial-constraint2ukn
- (for/list ([i mconstraints])
- (filter
- (lambda (signal) (
- utils:contains?
- unknown-list
- signal
- ))
- (list-ref constraint2signals i)
- )
- )
- )
- (printf "# initial constraints2ukn ~a\n" initial-constraint2ukn)
-
- ; compute the level-1 neighbors of the signals
- ; (not taking into account as neighbors the known signals)
- (define (compute-signal2neighborconstraints signal known)
- (foldl
- (lambda (x y)
- (set-union y (foldl (lambda (x1 y1) (
- set-union y1 (if (utils:contains? known-list x1) '() (list-ref signal2constraints x1))))
- '()
- (list-ref constraint2signals x)
- ) )
- )
- (list-ref signal2constraints signal)
- (list-ref signal2constraints signal)
- )
- )
-
-
- ; applies the base checking to the different bases: in case the activation
- ; is unique then all the propagation signals are unique
- (define (apply-basis-lemma known unknown constraint2ukn used-basis)
- (printf "# ==== new round of applying lemmas ===\n")
- (define pot-easy '())
- (for ([index (range (length base2activation-signal))])
- (define pot-activation (list-ref base2activation-signal index))
- (cond
- [(and (not (utils:contains? used-basis index)) (utils:contains? known pot-activation))
- (for ([pro-signal (list-ref base2propagation-signals index)])
- (printf "# Verified uniqueness of signal ~a via unique basis reasoning\n" pro-signal)
- (set! known (cons pro-signal known))
- (set! unknown (remove pro-signal unknown))
- (for ([pot-cnst (list-ref signal2constraints pro-signal)])
- (define new-value (remove pro-signal (list-ref constraint2ukn pot-cnst)))
- (set! constraint2ukn (list-set constraint2ukn pot-cnst new-value))
- )
- (set! pot-easy (append (list-ref signal2constraints pro-signal) pot-easy))
- )
- (set! used-basis (cons index used-basis))
- ]
- )
- )
-
- (values known unknown constraint2ukn pot-easy used-basis)
- )
-
- ;;; applies the propagation phase
- (define (apply-propagation known unknown constraint2ukn pot-easy)
- (printf "# ==== new round of propagation ===\n")
- (for ([cnst pot-easy])
- (define ukn-set (list-ref constraint2ukn cnst))
- (set!-values (known unknown constraint2ukn) (cond
- [(= (length ukn-set) 1)
- (define only-signal (car ukn-set))
- (cond
- [(utils:contains? (list-ref constraint2solvablesignals cnst) only-signal)
- (printf "# Verified uniqueness of signal ~a via constraint ~a\n" only-signal cnst)
- (set! known (cons only-signal known))
- (set! unknown (remove only-signal unknown))
- (for ([pot-cnst (list-ref signal2constraints only-signal)])
- (define new-value (remove only-signal (list-ref constraint2ukn pot-cnst)))
- (set! constraint2ukn (list-set constraint2ukn pot-cnst new-value))
- )
- (apply-propagation known unknown constraint2ukn (list-ref signal2constraints only-signal))
- ]
- [else (values known unknown constraint2ukn)]
- )
- ]
- [else (values known unknown constraint2ukn)]
- ))
- )
- (values known unknown constraint2ukn)
- )
-
-
- ;;; Functions related with the heuristics
- (define (get-bounded-signals constraints2ukn)
- (define bounded-constraints
- (filter
- (lambda (x)
- (= (length (list-ref constraints2ukn x)) 1)
- )
- (range mconstraints)
- )
- )
- (define bounded-signals
- (for/list ([cnst bounded-constraints])
- (car (list-ref constraints2ukn cnst))
- )
- )
- (values bounded-constraints bounded-signals)
- )
-
- (define (get-order-promising-signals constraint2ukn ukn triedAndFailed)
- ;(printf "constraint2ukn: ~a\n" constraint2ukn)
- (define-values (bounded-constraints bounded-signals) (get-bounded-signals constraint2ukn))
- ;(printf "Bounded signals: ~a\n" bounded-signals)
- ;(printf "Bounded constraints: ~a\n" bounded-constraints)
- (define constraint2UnUkn
- (for/list ([index mconstraints])
- (cond
- [(utils:contains? bounded-constraints index) -2]
- [else
- (define nUkn (length (list-ref constraint2ukn index)))
- (define nBoundedUkn (length
- (filter
- (lambda (x) (utils:contains? bounded-signals x))
- (list-ref constraint2ukn index)
- )
- ))
- (define nKnown (- (length (list-ref constraint2signals index)) (length (list-ref constraint2ukn index))))
- ;(printf "Known ~a Bounded ~a Ukn ~a\n" nKnown nBoundedUkn nUkn)
- (+ (* 0.1 nKnown) (* 0.5 nBoundedUkn) (- nUkn))
- ]
- )
-
- )
- )
- ;(printf "Constraint to points ~a\n" constraint2UnUkn)
- (define signal2totalPoints
- (for/list ([signal ukn])
- (define total-known
- (foldl
- (lambda (y x)(max x (list-ref constraint2UnUkn y)))
- -1000
- (list-ref signal2constraints signal)
- )
- )
- (define already-tried (utils:contains? triedAndFailed signal))
- (if already-tried
- (list signal (- total-known 100))
- (list signal total-known)
- )
- )
- )
- ;(printf "Signal to points ~a\n" signal2totalPoints)
- (define order-signal-val (
- sort signal2totalPoints (lambda (x y) (> (list-ref x 1) (list-ref y 1))))
- )
- (for/list ([value order-signal-val])
- (list-ref value 0)
- )
- )
-
-
- ;;; function that applies a complete iteration of the algorithm
- (define (apply-complete-iteration known unknown constraint2ukn pot-easy0 used-basis0 tried-and-failed)
- (define-values (kn0 ukn0 c2ukn0)
- (apply-propagation known unknown constraint2ukn pot-easy0)
- )
-
- (define-values (kn ukn c2ukn pot-easy used-basis)
- (apply-basis-lemma kn0 ukn0 c2ukn0 used-basis0)
- )
-
- (cond
- [(null? pot-easy)
- (cond
- [(and arg-weak (utils:empty_inter? ukn output-list))
- null
- ]
- [else
- (define promising-signals-ordered (get-order-promising-signals c2ukn ukn tried-and-failed))
- (printf "# ==== new round of SMT solvers ===\n")
- (set! round-has-unknown #f)
- (define-values (signal-smt new-failures) (try-solve-smt promising-signals-ordered kn tried-and-failed))
- (cond
- [(>= signal-smt 0)
- (set! kn (cons signal-smt kn))
- (set! ukn (remove signal-smt ukn))
- (for ([pot-cnst (list-ref signal2constraints signal-smt)])
- (define new-value (remove signal-smt (list-ref c2ukn pot-cnst)))
- (set! c2ukn (list-set c2ukn pot-cnst new-value))
- )
- (if (null? ukn)
- null
- (if arg-weak
- (if (utils:empty_inter? ukn output-list)
- ukn
- (apply-complete-iteration kn ukn c2ukn (list-ref signal2constraints signal-smt) used-basis new-failures)
- )
- (apply-complete-iteration kn ukn c2ukn (list-ref signal2constraints signal-smt) used-basis new-failures)
- )
- )
- ]
- [else ukn]
- )
- ]
- )
- ]
- [ else
- (apply-complete-iteration kn ukn c2ukn pot-easy used-basis tried-and-failed)
- ]
- )
- )
-
- ;;; function that applies the smt phase of the algorithm
- (define (try-solve-smt promising-signals-ordered known tried-and-failed)
- (cond
- [(null? promising-signals-ordered) (values -1 '())]
- [else
- (cond
- [(try-solve-smt-single-signal (car promising-signals-ordered) known)
- (values (car promising-signals-ordered) tried-and-failed)
- ]
- [else
- (set! tried-and-failed (cons (car promising-signals-ordered) tried-and-failed))
- (try-solve-smt (cdr promising-signals-ordered) known tried-and-failed)
- ]
- )
-
- ]
- )
- )
-
- ; function that tries to verify the uniqueness of signal s, assuming that the signals in known are unique
- (define (try-solve-smt-single-signal signal known)
- (printf " # checking: (~a ~a), " (list-ref xlist signal) (list-ref xlist0 signal))
- (define known-cmds (r1cs:rcmds (for/list ([j known])
- (r1cs:rassert (r1cs:req (r1cs:rvar (list-ref xlist j)) (r1cs:rvar (list-ref xlist0 j))))
- )))
- (define final-cmds (r1cs:append-rcmds
- (r1cs:rcmds (list (r1cs:rlogic (r1cs:rstr (solver:get-theory)))))
- partial-cmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "============================="))
- (r1cs:rcmt (r1cs:rstr "======== known block ========"))
- (r1cs:rcmt (r1cs:rstr "============================="))
- ))
- known-cmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "============================="))
- (r1cs:rcmt (r1cs:rstr "======== query block ========"))
- (r1cs:rcmt (r1cs:rstr "============================="))
- ))
- (r1cs:rcmds (list
- (r1cs:rassert (r1cs:rneq (r1cs:rvar (list-ref xlist signal)) (r1cs:rvar (list-ref xlist0 signal))))
- (r1cs:rsolve )
- ))
- ))
- ; perform optimization
- (define optimized-cmds ((optimizer:optimize) final-cmds))
- (define final-str (string-join ((rint:interpret-r1cs) optimized-cmds) "\n"))
- (define res ((solver:solve) final-str arg-timeout #:output-smt? #f))
- (when arg-smt
- (printf " # smt path: ~a\n" (solver:state-smt-path)))
- (cond
- [(equal? 'unsat (car res))
- (printf "verified.\n")
- #t
- ]
- [(equal? 'sat (car res))
- (if arg-model
- (printf "sat\n # model: ~a" (cdr res))
- (printf "sat\n")
- )
- #f
- ]
- [else
- (printf "skip\n")
- (set! round-has-unknown #t)
- #f
- ]
- )
- )
-
- (define res-ul (apply-complete-iteration known-list unknown-list initial-constraint2ukn (range mconstraints) '() '()))
- ; return
- (values res-ul round-has-unknown)
-)
\ No newline at end of file
diff --git a/picus/algorithms/constraint-graph.rkt b/picus/algorithms/constraint-graph.rkt
new file mode 100644
index 0000000..9bf0596
--- /dev/null
+++ b/picus/algorithms/constraint-graph.rkt
@@ -0,0 +1,171 @@
+#lang racket
+(require graph csv-reading
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
+)
+(provide (all-defined-out))
+
+; constraint graph
+; - g: graph object
+; - e2c: hash, edge to constraint id, key is a set of signals, val is a set of constraint ids
+; - s2o: vector, signal to order
+; - s2s: vector, signal to scope
+; - o2s: vector, order to scope
+(struct cgraph (g e2c s2o s2s o2s) #:mutable #:transparent #:reflection-name 'cgraph) ; constraint graph
+
+(define (extract-signal-id x) (string->number (substring x 1)))
+
+; scope is a set e.g. (set "adder" "main")
+(define (read-sym path-sym)
+ (define rd (csv->list (open-input-file path-sym)))
+ ; sym file doesn't have x0, so you need to manually add it
+ (define n-signals (+ 1 (length rd)))
+
+ ; 3rd column, could be topological order?
+ ; module order vector
+ (define order-vec (make-vector n-signals null))
+ ; scope vector
+ (define scope-vec (make-vector n-signals null))
+
+ ; parse module order and scope
+ ; no x0 is included in sym, so minus 1
+ (define ospairs (list ))
+ (for ([i (range (- n-signals 1))])
+ (define sid (+ 1 i)) ; shift, start from signal 1
+ (define entry (list-ref rd i))
+ ; parse order
+ (define order (string->number (list-ref entry 2)))
+ (vector-set! order-vec sid order)
+ ; parse scope, drop the last element since that's not a scope
+ (define scope (list->set (cdr (reverse (string-split (list-ref entry 3) ".")))))
+ (vector-set! scope-vec sid scope)
+ ; track os pairs
+ (set! ospairs (cons (cons order scope) ospairs))
+ )
+ (set! ospairs (set->list (list->set ospairs))) ; remove duplicates
+
+ ; set order and scope of x0
+ ; just copy from signal 1
+ (vector-set! order-vec 0 (vector-ref order-vec 1))
+ (vector-set! scope-vec 0 (vector-ref scope-vec 1))
+
+ ; (todo) verify order-scope mapping is unique
+ (define nos (length ospairs))
+ (define os-hash (make-hash ospairs))
+ (when (not (equal? nos (hash-count os-hash)))
+ (tokamak:exit "something is wrong with the sym file, ospairs: ~a" ospairs))
+ (define os-vec (build-vector nos (lambda (x) (hash-ref os-hash x))))
+
+ ; return
+ ; - order-vec: signal to order mapping, s2o
+ ; - scope-vec: signal to scope mapping, s2s
+ ; - os-vec: order to signal mapping, o2s
+ (values order-vec scope-vec os-vec)
+)
+
+; requires p1cnsts, no constraint id change after that
+; arguments:
+; - detach-x0?: whether or not to remove edges connected to x0 (x0 is always a constant 1)
+(define (compute-constraint-graph r0 arg-r1cs path-sym #:detach-x0? [detach-x0? #t])
+ (define input-list (r1cs:r1cs-inputs r0))
+ (define output-list (r1cs:r1cs-outputs r0))
+
+ ; read sym file
+ (define-values (order-vec scope-vec os-vec) (read-sym path-sym))
+
+ ; constraint graph
+ (define g (undirected-graph (list )))
+
+ (define vs (r1cs:rcmds-vs arg-r1cs))
+ (define n-edges (length vs))
+ (define n-nodes (r1cs:get-nwires r0))
+ ; first add all signals as vertices
+ (for ([i (range n-nodes)]) (add-vertex! g i))
+
+ ; then define e2c-map
+ (define e2c-map (make-hash))
+
+ ; then add edges
+ (for ([i (range n-edges)])
+ (define cnst (list-ref vs i))
+ (define asvs (r1cs:get-assert-variables cnst #t)) ; get all involving signals
+ ; add edges
+ (for ([b (combinations (set->list asvs) 2)])
+ (define node0 (list-ref b 0))
+ (define node1 (list-ref b 1))
+ (when (or
+ (and detach-x0? (not (= 0 node0)) (not (= 0 node1)))
+ (not detach-x0?)
+ )
+ (add-edge! g node0 node1) ; good enough, will automatically convert to bi-direct.
+ ; set label to constraint id, need to set for both directions
+ (define ek (set node0 node1)) ; key
+ (when (not (hash-has-key? e2c-map ek))
+ (hash-set! e2c-map ek (set )))
+ (hash-set! e2c-map ek (set-add (hash-ref e2c-map ek) i))
+ )
+ )
+ )
+
+ ; construct and return cgraph
+ (cgraph g e2c-map order-vec scope-vec os-vec)
+)
+
+; this extracts a subgraph with given scope
+; (fixme) the subgraph still has the full node info components, but with graph component cut
+; argumnts:
+; - arg-connections: a set that includes more nodes (usually connecting nodes)
+(define (get-scoped-subgraph arg-graph arg-scope arg-connections)
+ (define g (graph-copy (cgraph-g arg-graph))) ; make a copy
+ (define scope-vec (cgraph-s2s arg-graph))
+ ; get candidate signal ids
+ (define scope-sids (list->set (filter
+ (lambda (x) (equal? arg-scope (vector-ref scope-vec x)))
+ (range (vector-length scope-vec))
+ )))
+ (define all-sids (set-union scope-sids arg-connections))
+
+ ; then delete the nodes that are out of given scope
+ (for ([node (get-vertices g)])
+ (when (not (set-member? all-sids node))
+ (remove-vertex! g node))
+ )
+
+ ; return
+ (cgraph
+ g
+ (cgraph-e2c arg-graph)
+ (cgraph-s2o arg-graph)
+ (cgraph-s2s arg-graph)
+ (cgraph-o2s arg-graph)
+ )
+)
+
+; returns:
+; - set of pairs of signals (cons [signal inside scope] [signal outside scope])
+(define (get-connecting-pairs arg-graph arg-scope)
+ (define g0 (cgraph-g arg-graph))
+ (define scope-vec (cgraph-s2s arg-graph))
+ (define es (get-edges g0))
+ (define res (set ))
+ (for ([e es])
+ (define node0 (list-ref e 0))
+ (define node1 (list-ref e 1))
+ ; node0 is in scope
+ (when (and
+ (equal? arg-scope (vector-ref scope-vec node0))
+ (not (equal? arg-scope (vector-ref scope-vec node1)))
+ )
+ (set! res (set-add res (cons node0 node1)))
+ )
+ ; node1 is in scope
+ (when (and
+ (equal? arg-scope (vector-ref scope-vec node1))
+ (not (equal? arg-scope (vector-ref scope-vec node0)))
+ )
+ (set! res (set-add res (cons node1 node0)))
+ )
+ )
+ ; return
+ res
+)
\ No newline at end of file
diff --git a/picus/algorithms/dpvl.rkt b/picus/algorithms/dpvl.rkt
new file mode 100644
index 0000000..a0a301d
--- /dev/null
+++ b/picus/algorithms/dpvl.rkt
@@ -0,0 +1,509 @@
+#lang racket
+; this implements the decide & propagate verification loop algorithm
+(require
+ csv-reading
+
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
+ (prefix-in selector: "./selector.rkt")
+ ; lemmas
+ (prefix-in l0: "./lemmas/linear-lemma.rkt")
+ (prefix-in l1: "./lemmas/binary01-lemma.rkt")
+ (prefix-in l2: "./lemmas/basis2-lemma.rkt")
+ (prefix-in l3: "./lemmas/aboz-lemma.rkt")
+ (prefix-in l4: "./lemmas/bim-lemma.rkt")
+ ; (prefix-in ln0: "./lemmas/baby-lemma.rkt")
+)
+(provide (rename-out
+ [apply-algorithm apply-algorithm]
+))
+
+; ======== module global variables ======== ;
+
+; selector series, need arg-selector to resolve
+(define apply-selector null)
+(define selector-feedback null)
+(define selector-init null)
+
+; this is the selector context provided to every apply-selector call
+; grab the current context, then pack and return
+(define (selector-context) (make-hash (list
+ (cons 'rcdmap (l0:compute-rcdmap :sdmcnsts #t))
+)))
+
+; problem pack, needs to be set and initialized by apply- function
+(define :r0 null)
+(define :nwires null)
+(define :mconstraints null)
+(define :input-set null)
+(define :output-set null)
+(define :target-set null)
+
+(define :xlist null)
+(define :opts null)
+(define :defs null)
+(define :cnsts null) ; standard form
+(define :sdmcnsts null) ; normalized standard form (specifically for rcdmap, original only)
+(define :p0cnsts null) ; standard form optimized by phase 0 optimization
+(define :expcnsts null) ; expanded form
+(define :nrmcnsts null) ; normalized form
+(define :p1cnsts null) ; normalized form optimized by phase 1 optimization
+
+(define :alt-xlist null)
+(define :alt-defs null)
+(define :alt-cnsts null)
+(define :alt-p0cnsts null)
+(define :alt-expcnsts null)
+(define :alt-nrmcnsts null)
+(define :alt-p1cnsts null)
+
+(define :arg-selector null)
+(define :arg-prop null)
+(define :arg-slv null)
+(define :arg-timeout null)
+(define :arg-smt null)
+(define :arg-map null)
+
+(define :unique-set null)
+(define :precondition null)
+
+(define :solve null)
+(define :state-smt-path null)
+(define :interpret-r1cs null)
+
+(define :parse-r1cs null)
+(define :optimize-r1cs-p0 null)
+(define :expand-r1cs null)
+(define :normalize-r1cs null)
+(define :optimize-r1cs-p1 null)
+
+; optional arguments
+(define :extcnsts null)
+(define :skip-query? null)
+
+; problem intermediate results
+(define :partial-cmds null)
+
+; more specific range for all signals, potential values are (from abstract to concrete):
+; - 'bottom: it's {0, ..., p-1} (everything)
+; - a set of potential values
+; (note) this tracks the range, not the uniqueness status, they are different
+(define :range-vec null)
+
+; main solving procedure
+; returns:
+; - (values 'verified info): the given query is verified
+; - (values 'sat info): the given query has a counter-example (not verified)
+; - (values 'skip info): the given query times out (small step)
+(define (dpvl-solve ks us sid)
+ (printf " # checking: (~a ~a), " (list-ref :xlist sid) (list-ref :alt-xlist sid))
+ ; assemble commands
+ (define known-cmds (r1cs:rcmds (for/list ([j ks])
+ (r1cs:rassert (r1cs:req (r1cs:rvar (list-ref :xlist j)) (r1cs:rvar (list-ref :alt-xlist j))))
+ )))
+ (define final-cmds (r1cs:rcmds-append
+ :partial-cmds
+ (r1cs:rcmds (list
+ (r1cs:rcmt "=============================")
+ (r1cs:rcmt "======== known block ========")
+ (r1cs:rcmt "=============================")
+ ))
+ known-cmds
+ (r1cs:rcmds (list
+ (r1cs:rcmt "=============================")
+ (r1cs:rcmt "======== query block ========")
+ (r1cs:rcmt "=============================")
+ ))
+ (if :skip-query?
+ ; skip query
+ (r1cs:rcmds (list
+ (r1cs:rcmt "signal query is skipped")
+ (r1cs:rsolve )
+ ))
+ ; do not skip query
+ (r1cs:rcmds (list
+ (r1cs:rassert (r1cs:rneq (r1cs:rvar (list-ref :xlist sid)) (r1cs:rvar (list-ref :alt-xlist sid))))
+ (r1cs:rsolve )
+ ))
+ )
+ ))
+ ; perform optimization
+ (define final-str (string-join (:interpret-r1cs
+ (r1cs:rcmds-append :opts final-cmds))
+ "\n"
+ ))
+ (define res (:solve final-str :arg-timeout #:output-smt? #f))
+ (define solved? (cond
+ [(equal? 'unsat (car res))
+ (printf "verified.\n")
+ ; verified, safe
+ 'verified
+ ]
+ [(equal? 'sat (car res))
+ (if :skip-query?
+ ; skipping query, whatever sat is good
+ (begin (printf "sat (no query).\n") 'sat)
+ ; not skipping query, need to tell variable
+ ; (important) here if the current signal is not a target, it's ok to see a sat
+ (if (set-member? :target-set sid)
+ ; the current signal is a target, now there's a counter-example, unsafe
+ ; in pp, this counter-example is valid
+ (begin (printf "sat.\n") 'sat)
+ ; not a target, fine, just skip
+ (begin (printf "sat but not a target.\n") 'skip)
+ )
+ )
+ ]
+ [else
+ (printf "skip.\n")
+ ; possibly timeout in small step, result is unknown
+ 'skip
+ ]
+ ))
+ (when :arg-smt
+ (printf " # smt path: ~a\n" (:state-smt-path)))
+ ; return
+ (values solved? (cdr res))
+)
+
+; select and solve
+; returns:
+; - (values 'normal ks us info)
+; - (values 'break ks us info)
+; (note) since it's called recursively, at some level it could have new different ks with 'break
+; in that case you still break since a counter-example is already found
+; uspool is usually initialized as us
+(define (dpvl-select-and-solve ks us uspool)
+ (cond
+ [(set-empty? uspool)
+ ; can't solve any more signal in this iteration
+ (values 'normal ks us null)
+ ]
+ ; else, set not empty, move forward
+ [else
+ (define sid (apply-selector uspool (selector-context)))
+ (define-values (solved? info) (dpvl-solve ks us sid))
+ ; send feedback to selector
+ (selector-feedback sid solved?)
+ (cond
+ ; solved, update ks & us, then return
+ [(equal? 'verified solved?) (values 'normal (set-add ks sid) (set-remove us sid) null)]
+ ; found a counter-example here, forced stop, nothing more to solve
+ ; return the same ks & us to indicate the caller to stop
+ [(equal? 'sat solved?) (values 'break ks us info)]
+ ; unknown or timeout, update uspool and recursively call again
+ [(equal? 'skip solved?) (dpvl-select-and-solve ks us (set-remove uspool sid))]
+ [else (tokamak:error "unsupported solved? value, got: ~a." solved?)]
+ )
+ ]
+ )
+)
+
+; (define tmp-inspect (list 512 513 514 515 516 517 518 519 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511))
+; (define tmp-inspect (list 1024 1025 1026 1027 1028 1029 1030 1031 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023))
+; (define tmp-inspect (list 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047))
+; (define tmp-inspect (list 1806))
+
+; recursively apply all lemmas until fixed point
+(define (dpvl-propagate ks us)
+ ; (printf "range-vec[inspect]: ~a\n" (for/list ([i tmp-inspect]) (vector-ref :range-vec i)))
+
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+
+ ; prepare lemma 0
+ ; generate rcdmap requires no optimization to exclude ror and rand
+ ; rcdmap requires normalized constraints to get best results
+ (define rcdmap (l0:compute-rcdmap :sdmcnsts #t))
+ ; (for ([key (hash-keys rcdmap)]) (printf "~a => ~a\n" key (hash-ref rcdmap key)))
+
+ ; apply lemma 0: linear lemma
+ (set!-values (tmp-ks tmp-us) (l0:apply-lemma rcdmap tmp-ks tmp-us))
+
+ ; apply lemma 1: binary01 lemma
+ (set!-values (tmp-ks tmp-us) (l1:apply-lemma tmp-ks tmp-us :p1cnsts :range-vec))
+
+ ; apply lemma 2: basis2 lemma
+ (set!-values (tmp-ks tmp-us) (l2:apply-lemma tmp-ks tmp-us :p1cnsts :range-vec))
+
+ ; apply lemma 3: all-but-one-zero
+ (set!-values (tmp-ks tmp-us) (l3:apply-lemma tmp-ks tmp-us :p1cnsts :range-vec))
+
+ ; apply lemma 4: big-int-mul
+ (set!-values (tmp-ks tmp-us) (l4:apply-lemma tmp-ks tmp-us :p1cnsts :range-vec))
+
+ ; ; apply lemma ln0
+ ; (set!-values (tmp-ks tmp-us) (ln0:apply-lemma tmp-ks tmp-us :p1cnsts))
+
+ ; return
+ (if (= (set-count ks) (set-count tmp-ks))
+ ; no updates, return
+ (values tmp-ks tmp-us)
+ ; has updates, call again
+ (dpvl-propagate tmp-ks tmp-us)
+ )
+)
+
+; perform one iteration of pp algorithm
+; - ks: known set
+; - us: unknown set
+; returns:
+; - ('safe ks us info)
+; - ('unsafe ks us info)
+; - ('unknown ks us info)
+(define (dpvl-iterate ks us)
+
+ ; first, propagate
+ (define-values (new-ks new-us) (if :arg-prop
+ ; do propagation
+ (dpvl-propagate ks us)
+ ; don't do propagation
+ (values ks us)
+ ))
+ (cond
+ [(set-empty? (set-intersect :target-set new-us))
+ ; no target signal is unknown, no need to solve any more, return
+ (values 'safe new-ks new-us null)
+ ]
+ [else
+ ; still there's unknown target signal, continue
+ ; then select and solve
+ (define-values (s0 xnew-ks xnew-us info) (if :arg-slv
+ ; do solver phase
+ (dpvl-select-and-solve new-ks new-us new-us)
+ ; don't do solver phase
+ (values 'normal new-ks new-us null)
+ ))
+ (cond
+ ; normal means there's no counter-example
+ [(equal? 'normal s0)
+ (cond
+ [(set-empty? (set-intersect :target-set xnew-us))
+ ; no target signal is unknown, return
+ (values 'safe xnew-ks xnew-us null)
+ ]
+ [(equal? xnew-us new-us)
+ ; can't reduce any unknown any more, return
+ (values 'unknown xnew-ks xnew-us info)
+ ]
+ [else
+ ; continue the iteration
+ (dpvl-iterate xnew-ks xnew-us)
+ ]
+ )
+ ]
+ ; 'break means there's counter-example
+ [(equal? 'break s0) (values 'unsafe xnew-ks xnew-us info)]
+ [else (tokamak:error "unsupported s0 value, got: ~a." s0)]
+ )
+ ]
+ )
+)
+
+; this creates a new hash with r1cs variables replaced by corresponding circom variables
+; (note) this will remove helping variables like "one", "ps?", etc.
+(define (map-to-vars info path-sym)
+ (define rd (csv->list (open-input-file path-sym)))
+ ; create r1cs-id to circom-var mapping
+ (define r2c-map (make-hash (for/list ([p rd])
+ (cons (list-ref p 0) (list-ref p 3))
+ )))
+ (define pinfo (if (list? info) (make-hash) info)) ; patch for info type, fix later
+ (define new-info (make-hash))
+ (for ([k (hash-keys pinfo)])
+ (cond
+ [(equal? k "x0") (void)] ; skip since this is a constant
+ [(string-prefix? k "x")
+ (define rid (substring k 1))
+ (define cid (hash-ref r2c-map rid))
+ (define val (hash-ref pinfo k))
+
+ (define sid (format "m1.~a" cid))
+ (hash-set! new-info sid val)
+ ]
+ [(string-prefix? k "y")
+ (define rid (substring k 1))
+ (define cid (hash-ref r2c-map rid))
+ (define val (hash-ref pinfo k))
+
+ (define sid (format "m2.~a" cid))
+ (hash-set! new-info sid val)
+ ]
+ [else (void)] ; skip otherwise
+ )
+ )
+ new-info
+)
+
+; verifies signals in target-set
+; returns (same as dpvl-iterate):
+; - (values 'safe ks us info)
+; - (values 'unsafe ks us info)
+; - (values 'unknown ks us info)
+(define (apply-algorithm
+ r0 nwires mconstraints
+ input-set output-set target-set
+ xlist opts defs cnsts
+ alt-xlist alt-defs alt-cnsts
+ unique-set precondition
+ arg-selector arg-prop arg-slv arg-timeout arg-smt arg-map path-sym
+ solve state-smt-path interpret-r1cs
+ parse-r1cs optimize-r1cs-p0 expand-r1cs normalize-r1cs optimize-r1cs-p1
+ ; extra constraints, usually from cex module about partial model
+ #:extcnsts [extcnsts (r1cs:rcmds (list ))]
+ ; if true, then the query block will not be issued
+ ; this is required for the cex module to finalize a non-relevant part, which only requires a trivial model
+ #:skip-query? [skip-query? #f]
+ )
+
+ ; first load in all global variables
+ (set! :r0 r0)
+ (set! :nwires nwires)
+ (set! :mconstraints mconstraints)
+ (set! :input-set input-set)
+ (set! :output-set output-set)
+ (set! :target-set target-set)
+
+ (set! :xlist xlist)
+ (set! :opts opts)
+ (set! :defs defs)
+ (set! :cnsts cnsts)
+
+ (set! :alt-xlist alt-xlist)
+ (set! :alt-defs alt-defs)
+ (set! :alt-cnsts alt-cnsts)
+
+ (set! :arg-selector arg-selector)
+ (set! :arg-prop arg-prop)
+ (set! :arg-slv arg-slv)
+ (set! :arg-timeout arg-timeout)
+ (set! :arg-smt arg-smt)
+ (set! :arg-map arg-map)
+
+ (set! :unique-set unique-set)
+ (set! :precondition precondition)
+
+ (set! :solve solve)
+ (set! :state-smt-path state-smt-path)
+ (set! :interpret-r1cs interpret-r1cs)
+
+ (set! :parse-r1cs parse-r1cs)
+ (set! :optimize-r1cs-p0 optimize-r1cs-p0)
+ (set! :expand-r1cs expand-r1cs)
+ (set! :normalize-r1cs normalize-r1cs)
+ (set! :optimize-r1cs-p1 optimize-r1cs-p1)
+
+ ; optional arguments
+ (set! :extcnsts extcnsts)
+ (set! :skip-query? skip-query?)
+
+ ; keep track of index of xlist (not alt-xlist since that's incomplete)
+ (define known-set (list->set (filter
+ (lambda (x) (not (null? x)))
+ (for/list ([i (range :nwires)])
+ (if (utils:contains? :alt-xlist (list-ref :xlist i))
+ i
+ null
+ )
+ )
+ )))
+ (define unknown-set (list->set (filter
+ (lambda (x) (not (null? x)))
+ (for/list ([i (range :nwires)])
+ (if (utils:contains? :alt-xlist (list-ref :xlist i))
+ null
+ i
+ )
+ )
+ )))
+ (printf "# initial known-set ~a\n" known-set)
+ (printf "# initial unknown-set ~a\n" unknown-set)
+
+ ; (precondition related) incorporate unique-set if unique-set is not an empty set
+ (set! known-set (set-union known-set unique-set))
+ (set! unknown-set (set-subtract unknown-set unique-set))
+ (printf "# refined known-set: ~a\n" known-set)
+ (printf "# refined unknown-set: ~a\n" unknown-set)
+
+ ; ==== branch out: skip optimization phase 0 and apply expand & normalize ====
+ ; computing rcdmap need no ab0 lemma from optimization phase 0
+ (set! :sdmcnsts (:normalize-r1cs (:expand-r1cs :cnsts)))
+
+ ; ==== first apply optimization phase 0 ====
+ (set! :p0cnsts (:optimize-r1cs-p0 :cnsts))
+ (set! :alt-p0cnsts (:optimize-r1cs-p0 :alt-cnsts))
+
+ ; ==== then expand the constraints ====
+ (set! :expcnsts (:expand-r1cs :p0cnsts))
+ (set! :alt-expcnsts (:expand-r1cs :alt-p0cnsts))
+
+ ; ==== then normalize the constraints ====
+ (set! :nrmcnsts (:normalize-r1cs :expcnsts))
+ (set! :alt-nrmcnsts (:normalize-r1cs :alt-expcnsts))
+
+ ; initialize selector
+ (set! apply-selector (selector:apply-selector arg-selector))
+ (set! selector-feedback (selector:selector-feedback arg-selector))
+ (set! selector-init (selector:selector-init arg-selector))
+ (selector-init :nwires)
+
+ ; ==== then apply optimization phase 1 ====
+ (set! :p1cnsts (:optimize-r1cs-p1 :nrmcnsts #t)) ; include p defs
+ (set! :alt-p1cnsts (:optimize-r1cs-p1 :alt-nrmcnsts #f)) ; no p defs since this is alt-
+
+ ; prepare partial cmds for better reuse through out the algorithm
+ (set! :partial-cmds (r1cs:rcmds-append
+ (r1cs:rcmds (list
+ (r1cs:rcmt "================================")
+ (r1cs:rcmt "======== original block ========")
+ (r1cs:rcmt "================================")
+ ))
+ :defs
+ :p1cnsts
+ (r1cs:rcmds (list
+ (r1cs:rcmt "===================================")
+ (r1cs:rcmt "======== alternative block ========")
+ (r1cs:rcmt "===================================")
+ ))
+ :alt-defs
+ :alt-p1cnsts
+ (r1cs:rcmds (list
+ (r1cs:rcmt "====================================")
+ (r1cs:rcmt "======== precondition block ========")
+ (r1cs:rcmt "====================================")
+ ))
+ (if (null? :precondition)
+ ; no precondition
+ (r1cs:rcmds (list (r1cs:rcmt "(no precondition or skipped by user)")))
+ ; assemble precondition
+ (r1cs:rcmds (flatten (for/list ([v :precondition])
+ (cons
+ (r1cs:rcmt (format "precondition tag: ~a" (car v)))
+ (cdr v)
+ )
+ )))
+ )
+ (r1cs:rcmds (list
+ (r1cs:rcmt "========================================")
+ (r1cs:rcmt "======== extra constraint block ========")
+ (r1cs:rcmt "========================================")
+ ))
+ extcnsts
+ ))
+
+ ; initialize range set to all values
+ (set! :range-vec (build-vector :nwires (lambda (x) 'bottom)))
+ ; x0 is always 1
+ (vector-set! :range-vec 0 (list->set (list 1)))
+
+ ; invoke the algorithm iteration
+ (define-values (ret0 rks rus info) (dpvl-iterate known-set unknown-set))
+
+ ; do a remapping if enabled
+ (set! info (if arg-map (map-to-vars info path-sym) info))
+
+ ; return
+ (values ret0 rks rus info)
+)
\ No newline at end of file
diff --git a/picus/algorithms/inc.rkt b/picus/algorithms/inc.rkt
deleted file mode 100644
index 3982f60..0000000
--- a/picus/algorithms/inc.rkt
+++ /dev/null
@@ -1,129 +0,0 @@
-#lang rosette
-; this implements the propagation & preserving algorithm with base lemma
-(require
- (prefix-in tokamak: "../tokamak.rkt")
- (prefix-in utils: "../utils.rkt")
- (prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
-)
-(provide (rename-out
- [apply-inc apply-inc]
-))
-
-(define (apply-inc
- r0 nwires mconstraints input-list output-list
- xlist original-definitions original-cnsts
- xlist0 alternative-definitions alternative-cnsts
- arg-timeout arg-smt
- solver:get-theory solver:solve solver:state-smt-path parser:parse-r1cs optimizer:optimize rint:interpret-r1cs
- )
-
- ; state variable of whether the current round has unknown/timeout queries
- ; need to reset to #f at each new round
- (define round-has-unknown null)
-
- (define partial-cmds (r1cs:append-rcmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "================================"))
- (r1cs:rcmt (r1cs:rstr "======== original block ========"))
- (r1cs:rcmt (r1cs:rstr "================================"))
- ))
- original-definitions
- original-cnsts
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "==================================="))
- (r1cs:rcmt (r1cs:rstr "======== alternative block ========"))
- (r1cs:rcmt (r1cs:rstr "==================================="))
- ))
- alternative-definitions
- alternative-cnsts
- ))
-
- ; keep track of index of xlist (not xlist0 since that's incomplete)
- (define known-list (filter
- (lambda (x) (! (null? x)))
- (for/list ([i (range nwires)])
- (if (utils:contains? xlist0 (list-ref xlist i))
- i
- null
- )
- )
- ))
- (define unknown-list (filter
- (lambda (x) (! (null? x)))
- (for/list ([i (range nwires)])
- (if (utils:contains? xlist0 (list-ref xlist i))
- null
- i
- )
- )
- ))
- (printf "# initial knwon-list: ~a\n" known-list)
- (printf "# initial unknown-list: ~a\n" unknown-list)
-
- ; returns final unknown list, and if it's empty, it means all are known
- ; and thus verified
- (define (inc-solve kl ul)
- (printf "# ==== new round inc-solve ===\n")
- (define tmp-kl (for/list ([i kl]) i))
- (define tmp-ul (list ))
- (define changed? #f)
- (for ([i ul])
- (printf " # checking: (~a ~a), " (list-ref xlist i) (list-ref xlist0 i))
- (define known-cmds (r1cs:rcmds (for/list ([j tmp-kl])
- (r1cs:rassert (r1cs:req (r1cs:rvar (list-ref xlist j)) (r1cs:rvar (list-ref xlist0 j))))
- )))
- (define final-cmds (r1cs:append-rcmds
- (r1cs:rcmds (list (r1cs:rlogic (r1cs:rstr (solver:get-theory)))))
- partial-cmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "============================="))
- (r1cs:rcmt (r1cs:rstr "======== known block ========"))
- (r1cs:rcmt (r1cs:rstr "============================="))
- ))
- known-cmds
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "============================="))
- (r1cs:rcmt (r1cs:rstr "======== query block ========"))
- (r1cs:rcmt (r1cs:rstr "============================="))
- ))
- (r1cs:rcmds (list
- (r1cs:rassert (r1cs:rneq (r1cs:rvar (list-ref xlist i)) (r1cs:rvar (list-ref xlist0 i))))
- (r1cs:rsolve )
- ))
- ))
- ; perform optimization
- (define optimized-cmds ((optimizer:optimize) final-cmds))
- (define final-str (string-join ((rint:interpret-r1cs) optimized-cmds) "\n"))
- (define res ((solver:solve) final-str arg-timeout #:output-smt? #f))
- (cond
- [(equal? 'unsat (car res))
- (printf "verified.\n")
- (set! tmp-kl (cons i tmp-kl))
- (set! changed? #t)
- ]
- [(equal? 'sat (car res))
- (printf "sat.\n")
- (set! tmp-ul (cons i tmp-ul))
- ]
- [else
- (printf "skip.\n")
- (set! round-has-unknown #t)
- (set! tmp-ul (cons i tmp-ul))
- ]
- )
- (when arg-smt
- (printf " # smt path: ~a\n" (solver:state-smt-path)))
- )
- ; return
- (if changed?
- (inc-solve (reverse tmp-kl) (reverse tmp-ul))
- tmp-ul
- )
- )
-
- (set! round-has-unknown #f)
- (define res-ul (inc-solve known-list unknown-list))
- ; return
- (values res-ul round-has-unknown)
-)
\ No newline at end of file
diff --git a/picus/algorithms/lemmas/aboz-lemma.rkt b/picus/algorithms/lemmas/aboz-lemma.rkt
new file mode 100644
index 0000000..4c52e02
--- /dev/null
+++ b/picus/algorithms/lemmas/aboz-lemma.rkt
@@ -0,0 +1,155 @@
+#lang racket
+; this implements the all-but-one-zero lemma
+; y0 + ... + yn = (unique)
+; y0 * (x-0) = 0
+; ...
+; yn * (x-n) = 0
+;
+; then y0, ..., yn are unique
+
+; (fixme) this implements a special case of all-but-one-zero lemma, e.g.,
+; x8 * (x7 - 0) = 0
+; (1 - x8) * (x7 - 1) = 0
+
+; ( (1 * x11) ) * ( (1 * x8) ) = 0
+; ( (ps1 * x0) + (1 * x11) ) * ( (1 * x9) ) = 0
+; ( 0 ) * ( 0 ) = (1 * x8) + (1 * x9) + (ps1 * x10)
+; if x7 is unique, then x8 and (1-x8) are unique
+
+; its p1cnsts form is different, see process below
+; (fixme) this implements an inefficient version, could be improved
+
+(require
+ (prefix-in config: "../../config.rkt")
+ (prefix-in tokamak: "../../tokamak.rkt")
+ (prefix-in r1cs: "../../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [apply-lemma apply-lemma]
+))
+
+; recursively apply linear lemma
+(define (apply-lemma ks us p1cnsts range-vec)
+ (printf " # propagation (aboz lemma): ")
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+
+ (set!-values (tmp-ks tmp-us) (process tmp-ks tmp-us p1cnsts range-vec))
+ (let ([s0 (set-subtract tmp-ks ks)])
+ (if (set-empty? s0)
+ (printf "none.\n")
+ (printf "~a added.\n" s0)
+ )
+ )
+
+ ; apply once is enough, return
+ (values tmp-ks tmp-us)
+)
+
+(define (extract-signal-id x) (string->number (substring x 1)))
+
+(define (process ks us arg-r1cs range-vec)
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+ (define n (length (r1cs:rcmds-vs arg-r1cs)))
+ (for ([i (range (- n 2))])
+ (define icnsts (r1cs:rcmds (list
+ (r1cs:rcmds-ref arg-r1cs i)
+ (r1cs:rcmds-ref arg-r1cs (+ 1 i))
+ (r1cs:rcmds-ref arg-r1cs (+ 2 i))
+ )))
+ (define res (match-full icnsts))
+ (when (not (null? res))
+ ; matched, analyze vars
+ ; list is: x, y0, y1, c
+ ; if c and x are unique, then y0 and y1 are unique
+ (define xid (extract-signal-id (list-ref res 0)))
+ (define cid (extract-signal-id (list-ref res 3)))
+ (define y0id (extract-signal-id (list-ref res 1)))
+ (define y1id (extract-signal-id (list-ref res 2)))
+ (when (and (set-member? tmp-ks xid) (set-member? tmp-ks cid))
+ (set! tmp-ks (set-union tmp-ks (set y0id y1id)))
+ (set! tmp-us (set-subtract tmp-us (set y0id y1id)))
+ )
+ )
+ )
+ (values tmp-ks tmp-us)
+)
+
+; (fixme) list-no-order should be enforced
+; return a list of: x, y0, y1, c
+(define (match-full arg-obj)
+ (match arg-obj
+
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+ [(r1cs:rcmds (list
+
+ ; eq0
+ (r1cs:rassert (r1cs:ror (list
+ (r1cs:req (r1cs:rvar "zero") (r1cs:rvar xa)) ; (x-0)
+ (r1cs:req (r1cs:rvar "zero") (r1cs:rvar y0a)) ; y0
+ )))
+
+ ; eq1
+ (r1cs:rassert (r1cs:ror (list
+ (r1cs:req (r1cs:rvar "zero") (r1cs:rmod (r1cs:radd (list (r1cs:rvar "ps1") (r1cs:rvar xb))) (r1cs:rvar "p"))) ; (x-1)
+ (r1cs:req (r1cs:rvar "zero") (r1cs:rvar y1a)) ; y1
+ )))
+
+ ; eq2
+ ; y0 + y1 - c = 0, which is y0 + y1 = c
+ (r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rmod (r1cs:radd (list (r1cs:rvar y0b) (r1cs:rvar y1b) (r1cs:rmul (list (r1cs:rvar "ps1") (r1cs:rvar c))))) (r1cs:rvar "p"))
+ ))
+
+ ))
+ ; pattern matched, check for value
+ (if (and (equal? xa xb) (equal? y0a y0b) (equal? y1a y1b))
+ ; valu matched
+ (list xa y0a y1a c)
+ ; not matched
+ null
+ )
+ ]
+
+ ; ==============================
+ ; ==== finite field version ====
+ ; ==============================
+ [(r1cs:rcmds (list
+
+ ; eq0
+ (r1cs:rassert (r1cs:ror (list
+ (r1cs:req (r1cs:rvar "zero") (r1cs:rvar xa)) ; (x-0)
+ (r1cs:req (r1cs:rvar "zero") (r1cs:rvar y0a)) ; y0
+ )))
+
+ ; eq1
+ (r1cs:rassert (r1cs:ror (list
+ (r1cs:req (r1cs:rvar "zero") (r1cs:radd (list (r1cs:rvar "ps1") (r1cs:rvar xb)))) ; (x-1)
+ (r1cs:req (r1cs:rvar "zero") (r1cs:rvar y1a)) ; y1
+ )))
+
+ ; eq2
+ ; y0 + y1 - c = 0, which is y0 + y1 = c
+ (r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:radd (list (r1cs:rvar y0b) (r1cs:rvar y1b) (r1cs:rmul (list (r1cs:rvar "ps1") (r1cs:rvar c)))))
+ ))
+
+ ))
+ ; pattern matched, check for value
+ (if (and (equal? xa xb) (equal? y0a y0b) (equal? y1a y1b))
+ ; valu matched
+ (list xa y0a y1a c)
+ ; not matched
+ null
+ )
+ ]
+
+ ; otherwise, do not rewrite
+ [_ null]
+ )
+)
\ No newline at end of file
diff --git a/picus/algorithms/lemmas/baby-lemma.rkt b/picus/algorithms/lemmas/baby-lemma.rkt
new file mode 100644
index 0000000..a195570
--- /dev/null
+++ b/picus/algorithms/lemmas/baby-lemma.rkt
@@ -0,0 +1,336 @@
+#lang racket
+; this implements the baby lemma
+; p1 * x3 * x6 = p1 * x7
+; p1 * x4 * x5 = p1 * x8
+; (a * x3 + p1 * x4) * (x5 + x6) = p1 * x9
+; p1 * x7 * x8 = p1 * x10
+; (1 + d * x10) * x1 = x7 + x8
+; (1 + pd * x10) * x2 = a * x7 + p1 * x8 + x9
+; where a=168700, d=168696, p?=p-?
+; if x3, x4, x5 and x6 are all uniquely determined
+; then x1 and x2 are uniquely determined, so as other intermediate signals
+
+; (fixme) currently this lemma implementation is not super efficient
+(require
+ (prefix-in config: "../../config.rkt")
+ (prefix-in tokamak: "../../tokamak.rkt")
+ (prefix-in r1cs: "../../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [apply-lemma apply-lemma]
+))
+
+(define (apply-lemma ks us p1cnsts)
+ (printf " # propagation (baby lemma): ")
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+
+ (set!-values (tmp-ks tmp-us) (process tmp-ks tmp-us p1cnsts))
+ (let ([s0 (set-subtract tmp-ks ks)])
+ (if (set-empty? s0)
+ (printf "none.\n")
+ (printf "~a added.\n" s0)
+ )
+ )
+
+ ; apply once is enough, return
+ (values tmp-ks tmp-us)
+)
+
+(define (extract-signal-id x) (string->number (substring x 1)))
+
+; bag of signals: (x1 x2 x3 x4 x5 x6 x7 x8 x9 x10)
+(define (process ks us arg-r1cs)
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+ (for ([obj (r1cs:rcmds-vs arg-r1cs)])
+ (define mvec (build-vector 11 (lambda (n) null)))
+ (vector-set! mvec 0 "x0")
+ (if (match-x2 obj mvec)
+ ; successful, continue to match x1
+ (for ([obj2 (r1cs:rcmds-vs arg-r1cs)])
+ (if (match-x1 obj2 mvec)
+ ; successful, continue to match rel
+ (for ([obj3 (r1cs:rcmds-vs arg-r1cs)])
+ (if (match-rel obj3 mvec)
+ ; successful, check for uniqueness status of x7, x8 and x9
+ (begin
+ (if (and
+ (set-member? tmp-ks (extract-signal-id (vector-ref mvec 7)))
+ (set-member? tmp-ks (extract-signal-id (vector-ref mvec 8)))
+ (set-member? tmp-ks (extract-signal-id (vector-ref mvec 9)))
+ (set-member? tmp-ks (extract-signal-id (vector-ref mvec 10)))
+ )
+ ; yes, conclude and add x1 x2 to known set
+ (begin
+ (set! tmp-ks (set-union tmp-ks (list->set (list
+ (extract-signal-id (vector-ref mvec 1))
+ (extract-signal-id (vector-ref mvec 2))
+ ))))
+ (set! tmp-us (set-subtract tmp-us (list->set (list
+ (extract-signal-id (vector-ref mvec 1))
+ (extract-signal-id (vector-ref mvec 2))
+ ))))
+ )
+ ; no, continue
+ (void)
+ )
+ )
+ ; not successful, continue
+ (void)
+ )
+ )
+ ; not successful, continue
+ (void)
+ )
+ )
+ ; not successful, continue
+ (void)
+ )
+ )
+ (values tmp-ks tmp-us)
+)
+
+; match x2 x7 x8 x9 x10
+(define (match-x2 arg-obj arg-vec)
+ (match arg-obj
+
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+ ; pattern: (1 + pd * x10) * x2 = a * x7 + p1 * x8 + x9
+ ; (assert (=
+ ; (rem
+ ; (+ x2 (* 21888242871839275222246405745257275088548364400416034343698204186575808326921 (* x10 x2)))
+ ; p
+ ; )
+ ; (rem
+ ; (+ (* 168700 x7) (+ (* ps1 x8) x9))
+ ; p
+ ; )
+ ; ))
+ ; (fixme) x10 and x2b could be mixed!
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x2a)
+ (r1cs:rmul (list-no-order
+ (r1cs:rint 21888242871839275222246405745257275088548364400416034343698204186575808326921)
+ (r1cs:rvar x10)
+ (r1cs:rvar x2b)
+ ))
+ ))
+ _
+ )
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rmul (list-no-order
+ (r1cs:rint 168700)
+ (r1cs:rvar x7)
+ ))
+ (r1cs:rmul (list-no-order
+ (r1cs:rvar "ps1")
+ (r1cs:rvar x8)
+ ))
+ (r1cs:rvar x9)
+ ))
+ _
+ )
+ ))
+ (if (equal? x2a x2b)
+ (begin
+ (vector-set! arg-vec 2 x2a)
+ (vector-set! arg-vec 7 x7)
+ (vector-set! arg-vec 8 x8)
+ (vector-set! arg-vec 9 x9)
+ (vector-set! arg-vec 10 x10)
+ #t
+ )
+ #f
+ )
+ ]
+
+ ; ==============================
+ ; ==== finite field version ====
+ ; ==============================
+ [(r1cs:rassert (r1cs:req
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x2a)
+ (r1cs:rmul (list-no-order
+ (r1cs:rint 21888242871839275222246405745257275088548364400416034343698204186575808326921)
+ (r1cs:rvar x10)
+ (r1cs:rvar x2b)
+ ))
+ ))
+ (r1cs:radd (list-no-order
+ (r1cs:rmul (list-no-order
+ (r1cs:rint 168700)
+ (r1cs:rvar x7)
+ ))
+ (r1cs:rmul (list-no-order
+ (r1cs:rvar "ps1")
+ (r1cs:rvar x8)
+ ))
+ (r1cs:rvar x9)
+ ))
+ ))
+ (if (equal? x2a x2b)
+ (begin
+ (vector-set! arg-vec 2 x2a)
+ (vector-set! arg-vec 7 x7)
+ (vector-set! arg-vec 8 x8)
+ (vector-set! arg-vec 9 x9)
+ (vector-set! arg-vec 10 x10)
+ #t
+ )
+ #f
+ )
+ ]
+
+ ; otherwise, do not rewrite
+ [_ #f]
+ )
+)
+
+; returns (list x1)
+(define (match-x1 arg-obj arg-vec)
+ (match arg-obj
+
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+ ; pattern: (1 + d * x10) * x1 = x7 + x8
+ ; (assert (= (rem (+ x1 (* 168696 (* x10 x1))) p) (rem (+ x7 x8) p)))
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x1a)
+ (r1cs:rmul (list-no-order
+ (r1cs:rint 168696)
+ (r1cs:rvar x10)
+ (r1cs:rvar x1b)
+ ))
+ ))
+ _
+ )
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x7)
+ (r1cs:rvar x8)
+ ))
+ _
+ )
+ ))
+ (if (and
+ (equal? x1a x1b)
+ (equal? (vector-ref arg-vec 7) x7)
+ (equal? (vector-ref arg-vec 8) x8)
+ (equal? (vector-ref arg-vec 10) x10)
+ )
+ (begin
+ (vector-set! arg-vec 1 x1a)
+ #t
+ )
+ #f
+ )
+ ]
+
+ ; ==============================
+ ; ==== finite field version ====
+ ; ==============================
+ [(r1cs:rassert (r1cs:req
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x1a)
+ (r1cs:rmul (list-no-order
+ (r1cs:rint 168696)
+ (r1cs:rvar x10)
+ (r1cs:rvar x1b)
+ ))
+ ))
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x7)
+ (r1cs:rvar x8)
+ ))
+ ))
+ (if (and
+ (equal? x1a x1b)
+ (equal? (vector-ref arg-vec 7) x7)
+ (equal? (vector-ref arg-vec 8) x8)
+ (equal? (vector-ref arg-vec 10) x10)
+ )
+ (begin
+ (vector-set! arg-vec 1 x1a)
+ #t
+ )
+ #f
+ )
+ ]
+
+ ; otherwise, do not rewrite
+ [_ #f]
+ )
+)
+
+(define (match-rel arg-obj arg-vec)
+ (match arg-obj
+
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+ ; pattern: p1 * x7 * x8 = p1 * x10
+ ; (assert (= (rem (* ps1 (* x7 x8)) p) (rem (* ps1 x10) p)))
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmod
+ (r1cs:rmul (list-no-order
+ (r1cs:rvar "ps1")
+ (r1cs:rvar x7)
+ (r1cs:rvar x8)
+ ))
+ _
+ )
+ (r1cs:rmod
+ (r1cs:rmul (list-no-order
+ (r1cs:rvar "ps1")
+ (r1cs:rvar x10)
+ ))
+ _
+ )
+ ))
+ (if (and
+ (equal? (vector-ref arg-vec 7) x7)
+ (equal? (vector-ref arg-vec 8) x8)
+ (equal? (vector-ref arg-vec 10) x10)
+ )
+ #t
+ #f
+ )
+ ]
+
+ ; ==============================
+ ; ==== finite field version ====
+ ; ==============================
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmul (list-no-order
+ (r1cs:rvar "ps1")
+ (r1cs:rvar x7)
+ (r1cs:rvar x8)
+ ))
+ (r1cs:rmul (list-no-order
+ (r1cs:rvar "ps1")
+ (r1cs:rvar x10)
+ ))
+ ))
+ (if (and
+ (equal? (vector-ref arg-vec 7) x7)
+ (equal? (vector-ref arg-vec 8) x8)
+ (equal? (vector-ref arg-vec 10) x10)
+ )
+ #t
+ #f
+ )
+ ]
+
+ ; otherwise, do not rewrite
+ [_ #f]
+ )
+)
\ No newline at end of file
diff --git a/picus/algorithms/lemmas/basis2-lemma.rkt b/picus/algorithms/lemmas/basis2-lemma.rkt
new file mode 100644
index 0000000..1f5c985
--- /dev/null
+++ b/picus/algorithms/lemmas/basis2-lemma.rkt
@@ -0,0 +1,210 @@
+#lang racket
+; this implements the basis-2 lemma (similar to Ecne Rule 3/5):
+; if z = 2^0 * x0 + 2^1 * x1 + ... + 2^n * xn, and x0, x1, ..., xn are all in {0,1}
+; then if z is uniquely determined, so as x0, x1, ..., xn
+; this requires p1cnsts
+(require
+ (prefix-in config: "../../config.rkt")
+ (prefix-in tokamak: "../../tokamak.rkt")
+ (prefix-in r1cs: "../../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [apply-lemma apply-lemma]
+))
+
+; recursively apply linear lemma
+(define (apply-lemma ks us p1cnsts range-vec)
+ (printf " # propagation (basis2 lemma): ")
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+
+ (set!-values (tmp-ks tmp-us) (process tmp-ks tmp-us p1cnsts range-vec))
+ (let ([s0 (set-subtract tmp-ks ks)])
+ (if (set-empty? s0)
+ (printf "none.\n")
+ (printf "~a added.\n" s0)
+ )
+ )
+
+ ; apply once is enough, return
+ (values tmp-ks tmp-us)
+)
+
+(define basis2-seqs (for/set ([i (range 270)])
+ (for/set ([j (range (+ 1 i))])
+ (expt 2 j)
+ )
+))
+
+(define (extract-signal-id x) (string->number (substring x 1)))
+(define (ffsub v) (- config:p v))
+
+(define (all-binary01? range-vec sids)
+ (if (null? sids)
+ #t
+ (let ([sid (car sids)][sids-rest (cdr sids)])
+ (if (set? (vector-ref range-vec sid))
+ ; it's a set, then chec set value
+ (cond
+ [(or
+ (equal? (set 0 1) (vector-ref range-vec sid))
+ (equal? (set 0) (vector-ref range-vec sid))
+ (equal? (set 1) (vector-ref range-vec sid))
+ )
+ (all-binary01? range-vec sids-rest)
+ ]
+ [else #f]
+ )
+ ; not a set, then no
+ #f
+ )
+ )
+ )
+)
+
+(define (process ks us arg-r1cs range-vec)
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+ (for ([obj (r1cs:rcmds-vs arg-r1cs)])
+ (match obj
+
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+ ; pattern: 0 = a0x0 + a1x1 + ... + anxn + x
+ ; use vs here since there's also ps1/ps2/ps4 that could fall into the loop
+ ; so it could be (rvar "ps1") or (rint 2^n)
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x0)
+ (r1cs:rmul (list-no-order vs (r1cs:rvar xs))) ...
+ ))
+ _
+ )
+ ))
+ ; (fixme) vs could be matched to x?? since it's not typed in the pattern
+ ; need a procedure to adjust this
+ ; (printf "matched.\n")
+ ; (when (equal? x0 "x2059")
+ ; (printf "x2059 matched.\n")
+ ; (printf "vs: ~a\n" vs)
+ ; (printf "xs: ~a\n" xs)
+ ; )
+ (set!-values (tmp-ks tmp-us) (update tmp-ks tmp-us x0 vs xs range-vec))
+ ]
+ ; flip
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x0)
+ (r1cs:rmul (list-no-order vs (r1cs:rvar xs))) ...
+ ))
+ _
+ )
+ (r1cs:rvar "zero")
+ ))
+ (set!-values (tmp-ks tmp-us) (update tmp-ks tmp-us x0 vs xs range-vec))
+ ]
+
+ ; ==============================
+ ; ==== finite field version ====
+ ; ==============================
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x0)
+ (r1cs:rmul (list-no-order vs (r1cs:rvar xs))) ...
+ ))
+ ))
+ (set!-values (tmp-ks tmp-us) (update tmp-ks tmp-us x0 vs xs range-vec))
+ ]
+ ; flip
+ [(r1cs:rassert (r1cs:req
+ (r1cs:radd (list-no-order
+ (r1cs:rvar x0)
+ (r1cs:rmul (list-no-order vs (r1cs:rvar xs))) ...
+ ))
+ (r1cs:rvar "zero")
+ ))
+ (set!-values (tmp-ks tmp-us) (update tmp-ks tmp-us x0 vs xs range-vec))
+ ]
+
+ ; otherwise, do not rewrite
+ [_ (void)]
+ )
+ )
+ (values tmp-ks tmp-us)
+)
+
+(define (update ks us x0 vs xs range-vec)
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+ ; extract coefficients
+ ; need to remap by calling p-v since they are all in form of pv
+ ; when moved to the other side they become v
+ (define coelist (for/list ([v vs])
+ (match v
+ [(r1cs:rvar "ps1") (- config:p 1)]
+ [(r1cs:rvar "ps2") (- config:p 2)]
+ [(r1cs:rvar "ps4") (- config:p 4)]
+ [(r1cs:rint z) z]
+ [_ (tokamak:exit "unsupported coefficient, got: ~a" v)]
+ )
+ ))
+ (define coelist2 (for/list ([v vs])
+ (match v
+ [(r1cs:rvar "ps1") (ffsub (- config:p 1))]
+ [(r1cs:rvar "ps2") (ffsub (- config:p 2))]
+ [(r1cs:rvar "ps4") (ffsub (- config:p 4))]
+ [(r1cs:rint z) (ffsub z)]
+ [_ (tokamak:exit "unsupported coefficient, got: ~a" v)]
+ )
+ ))
+ (define coeset (list->set coelist))
+ (define coeset2 (list->set coelist2))
+ (define siglist (for/list ([x xs]) (extract-signal-id x)))
+ (cond
+ [(= (length coelist) (set-count coeset))
+ ; (printf "hi: ~a\n" (set-member? basis2-seqs coeset))
+ ; (printf "coeset2 ~a\n" coeset2)
+ ; (when (equal? x0 "x2059")
+ ; (printf "coeset2: ~a\n" coeset2)
+ ; (printf "siglist: ~a\n" siglist)
+ ; )
+ (if (or (set-member? basis2-seqs coeset) (set-member? basis2-seqs coeset2))
+ ; yes it's a basis sequence
+ ; check for signal ranges
+ (if (all-binary01? range-vec siglist)
+ ; good, all binary01
+ ; check if the target signal is already unique
+ (if (set-member? ks (extract-signal-id x0))
+ ; yes it's unique, then add all basis signals to known set
+ (begin
+ (set! tmp-ks (set-union tmp-ks (list->set siglist)))
+ (set! tmp-us (set-remove tmp-us (list->set siglist)))
+ ; (when (equal? x0 "x2059")
+ ; (printf "succeed.\n")
+ ; (printf "old ks: ~a\n" ks)
+ ; (printf "tmp ks: ~a\n" tmp-ks)
+ ; )
+ )
+ ; no
+ (void)
+ )
+ ; no good
+ (void)
+ )
+ ; not a basis sequence
+ (void)
+ )
+ ]
+ [else
+ ; there are duplicate numbers, can't apply basis lemma, skip
+ ; (note) duplicate variables are acceptable, but duplicate bases ar enot
+ (void)
+ ]
+ )
+ (values tmp-ks tmp-us)
+)
\ No newline at end of file
diff --git a/picus/algorithms/lemmas/bim-lemma.rkt b/picus/algorithms/lemmas/bim-lemma.rkt
new file mode 100644
index 0000000..fd972b2
--- /dev/null
+++ b/picus/algorithms/lemmas/bim-lemma.rkt
@@ -0,0 +1,161 @@
+#lang racket
+; this implements the big-int-mul lemma
+; Ax - b = 0
+; if A is constant squared matrix, det(A) != 0, and b is unique
+; then x is unique
+; (fixme) one-take implementation, you need a big fix on this
+; (fixme) this impelements a special case where b = 0
+(require math
+ (prefix-in config: "../../config.rkt")
+ (prefix-in tokamak: "../../tokamak.rkt")
+ (prefix-in r1cs: "../../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [apply-lemma apply-lemma]
+))
+
+; recursively apply linear lemma
+(define (apply-lemma ks us p1cnsts range-vec)
+ (printf " # propagation (aboz lemma): ")
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+
+ (set!-values (tmp-ks tmp-us) (process tmp-ks tmp-us p1cnsts range-vec))
+ (let ([s0 (set-subtract tmp-ks ks)])
+ (if (set-empty? s0)
+ (printf "none.\n")
+ (printf "~a added.\n" s0)
+ )
+ )
+
+ ; apply once is enough, return
+ (values tmp-ks tmp-us)
+)
+
+(define (extract-signal-id x) (string->number (substring x 1)))
+(define (signal? x) (or (string-prefix? x "x") (string-prefix? x "y")))
+(define (extract-constant x)
+ (cond
+ [(equal? x "p") config:p]
+ [(equal? x "ps1") (- config:p 1)]
+ [(equal? x "ps2") (- config:p 2)]
+ [(equal? x "ps3") (- config:p 3)]
+ [(equal? x "ps4") (- config:p 4)]
+ [(equal? x "ps5") (- config:p 5)]
+ [(equal? x "zero") 0]
+ [(equal? x "one") 1]
+ [else (tokamak:exit "unsupported constant, got: ~a" x)]
+ )
+)
+
+(define (process ks us arg-r1cs range-vec)
+ (define tmp-ks (list->set (set->list ks)))
+ (define tmp-us (list->set (set->list us)))
+ (define eqs (list ))
+ (for ([v (r1cs:rcmds-vs arg-r1cs)])
+ (define res (match-single v))
+ (when (list? res)
+ (set! eqs (cons res eqs))
+ )
+ )
+ ; (printf "# [debug] eqs is: ~a\n" (reverse eqs))
+ ; sort and construct matrix
+ (define eqmaps (make-vector (length eqs) null))
+ (define smap (make-hash))
+ (for ([i (range (length eqs))])
+ (vector-set! eqmaps i (make-hash (list-ref eqs i)))
+ (for ([p (list-ref eqs i)])
+ (when (not (hash-has-key? smap (car p)))
+ (hash-set! smap (car p) (hash-count smap)))
+ )
+ )
+ (define slist (hash-values smap))
+ (define nrow (vector-length eqmaps))
+ (define ncol (hash-count smap))
+ ; (printf "# [debug] row: ~a, col: ~a\n" (vector-length eqmaps) (hash-count smap))
+ ; (printf "# [debug] smaps is ~a\n" smaps)
+ (cond
+ [(and (equal? nrow ncol) (> nrow 0))
+ ; construct A matrix
+ (define Amtx (build-matrix nrow ncol (lambda (r c)
+ (let ([em0 (vector-ref eqmaps r)][sig0 (list-ref slist c)])
+ (if (hash-has-key? em0 sig0) (hash-ref em0 sig0) 0)
+ )
+ )))
+ (define det (matrix-determinant Amtx))
+ (when (not (equal? 0 det))
+ (set! tmp-ks (set-union tmp-ks (list->set slist)))
+ (set! tmp-us (set-subtract tmp-us (list->set slist)))
+ )
+ ]
+ ; else do nothing since it's not a squared matrix
+ )
+ (values tmp-ks tmp-us)
+)
+
+; match 0 = a * x0 + ... + c * xn form
+; extract list of pairs of (coefficient signal-id)
+(define (match-single arg-obj)
+ (match arg-obj
+
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rmod (r1cs:radd (list vs ...)) (r1cs:rvar "p"))
+ ))
+ ; top level match, go to match smaller ones
+ (define res (for/list ([v vs]) (extract-pairs v)))
+ (if (set-member? (list->set res) #f)
+ #f
+ res
+ )
+ ]
+
+ ; ==================================
+ ; ==== finite field version ====
+ ; ==================================
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:radd (list vs ...))
+ ))
+ ; top level match, go to match smaller ones
+ (define res (for/list ([v vs]) (extract-pairs v)))
+ (if (set-member? (list->set res) #f)
+ #f
+ res
+ )
+ ]
+
+ ; otherwise, do not rewrite
+ [_ #f]
+ )
+)
+
+; pair is (signal-id coefficient)
+(define (extract-pairs arg-obj)
+ (match arg-obj
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+ [(r1cs:rvar x)
+ (if (signal? x)
+ ; coefficient is one
+ (cons (extract-signal-id x) 1)
+ ; not a signal, this is probably a named constant, abort
+ #f
+ )
+
+ ]
+ [(r1cs:rmul (list (r1cs:rvar c) (r1cs:rvar x)))
+ (if (and (not (signal? c)) (signal? x))
+ ; correct format
+ (cons (extract-signal-id x) (extract-constant c))
+ ; incorrect format, give up
+ #f
+ )
+ ]
+ [_ #f]
+ )
+)
\ No newline at end of file
diff --git a/picus/algorithms/lemmas/binary01-lemma.rkt b/picus/algorithms/lemmas/binary01-lemma.rkt
new file mode 100644
index 0000000..39af9c7
--- /dev/null
+++ b/picus/algorithms/lemmas/binary01-lemma.rkt
@@ -0,0 +1,305 @@
+#lang racket
+; this implements the binary lemma (similar to Ecne Rule 2a):
+; if (x-a)*(x-b)=0, then x \in {a,b}; namely if {a,b}={0,1}, then x \in {0,1}
+; this requires p1cnsts
+; (note) this lemma currently only applies to {a,b}={0,1}, add support for other values if necessary later
+; (note) this lemma requires ab0 optimization first, applies on p1cnsts
+(require
+ (prefix-in config: "../../config.rkt")
+ (prefix-in tokamak: "../../tokamak.rkt")
+ (prefix-in r1cs: "../../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [apply-lemma apply-lemma]
+))
+
+; recursively apply linear lemma
+(define (apply-lemma ks us p1cnsts range-vec)
+ (printf " # propagation (binary01 lemma): ")
+ (define new-ks (list->set (set->list ks)))
+ (define new-us (list->set (set->list us)))
+
+ (process p1cnsts range-vec)
+
+ ; for signals with only 1 value, they are already unique
+ ; (note) but we also need to check for signals that have no valid values, which may be compilation error
+ (for ([sid (range (vector-length range-vec))])
+ (when (set? (vector-ref range-vec sid))
+ (cond
+ [(equal? 0 (set-count (vector-ref range-vec sid)))
+ (tokamak:exit "range-vec has 0 candidate values, got ~a for signal ~a" (vector-ref range-vec sid) sid)
+ ]
+ ; (fixme) is this valid?
+ [(equal? 1 (set-count (vector-ref range-vec sid)))
+ ; good, this is unique
+ (set! new-ks (set-add new-ks sid))
+ (set! new-us (set-remove new-us sid))
+ ]
+ [else (void)] ; else do nothing
+ )
+ )
+ )
+ (let ([s0 (set-subtract new-ks ks)])
+ (if (set-empty? s0)
+ (printf "none.\n")
+ (printf "~a added.\n" s0)
+ )
+ )
+ ; apply once is enough, return
+ (values new-ks new-us)
+)
+
+(define (override!-range range-vec sid rng)
+ (cond
+ [(equal? 'bottom (vector-ref range-vec sid))
+ ; bottom, update the range
+ (vector-set! range-vec sid rng)
+ ]
+ [(set? (vector-ref range-vec sid))
+ ; a set, get interssection
+ (vector-set! range-vec sid (set-intersect (vector-ref range-vec sid) rng))
+ ]
+ [else (tokamak:exit "unsupported range-vec value, got: ~a\n" (vector-ref range-vec sid))]
+ )
+)
+
+(define (extract-signal-id x) (string->number (substring x 1)))
+
+; actual matching funtion of the lemma
+; we are looking for expanded forms of (x-0)(x-1)=0 (also: x*(x+p1)=0), which is e.g.,:
+; - (assert (= (rem (+ (* ps1 y639) (* y639 y639)) p) zero)) --> not captured by ab0
+; - (assert (or (= zero (ff.add ps1 x701)) (= zero x701))) --> captured by ab0
+; need to consider grammar of finite field and non finite field
+(define (process arg-r1cs range-vec)
+ (define vs (r1cs:rcmds-vs arg-r1cs))
+ (for ([i (range (length vs))])
+ (define obj (list-ref vs i))
+ (match obj
+
+ ; ==================================
+ ; ==== non finite field version ====
+ ; ==================================
+
+ ; - (assert (= (rem (+ (* ps1 y639) (* y639 y639)) p) zero))
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rmul (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ (r1cs:rmul (list (r1cs:rvar x1) (r1cs:rvar x1)))
+ ))
+ _
+ )
+ (r1cs:rvar "zero")
+ ))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#1
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rmod
+ (r1cs:radd (list-no-order
+ (r1cs:rmul (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ (r1cs:rmul (list (r1cs:rvar x1) (r1cs:rvar x1)))
+ ))
+ _
+ )
+ ))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+
+ ; (assert (or (= zero (ff.add ps1 x701)) (= zero x701)))
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rmod
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ _
+ )
+ )
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rvar x1)
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#1
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rmod
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ _
+ )
+ )
+ (r1cs:req
+ (r1cs:rvar x1)
+ (r1cs:rvar "zero")
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#2
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:rmod
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ _
+ )
+ (r1cs:rvar "zero")
+ )
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rvar x1)
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#3
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:rmod
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ _
+ )
+ (r1cs:rvar "zero")
+ )
+ (r1cs:req
+ (r1cs:rvar x1)
+ (r1cs:rvar "zero")
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+
+ ; ==============================
+ ; ==== finite field version ====
+ ; ==============================
+
+ ; - (assert (= (rem (+ (* ps1 y639) (* y639 y639)) p) zero))
+ [(r1cs:rassert (r1cs:req
+ (r1cs:radd (list-no-order
+ (r1cs:rmul (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ (r1cs:rmul (list (r1cs:rvar x1) (r1cs:rvar x1)))
+ ))
+ (r1cs:rvar "zero")
+ ))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#1
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:radd (list-no-order
+ (r1cs:rmul (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ (r1cs:rmul (list (r1cs:rvar x1) (r1cs:rvar x1)))
+ ))
+ ))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+
+ ; (assert (or (= zero (ff.add ps1 x701)) (= zero x701)))
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ )
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rvar x1)
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#1
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ )
+ (r1cs:req
+ (r1cs:rvar x1)
+ (r1cs:rvar "zero")
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#2
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ (r1cs:rvar "zero")
+ )
+ (r1cs:req
+ (r1cs:rvar "zero")
+ (r1cs:rvar x1)
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+ ; flip#3
+ [(r1cs:rassert (r1cs:ror (list-no-order
+ (r1cs:req
+ (r1cs:radd (list-no-order (r1cs:rvar "ps1") (r1cs:rvar x0)))
+ (r1cs:rvar "zero")
+ )
+ (r1cs:req
+ (r1cs:rvar x1)
+ (r1cs:rvar "zero")
+ )
+ )))
+ ; signal x is bounded to {0,1}, extract signal number
+ (when (equal? x0 x1)
+ ; (printf "binary01 add: ~a\n" x0)
+ (override!-range range-vec (extract-signal-id x0) (list->set (list 0 1)))
+ )
+ ]
+
+ ; otherwise, do not rewrite
+ [_ (void)]
+ )
+ )
+)
\ No newline at end of file
diff --git a/picus/algorithms/lemmas/copy-lemma.rkt b/picus/algorithms/lemmas/copy-lemma.rkt
new file mode 100644
index 0000000..6833ec4
--- /dev/null
+++ b/picus/algorithms/lemmas/copy-lemma.rkt
@@ -0,0 +1,13 @@
+#lang racket
+; this implements the rangecopy lemma (similar to Ecne Rule 4a)
+; this will copy both the uniqueness status and ranges
+(require
+ (prefix-in config: "../../config.rkt")
+ (prefix-in tokamak: "../../tokamak.rkt")
+ (prefix-in r1cs: "../../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [apply-lemma apply-lemma]
+))
+
+; (todo) add later
\ No newline at end of file
diff --git a/picus/algorithms/lemmas/linear-lemma.rkt b/picus/algorithms/lemmas/linear-lemma.rkt
new file mode 100644
index 0000000..fca5d16
--- /dev/null
+++ b/picus/algorithms/lemmas/linear-lemma.rkt
@@ -0,0 +1,112 @@
+#lang racket
+; this implements the linear lemma:
+; if c * x = (unique), and c != 0 is a constant, then x is also uniquely determined
+; note that this lemma doesn't apply to the following:
+; c * x0 * x1 = (unique), and c * x0 != 0
+(require
+ (prefix-in r1cs: "../../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [compute-cdmap compute-cdmap]
+ [compute-rcdmap compute-rcdmap]
+ [apply-lemma apply-lemma]
+))
+
+; global variable, cached rcdmap
+; store and ref with tag (key)
+(define :cached-rcdmaps (make-hash))
+
+; get constraint dependency map
+; input is the *normalized main constraint part* of r1cs ast
+; - main constraints is the `cnsts part (r1cs:rcmds) from parse-r1cs
+; returns a map of:
+; - key: index of a variable
+; - val: list of sets of variables
+; meaning: if a key wants to be determined as unique,
+; one of the sets from val should be completely determined
+; construction rules (++terms):
+; - only non-non-linear (YES, no typo here) variable can be determined (put to key)
+; because for x*y=k, x can't be guaranteed to be unique,
+; even if knowing y and k (due to field mul)
+(define (compute-cdmap arg-cnsts [arg-indexonly #f])
+ (define res (make-hash))
+ ; for every single constraint
+ (for ([p (r1cs:rcmds-vs arg-cnsts)])
+ (define all-vars (r1cs:get-assert-variables p arg-indexonly))
+ (define nonlinear-vars (r1cs:get-assert-variables/nonlinear p arg-indexonly))
+ ; (note) you can't use linears directly, because one var could be both linear and non-linear
+ ; in this case, it's still non-linear in the current constraint
+ (define deducible-vars (set-subtract all-vars nonlinear-vars))
+ (for ([key deducible-vars])
+ (when (not (hash-has-key? res key)) (hash-set! res key (list )))
+ (hash-set! res key (cons (set-subtract all-vars (list->set (list key))) (hash-ref res key)))
+ )
+ )
+ res
+)
+
+; get a reversed cdmap
+; - arg-indexonly: whether to extract the indices instead of keeping the full variable name
+; example output:
+; # => #
+; # => #
+; # => #
+; # => #
+; # => #
+; # => #
+; # => #
+; # => #
+; # => #
+(define (compute-rcdmap arg-cnsts [arg-indexonly #f] [arg-tag 'default])
+ (cond
+ ; there's a cached version for the given tag, no more computation, just fetch & return
+ [(hash-has-key? :cached-rcdmaps arg-tag) (hash-ref :cached-rcdmaps arg-tag)]
+ ; no cached version, compute, cache and return
+ [else
+ (define res (compute-cdmap arg-cnsts arg-indexonly))
+ (define new-res (make-hash))
+ (for ([key (hash-keys res)])
+ (define vals (hash-ref res key))
+ (for ([val vals])
+ (when (not (hash-has-key? new-res val)) (hash-set! new-res val (list )))
+ (hash-set! new-res val (cons key (hash-ref new-res val)))
+ )
+ )
+ ; make immutable
+ (for ([key (hash-keys new-res)])
+ (hash-set! new-res key (list->set (hash-ref new-res key)))
+ )
+ ; store to cache
+ (hash-set! :cached-rcdmaps arg-tag new-res)
+ ; return
+ new-res
+ ]
+ )
+)
+
+; recursively apply linear lemma
+(define (apply-lemma rcdmap ks us)
+ (printf " # propagation (linear lemma): ")
+ (define new-ks (list->set (set->list ks))) ; (fixme) do this to copy into a mutable set, required by set-* operations
+ (define new-us (list->set (set->list us))) ; (fixme) same as above
+ (define rec? #f) ; whether propagate should be called again
+ (for* ([key (hash-keys rcdmap)])
+ (when (set-empty? (set-subtract key ks))
+ ; all ks are in key, propagate
+ (set! new-ks (set-union new-ks (hash-ref rcdmap key)))
+ (set! new-us (set-subtract new-us (hash-ref rcdmap key)))
+ )
+ )
+ (let ([s0 (set-subtract new-ks ks)])
+ (if (set-empty? s0)
+ (printf "none.\n")
+ (printf "~a added.\n" s0)
+ )
+ )
+ (if (= (set-count ks) (set-count new-ks))
+ ; no updates, return now
+ (values new-ks new-us)
+ ; has updates, call again
+ (apply-lemma rcdmap new-ks new-us)
+ )
+)
\ No newline at end of file
diff --git a/picus/algorithms/selector.rkt b/picus/algorithms/selector.rkt
new file mode 100644
index 0000000..487d4f2
--- /dev/null
+++ b/picus/algorithms/selector.rkt
@@ -0,0 +1,35 @@
+#lang racket
+; switcher for selector related components
+(require json
+ (prefix-in tokamak: "../tokamak.rkt")
+ ; selectors
+ (prefix-in first: "./selectors/first-selector.rkt")
+ (prefix-in counter: "./selectors/counter-selector.rkt")
+)
+(provide (rename-out
+ [apply-selector apply-selector]
+ [selector-feedback selector-feedback]
+ [selector-init selector-init]
+))
+
+(define (apply-selector arg-selector)
+ (cond
+ [(equal? "first" arg-selector) first:apply-selector]
+ [(equal? "counter" arg-selector) counter:apply-selector]
+ [else (tokamak:exit "unsupported selector: ~a." arg-selector)]
+ )
+)
+(define (selector-feedback arg-selector)
+ (cond
+ [(equal? "first" arg-selector) first:selector-feedback]
+ [(equal? "counter" arg-selector) counter:selector-feedback]
+ [else (tokamak:exit "unsupported selector: ~a." arg-selector)]
+ )
+)
+(define (selector-init arg-selector)
+ (cond
+ [(equal? "first" arg-selector) first:selector-init]
+ [(equal? "counter" arg-selector) counter:selector-init]
+ [else (tokamak:exit "unsupported selector: ~a." arg-selector)]
+ )
+)
\ No newline at end of file
diff --git a/picus/algorithms/selectors/counter-selector.rkt b/picus/algorithms/selectors/counter-selector.rkt
new file mode 100644
index 0000000..5497637
--- /dev/null
+++ b/picus/algorithms/selectors/counter-selector.rkt
@@ -0,0 +1,68 @@
+#lang racket
+(provide (rename-out
+ [apply-selector apply-selector]
+ [selector-init selector-init]
+ [selector-feedback selector-feedback]
+))
+
+; shared stateful variables and methods
+; signal weights
+(define signal-weights null)
+(define (signal-weights-reset!) (set! signal-weights (make-hash)))
+(define (signal-weights-set! k v) (hash-set! signal-weights k v))
+(define (signal-weights-ref k) (hash-ref signal-weights k))
+(define (signal-weights-inc! k v) (hash-set! signal-weights k (+ (hash-ref signal-weights k) v)))
+(define (signal-weights-dec! k v) (hash-set! signal-weights k (- (hash-ref signal-weights k) v)))
+
+; =======================
+; counter select strategy
+; choose the signal that appears the most in the keys of rcdmap
+; i.e. the most "critical" one for propagation
+(define state-rcdkey-counter null) ; cached rcdkey counter, key: index, val: count
+; key first select: select the key with higher appearance in rcdmap
+(define (apply-selector uspool cntx)
+ ; check for existence of counter
+ (when (null? state-rcdkey-counter)
+ ; counter not created yet, create one
+ (define tmp-counter (make-hash))
+ (for ([keys (hash-keys (hash-ref cntx 'rcdmap))])
+ (for ([key keys])
+ (when (not (hash-has-key? tmp-counter key)) (hash-set! tmp-counter key 0))
+ (hash-set! tmp-counter key (+ 1 (hash-ref tmp-counter key)))
+ )
+ )
+ (set! state-rcdkey-counter tmp-counter)
+ )
+ ; copy the counter and filter out non uspool ones
+ (define tmp-counter (make-hash))
+ (for ([key (hash-keys state-rcdkey-counter)])
+ (when (set-member? uspool key)
+ ; copy and calculate the weight
+ (hash-set! tmp-counter key
+ (+ (hash-ref state-rcdkey-counter key) (signal-weights-ref key))
+ )
+ )
+ )
+ ; add remaining uspool ones into the counter
+ (for ([key uspool])
+ (when (not (hash-has-key? tmp-counter key)) (hash-set! tmp-counter key 0)))
+ ; sort and pick
+ (define p0 (argmax cdr (hash->list tmp-counter)))
+ ; return
+ (car p0)
+)
+
+(define (selector-init nwires)
+ (signal-weights-reset!)
+ (for ([key (range nwires)]) (signal-weights-set! key 0))
+)
+
+; adjust internal states according to the solver result
+(define (selector-feedback sid act)
+ (cond
+ ; decrease the weight of the selected id since it's not solved
+ [(equal? 'skip act) (signal-weights-dec! sid 1)]
+ ; otherwise do nothing
+ [else (void)]
+ )
+)
\ No newline at end of file
diff --git a/picus/algorithms/selectors/first-selector.rkt b/picus/algorithms/selectors/first-selector.rkt
new file mode 100644
index 0000000..272eb99
--- /dev/null
+++ b/picus/algorithms/selectors/first-selector.rkt
@@ -0,0 +1,12 @@
+#lang racket
+(provide (rename-out
+ [apply-selector apply-selector]
+ [selector-init selector-init]
+ [selector-feedback selector-feedback]
+))
+
+; naive select strategy
+; simply choose the first signal from the pool
+(define (apply-selector uspool cntx) (set-first uspool))
+(define (selector-init nwires) (void))
+(define (selector-feedback sid act) (void))
\ No newline at end of file
diff --git a/picus/circom-vm.rkt b/picus/circom-vm.rkt
deleted file mode 100644
index 956b7d5..0000000
--- a/picus/circom-vm.rkt
+++ /dev/null
@@ -1,1061 +0,0 @@
-; (fixme) this file is outdated
-#lang rosette
-(require rosette/lib/destruct) ; match syntax in rosette
-(require "./tokamak.rkt")
-(require "./mhash.rkt")
-(require "./utils.rkt")
-(require "./config.rkt")
-(require "./circom-grammar.rkt")
-(provide (all-defined-out))
-
-(define circom-vm%
- (class object%
- (super-new)
- (field
- [variable-book null] ; variable book is the top-level scope
- [template-book null] ; stores all templates and functions
- [circom-root null] ; the top-level node, if you want to start, go with the list of components
- [builtin-operators null] ; stores all builtin operators
-
- ; stateful members
- [input-book null] ; hash mapping from string to symbolic variable
- [output-book null] ; hash mapping from string to symbolic variable
- [intermediate-book null] ; hash mapping from string to symbolic variable
-
- ; constants
- [bv-zero (bv 0 config:bvtyp)]
- [bv-one (bv 1 config:bvtyp)]
- [bv-two (bv 2 config:bvtyp)]
- )
-
- ; also do initializations
- ; (concrete:top) arg-node
- (define/public (deploy arg-node arg-init)
- (when arg-init
- (set! variable-book (make-mhash config:cap))
- (set! template-book (make-hash))
- (init-builtin-operators); initialize all builtin operators
- )
- (do-deploy arg-node)
- )
-
- ; store all the templates into template book
- ; (concrete:top) arg-node
- (define (do-deploy arg-node)
- (destruct arg-node
- [(circom:circom m-meta m-ver m-incs m-defs m-main)
- ; set root node
- (set! circom-root arg-node)
- ; continue to find out all template definitions
- (for ([node0 m-defs])
- (do-deploy node0)
- )
- ]
-
- ; pass on
- [(circom:definition v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 circom:template? circom:function?)
- (do-deploy v)
- )
- ]
-
- [(circom:template m-meta m-name m-args m-argloc m-body m-parallel)
- ; add template definition
- (hash-set! template-book m-name arg-node)
- ]
-
- [(circom:function m-meta m-name m-args m-argloc m-body)
- ; add function definition
- (hash-set! template-book m-name arg-node)
- ]
-
- [_ (tokamak:exit "[do-deploy] unsupported node, got: ~a." arg-node)]
- )
- )
-
- ; (concrete:top) arg-node
- (define/public (interpret arg-node arg-init)
- ; first clear all stateful vars
- (when arg-init
- (set! input-book (make-hash))
- (set! output-book (make-hash))
- (set! intermediate-book (make-hash))
- )
- (do-interpret arg-node (list variable-book) "" "")
- )
-
- ; (concrete:top) arg-node
- ; (symbolic:top) arg-scopes: a stacked list of scopes
- ; (symbolic:top) arg-prefix: the prefix attached to every variable interacted (esp. when applied to template)
- ; (symbolic:top) arg-cprx: (call prefix) for fetching the argument in the correct scope
- ; when assignment to a component, a call need to append a scope, but when fetching arguments
- ; it should still use the old prefix
- ; e.g., component lt = LessThan(n), "lt" should be appended, but "n" the argument come without "lt"
- ; main.lt.??, but main.n should be fetched before entering LessThan
- ; (note) only declstmt with 'comp and call related operation need to modify this field
- ; otherwise, just inherit and ignore
- (define (do-interpret arg-node arg-scopes arg-prefix arg-cprx)
- (tokamak:typed arg-node circom:lang?)
-
- ; still use destruct to not lose track of vc
- (destruct arg-node
-
- [(circom:setype v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 symbol?)
- (tokamak:typed v0 circom:setype:terminal?)
-
- v0
- )
- ]
-
- [(circom:stype v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 symbol?)
- (tokamak:typed v0 circom:stype:terminal?)
-
- v0
- )
- ]
-
- [(circom:signal first second)
- (for*/all ([first0 first #:exhaustive] [second0 second #:exhaustive])
- (tokamak:typed first0 circom:stype?)
- (tokamak:typed second0 circom:setype?)
-
- (define tmp-first (do-interpret first0 arg-scopes arg-prefix arg-cprx))
- (define tmp-second (do-interpret second0 arg-scopes arg-prefix arg-cprx))
- (for*/all ([first1 tmp-first #:exhaustive] [second1 tmp-second #:exhaustive])
- (tokamak:typed first1 symbol?)
- (tokamak:typed second1 symbol?)
-
- ; return
- (cons first1 second1)
- )
- )
- ]
-
- [(circom:vtype v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 symbol? circom:signal?)
-
- (cond
- [(symbol? v0) v0]
- [(circom:signal? v0) (do-interpret v0 arg-scopes arg-prefix arg-cprx)]
- [else (tokamak:exit "[do-interpret] you can't reach here.")]
- )
- )
- ]
-
- [(circom:access v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 string? circom:expression?)
- ; cond and return
- (cond
- [(string? v0) v0] ; direct return
- [(circom:expression? v0)
- ; get the value
- (do-interpret v0 arg-scopes arg-prefix arg-cprx)
- ]
- )
- )
- ]
-
- [(circom:assignop v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 symbol?)
- (tokamak:typed v0 circom:assignop:terminal?)
-
- v0
- )
- ]
-
- [(circom:infixop v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 symbol?)
- (tokamak:typed v0 circom:infixop:terminal?)
-
- v0
- )
- ]
-
- [(circom:prefixop v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 symbol?)
- (tokamak:typed v0 circom:prefixop:terminal?)
-
- v0
- )
- ]
-
- [(circom:circom m-meta m-ver m-incs m-defs m-main)
- (for/all ([main0 m-main #:exhaustive])
- (tokamak:typed main0 circom:component? null?)
-
- (cond
- [(null? main0) (void)] ; do nothing
- [else (do-interpret main0 arg-scopes arg-prefix arg-cprx)]
- )
- )
- ]
-
- [(circom:component m-public m-call)
- ; just execute the expression in m-call
- (for*/all ([call0 m-call #:exhaustive] [prefix0 arg-prefix #:exhaustive])
- (tokamak:typed call0 circom:expression?)
- (tokamak:typed prefix0 string?)
-
- ; (fixme) the prefix seems to only be "main.", otherwise circom complains
- (do-interpret call0 arg-scopes prefix0 (string-append prefix0 "main")) ; top level doesn't need a dot
- )
- ]
-
- [(circom:template m-meta m-name m-args m-argloc m-body m-parallel)
- (tokamak:exit "[do-interpret] [template.0] a template node should not be directly interpreted.")
- ]
-
- ; pass on
- [(circom:statement v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 circom:itestmt? circom:whilestmt? circom:retstmt? circom:declstmt? circom:substmt?
- circom:ceqstmt? circom:logcallstmt? circom:assertstmt? circom:initblock? circom:block?)
-
- (do-interpret v0 arg-scopes arg-prefix arg-cprx)
- )
- ]
-
- [(circom:itestmt m-meta m-cond m-if m-else)
- (for*/all ([cond0 m-cond #:exhaustive] [if0 m-if #:exhaustive] [else0 m-else #:exhaustive])
- (tokamak:typed cond0 circom:expression?)
- (tokamak:typed if0 circom:statement?)
- (tokamak:typed else0 circom:statement? null?)
-
- (define tmp-cond (do-interpret cond0 arg-scopes arg-prefix arg-cprx))
- (for/all ([cond1 tmp-cond #:exhaustive])
- ; (note) for if, this can be symbolic
- (tokamak:typed cond1 boolean?)
-
- (cond
- [cond1
- ; cond is true, go to if branch
- (do-interpret if0 arg-scopes arg-prefix arg-cprx)
- ]
- [else
- ; cond is false, go to else branch
- (cond
- [(null? else0) (void)] ; else branch is empty
- [else (do-interpret else0 arg-scopes arg-prefix arg-cprx)]
- )
- ]
- )
- )
- )
- ]
-
- ; (note) it seems that the while construct here doesn't open up new scope
- [(circom:whilestmt m-meta m-cond m-stmt)
- (for*/all ([cond0 m-cond #:exhaustive] [stmt0 m-stmt #:exhaustive])
- (tokamak:typed cond0 circom:expression?)
- (tokamak:typed stmt0 circom:statement?)
-
- ; define a recursive loop
- (define (do-while lscopes lprefix lcprx)
- (define tmp-cond (do-interpret cond0 lscopes lprefix lcprx))
- (for/all ([cond1 tmp-cond #:exhaustive])
- ; (note) this has to be both concrete and boolean
- (tokamak:typed cond1 concrete?)
- (tokamak:typed cond1 boolean?)
-
- (cond
- [cond1
- ; cond is true, go to statement
- (do-interpret stmt0 lscopes lprefix lcprx)
- (do-while lscopes lprefix lcprx)
- ]
- ; cond is false, do nothing and exit the loop
- [else (void)]
- )
- )
- )
-
- ; initiate the loop
- (do-while arg-scopes arg-prefix arg-cprx)
-
- )
- ]
-
- [(circom:retstmt m-meta m-val)
- (for*/all ([val0 m-val #:exhaustive])
- (tokamak:typed val0 circom:expression?)
- ; return
- (do-interpret val0 arg-scopes arg-prefix arg-cprx)
- )
- ]
-
- ; this creates new symbolic variables
- ; (fixme) you need to properly deal with dims
- [(circom:declstmt m-meta m-xtype m-name m-dims m-constant)
- (for*/all ([xtype0 m-xtype #:exhaustive] [name0 m-name #:exhaustive] [dims0 m-dims #:exhaustive]
- [scopes0 arg-scopes #:exhaustive] [prefix0 arg-prefix #:exhaustive] [cprx0 arg-cprx #:exhaustive])
- (tokamak:typed xtype0 circom:vtype?)
- (tokamak:typed name0 string?)
- (tokamak:typed dims0 list?)
- (tokamak:typed scopes0 list?)
- (tokamak:typed prefix0 string?)
- (tokamak:typed cprx0 string?)
-
- ; (note) if the original name0 is an inline array's identifier, register its type as 'arr
- ; as a special type to help the next substitution, and register its value as its dims in list
- ; e.g., (list 3 4) is arr[3][4]
- (when (not (null? dims0))
- (make-var scopes0 (string-append prefix0 "." name0) (get-dims scopes0 prefix0 cprx0 dims0))
- (make-var scopes0 (string-append prefix0 "." name0 "@") 'arr)
- )
-
- ; dynamically create symbolic variable
- (define dimstrs (assemble-dims scopes0 prefix0 cprx0 dims0)) ; (fixme) currently it's concrete, but it could be symbolic
- (define vnames (for/list ([ds dimstrs])
- (string-append prefix0 "." name0 ds)
- ))
-
- (define syms (for/list ([vv vnames])
- (tokamak:symbolic* (string->symbol vv) config:bvsym)
- ))
-
- ; register in the scope
- (for ([vname vnames] [sym syms])
- (make-var scopes0 vname sym)
- )
-
- ; update states
- (define v (do-interpret xtype0 scopes0 prefix0 cprx0))
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 symbol? pair?)
-
- (cond
- [(pair? v0)
- (let ([first (car v0)] [second (cdr v0)])
- (for*/all ([first0 first #:exhaustive] [second0 second #:exhaustive])
- (tokamak:typed first0 symbol?)
- (tokamak:typed second0 symbol?) ; (fixme) need to consider 2nd pos here
-
- (cond
- [(equal? 'output first0)
- (for ([vname vnames] [sym syms])
- (hash-set! output-book vname sym)
- )
- ; var is made before, register as 'output type
- (for ([vname vnames])
- (make-var scopes0 (string-append vname "@") 'output)
- )
- ]
- [(equal? 'input first0)
- (for ([vname vnames] [sym syms])
- (hash-set! input-book vname sym)
- )
- ; var is made before, register as 'input type
- (for ([vname vnames])
- (make-var scopes0 (string-append vname "@") 'input)
- )
- ]
- [(equal? 'intermediate first0)
- (for ([vname vnames] [sym syms])
- (hash-set! intermediate-book vname sym)
- )
- ; var is made before; var is made before, register as 'intermediate type
- (for ([vname vnames])
- (make-var scopes0 (string-append vname "@") 'intermediate)
- )
- ]
- [else (tokamak:exit "[do-interpret] [declstmt.0] unsupported first0, got: ~a." first0)]
- )
- )
- )
- ]
- [(symbol? v0)
- (cond
- [(equal? 'var v0)
- ; var is made before, register as 'var type
- (for ([vname vnames])
- (make-var scopes0 (string-append vname "@") 'var)
- )
- ]
- [(equal? 'comp v0)
- ; component is made before, register as 'comp type
- (for ([vname vnames])
- (make-var scopes0 (string-append vname "@") 'comp)
- )
- ]
- [else (tokamak:exit "[do-interpret] [declstmt.1] unsupported v0, got: ~a." v0)]
- )
- ]
- [else (tokamak:exit "[do-interpret] [declstmt.2] you can't reach here.")]
- )
- )
- )
- ]
-
- ; this creates assertions
- ; (fixme) you need to properly deal with access
- [(circom:substmt m-meta m-var m-access m-op m-rhe)
- (for*/all ([var0 m-var #:exhaustive] [access0 m-access #:exhaustive] [op0 m-op #:exhaustive]
- [rhe0 m-rhe #:exhaustive] [scopes0 arg-scopes #:exhaustive] [prefix0 arg-prefix #:exhaustive]
- [cprx0 arg-cprx #:exhaustive])
- (tokamak:typed var0 string?)
- (tokamak:typed access0 list?)
- (tokamak:typed op0 circom:assignop?)
- (tokamak:typed rhe0 circom:expression?)
- (tokamak:typed scopes0 list?)
- (tokamak:typed prefix0 string?)
- (tokamak:typed cprx0 string?)
-
- (define tmp-accstr (assemble-access scopes0 prefix0 cprx0 access0))
- (define tmp-var (string-append prefix0 "." var0 tmp-accstr)) ; don't forget the prefix
- (define tmp-op (do-interpret op0 scopes0 prefix0 cprx0))
-
- ; (fixme) maybe there's better way
- ; if tmp-var is a component, then rhe needs to append a prefix when interpreting
- (define tmp-vtype (read-var scopes0 (string-append tmp-var "@")))
- (tokamak:typed tmp-vtype symbol?)
- (define tmp-rhe (cond
- ; (note) if rhe0 is a call, it will need a new prefix tmp-var
- ; (fixme) this overrides/ignores the existing cprx0, is this right?
- [(equal? 'comp tmp-vtype) (do-interpret rhe0 scopes0 prefix0 tmp-var)]
-
- [(equal? 'var tmp-vtype) (do-interpret rhe0 scopes0 prefix0 cprx0)]
- [(equal? 'input tmp-vtype) (do-interpret rhe0 scopes0 prefix0 cprx0)]
- [(equal? 'output tmp-vtype) (do-interpret rhe0 scopes0 prefix0 cprx0)]
- [(equal? 'intermediate tmp-vtype) (do-interpret rhe0 scopes0 prefix0 cprx0)]
-
- ; special type from picus, array identifier for inline array
- [(equal? 'arr tmp-vtype) (do-interpret rhe0 scopes0 prefix0 cprx0)]
-
- [else (tokamak:exit "[do-interpret] [substmt.0] unsupported tmp-vtype, got: ~a." tmp-vtype)]
- ))
-
- (for/all ([op1 tmp-op #:exhaustive])
- (tokamak:typed op1 symbol?)
- ; (note) no need to decompose tmp-rhe, sicne union assertion is also acceptable
- (cond
- [(equal? 'arr tmp-vtype)
- ; inline array assignment
- (for/all ([rhe1 tmp-rhe #:exhaustive])
- (tokamak:typed rhe1 list?) ; inline array must return a list
- (cond
- [(equal? 'var op1)
- ; only support `=` symbol for now
- ; (fixme) we should properly check lengths match between var dims and rhe1 dims
- ; the current impl is not considering symbolic elem in rhe1
- (define ld (get-list-dims0 rhe1))
- (define vd (read-var scopes0 tmp-var))
- (when (not (equal? ld vd))
- (tokamak:exit "[do-interpret] [substmt.1] dims mismatch, declared: ~a, returned: ~a." vd ld))
- (define inds (apply cartesian-product (for/list ([z ld]) (range z))))
- (for ([ind inds])
- (define retv (nested-list-ref rhe1 ind))
- ; no need to add prefix since tmp-var already has prefix settled
- (define srcv (string-append
- tmp-var
- (apply string-append (for/list ([nn ind])
- (string-append "[" (number->string nn) "]")
- ))
- ))
- (write-var scopes0 srcv retv)
- )
- ]
- [else (tokamak:exit "[do-interpret] [substmt.2] unsupported op1 for inline array, got: ~a." op1)]
- )
- )
- ]
- [else
- ; other substitution
- (define tmp-val (read-var scopes0 tmp-var))
- (cond
- [(equal? 'csig op1)
- ; `<==` symbol: assert and then update
- (assert (equal? tmp-val tmp-rhe))
- (write-var scopes0 tmp-var tmp-rhe)
- ]
- [(equal? 'var op1)
- ; `=` symbol: only update
- (write-var scopes0 tmp-var tmp-rhe)
- ]
- [(equal? 'sig op1)
- ; `<--` symbol: only assert
- (assert (equal? tmp-val tmp-rhe))
- ]
- [else (tokamak:exit "[do-interpret] [substmt.3] unsupported op1 in substmt, got: ~a." op1)]
- )
- ]
- )
- )
- )
- ]
-
- [(circom:ceqstmt m-meta m-lhe m-rhe)
- (for*/all ([lhe0 m-lhe #:exhaustive] [rhe0 m-rhe #:exhaustive])
- (tokamak:typed lhe0 circom:expression?)
- (tokamak:typed rhe0 circom:expression?)
-
- (define tmp-lhe (do-interpret lhe0 arg-scopes arg-prefix arg-cprx))
- (define tmp-rhe (do-interpret rhe0 arg-scopes arg-prefix arg-cprx))
- ; ceqstmt has default operator: ===, we will do assertion only here
- ; (note) no need to decompose tmp-lhe or tmp-rhe, sicne union assertion is also acceptable
- (assert (equal? tmp-lhe tmp-rhe))
- )
- ]
-
- [(circom:assertstmt m-meta m-arg)
- (for/all ([arg0 m-arg #:exhaustive])
- (tokamak:typed arg0 circom:expression?)
-
- (define tmp-arg (do-interpret arg0 arg-scopes arg-prefix arg-cprx))
- ; (fixme) directly make assertion here, is it right?
- ; no need to lift tmp-arg
- ; but this assert is supposed to be triggered at circom compile time, no?
- (assert tmp-arg)
- )
- ]
-
- [(circom:block m-meta m-stmts)
- (for/all ([stmts0 m-stmts #:exhaustive])
- (tokamak:typed stmts0 list?)
-
- ; (fixme) beware for/last may not be supported by rosette
- (for/last ([s stmts0])
- (for/all ([s0 s #:exhaustive])
- (tokamak:typed s0 circom:statement?)
-
- (do-interpret s0 arg-scopes arg-prefix arg-cprx)
- )
- )
- )
- ]
-
- [(circom:initblock m-meta m-xtype m-inits)
- (for/all ([inits0 m-inits #:exhaustive])
- (tokamak:typed inits0 list?)
-
- ; (fixme) beware for/last may not be supported by rosette
- (for/last ([i inits0])
- (for/all ([i0 i #:exhaustive])
- (tokamak:typed i0 circom:statement?)
-
- (do-interpret i0 arg-scopes arg-prefix arg-cprx)
- )
- )
- )
- ]
-
- ; pass on
- [(circom:expression v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 circom:infix? circom:prefix? circom:inlineswitch?
- circom:variable? circom:call? circom:arrayinline? circom:number?)
-
- (do-interpret v0 arg-scopes arg-prefix arg-cprx)
- )
- ]
-
- [(circom:call m-meta m-id m-args)
- (for*/all ([id0 m-id #:exhaustive] [args0 m-args #:exhaustive])
- (tokamak:typed id0 string?)
- (tokamak:typed args0 list?)
-
- ; grab args
- (define tmp-args (for/list ([arg args0])
- (for/all ([arg0 arg #:exhaustive])
- (tokamak:typed arg0 circom:expression?)
-
- (do-interpret arg0 arg-scopes arg-prefix arg-cprx)
- )
- ))
-
- ; call and return
- (for*/all ([args1 tmp-args #:exhaustive] [scopes0 arg-scopes #:exhaustive] [cprx0 arg-cprx #:exhaustive])
- (tokamak:typed args1 list?)
- (tokamak:typed scopes0 list?)
- (tokamak:typed cprx0 string?)
-
- ; (note) this should switch to call prefix, don't use the original prefix
- (call-template scopes0 cprx0 id0 args1)
- )
- )
- ]
-
- [(circom:infix m-meta m-lhe m-op m-rhe)
- (for*/all ([lhe0 m-lhe #:exhaustive] [op0 m-op #:exhaustive] [rhe0 m-rhe #:exhaustive])
- (tokamak:typed lhe0 circom:expression?)
- (tokamak:typed op0 circom:infixop?)
- (tokamak:typed rhe0 circom:expression?)
-
- (define tmp-lhe (do-interpret lhe0 arg-scopes arg-prefix arg-cprx))
- (define tmp-rhe (do-interpret rhe0 arg-scopes arg-prefix arg-cprx))
- (define tmp-op (do-interpret op0 arg-scopes arg-prefix arg-cprx))
- ; (note) `apply` is not listed as rosette's lifted form (but can be found in rosette/safe)
- ; for safety we still manually lift it here
- (define tmp-result (for*/all ([lhe1 tmp-lhe #:exhaustive] [op1 tmp-op #:exhaustive] [rhe1 tmp-rhe #:exhaustive])
- ; (fixme) lhe1 is indecomposable, for all ops here, it's good to go (no type checking required)
- ; (fixme) rhe1 is indecomposable, for all ops here, it's good to go (no type checking required)
- (tokamak:typed op1 symbol?)
-
- (apply (hash-ref builtin-operators op1) (list lhe1 rhe1))
- ))
- ; return
- tmp-result
- )
- ]
-
- [(circom:prefix m-meta m-op m-rhe)
- (for*/all ([op0 m-op #:exhaustive] [rhe0 m-rhe #:exhaustive])
- (tokamak:typed op0 circom:prefixop?)
- (tokamak:typed rhe0 circom:expression?)
-
- (define tmp-rhe (do-interpret rhe0 arg-scopes arg-prefix arg-cprx))
- (define tmp-op (do-interpret op0 arg-scopes arg-prefix arg-cprx))
- ; (note) `apply` is not listed as rosette's lifted form (but can be found in rosette/safe)
- ; for safety we still manually lift it here
- (define tmp-result (for*/all ([rhe1 tmp-rhe #:exhaustive] [op1 tmp-op #:exhaustive])
- ; (fixme) rhe1 is indecomposable, for all ops here, it's good to go (no type checking required)
- (tokamak:typed op1 symbol?)
-
- (apply (hash-ref builtin-operators op1) (list rhe1))
- ))
- ; return
- tmp-result
- )
- ]
-
- [(circom:inlineswitch m-meta m-cond m-true m-false)
- (for*/all ([cond0 m-cond #:exhaustive] [true0 m-true #:exhaustive] [false0 m-false #:exhaustive])
- (tokamak:typed cond0 circom:expression?)
- (tokamak:typed true0 circom:expression?)
- (tokamak:typed false0 circom:expression?)
-
- (define tmp-cond (do-interpret cond0 arg-scopes arg-prefix arg-cprx))
- (for/all ([cond1 tmp-cond #:exhaustive])
- (tokamak:typed cond1 boolean?)
-
- (cond
- [cond1
- ; cond is true, go to true branch
- (do-interpret true0 arg-scopes arg-prefix arg-cprx)
- ]
- [else
- ; cond is false, go to false branch
- ; unlike ifthenelse, this must have a false branch
- (do-interpret false0 arg-scopes arg-prefix arg-cprx)
- ]
- )
- )
- )
- ]
-
- [(circom:number m-meta v)
- (for/all ([v0 v #:exhaustive])
- (tokamak:typed v0 integer?)
-
- (bv v0 config:bvtyp) ; wrap into bitvector
- )
- ]
-
- ; (fixme) you need to properly deal with access
- [(circom:variable m-meta m-name m-access)
- (for*/all ([name0 m-name #:exhaustive] [access0 m-access #:exhaustive] [scopes0 arg-scopes #:exhaustive]
- [prefix0 arg-prefix #:exhaustive] [cprx0 arg-cprx #:exhaustive])
- (tokamak:typed name0 string?)
- (tokamak:typed access0 list?)
- (tokamak:typed scopes0 list?)
- (tokamak:typed prefix0 string?)
- (tokamak:typed cprx0 string?)
-
- (define tmp-accstr (assemble-access scopes0 prefix0 cprx0 access0))
- (read-var scopes0 (string-append prefix0 "." name0 tmp-accstr))
- )
- ]
-
- [(circom:arrayinline m-meta m-vals)
- (for/all ([vals0 m-vals #:exhaustive])
- (tokamak:typed vals0 list?)
-
- (for/list ([val vals0])
- (do-interpret val arg-scopes arg-prefix arg-cprx)
- )
- )
- ]
-
- [_ (tokamak:exit "[do-interpret] unsupported node, got: ~a." arg-node)]
- )
- )
-
- ; (concrete:top) arg-scopes
- ; (concrete:top) arg-prefix
- ; (concrete:top) arg-name
- ; (concrete:top) arg-args
- (define/public (call-template arg-scopes arg-prefix arg-name arg-args)
- (tokamak:typed arg-scopes list?)
- (tokamak:typed arg-prefix string?)
- (tokamak:typed arg-name string?)
- (tokamak:typed arg-args list?)
-
- (define tmp-template (hash-ref template-book arg-name)) ; fetch the template node
- ; you could've stored a symbolic template, couldn't you?
- (for/all ([template0 tmp-template #:exhaustive])
- (tokamak:typed template0 circom:template? circom:function?)
- (cond
- [(circom:template? template0)
- (define tmp-args (circom:template-args template0)) ; fetch the template args
- (define tmp-body (circom:template-body template0)) ; fetch the template body
-
- (for*/all ([args0 tmp-args #:exhaustive] [body0 tmp-body #:exhaustive])
- (tokamak:typed args0 list?)
- (tokamak:typed body0 circom:statement?)
-
- ; check arity
- (when (not (equal? (length args0) (length arg-args)))
- (tokamak:exit "[call-template] argument arities mismatch, template requires ~a, but ~a is provided."
- (length args0) (length arg-args)))
-
- (for ([local-id args0] [local-val arg-args])
- ; (fixme) ideally local variables from arguments should not have additional prefix
- ; but we don't want to spend more efforts separating them, so let's add the prefix
- ; for now so it fits the current call model
- ; ....... and maybe this is right
- (make-var arg-scopes (string-append arg-prefix "." local-id) local-val)
- ; (fixme) argument assignment, let's not register any type info
- )
- ; interpret template body
- (do-interpret body0 arg-scopes arg-prefix arg-prefix)
- )
- ]
- [(circom:function? template0)
- ; (fixme) you probably need to create a local scope here
- ; we will see
-
- (define tmp-args (circom:function-args template0)) ; fetch the function args
- (define tmp-body (circom:function-body template0)) ; fetch the function body
-
- (for*/all ([args0 tmp-args #:exhaustive] [body0 tmp-body #:exhaustive])
- (tokamak:typed args0 list?)
- (tokamak:typed body0 circom:statement?)
-
- ; check arity
- (when (not (equal? (length args0) (length arg-args)))
- (tokamak:exit "[call-function] argument arities mismatch, function requires ~a, but ~a is provided."
- (length args0) (length arg-args)))
-
- (for ([local-id args0] [local-val arg-args])
- ; (fixme) ideally local variables from arguments should not have additional prefix
- ; but we don't want to spend more efforts separating them, so let's add the prefix
- ; for now so it fits the current call model
- ; ....... and maybe this is right
- (make-var arg-scopes (string-append arg-prefix "." local-id) local-val)
- ; (fixme) argument assignment, let's not register any type info
- )
- ; interpret function body
- (do-interpret body0 arg-scopes arg-prefix arg-prefix)
- )
- ]
- [else (tokamak:exit "[call-template] you can't reach here.")]
- )
- )
- )
-
- ; (concrete:top) arg-scopes
- ; (concrete:top) arg-prefix
- ; (concrete:top) arg-dims
- ; this returns a list of dims, e.g., (list 3 4) is for arr[3][4]
- ; (fixme) you need to properly deal with symbolic case
- (define (get-dims arg-scopes arg-prefix arg-cprx arg-dims)
- (tokamak:typed arg-scopes list?)
- (tokamak:typed arg-prefix string?)
- (tokamak:typed arg-dims list?)
-
- ; generate concrete dims
- (define tmp-dims (for/list ([dim arg-dims])
- (tokamak:typed dim circom:expression?)
-
- (define tmp-dim (do-interpret dim arg-scopes arg-prefix arg-cprx))
- ; (note) dim must be concrete, and you need to convert it to integer
- (tokamak:typed tmp-dim concrete?)
- (tokamak:typed tmp-dim bv?)
-
- (bitvector->integer tmp-dim)
- ))
-
- ; return
- tmp-dims
- )
-
- ; (concrete:top) arg-scopes
- ; (concrete:top) arg-prefix
- ; (concrete:top) arg-dims
- ; (note) this method returns a list of all dims strings
- ; (fixme) you need to properly deal with symbolic case
- (define (assemble-dims arg-scopes arg-prefix arg-cprx arg-dims)
- (tokamak:typed arg-scopes list?)
- (tokamak:typed arg-prefix string?)
- (tokamak:typed arg-dims list?)
-
- (cond
- [(null? arg-dims) (list "")] ; no dims
- [else
- ; generate concrete dims
- (define tmp-dims (get-dims arg-scopes arg-prefix arg-cprx arg-dims))
- (define tmp-lls (for/list ([d tmp-dims])
- ; create a range
- (for/list ([i (range d)])
- (string-append "[" (number->string i) "]")
- )
- ))
- ; then do a cartesian product
- (define tmp-strs (apply cartesian-product tmp-lls))
- ; (printf "tmp-strs: ~a\n" tmp-strs)
-
- ; assemble and return
- (for/list ([s tmp-strs])
- (apply string-append s)
- )
- ]
- )
- )
-
- ; (concrete:top) arg-scopes
- ; (concrete:top) arg-prefix
- ; (concrete:top) arg-access
- ; (fixme) you need to properly deal with symbolic case
- (define (assemble-access arg-scopes arg-prefix arg-cprx arg-access)
- (tokamak:typed arg-scopes list?)
- (tokamak:typed arg-prefix string?)
- (tokamak:typed arg-access list?)
-
- (cond
- [(null? arg-access) ""] ; no access
- [else
- ; generate concrete access, like dims
- (define tmp-access (for/list ([acc arg-access])
- (tokamak:typed acc circom:access?)
-
- (define tmp-acc (do-interpret acc arg-scopes arg-prefix arg-cprx))
- (tokamak:typed tmp-acc concrete?)
- (tokamak:typed tmp-acc bv? string?)
- ; convert to formatted string
- (cond
- ; [(string? tmp-acc) (string-append "[" tmp-acc "]")]
- [(string? tmp-acc) (string-append "." tmp-acc )] ; (fixme) this is usually component access, right?
- [(bv? tmp-acc) (string-append "[" (number->string (bitvector->integer tmp-acc)) "]")]
- )
- ))
-
- ; assemble and return
- (apply string-append tmp-access)
- ]
- )
- )
-
- ; create a variable in the nearest scope
- ; (symbolic:top) arg-stack
- ; (concrete:top) arg-id
- ; (symbolic:top) arg-val
- (define (make-var arg-stack arg-id arg-val)
- (tokamak:typed arg-id string?)
- (for/all ([stack0 arg-stack #:exhaustive])
- (tokamak:typed stack0 list?)
-
- (when (null? stack0) (tokamak:exit "[make-var] stack0 is empty."))
- (let ([scope (car stack0)])
- (for/all ([scope0 scope #:exhaustive])
- (tokamak:typed scope0 mhash?)
-
- (mhash-set! scope arg-id arg-val)
- )
- )
- )
- )
-
- ; read a variable from the stack of scopes, from nearest to farthest (top)
- ; (symbolic:top) arg-stack
- ; (concrete:top) arg-id
- (define (read-var arg-stack arg-id)
- (tokamak:typed arg-id string?)
- (for/all ([stack0 arg-stack #:exhaustive])
- (tokamak:typed stack0 list?)
-
- (let ([scope (car stack0)] [stack-res (cdr stack0)])
- (for/all ([scope0 scope #:exhaustive])
- (tokamak:typed scope0 mhash?)
-
- (cond
- [(mhash-has-key? scope0 arg-id)
- (mhash-ref scope0 arg-id)
- ]
- [(null? stack-res)
- (tokamak:exit "[read-var] cannot find variable in all scopes, got: ~a." arg-id)
- ]
- [else
- (read-var stack-res arg-id)
- ]
- )
- )
- )
- )
- )
-
- ; write a variable to the stack of scopes, nearest first
- ; this requires the variable to exist before writing
- ; (symbolic:top) arg-stack
- ; (concrete:top) arg-id
- ; (symbolic:top) arg-val
- (define (write-var arg-stack arg-id arg-val)
- (tokamak:typed arg-id string?)
- (for/all ([stack0 arg-stack #:exhaustive])
- (tokamak:typed stack0 list?)
-
- (let ([scope (car stack0)] [stack-res (cdr stack0)])
- (for/all ([scope0 scope #:exhaustive])
- (tokamak:typed scope0 mhash?)
-
- (cond
- [(mhash-has-key? scope0 arg-id)
- (mhash-set! scope0 arg-id arg-val)
- ]
- [(null? stack-res)
- (tokamak:exit "[write-var] cannot find variable in all scopes, got: ~a." arg-id)
- ]
- [else
- (write-var stack-res arg-id arg-val)
- ]
- )
- )
- )
- )
- )
-
- (define (init-builtin-operators)
- ; (note) (fixme) all arguments should be concrete, you are not checking them all
- (set! builtin-operators (make-hash))
-
- ; ; borrowed from ecne for speed up
- ; (define (circom-mod x k)
- ; (if (bvugt x k)
- ; (bvsub x k)
- ; x
- ; )
- ; )
- (define (circom-mod x k) x)
-
- ; helper functions
- (define (circom-pow x k)
- ; (tokamak:exit "[debug] circom-pow x=~a k=~a" x k)
- (tokamak:typed x bv?)
- ; (note) k needs to be both concrete and bv
- (tokamak:typed k bv?)
- (tokamak:typed k concrete?)
-
- (if (bvzero? k)
- bv-one
- (config:mul x (circom-pow x (bvsub k bv-one)))
- )
- )
-
- ; ref: https://docs.circom.io/circom-language/basic-operators/#bitwise-operators
- (define (circom-shr x k)
- (tokamak:typed x bv?)
- ; (note) k needs to be both concrete and bv
- (tokamak:typed k bv?)
- (tokamak:typed k concrete?)
-
- (cond
- ; 0=< k <= p/2
- [(&&
- (bvsle bv-zero k)
- (bvsle k (bvsdiv config:bvp bv-two))
- )
- ; equals to: x/(2**k)
- (bvsdiv x (circom-pow bv-two k))
- ]
- ; p/2 +1<= k < p
- [(&&
- (bvsle (bvadd bv-one (bvsdiv config:bvp bv-two)) k)
- (bvslt k config:bvp)
- )
- ; equals to: x << (p-k)
- (circom-shl x (bvsub config:bvp k))
- ]
- [else (tokamak:exit "[circom-shr] you can't reach here.")]
- )
- )
-
- ; ref: https://docs.circom.io/circom-language/basic-operators/#bitwise-operators
- (define (circom-shl x k)
- (tokamak:typed x bv?)
- ; (note) k needs to be both concrete and bv
- (tokamak:typed k bv?)
- (tokamak:typed k concrete?)
-
- (cond
- ; 0=< k <= p/2
- [(&&
- (bvsle bv-zero k)
- (bvsle k (bvsdiv config:bvp bv-two))
- )
- ; (fixme) you probably need to remove circom-mod temporarily
- ; equals to: (x*(2{**}k)~ & ~mask) % p
- (circom-mod
- (bvand
- (config:mul x (circom-pow bv-two k))
- (bvnot config:bvmask)
- )
- config:bvp
- )
- ]
- ; p/2 +1<= k < p
- [(&&
- (bvsle (bvadd bv-one (bvsdiv config:bvp bv-two)) k)
- (bvslt k config:bvp)
- )
- ; equals to: x >> (p-k)
- (circom-shr x (bvsub config:bvp k))
- ]
- [else (tokamak:exit "[circom-shl] you can't reach here.")]
- )
- )
-
- ; arithmethc operators (input: bitvector, output: boolean)
- (hash-set! builtin-operators 'mul (lambda (x y) (config:mul x y)))
- (hash-set! builtin-operators 'add (lambda (x y) (bvadd x y)))
- (hash-set! builtin-operators 'div (lambda (x y) (bvsdiv x y))) ; (fixme) this should be raw division, but bvsdiv is quotient, see doc
- (hash-set! builtin-operators 'intdiv (lambda (x y) (bvsdiv x y))) ; quotient
- (hash-set! builtin-operators 'mod (lambda (x y) (bvsrem x y))); remainder
- (hash-set! builtin-operators 'sub (lambda (x y) (bvsub x y) ))
- (hash-set! builtin-operators 'pow (lambda (x y) (circom-pow x y)))
-
- (hash-set! builtin-operators 'neg (lambda (x) (bvneg x)))
-
- ; relational operators (input: bitvector, output: boolean)
- (hash-set! builtin-operators 'lt (lambda (x y) (bvslt x y)))
- (hash-set! builtin-operators 'leq (lambda (x y) (bvsle x y)))
- (hash-set! builtin-operators 'gt (lambda (x y) (bvsgt x y)))
- (hash-set! builtin-operators 'geq (lambda (x y) (bvsge x y)))
- (hash-set! builtin-operators 'eq (lambda (x y) (bveq x y)))
- (hash-set! builtin-operators 'neq (lambda (x y) (not (bveq x y))))
-
- ; boolean operators (input: boolean, output: boolean)
- (hash-set! builtin-operators 'and (lambda (x y) (&& x y)))
- (hash-set! builtin-operators 'or (lambda (x y) (|| x y)))
- (hash-set! builtin-operators 'not (lambda (x) (not x)))
-
- ; bitwise operators
- ; ref: https://docs.circom.io/circom-language/basic-operators/#bitwise-operators
- (hash-set! builtin-operators 'band (lambda (x y) (bvand x y)))
- (hash-set! builtin-operators 'bor (lambda (x y) (bvor x y)))
- (hash-set! builtin-operators 'comp (lambda (x) (bvnot x))) ; (fixme) is this right?
- (hash-set! builtin-operators 'bxor' (lambda (x y) (bvxor x y)))
- (hash-set! builtin-operators 'shr (lambda (x k) (circom-shr x k)))
- (hash-set! builtin-operators 'shl (lambda (x k) (circom-shl x k)))
-
- )
-
- )
-)
\ No newline at end of file
diff --git a/picus/circom-grammar.rkt b/picus/circom/circom-grammar.rkt
similarity index 99%
rename from picus/circom-grammar.rkt
rename to picus/circom/circom-grammar.rkt
index 8ea19f1..97a8a4b 100644
--- a/picus/circom-grammar.rkt
+++ b/picus/circom/circom-grammar.rkt
@@ -1,4 +1,4 @@
-#lang rosette
+#lang racket
(provide (all-defined-out))
; (note) see NOTES.md for transcribed CFG
diff --git a/picus/circom-parser.rkt b/picus/circom/circom-parser.rkt
similarity index 99%
rename from picus/circom-parser.rkt
rename to picus/circom/circom-parser.rkt
index 7234a88..4d8636b 100644
--- a/picus/circom-parser.rkt
+++ b/picus/circom/circom-parser.rkt
@@ -1,6 +1,6 @@
-#lang rosette
+#lang racket
(require
- (prefix-in tokamak: "./tokamak.rkt")
+ (prefix-in tokamak: "../tokamak.rkt")
(prefix-in circom: "./circom-grammar.rkt")
)
(provide (all-defined-out))
diff --git a/picus/config.rkt b/picus/config.rkt
index c0fc43f..4db23ea 100644
--- a/picus/config.rkt
+++ b/picus/config.rkt
@@ -1,4 +1,4 @@
-#lang rosette
+#lang racket
(provide (rename-out
[p p]
))
diff --git a/picus/optimizers/r1cs-cvc5-ab0-optimizer.rkt b/picus/optimizers/r1cs-cvc5-ab0-optimizer.rkt
new file mode 100644
index 0000000..bed81d6
--- /dev/null
+++ b/picus/optimizers/r1cs-cvc5-ab0-optimizer.rkt
@@ -0,0 +1,46 @@
+#lang racket
+; (note) this is applied in optimization phase 0
+; this implements the following lemma
+; A * B = 0 => A = 0 or B = 0
+(require
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [optimize-r1cs optimize-r1cs]
+))
+
+(define (optimize-r1cs arg-r1cs)
+ (match arg-r1cs
+
+ ; command level
+ [(r1cs:rcmds vs) (r1cs:rcmds (for/list ([v vs]) (optimize-r1cs v)))]
+ [(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v))]
+
+ ; (note) yes, this is the specific shape in standard form about A*B=0
+ [(r1cs:req
+ (r1cs:rmul (list vs ...))
+ (r1cs:radd (list (r1cs:rint 0)))
+ )
+ ; rewrite
+ (r1cs:ror
+ (for/list ([v vs]) (r1cs:req (r1cs:rint 0) v))
+ )
+ ]
+
+ [(r1cs:req
+ (r1cs:radd (list (r1cs:rint 0)))
+ (r1cs:rmul (list vs ...))
+ )
+ ; rewrite
+ (r1cs:ror
+ (for/list ([v vs]) (r1cs:req (r1cs:rint 0) v))
+ )
+ ]
+
+ ; otherwise, do not rewrite
+ [_ arg-r1cs]
+ )
+)
\ No newline at end of file
diff --git a/picus/optimizers/r1cs-cvc5-simple-optimizer.rkt b/picus/optimizers/r1cs-cvc5-simple-optimizer.rkt
index 00b295f..f3707bc 100644
--- a/picus/optimizers/r1cs-cvc5-simple-optimizer.rkt
+++ b/picus/optimizers/r1cs-cvc5-simple-optimizer.rkt
@@ -1,10 +1,10 @@
-#lang rosette
+#lang racket
+; (note) this is applied in the normalization phase
; this contains a list of simple and basic optimization steps
; - add p related definition and replace p
; - remove *1 in mul
; - remove +0 in add
; - rewrite *x as x
-; - rewrite -x as -x
; - rewrite +x as x
; - replace x0 with 1
; - partial evaluation: compute concrete results, e.g., 0*0 => 0
@@ -13,7 +13,7 @@
(prefix-in tokamak: "../tokamak.rkt")
(prefix-in utils: "../utils.rkt")
(prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
)
(provide (rename-out
[optimize-r1cs optimize-r1cs]
@@ -58,82 +58,19 @@
(match arg-r1cs
; command level
- ; probably the original block
- [(r1cs:rcmds (list (r1cs:rlogic v0) vs ...))
- (r1cs:rcmds
- (append
- (list
- (r1cs:rlogic v0)
- (r1cs:rraw "(set-info :smt-lib-version 2.6)")
- (r1cs:rraw "(set-info :category \"crafted\")")
- (r1cs:rraw "(define-sort F () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617))")
- ; add p definition
- (r1cs:rdef (r1cs:rvar "p") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "p") (r1cs:rint config:p)))
- (r1cs:rdef (r1cs:rvar "ps1") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps1") (r1cs:rint (- config:p 1))))
- (r1cs:rdef (r1cs:rvar "ps2") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps2") (r1cs:rint (- config:p 2))))
- (r1cs:rdef (r1cs:rvar "ps3") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps3") (r1cs:rint (- config:p 3))))
- (r1cs:rdef (r1cs:rvar "ps4") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps4") (r1cs:rint (- config:p 4))))
- (r1cs:rdef (r1cs:rvar "ps5") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps5") (r1cs:rint (- config:p 5))))
- ; add 0 definition
- (r1cs:rdef (r1cs:rvar "zero") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "zero") (r1cs:rint 0)))
- ; add 1 definition
- (r1cs:rdef (r1cs:rvar "one") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "one") (r1cs:rint 1)))
- )
- (for/list ([v vs]) (optimize-r1cs v))
- )
- )
- ]
- ; probably the alternative block, no need to define F again
- [(r1cs:rcmds vs) (r1cs:rcmds
- (append
- (list
- ; add p definition
- (r1cs:rdef (r1cs:rvar "p") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "p") (r1cs:rint config:p)))
- (r1cs:rdef (r1cs:rvar "ps1") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps1") (r1cs:rint (- config:p 1))))
- (r1cs:rdef (r1cs:rvar "ps2") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps2") (r1cs:rint (- config:p 2))))
- (r1cs:rdef (r1cs:rvar "ps3") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps3") (r1cs:rint (- config:p 3))))
- (r1cs:rdef (r1cs:rvar "ps4") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps4") (r1cs:rint (- config:p 4))))
- (r1cs:rdef (r1cs:rvar "ps5") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "ps5") (r1cs:rint (- config:p 5))))
- ; add 0 definition
- (r1cs:rdef (r1cs:rvar "zero") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "zero") (r1cs:rint 0)))
- ; add 1 definition
- (r1cs:rdef (r1cs:rvar "one") (r1cs:rtype "F"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "one") (r1cs:rint 0)))
- )
- (for/list ([v vs]) (optimize-r1cs v))
- )
- )]
+ [(r1cs:rcmds vs) (r1cs:rcmds (for/list ([v vs]) (optimize-r1cs v)))]
[(r1cs:rraw v) (r1cs:rraw v)]
- [(r1cs:rlogic v) (r1cs:rlogic (optimize-r1cs v))]
+ [(r1cs:rlogic v) (r1cs:rlogic v)]
; (note) don't optimize declaration line
[(r1cs:rdef v t) (r1cs:rdef v (optimize-r1cs t))]
[(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v))]
- [(r1cs:rcmt v) (r1cs:rcmt (optimize-r1cs v))]
+ [(r1cs:rcmt v) (r1cs:rcmt v)]
[(r1cs:rsolve ) (r1cs:rsolve )]
; sub-command level
[(r1cs:req lhs rhs) (r1cs:req (optimize-r1cs lhs) (optimize-r1cs rhs))]
[(r1cs:rneq lhs rhs) (r1cs:rneq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rleq lhs rhs) (r1cs:rleq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rlt lhs rhs) (r1cs:rlt (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgeq lhs rhs) (r1cs:rgeq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgt lhs rhs) (r1cs:rgt (optimize-r1cs lhs) (optimize-r1cs rhs))]
[(r1cs:rand vs)
(define new-vs (for/list ([v vs]) (optimize-r1cs v)))
@@ -148,30 +85,11 @@
; if there's only one element, extract content directly
(if (= 1 (length new-vs))
(car new-vs)
- (r1cs:ror (for/list ([v vs]) v))
+ (r1cs:ror (for/list ([v new-vs]) v))
)
]
- [(r1cs:rimp lhs rhs) (r1cs:rimp (optimize-r1cs lhs) (optimize-r1cs rhs))]
-
- [(r1cs:rint v)
- (cond
- ; replace as p
- [(= config:p v) (r1cs:rint 0)]
- [(= (- config:p 1) v) (r1cs:rvar "ps1")]
- [(= (- config:p 2) v) (r1cs:rvar "ps2")]
- [(= (- config:p 3) v) (r1cs:rvar "ps3")]
- [(= (- config:p 4) v) (r1cs:rvar "ps4")]
- [(= (- config:p 5) v) (r1cs:rvar "ps5")]
- ; replace as zero
- [(= 0 v) (r1cs:rvar "zero")]
- ; replace as one
- [(= 1 v) (r1cs:rvar "one")]
- ; do nothing
- [else (r1cs:rint v)]
- )
- ]
- [(r1cs:rstr v) (r1cs:rstr v)]
+ [(r1cs:rint v) (r1cs:rint v)]
; (note) we assume "x0" is the first wire with prefix "x"
[(r1cs:rvar v)
(cond
@@ -184,10 +102,9 @@
[(r1cs:radd vs)
; remove 0
(define new-vs (filter
- (lambda (x) (! (is-rint-zero x)))
+ (lambda (x) (not (is-rint-zero x)))
(for/list ([v vs]) (optimize-r1cs v))
))
- ; (printf "radd new-vs is: ~a\n" new-vs)
(cond
; no element, all values are 0 and filtered out, return base 0
[(= 0 (length new-vs)) (r1cs:rint 0)]
@@ -197,15 +114,11 @@
[else (r1cs:radd new-vs)]
)
]
- ; (fixme) this could have rewrite issues
- [(r1cs:rsub vs) (tokamak:exit "cvc5 doesn't support sub")]
[(r1cs:rmul vs)
(define new-vs (filter
- (lambda (x) (! (is-rint-one x)))
+ (lambda (x) (not (is-rint-one x)))
(for/list ([v vs]) (optimize-r1cs v))
))
- ; (printf "# rmul new-vs is: ~a\n" new-vs)
- ; (printf "# cont: ~a\n vs ~a\n" (contains-rint-zero vs) vs)
(cond
; if there's zero already in multiplication, directly return 0
[(contains-rint-zero new-vs) (r1cs:rint 0)]
@@ -217,9 +130,7 @@
[else (r1cs:rmul new-vs)]
)
]
- [(r1cs:rneg v) (r1cs:rneg (optimize-r1cs v))]
- [(r1cs:rmod v mod) (tokamak:exit "cvc5 doesn't support mod")]
- [else (tokamak:exit "not supported: ~a" arg-r1cs)]
+ [_ (tokamak:exit "not supported: ~a" arg-r1cs)]
)
)
\ No newline at end of file
diff --git a/picus/optimizers/r1cs-cvc5-subp-optimizer.rkt b/picus/optimizers/r1cs-cvc5-subp-optimizer.rkt
new file mode 100644
index 0000000..b97ff96
--- /dev/null
+++ b/picus/optimizers/r1cs-cvc5-subp-optimizer.rkt
@@ -0,0 +1,112 @@
+#lang racket
+; (note) this is applied in optimization phase 1
+; this contains the following optimizations:
+; - add p related definition and replace p
+(require
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [optimize-r1cs optimize-r1cs]
+))
+
+(define (optimize-r1cs arg-r1cs pdef?)
+ (match arg-r1cs
+
+ ; command level
+ [(r1cs:rcmds vs) (r1cs:rcmds
+ (append
+ (if pdef?
+ ; should include p definitions
+ (list
+ ; add p definition
+ (r1cs:rcmt "======== p definitions ========")
+ (r1cs:rdef (r1cs:rvar "p") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "p") (r1cs:rint config:p)))
+ (r1cs:rdef (r1cs:rvar "ps1") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps1") (r1cs:rint (- config:p 1))))
+ (r1cs:rdef (r1cs:rvar "ps2") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps2") (r1cs:rint (- config:p 2))))
+ (r1cs:rdef (r1cs:rvar "ps3") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps3") (r1cs:rint (- config:p 3))))
+ (r1cs:rdef (r1cs:rvar "ps4") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps4") (r1cs:rint (- config:p 4))))
+ (r1cs:rdef (r1cs:rvar "ps5") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps5") (r1cs:rint (- config:p 5))))
+ ; add 0 definition
+ (r1cs:rdef (r1cs:rvar "zero") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "zero") (r1cs:rint 0)))
+ ; add 1 definition
+ (r1cs:rdef (r1cs:rvar "one") (r1cs:rtype "F"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "one") (r1cs:rint 1)))
+ )
+ ; should not include p definitions, usually in alt- series
+ ; use placeholder to avoid changing the number of constraints
+ (list
+ (r1cs:rcmt "======== p definitions: alt skip ========")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ )
+ )
+ (for/list ([v vs]) (optimize-r1cs v pdef?))
+ )
+ )]
+
+ [(r1cs:rraw v) (r1cs:rraw v)]
+ [(r1cs:rlogic v) (r1cs:rlogic v)]
+ ; (note) don't optimize declaration line
+ [(r1cs:rdef v t) (r1cs:rdef v (optimize-r1cs t pdef?))]
+ [(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v pdef?))]
+ [(r1cs:rcmt v) (r1cs:rcmt v)]
+ [(r1cs:rsolve ) (r1cs:rsolve )]
+
+ ; sub-command level
+ [(r1cs:req lhs rhs) (r1cs:req (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+ [(r1cs:rneq lhs rhs) (r1cs:rneq (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+
+ [(r1cs:rand vs) (r1cs:rand (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+ [(r1cs:ror vs) (r1cs:ror (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+
+ [(r1cs:rint v)
+ (cond
+ ; replace as p
+ [(= config:p v) (r1cs:rint 0)]
+ [(= (- config:p 1) v) (r1cs:rvar "ps1")]
+ [(= (- config:p 2) v) (r1cs:rvar "ps2")]
+ [(= (- config:p 3) v) (r1cs:rvar "ps3")]
+ [(= (- config:p 4) v) (r1cs:rvar "ps4")]
+ [(= (- config:p 5) v) (r1cs:rvar "ps5")]
+ ; replace as zero
+ [(= 0 v) (r1cs:rvar "zero")]
+ ; replace as one
+ [(= 1 v) (r1cs:rvar "one")]
+ ; do nothing
+ [else (r1cs:rint v)]
+ )
+ ]
+ ; (note) we assume "x0" is the first wire with prefix "x"
+ [(r1cs:rvar v) (r1cs:rvar v)]
+ [(r1cs:rtype v) (r1cs:rtype v)]
+
+ [(r1cs:radd vs) (r1cs:radd (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+ [(r1cs:rmul vs) (r1cs:rmul (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+
+ [_ (tokamak:exit "not supported: ~a" arg-r1cs)]
+ )
+)
\ No newline at end of file
diff --git a/picus/optimizers/r1cs-cvc5-template-optimizer.rkt b/picus/optimizers/r1cs-cvc5-template-optimizer.rkt
deleted file mode 100644
index 9f91cb5..0000000
--- a/picus/optimizers/r1cs-cvc5-template-optimizer.rkt
+++ /dev/null
@@ -1,50 +0,0 @@
-#lang rosette
-; this is a template for optimizer
-(require
- (prefix-in tokamak: "../tokamak.rkt")
- (prefix-in utils: "../utils.rkt")
- (prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
-)
-(provide (rename-out
- [optimize-r1cs optimize-r1cs]
-))
-
-(define (optimize-r1cs arg-r1cs)
- (match arg-r1cs
-
- ; command level
- [(r1cs:rcmds vs) (r1cs:rcmds (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rraw v) (r1cs:rraw v)]
- [(r1cs:rlogic v) (r1cs:rlogic (optimize-r1cs v))]
- [(r1cs:rdef v t) (r1cs:rdef v (optimize-r1cs t))]
- [(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v))]
- [(r1cs:rcmt v) (r1cs:rcmt (optimize-r1cs v))]
- [(r1cs:rsolve ) (r1cs:rsolve )]
-
- ; sub-command level
- [(r1cs:req lhs rhs) (r1cs:req (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rneq lhs rhs) (r1cs:rneq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rleq lhs rhs) (r1cs:rleq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rlt lhs rhs) (r1cs:rlt (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgeq lhs rhs) (r1cs:rgeq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgt lhs rhs) (r1cs:rgt (optimize-r1cs lhs) (optimize-r1cs rhs))]
-
- [(r1cs:rand vs) (r1cs:rand (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:ror vs) (r1cs:ror (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rimp lhs rhs) (r1cs:rimp (optimize-r1cs lhs) (optimize-r1cs rhs))]
-
- [(r1cs:rint v) (r1cs:rint v)]
- [(r1cs:rstr v) (r1cs:rstr v)]
- [(r1cs:rvar v) (r1cs:rvar v)]
- [(r1cs:rtype v) (r1cs:rtype v)]
-
- [(r1cs:radd vs) (r1cs:radd (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rsub vs) (tokamak:exit "cvc5 doesn't support sub")]
- [(r1cs:rmul vs) (r1cs:rmul (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rneg v) (r1cs:rneg (optimize-r1cs v))]
- [(r1cs:rmod v mod) (tokamak:exit "cvc5 doesn't support mod")]
-
- [else (tokamak:exit "not supported: ~a" arg-r1cs)]
- )
-)
\ No newline at end of file
diff --git a/picus/optimizers/r1cs-z3-AB0-optimizer.rkt b/picus/optimizers/r1cs-z3-AB0-optimizer.rkt
index df92d10..aef786a 100644
--- a/picus/optimizers/r1cs-z3-AB0-optimizer.rkt
+++ b/picus/optimizers/r1cs-z3-AB0-optimizer.rkt
@@ -1,98 +1,56 @@
-#lang rosette
+#lang racket
+; (note) this is applied in optimization phase 0
; this implements the following lemma
; A * B = 0 => A = 0 or B = 0
(require
(prefix-in tokamak: "../tokamak.rkt")
(prefix-in utils: "../utils.rkt")
(prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
)
(provide (rename-out
[optimize-r1cs optimize-r1cs]
))
-(define (is-rint-zero x)
- (if (r1cs:rint? x)
- (if (= 0 (r1cs:rint-v x))
- #t
- #f
- )
- #f
- )
-)
-
-(define (is-rint-one x)
- (if (r1cs:rint? x)
- (if (= 1 (r1cs:rint-v x))
- #t
- #f
- )
- #f
- )
-)
-
(define (optimize-r1cs arg-r1cs)
(match arg-r1cs
; command level
[(r1cs:rcmds vs) (r1cs:rcmds (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rraw v) (r1cs:rraw v)]
- [(r1cs:rlogic v) (r1cs:rlogic (optimize-r1cs v))]
- [(r1cs:rdef v t) (r1cs:rdef v (optimize-r1cs t))]
[(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v))]
- [(r1cs:rcmt v) (r1cs:rcmt (optimize-r1cs v))]
- [(r1cs:rsolve ) (r1cs:rsolve )]
- ; sub-command level
- [(r1cs:req lhs rhs)
- (cond
- [(is-rint-zero lhs)
- (match rhs
- [(r1cs:rmod (r1cs:rmul vs) mod)
- ; apply lemma
- (r1cs:ror (for/list ([v vs])
- (r1cs:req (r1cs:rint 0) (r1cs:rmod v mod))
- ))
- ]
- [else (r1cs:req (optimize-r1cs lhs) (optimize-r1cs rhs))]
- )
- ]
- [(is-rint-zero rhs)
- (match lhs
- [(r1cs:rmod (r1cs:rmul vs) mod)
- ; apply lemma
- (r1cs:ror (for/list ([v vs])
- (r1cs:req (r1cs:rint 0) (r1cs:rmod v mod))
- ))
- ]
- [else (r1cs:req (optimize-r1cs lhs) (optimize-r1cs rhs))]
+ ; (note) yes, this is the specific shape in standard form about A*B=0
+ [(r1cs:req
+ (r1cs:rmod (r1cs:rmul (list vs ...)) _)
+ (r1cs:rmod (r1cs:radd (list (r1cs:rint 0))) _)
+ )
+ ; rewrite
+ (r1cs:ror
+ (for/list ([v vs])
+ (r1cs:req
+ (r1cs:rint 0)
+ (r1cs:rmod v (r1cs:rint config:p))
)
- ]
- [else (r1cs:req (optimize-r1cs lhs) (optimize-r1cs rhs))]
+ )
)
]
- [(r1cs:rneq lhs rhs) (r1cs:rneq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rleq lhs rhs) (r1cs:rleq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rlt lhs rhs) (r1cs:rlt (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgeq lhs rhs) (r1cs:rgeq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgt lhs rhs) (r1cs:rgt (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rand vs) (r1cs:rand (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:ror vs) (r1cs:ror (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rimp lhs rhs) (r1cs:rimp (optimize-r1cs lhs) (optimize-r1cs rhs))]
-
-
- [(r1cs:rint v) (r1cs:rint v)]
- [(r1cs:rstr v) (r1cs:rstr v)]
- [(r1cs:rvar v) (r1cs:rvar v)]
- [(r1cs:rtype v) (r1cs:rtype v)]
-
- [(r1cs:radd vs) (r1cs:radd (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rsub vs) (r1cs:rsub (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rmul vs) (r1cs:rmul (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rneg v) (r1cs:rneg (optimize-r1cs v))]
- [(r1cs:rmod v mod) (r1cs:rmod (optimize-r1cs v) (optimize-r1cs mod))]
+ [(r1cs:req
+ (r1cs:rmod (r1cs:radd (list (r1cs:rint 0))) _)
+ (r1cs:rmod (r1cs:rmul (list vs ...)) _)
+ )
+ ; rewrite
+ (r1cs:ror
+ (for/list ([v vs])
+ (r1cs:req
+ (r1cs:rint 0)
+ (r1cs:rmod v (r1cs:rint config:p))
+ )
+ )
+ )
+ ]
- [else (tokamak:exit "not supported for AB optimization: ~a" arg-r1cs)]
+ ; otherwise, do not rewrite
+ [_ arg-r1cs]
)
)
\ No newline at end of file
diff --git a/picus/optimizers/r1cs-z3-simple-optimizer.rkt b/picus/optimizers/r1cs-z3-simple-optimizer.rkt
index 41df365..13bf82f 100644
--- a/picus/optimizers/r1cs-z3-simple-optimizer.rkt
+++ b/picus/optimizers/r1cs-z3-simple-optimizer.rkt
@@ -1,21 +1,19 @@
-#lang rosette
+#lang racket
+; (note) this is applied in the normalization phase
; this contains a list of simple and basic optimization steps
; - add p related definition and replace p
; - remove *1 in mul
; - remove +0 in add
-; - remove -0 in sub
; - rewrite *x as x
-; - rewrite -x as -x
; - rewrite +x as x
; - replace x0 with 1
-; - rewrite 0 = -x mod p to 0 = x mod p (also -x = 0)
+; - remove mod on variable and int (brought by ab0 lemma)
; - partial evaluation: compute concrete results, e.g., 0*0 => 0
-; - (fixme) current only modify 0*...*x to 0
(require
(prefix-in tokamak: "../tokamak.rkt")
(prefix-in utils: "../utils.rkt")
(prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
)
(provide (rename-out
[optimize-r1cs optimize-r1cs]
@@ -60,62 +58,18 @@
(match arg-r1cs
; command level
- [(r1cs:rcmds (list (r1cs:rlogic v0) vs ...))
- (r1cs:rcmds
- (append
- (list (r1cs:rlogic v0))
- ; add p definition
- (list
- (r1cs:rdef (r1cs:rvar "p") (r1cs:rtype "Int"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "p") (r1cs:rint config:p)))
- )
- (for/list ([v vs]) (optimize-r1cs v))
- )
- )
- ]
- [(r1cs:rcmds vs) (r1cs:rcmds
- (append
- (list
- (r1cs:rdef (r1cs:rvar "p") (r1cs:rtype "Int"))
- (r1cs:rassert (r1cs:req (r1cs:rvar "p") (r1cs:rint config:p)))
- )
- (for/list ([v vs]) (optimize-r1cs v))
- )
- )]
+ [(r1cs:rcmds vs) (r1cs:rcmds (for/list ([v vs]) (optimize-r1cs v)))]
[(r1cs:rraw v) (r1cs:rraw v)]
- [(r1cs:rlogic v) (r1cs:rlogic (optimize-r1cs v))]
+ [(r1cs:rlogic v) (r1cs:rlogic v)]
; (note) don't optimize declaration line
[(r1cs:rdef v t) (r1cs:rdef v (optimize-r1cs t))]
[(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v))]
- [(r1cs:rcmt v) (r1cs:rcmt (optimize-r1cs v))]
+ [(r1cs:rcmt v) (r1cs:rcmt v)]
[(r1cs:rsolve ) (r1cs:rsolve )]
; sub-command level
- [(r1cs:req lhs rhs)
- ; post order
- (define new-lhs (optimize-r1cs lhs))
- (define new-rhs (optimize-r1cs rhs))
- (cond
- [(&& (is-rint-zero new-lhs) (r1cs:rmod? new-rhs))
- (if (r1cs:rneg? (r1cs:rmod-v new-rhs))
- ; remove neg
- (r1cs:req new-lhs (r1cs:rmod (r1cs:rneg-v (r1cs:rmod-v new-rhs)) (r1cs:rmod-mod new-rhs)))
- ; else do nothing
- (r1cs:req new-lhs new-rhs)
- )
- ]
- [(&& (is-rint-zero new-rhs) (r1cs:rmod? new-lhs))
- (if (r1cs:rneg? (r1cs:rmod-v new-lhs))
- ; remove neg
- (r1cs:req (r1cs:rmod (r1cs:rneg-v (r1cs:rmod-v new-lhs)) (r1cs:rmod-mod new-lhs)) new-rhs)
- ; else do nothing
- (r1cs:req new-lhs new-rhs)
- )
- ]
- [else (r1cs:req new-lhs new-rhs)]
- )
- ]
+ [(r1cs:req lhs rhs) (r1cs:req (optimize-r1cs lhs) (optimize-r1cs rhs))]
[(r1cs:rneq lhs rhs) (r1cs:rneq (optimize-r1cs lhs) (optimize-r1cs rhs))]
[(r1cs:rleq lhs rhs) (r1cs:rleq (optimize-r1cs lhs) (optimize-r1cs rhs))]
[(r1cs:rlt lhs rhs) (r1cs:rlt (optimize-r1cs lhs) (optimize-r1cs rhs))]
@@ -130,27 +84,17 @@
(r1cs:rand (for/list ([v new-vs]) v))
)
]
- [(r1cs:rimp lhs rhs) (r1cs:rimp (optimize-r1cs lhs) (optimize-r1cs rhs))]
[(r1cs:ror vs)
(define new-vs (for/list ([v vs]) (optimize-r1cs v)))
; if there's only one element, extract content directly
(if (= 1 (length new-vs))
(car new-vs)
- (r1cs:ror (for/list ([v vs]) v))
+ (r1cs:ror (for/list ([v new-vs]) v))
)
]
- [(r1cs:rint v)
- (cond
- ; replace to normalized form
- [(> v (quotient config:p 2))
- (r1cs:rint (- v config:p))]
- ; do nothing
- [else (r1cs:rint v)]
- )
- ]
- [(r1cs:rstr v) (r1cs:rstr v)]
+ [(r1cs:rint v) (r1cs:rint v)]
; (note) we assume "x0" is the first wire with prefix "x"
[(r1cs:rvar v)
(cond
@@ -163,10 +107,9 @@
[(r1cs:radd vs)
; remove 0
(define new-vs (filter
- (lambda (x) (! (is-rint-zero x)))
+ (lambda (x) (not (is-rint-zero x)))
(for/list ([v vs]) (optimize-r1cs v))
))
- ; (printf "radd new-vs is: ~a\n" new-vs)
(cond
; no element, all values are 0 and filtered out, return base 0
[(= 0 (length new-vs)) (r1cs:rint 0)]
@@ -176,29 +119,11 @@
[else (r1cs:radd new-vs)]
)
]
- ; (fixme) this could have rewrite issues
- [(r1cs:rsub vs)
- ; remove 0
- (define new-vs (filter
- (lambda (x) (! (is-rint-zero x)))
- (for/list ([v vs]) (optimize-r1cs v))
- ))
- (cond
- ; no element, all values are 0 and filtered out, return base 0
- [(= 0 (length new-vs)) (r1cs:rint 0)]
- ; if there's only one element, rewrite to neg
- [(= 1 (length new-vs)) (r1cs:rneg (car new-vs))]
- ; do nothing
- [else (r1cs:rsub new-vs)]
- )
- ]
[(r1cs:rmul vs)
(define new-vs (filter
- (lambda (x) (! (is-rint-one x)))
+ (lambda (x) (not (is-rint-one x)))
(for/list ([v vs]) (optimize-r1cs v))
))
- ; (printf "# rmul new-vs is: ~a\n" new-vs)
- ; (printf "# cont: ~a\n vs ~a\n" (contains-rint-zero vs) vs)
(cond
; if there's zero already in multiplication, directly return 0
[(contains-rint-zero new-vs) (r1cs:rint 0)]
@@ -210,9 +135,17 @@
[else (r1cs:rmul new-vs)]
)
]
- [(r1cs:rneg v) (r1cs:rneg (optimize-r1cs v))]
- [(r1cs:rmod v mod) (r1cs:rmod (optimize-r1cs v) (optimize-r1cs mod))]
+ [(r1cs:rmod v mod)
+ (define ov (optimize-r1cs v))
+ (define om (optimize-r1cs mod))
+ (if (or (r1cs:rvar? ov) (r1cs:rint? ov))
+ ; no need for mod
+ ov
+ ; still need mod
+ (r1cs:rmod ov om)
+ )
+ ]
- [else (tokamak:exit "not supported: ~a" arg-r1cs)]
+ [_ (tokamak:exit "not supported: ~a" arg-r1cs)]
)
)
\ No newline at end of file
diff --git a/picus/optimizers/r1cs-z3-subp-optimizer.rkt b/picus/optimizers/r1cs-z3-subp-optimizer.rkt
new file mode 100644
index 0000000..1ee64fa
--- /dev/null
+++ b/picus/optimizers/r1cs-z3-subp-optimizer.rkt
@@ -0,0 +1,116 @@
+#lang racket
+; (note) this is applied in optimization phase 1
+; this contains the following optimizations:
+; - add p related definition and replace p
+(require
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "../r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [optimize-r1cs optimize-r1cs]
+))
+
+(define (optimize-r1cs arg-r1cs pdef?)
+ (match arg-r1cs
+
+ ; command level
+ [(r1cs:rcmds vs) (r1cs:rcmds
+ (append
+ (if pdef?
+ ; should include p definitions
+ (list
+ (r1cs:rcmt "======== p definitions ========")
+ (r1cs:rdef (r1cs:rvar "p") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "p") (r1cs:rint config:p)))
+ (r1cs:rdef (r1cs:rvar "ps1") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps1") (r1cs:rint (- config:p 1))))
+ (r1cs:rdef (r1cs:rvar "ps2") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps2") (r1cs:rint (- config:p 2))))
+ (r1cs:rdef (r1cs:rvar "ps3") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps3") (r1cs:rint (- config:p 3))))
+ (r1cs:rdef (r1cs:rvar "ps4") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps4") (r1cs:rint (- config:p 4))))
+ (r1cs:rdef (r1cs:rvar "ps5") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "ps5") (r1cs:rint (- config:p 5))))
+ ; add 0 definition
+ (r1cs:rdef (r1cs:rvar "zero") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "zero") (r1cs:rint 0)))
+ ; add 1 definition
+ (r1cs:rdef (r1cs:rvar "one") (r1cs:rtype "Int"))
+ (r1cs:rassert (r1cs:req (r1cs:rvar "one") (r1cs:rint 1)))
+ )
+ ; should not include p definitions, usually in alt- series
+ ; use placeholder to avoid changing the number of constraints
+ (list
+ (r1cs:rcmt "======== p definitions: alt skip ========")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ (r1cs:rcmt "p definition placeholder")
+ )
+ )
+ (for/list ([v vs]) (optimize-r1cs v pdef?))
+ )
+ )]
+
+ [(r1cs:rraw v) (r1cs:rraw v)]
+ [(r1cs:rlogic v) (r1cs:rlogic v)]
+ ; (note) don't optimize declaration line
+ [(r1cs:rdef v t) (r1cs:rdef v (optimize-r1cs t pdef?))]
+ [(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v pdef?))]
+ [(r1cs:rcmt v) (r1cs:rcmt v)]
+ [(r1cs:rsolve ) (r1cs:rsolve )]
+
+ ; sub-command level
+ [(r1cs:req lhs rhs) (r1cs:req (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+ [(r1cs:rneq lhs rhs) (r1cs:rneq (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+ [(r1cs:rleq lhs rhs) (r1cs:rleq (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+ [(r1cs:rlt lhs rhs) (r1cs:rlt (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+ [(r1cs:rgeq lhs rhs) (r1cs:rgeq (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+ [(r1cs:rgt lhs rhs) (r1cs:rgt (optimize-r1cs lhs pdef?) (optimize-r1cs rhs pdef?))]
+
+ [(r1cs:rand vs) (r1cs:rand (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+ [(r1cs:ror vs) (r1cs:ror (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+
+ [(r1cs:rint v)
+ (cond
+ ; replace as p
+ [(= config:p v) (r1cs:rvar "p")]
+ [(= (- config:p 1) v) (r1cs:rvar "ps1")]
+ [(= (- config:p 2) v) (r1cs:rvar "ps2")]
+ [(= (- config:p 3) v) (r1cs:rvar "ps3")]
+ [(= (- config:p 4) v) (r1cs:rvar "ps4")]
+ [(= (- config:p 5) v) (r1cs:rvar "ps5")]
+ ; replace as zero
+ [(= 0 v) (r1cs:rvar "zero")]
+ ; replace as one
+ [(= 1 v) (r1cs:rvar "one")]
+ ; do nothing
+ [else (r1cs:rint v)]
+ )
+ ]
+ ; (note) we assume "x0" is the first wire with prefix "x"
+ [(r1cs:rvar v) (r1cs:rvar v)]
+ [(r1cs:rtype v) (r1cs:rtype v)]
+
+ [(r1cs:radd vs) (r1cs:radd (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+ [(r1cs:rmul vs) (r1cs:rmul (for/list ([v vs]) (optimize-r1cs v pdef?)))]
+ [(r1cs:rmod v mod) (r1cs:rmod (optimize-r1cs v pdef?) (optimize-r1cs mod pdef?))]
+
+ [_ (tokamak:exit "not supported: ~a" arg-r1cs)]
+ )
+)
\ No newline at end of file
diff --git a/picus/optimizers/r1cs-z3-template-optimizer.rkt b/picus/optimizers/r1cs-z3-template-optimizer.rkt
deleted file mode 100644
index b88504b..0000000
--- a/picus/optimizers/r1cs-z3-template-optimizer.rkt
+++ /dev/null
@@ -1,50 +0,0 @@
-#lang rosette
-; this is a template for optimizer
-(require
- (prefix-in tokamak: "../tokamak.rkt")
- (prefix-in utils: "../utils.rkt")
- (prefix-in config: "../config.rkt")
- (prefix-in r1cs: "../r1cs-grammar.rkt")
-)
-(provide (rename-out
- [optimize-r1cs optimize-r1cs]
-))
-
-(define (optimize-r1cs arg-r1cs)
- (match arg-r1cs
-
- ; command level
- [(r1cs:rcmds vs) (r1cs:rcmds (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rraw v) (r1cs:rraw v)]
- [(r1cs:rlogic v) (r1cs:rlogic (optimize-r1cs v))]
- [(r1cs:rdef v t) (r1cs:rdef v (optimize-r1cs t))]
- [(r1cs:rassert v) (r1cs:rassert (optimize-r1cs v))]
- [(r1cs:rcmt v) (r1cs:rcmt (optimize-r1cs v))]
- [(r1cs:rsolve ) (r1cs:rsolve )]
-
- ; sub-command level
- [(r1cs:req lhs rhs) (r1cs:req (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rneq lhs rhs) (r1cs:rneq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rleq lhs rhs) (r1cs:rleq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rlt lhs rhs) (r1cs:rlt (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgeq lhs rhs) (r1cs:rgeq (optimize-r1cs lhs) (optimize-r1cs rhs))]
- [(r1cs:rgt lhs rhs) (r1cs:rgt (optimize-r1cs lhs) (optimize-r1cs rhs))]
-
- [(r1cs:rand vs) (r1cs:rand (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:ror vs) (r1cs:ror (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rimp lhs rhs) (r1cs:rimp (optimize-r1cs lhs) (optimize-r1cs rhs))]
-
- [(r1cs:rint v) (r1cs:rint v)]
- [(r1cs:rstr v) (r1cs:rstr v)]
- [(r1cs:rvar v) (r1cs:rvar v)]
- [(r1cs:rtype v) (r1cs:rtype v)]
-
- [(r1cs:radd vs) (r1cs:radd (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rsub vs) (r1cs:rsub (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rmul vs) (r1cs:rmul (for/list ([v vs]) (optimize-r1cs v)))]
- [(r1cs:rneg v) (r1cs:rneg (optimize-r1cs v))]
- [(r1cs:rmod v mod) (r1cs:rmod (optimize-r1cs v) (optimize-r1cs mod))]
-
- [else (tokamak:exit "not supported: ~a" arg-r1cs)]
- )
-)
\ No newline at end of file
diff --git a/picus/precondition.rkt b/picus/precondition.rkt
new file mode 100644
index 0000000..0d1d454
--- /dev/null
+++ b/picus/precondition.rkt
@@ -0,0 +1,50 @@
+#lang racket
+(require json
+ (prefix-in tokamak: "./tokamak.rkt")
+ (prefix-in r1cs: "./r1cs/r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [read-precondition read-precondition]
+))
+
+; parse the json precondition into program in r1cs grammar
+; (note) you should provide each piece of precondition, not the entire json
+(define (parse-precondition arg-json)
+ (match arg-json
+ ; language component
+ [(list "rassert" v) (r1cs:rassert (parse-precondition v))]
+ [(list "rneq" lhs rhs) (r1cs:rneq (parse-precondition lhs) (parse-precondition rhs))]
+ [(list "req" lhs rhs) (r1cs:req (parse-precondition lhs) (parse-precondition rhs))]
+ [(list "rmul" vs) (r1cs:rmul (for/list ([v vs]) (parse-precondition v)))]
+ [(list "rmod" lhs rhs) (r1cs:rmod (parse-precondition lhs) (parse-precondition rhs))]
+ [(list "rvar" v) (r1cs:rvar v)] ; make sure v is a string
+ [(list "rint" v) (r1cs:rint v)] ; make sure v is a number/integer
+
+ ; (note) each precondition is only one rassert command, don't include rcmds
+ [_ (tokamak:error "unsupported precondition form, got: ~a." arg-json)]
+ )
+)
+
+; returns:
+; - (values unique-set pres), where
+; - unique-set: a set of assumed unique signals
+; - pres: list of (tag r1cs command)
+; where r1cs command is a single command with not rcmds wrapper
+(define (read-precondition arg-path)
+ (define pre-json (string->jsexpr (file->string arg-path)))
+
+ (define unique-json (filter (lambda (x) (equal? "unique" (car x))) pre-json))
+ (define cmd-json (filter (lambda (x) (not (equal? "unique" (car x)))) pre-json))
+
+ ; process the unique set
+ (define unique-set (list->set (filter (lambda (x) (not (equal? "unique" x))) (flatten unique-json))))
+
+ ; process precondition
+ (define pres (for/list ([v cmd-json])
+ (when (not (= 2 (length v)))
+ (tokamak:error "precondition entry should contain exactly 2 elements, got: ~a." v))
+ (cons (list-ref v 0) (parse-precondition (list-ref v 1)))
+ ))
+
+ (values unique-set pres)
+)
\ No newline at end of file
diff --git a/picus/r1cs-cvc5-parser.rkt b/picus/r1cs-cvc5-parser.rkt
deleted file mode 100644
index 4f69b12..0000000
--- a/picus/r1cs-cvc5-parser.rkt
+++ /dev/null
@@ -1,117 +0,0 @@
-#lang rosette
-; this interprets binary r1cs into its grammar representation
-(require
- (prefix-in tokamak: "./tokamak.rkt")
- (prefix-in utils: "./utils.rkt")
- (prefix-in config: "./config.rkt")
- (prefix-in r1cs: "./r1cs-grammar.rkt")
-)
-(provide (rename-out
- [parse-r1cs parse-r1cs]
-))
-
-(define (parse-r1cs arg-r1cs arg-xlist)
- (define raw-declarations (list)) ; a list of commands
- (define raw-cmds (list)) ; a list of commands
-
- ; first create a list of all symbolic variables according to nwires
- (define nwires (r1cs:get-nwires arg-r1cs))
- ; strictly align with wid
- (define xlist (if (null? arg-xlist)
- ; create fresh new
- (for/list ([i nwires]) (format "x~a" i))
- ; use existing one
- arg-xlist
- ))
-
- ; add declarations for variables
- ; for cvc5, no range constraints are needed
- (set! raw-declarations (append raw-declarations
- (list (r1cs:rcmt (r1cs:rstr "======== declaration constraints ========")))
- (for/list ([x xlist])
- (if (&& (! (null? arg-xlist)) (string-prefix? x "x"))
- ; provided list with already defined x, skip
- (r1cs:rcmt (r1cs:rstr (format "~a: already defined" x)))
- ; otherwise you need to define this variable
- (r1cs:rdef (r1cs:rvar (format "~a" x)) (r1cs:rtype "F"))
- )
- )
- ))
-
- ; then start creating constraints
- (define m (r1cs:get-mconstraints arg-r1cs))
- (define rconstraints (r1cs:get-constraints arg-r1cs)) ; r1cs constraints
-
- ; symbolic constraints
- (define sconstraints (for/list ([cnst rconstraints])
-
- ; get block
- (define curr-block-a (r1cs:constraint-a cnst))
- (define curr-block-b (r1cs:constraint-b cnst))
- (define curr-block-c (r1cs:constraint-c cnst))
-
- ; process block a
- (define nnz-a (r1cs:constraint-block-nnz curr-block-a))
- (define wids-a (r1cs:constraint-block-wids curr-block-a))
- (define factors-a (r1cs:constraint-block-factors curr-block-a))
-
- ; process block b
- (define nnz-b (r1cs:constraint-block-nnz curr-block-b))
- (define wids-b (r1cs:constraint-block-wids curr-block-b))
- (define factors-b (r1cs:constraint-block-factors curr-block-b))
-
- ; process block c
- (define nnz-c (r1cs:constraint-block-nnz curr-block-c))
- (define wids-c (r1cs:constraint-block-wids curr-block-c))
- (define factors-c (r1cs:constraint-block-factors curr-block-c))
-
- ; assemble symbolic terms
- ; note that terms could be empty, in which case 0 is used
- ; (printf "# wids-a is: ~a\n" wids-a)
- (define terms-a (cons (r1cs:rint 0) (for/list ([w0 wids-a] [f0 factors-a])
- ; optimized form
- (let ([x0 (list-ref xlist w0)])
- (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
- )
- )))
- ; (printf "# wids-b is: ~a\n" wids-b)
- (define terms-b (cons (r1cs:rint 0) (for/list ([w0 wids-b] [f0 factors-b])
- ; optimized form
- (let ([x0 (list-ref xlist w0)])
- (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
- )
- )))
- ; (printf "# wids-c is: ~a\n" wids-c)
- (define terms-c (cons (r1cs:rint 0) (for/list ([w0 wids-c] [f0 factors-c])
- ; optimized form
- (let ([x0 (list-ref xlist w0)])
- (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
- )
- )))
- ; (printf "# done wids\n")
-
- (define sum-a (r1cs:radd terms-a))
- (define sum-b (r1cs:radd terms-b))
- (define sum-c (r1cs:radd terms-c))
- ; original form
- (define ret-cnst (r1cs:rassert (r1cs:req
- (r1cs:rmul (list sum-a sum-b))
- sum-c
- )))
-
- ; return this assembled constraint
- ret-cnst
- ))
-
- ; update smt with comments and fixed constraints
- (set! raw-cmds (append
- raw-cmds
- ;(list (r1cs:rcmt (r1cs:rstr "======== r1cs constraints ========")))
- sconstraints
- (list (r1cs:rassert (r1cs:req
- (r1cs:rint 1) (r1cs:rvar (format "~a" (list-ref xlist 0)))
- )))
- ))
-
- (values xlist (r1cs:rcmds raw-declarations) (r1cs:rcmds raw-cmds))
-)
diff --git a/picus/r1cs-z3-parser.rkt b/picus/r1cs-z3-parser.rkt
deleted file mode 100644
index 860e319..0000000
--- a/picus/r1cs-z3-parser.rkt
+++ /dev/null
@@ -1,141 +0,0 @@
-#lang rosette
-; this interprets binary r1cs into its grammar representation
-(require
- (prefix-in tokamak: "./tokamak.rkt")
- (prefix-in utils: "./utils.rkt")
- (prefix-in config: "./config.rkt")
- (prefix-in r1cs: "./r1cs-grammar.rkt")
-)
-(provide (rename-out
- [parse-r1cs parse-r1cs]
-))
-
-(define (parse-r1cs arg-r1cs arg-xlist)
- (define raw-cmds (list)) ; a list of commands
- (define raw-declarations (list)) ; a list of variable declarations
-
- ; first create a list of all symbolic variables according to nwires
- (define nwires (r1cs:get-nwires arg-r1cs))
- ; strictly align with wid
- (define xlist (if (null? arg-xlist)
- ; create fresh new
- (for/list ([i nwires]) (format "x~a" i))
- ; use existing one
- arg-xlist
- ))
-
- ; add declarations for variables
- (set! raw-declarations (append raw-declarations
- (list (r1cs:rcmt (r1cs:rstr "======== declaration constraints ========")))
- (for/list ([x xlist])
- (if (&& (! (null? arg-xlist)) (string-prefix? x "x"))
- ; provided list with already defined x, skip
- (r1cs:rcmt (r1cs:rstr (format "~a: already defined" x)))
- ; otherwise you need to define this variable
- (r1cs:rdef (r1cs:rvar (format "~a" x)) (r1cs:rtype "Int"))
- )
- )
- ))
-
- ; add range constraints for declared variables
- (set! raw-declarations (append raw-declarations
- (list (r1cs:rcmt (r1cs:rstr "======== range constraints ========")))
- (for/list ([x xlist])
- (if (&& (! (null? arg-xlist)) (string-prefix? x "x"))
- ; provided list with already defined x, skip
- (r1cs:rcmt (r1cs:rstr (format "~a: already defined" x)))
- ; otherwise you need to define this variable
- (r1cs:rassert (r1cs:rand (list
- (r1cs:rleq (r1cs:rint 0) (r1cs:rvar (format "~a" x)))
- (r1cs:rlt (r1cs:rvar (format "~a" x)) (r1cs:rint config:p))
- )))
- )
- )
- ))
-
- ; then start creating constraints
- (define m (r1cs:get-mconstraints arg-r1cs))
- (define rconstraints (r1cs:get-constraints arg-r1cs)) ; r1cs constraints
-
- ; symbolic constraints
- (define sconstraints (for/list ([cnst rconstraints])
-
- ; get block
- (define curr-block-a (r1cs:constraint-a cnst))
- (define curr-block-b (r1cs:constraint-b cnst))
- (define curr-block-c (r1cs:constraint-c cnst))
-
- ; process block a
- (define nnz-a (r1cs:constraint-block-nnz curr-block-a))
- (define wids-a (r1cs:constraint-block-wids curr-block-a))
- (define factors-a (r1cs:constraint-block-factors curr-block-a))
-
- ; process block b
- (define nnz-b (r1cs:constraint-block-nnz curr-block-b))
- (define wids-b (r1cs:constraint-block-wids curr-block-b))
- (define factors-b (r1cs:constraint-block-factors curr-block-b))
-
- ; process block c
- (define nnz-c (r1cs:constraint-block-nnz curr-block-c))
- (define wids-c (r1cs:constraint-block-wids curr-block-c))
- (define factors-c (r1cs:constraint-block-factors curr-block-c))
-
- ; assemble symbolic terms
- ; note that terms could be empty, in which case 0 is used
- ; (printf "# wids-a is: ~a\n" wids-a)
- (define terms-a (cons (r1cs:rint 0) (for/list ([w0 wids-a] [f0 factors-a])
- ; (format "(* ~a ~a)" f0 x0)
- ; optimized form
- (let ([x0 (list-ref xlist w0)])
- (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
- )
- )))
- ; (printf "# wids-b is: ~a\n" wids-b)
- (define terms-b (cons (r1cs:rint 0) (for/list ([w0 wids-b] [f0 factors-b])
- ; (format "(* ~a ~a)" f0 x0)
- ; optimized form
- (let ([x0 (list-ref xlist w0)])
- (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
- )
- )))
- ; (printf "# wids-c is: ~a\n" wids-c)
- (define terms-c (cons (r1cs:rint 0) (for/list ([w0 wids-c] [f0 factors-c])
- ; (format "(* ~a ~a)" f0 x0)
- ; optimized form
- (let ([x0 (list-ref xlist w0)])
- (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
- )
- )))
- ; (printf "# done wids\n")
-
- (define sum-a (r1cs:radd terms-a))
- (define sum-b (r1cs:radd terms-b))
- (define sum-c (r1cs:radd terms-c))
- ; original form
- (define ret-cnst (r1cs:rassert (r1cs:req
- (r1cs:rint 0)
- (r1cs:rmod
- (r1cs:rsub (list
- (r1cs:rmul (list sum-a sum-b))
- sum-c
- ))
- (r1cs:rint config:p)
- ) ; only enable mod here
- )))
-
- ; return this assembled constraint
- ret-cnst
- ))
-
- ; update smt with comments and fixed constraints
- (set! raw-cmds (append
- raw-cmds
- ;(list (r1cs:rcmt (r1cs:rstr "======== r1cs constraints ========")))
- sconstraints
- (list (r1cs:rassert (r1cs:req
- (r1cs:rint 1) (r1cs:rvar (format "~a" (list-ref xlist 0)))
- )))
- ))
-
- (values xlist (r1cs:rcmds raw-declarations) (r1cs:rcmds raw-cmds))
-)
diff --git a/picus/r1cs-cvc5-interpreter.rkt b/picus/r1cs/r1cs-cvc4-interpreter.rkt
similarity index 67%
rename from picus/r1cs-cvc5-interpreter.rkt
rename to picus/r1cs/r1cs-cvc4-interpreter.rkt
index 2e01f3d..29d9e4a 100644
--- a/picus/r1cs-cvc5-interpreter.rkt
+++ b/picus/r1cs/r1cs-cvc4-interpreter.rkt
@@ -1,9 +1,9 @@
-#lang rosette
+#lang racket
; this interprets r1cs commands into z3 constraints
(require
- (prefix-in tokamak: "./tokamak.rkt")
- (prefix-in utils: "./utils.rkt")
- (prefix-in config: "./config.rkt")
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
(prefix-in r1cs: "./r1cs-grammar.rkt")
)
(provide (rename-out
@@ -13,8 +13,8 @@
(define (make-format-op op)
(define (format-op x y)
(cond
- ; [(&& (null? x) (null? y)) (tokamak:exit "x and y can't both be null")]
- [(&& (null? x) (null? y)) ""]
+ ; [(and (null? x) (null? y)) (tokamak:exit "x and y can't both be null")]
+ [(and (null? x) (null? y)) ""]
[(null? x) y]
[(null? y) x]
[else (format "(~a ~a ~a)" op x y)]
@@ -31,10 +31,10 @@
[(r1cs:rcmds vs) (for/list ([v vs]) (interpret-r1cs v))]
[(r1cs:rraw v) (format "~a" v)]
- [(r1cs:rlogic v) (format "(set-logic ~a)" (interpret-r1cs v))]
+ [(r1cs:rlogic v) (format "(set-logic ~a)" v)]
[(r1cs:rdef v t) (format "(declare-const ~a ~a)" (interpret-r1cs v) (interpret-r1cs t))]
[(r1cs:rassert v) (format "(assert ~a)" (interpret-r1cs v))]
- [(r1cs:rcmt v) (format "; ~a" (interpret-r1cs v))]
+ [(r1cs:rcmt v) (format "; ~a" v)]
[(r1cs:rsolve ) "(check-sat)\n(get-model)"]
; sub-command level
@@ -49,16 +49,16 @@
[(r1cs:ror vs) (foldr (make-format-op "or") null (for/list ([v vs]) (interpret-r1cs v)))]
[(r1cs:rimp lhs rhs) (format "(=> ~a ~a)" (interpret-r1cs lhs) (interpret-r1cs rhs))]
- [(r1cs:rint v) (format "#f~am~a" v config:p)]
- [(r1cs:rstr v) v]
+ [(r1cs:rint v) (format "~a" v)]
[(r1cs:rvar v) (format "~a" v)]
[(r1cs:rtype v) (format "~a" v)]
- [(r1cs:radd vs) (foldr (make-format-op "ff.add") null (for/list ([v vs]) (interpret-r1cs v)))]
- [(r1cs:rsub vs) (tokamak:exit "cvc5 doesn't support sub")]
- [(r1cs:rmul vs) (foldr (make-format-op "ff.mul") null (for/list ([v vs]) (interpret-r1cs v)))]
- [(r1cs:rneg v) (format "(ff.neg ~a)" (interpret-r1cs v))]
- [(r1cs:rmod v mod) (tokamak:exit "cvc5 doesn't support mod")]
+ [(r1cs:radd vs) (foldr (make-format-op "+") null (for/list ([v vs]) (interpret-r1cs v)))]
+ [(r1cs:rsub vs) (foldr (make-format-op "-") null (for/list ([v vs]) (interpret-r1cs v)))]
+ [(r1cs:rmul vs) (foldr (make-format-op "*") null (for/list ([v vs]) (interpret-r1cs v)))]
+ [(r1cs:rneg v) (format "(- ~a)" (interpret-r1cs v))]
+ ; use mod for cvc4 since there's no rem
+ [(r1cs:rmod v mod) (format "(mod ~a ~a)" (interpret-r1cs v) (interpret-r1cs mod))]
[else (tokamak:exit "not supported: ~a" arg-r1cs)]
)
diff --git a/picus/r1cs/r1cs-cvc5-interpreter.rkt b/picus/r1cs/r1cs-cvc5-interpreter.rkt
new file mode 100644
index 0000000..23dfdb0
--- /dev/null
+++ b/picus/r1cs/r1cs-cvc5-interpreter.rkt
@@ -0,0 +1,58 @@
+#lang racket
+; this interprets r1cs commands into z3 constraints
+(require
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "./r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [interpret-r1cs interpret-r1cs]
+))
+
+(define (make-format-op op)
+ (define (format-op x y)
+ (cond
+ ; [(and (null? x) (null? y)) (tokamak:exit "x and y can't both be null")]
+ [(and (null? x) (null? y)) ""]
+ [(null? x) y]
+ [(null? y) x]
+ [else (format "(~a ~a ~a)" op x y)]
+ )
+ )
+ ; return a function
+ format-op
+)
+
+(define (interpret-r1cs arg-r1cs)
+ (match arg-r1cs
+
+ ; command level
+ [(r1cs:rcmds vs) (for/list ([v vs]) (interpret-r1cs v))]
+
+ [(r1cs:rraw v) (format "~a" v)]
+ [(r1cs:rlogic v) (format "(set-logic ~a)" v)]
+ [(r1cs:rdef v t) (format "(declare-const ~a ~a)" (interpret-r1cs v) (interpret-r1cs t))]
+ [(r1cs:rassert v) (format "(assert ~a)" (interpret-r1cs v))]
+ [(r1cs:rcmt v) (format "; ~a" v)]
+ [(r1cs:rsolve ) "(check-sat)\n(get-model)"]
+
+ ; sub-command level
+ [(r1cs:req lhs rhs) (format "(= ~a ~a)" (interpret-r1cs lhs) (interpret-r1cs rhs))]
+ [(r1cs:rneq lhs rhs) (format "(not (= ~a ~a))" (interpret-r1cs lhs) (interpret-r1cs rhs))]
+
+ [(r1cs:rand vs) (foldr (make-format-op "and") null (for/list ([v vs]) (interpret-r1cs v)))]
+ [(r1cs:ror vs) (foldr (make-format-op "or") null (for/list ([v vs]) (interpret-r1cs v)))]
+ [(r1cs:rimp lhs rhs) (format "(=> ~a ~a)" (interpret-r1cs lhs) (interpret-r1cs rhs))]
+
+ [(r1cs:rint v) (format "#f~am~a" v config:p)]
+ [(r1cs:rvar v) (format "~a" v)]
+ [(r1cs:rtype v) (format "~a" v)]
+
+ [(r1cs:radd vs) (foldr (make-format-op "ff.add") null (for/list ([v vs]) (interpret-r1cs v)))]
+ [(r1cs:rmul vs) (foldr (make-format-op "ff.mul") null (for/list ([v vs]) (interpret-r1cs v)))]
+ [(r1cs:rmod v mod) (tokamak:exit "cvc5 doesn't support mod")]
+
+ [else (tokamak:exit "not supported: ~a" arg-r1cs)]
+ )
+)
\ No newline at end of file
diff --git a/picus/r1cs/r1cs-cvc5-parser.rkt b/picus/r1cs/r1cs-cvc5-parser.rkt
new file mode 100644
index 0000000..7f64966
--- /dev/null
+++ b/picus/r1cs/r1cs-cvc5-parser.rkt
@@ -0,0 +1,352 @@
+#lang racket
+; this interprets binary r1cs into its grammar representation
+(require
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "./r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [parse-r1cs parse-r1cs]
+ [expand-r1cs expand-r1cs]
+ [parse-r1cs-old parse-r1cs-old]
+))
+
+; turns r1cs binary form into standard form
+; arguments:
+; - arg-r1cs: r1cs binary form instance using the struct r1cs grammar
+; - arg-xlist: symbols (in string) to use, usually in "x?" form
+; when parsing alt constraints, non-input symbols are replaced with "y?" series
+; returns:
+; - (values xlist options declarations constraints)
+(define (parse-r1cs arg-r1cs arg-xlist)
+
+ ; a list of options
+ (define raw-opts (list
+ (r1cs:rlogic "QF_FF")
+ (r1cs:rraw "(set-info :smt-lib-version 2.6)")
+ (r1cs:rraw "(set-info :category \"crafted\")")
+ (r1cs:rraw (format "(define-sort F () (_ FiniteField ~a))" config:p))
+ ))
+
+ (define raw-cnsts (list)) ; a list of commands
+ (define raw-decls (list)) ; a list of variable declarations
+
+ ; first create a list of all symbolic variables according to nwires
+ (define nwires (r1cs:get-nwires arg-r1cs))
+ ; strictly align with wid
+ (define xlist (if (null? arg-xlist)
+ ; create fresh new
+ (for/list ([i nwires]) (format "x~a" i))
+ ; use existing one
+ arg-xlist
+ ))
+
+ ; add declarations for variables
+ (set! raw-decls (append raw-decls
+ (list (r1cs:rcmt "======== declaration constraints ========"))
+ (for/list ([x xlist])
+ (if (and (not (null? arg-xlist)) (string-prefix? x "x"))
+ ; provided list with already defined x, skip
+ (r1cs:rcmt (format "~a: already defined" x))
+ ; otherwise you need to define this variable
+ (r1cs:rdef (r1cs:rvar (format "~a" x)) (r1cs:rtype "F"))
+ )
+ )
+ ))
+
+ ; then start creating constraints
+ (define m (r1cs:get-mconstraints arg-r1cs))
+ (define rconstraints (r1cs:get-constraints arg-r1cs)) ; r1cs constraints
+
+ ; symbolic constraints
+ (define sconstraints (for/list ([cnst rconstraints])
+
+ ; get block
+ (define curr-block-a (r1cs:constraint-a cnst))
+ (define curr-block-b (r1cs:constraint-b cnst))
+ (define curr-block-c (r1cs:constraint-c cnst))
+
+ ; process block a
+ (define nnz-a (r1cs:constraint-block-nnz curr-block-a))
+ (define wids-a (r1cs:constraint-block-wids curr-block-a))
+ (define factors-a (r1cs:constraint-block-factors curr-block-a))
+
+ ; process block b
+ (define nnz-b (r1cs:constraint-block-nnz curr-block-b))
+ (define wids-b (r1cs:constraint-block-wids curr-block-b))
+ (define factors-b (r1cs:constraint-block-factors curr-block-b))
+
+ ; process block c
+ (define nnz-c (r1cs:constraint-block-nnz curr-block-c))
+ (define wids-c (r1cs:constraint-block-wids curr-block-c))
+ (define factors-c (r1cs:constraint-block-factors curr-block-c))
+
+ ; ======== parse into original form: A*B = C ========
+ ; note that terms could be empty, in which case 0 is used
+ (define terms-a (cons (r1cs:rint 0) (for/list ([w0 wids-a] [f0 factors-a])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ )
+ )))
+ (define terms-b (cons (r1cs:rint 0) (for/list ([w0 wids-b] [f0 factors-b])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ )
+ )))
+ (define terms-c (cons (r1cs:rint 0) (for/list ([w0 wids-c] [f0 factors-c])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ )
+ )))
+ (define sum-a (r1cs:radd terms-a))
+ (define sum-b (r1cs:radd terms-b))
+ (define sum-c (r1cs:radd terms-c))
+ ; original form: A*B = C
+ (define ret-cnst (r1cs:rassert (r1cs:req
+ (r1cs:rmul (list sum-a sum-b))
+ sum-c
+ )))
+
+ ret-cnst
+ ))
+
+ ; update smt with comments and fixed constraints
+ (set! raw-cnsts (append
+ raw-cnsts
+ (list (r1cs:rcmt "======== main constraints ========"))
+ sconstraints
+ (list (r1cs:rassert (r1cs:req
+ (r1cs:rint 1) (r1cs:rvar (format "~a" (list-ref xlist 0)))
+ )))
+ ))
+
+ (values
+ xlist
+ (r1cs:rcmds raw-opts)
+ (r1cs:rcmds raw-decls)
+ (r1cs:rcmds raw-cnsts)
+ )
+)
+
+
+; expands standard r1cs into terms++ form (sum of terms)
+; usually only the cnsts part is provided
+; arguments:
+; - arg-r1cs: r1cs standard form instance using the struct rcmds grammar
+; returns:
+; - expanded-r1cs
+(define (expand-r1cs arg-r1cs)
+ (define ret-cnsts (for/list ([v (r1cs:rcmds-vs arg-r1cs)])
+ (match v
+ ; match the standard form a*b=c
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmul (list
+ (r1cs:radd (list (r1cs:rint 0) (r1cs:rmul (list (r1cs:rint a0s) (r1cs:rvar a1s))) ...)) ; shape of A
+ (r1cs:radd (list (r1cs:rint 0) (r1cs:rmul (list (r1cs:rint b0s) (r1cs:rvar b1s))) ...)) ; shape of B
+ ))
+ (r1cs:radd (list (r1cs:rint 0) (r1cs:rmul (list (r1cs:rint c0s) (r1cs:rvar c1s))) ...)) ; shape of C
+ ))
+ ; start the expansion
+ (define terms-a (for/list ([a0 a0s][a1 a1s]) (cons a0 a1)))
+ (define terms-b (for/list ([b0 b0s][b1 b1s]) (cons b0 b1)))
+ (define terms-c (for/list ([c0 c0s][c1 c1s]) (cons c0 c1)))
+ ; A*B = C but expand A*B into ++terms
+ (r1cs:rassert (r1cs:req
+ ; A*B part
+ (if (or (empty? terms-a) (empty? terms-b))
+ ; A*B is empty
+ (r1cs:rint 0)
+ ; A*B is not empty
+ (r1cs:radd (for*/list ([va terms-a][vb terms-b])
+ (r1cs:rmul (list
+ (r1cs:rint (remainder (* (car va) (car vb)) config:p))
+ (r1cs:rvar (cdr va))
+ (r1cs:rvar (cdr vb))
+ ))
+ ))
+ )
+ ; C part
+ (if (empty? terms-c)
+ ; C is empty
+ (r1cs:rint 0)
+ ; C is not empty
+ (r1cs:radd (for/list ([v terms-c]) (r1cs:rmul (list (r1cs:rint (car v)) (r1cs:rvar (cdr v))))))
+ )
+ ))
+ ]
+ ; otherwise, just keep the form
+ [_
+ ; (tokamak:log "out of pattern: ~a" v)
+ v
+ ]
+ )
+ ))
+ ; return
+ (r1cs:rcmds ret-cnsts)
+)
+
+
+; to be deleted
+(define (parse-r1cs-old arg-r1cs arg-xlist)
+
+ ; a list of options
+ (define raw-options (list
+ (r1cs:rlogic "QF_FF")
+ (r1cs:rraw "(set-info :smt-lib-version 2.6)")
+ (r1cs:rraw "(set-info :category \"crafted\")")
+ (r1cs:rraw (format "(define-sort F () (_ FiniteField ~a))" config:p))
+ ))
+
+ (define raw-declarations (list)) ; a list of commands
+ (define raw-cmds (list)) ; a list of commands
+
+ ; first create a list of all symbolic variables according to nwires
+ (define nwires (r1cs:get-nwires arg-r1cs))
+ ; strictly align with wid
+ (define xlist (if (null? arg-xlist)
+ ; create fresh new
+ (for/list ([i nwires]) (format "x~a" i))
+ ; use existing one
+ arg-xlist
+ ))
+
+ ; add declarations for variables
+ ; for cvc5, no range constraints are needed
+ (set! raw-declarations (append raw-declarations
+ (list (r1cs:rcmt "======== declaration constraints ========"))
+ (for/list ([x xlist])
+ (if (and (not (null? arg-xlist)) (string-prefix? x "x"))
+ ; provided list with already defined x, skip
+ (r1cs:rcmt (format "~a: already defined" x))
+ ; otherwise you need to define this variable
+ (r1cs:rdef (r1cs:rvar (format "~a" x)) (r1cs:rtype "F"))
+ )
+ )
+ ))
+
+ ; then start creating constraints
+ (define m (r1cs:get-mconstraints arg-r1cs))
+ (define rconstraints (r1cs:get-constraints arg-r1cs)) ; r1cs constraints
+
+ ; symbolic constraints
+ (define sconstraints (for/list ([cnst rconstraints])
+
+ ; get block
+ (define curr-block-a (r1cs:constraint-a cnst))
+ (define curr-block-b (r1cs:constraint-b cnst))
+ (define curr-block-c (r1cs:constraint-c cnst))
+
+ ; process block a
+ (define nnz-a (r1cs:constraint-block-nnz curr-block-a))
+ (define wids-a (r1cs:constraint-block-wids curr-block-a))
+ (define factors-a (r1cs:constraint-block-factors curr-block-a))
+
+ ; process block b
+ (define nnz-b (r1cs:constraint-block-nnz curr-block-b))
+ (define wids-b (r1cs:constraint-block-wids curr-block-b))
+ (define factors-b (r1cs:constraint-block-factors curr-block-b))
+
+ ; process block c
+ (define nnz-c (r1cs:constraint-block-nnz curr-block-c))
+ (define wids-c (r1cs:constraint-block-wids curr-block-c))
+ (define factors-c (r1cs:constraint-block-factors curr-block-c))
+
+ ; ======== parse into original form: A*B = C ========
+ ; assemble symbolic terms
+ ; note that terms could be empty, in which case 0 is used
+ ; (define terms-a (cons (r1cs:rint 0) (for/list ([w0 wids-a] [f0 factors-a])
+ ; ; (format "(* ~a ~a)" f0 x0)
+ ; (let ([x0 (list-ref xlist w0)])
+ ; (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ ; )
+ ; )))
+ ; (define terms-b (cons (r1cs:rint 0) (for/list ([w0 wids-b] [f0 factors-b])
+ ; ; (format "(* ~a ~a)" f0 x0)
+ ; (let ([x0 (list-ref xlist w0)])
+ ; (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ ; )
+ ; )))
+ ; (define terms-c (cons (r1cs:rint 0) (for/list ([w0 wids-c] [f0 factors-c])
+ ; ; (format "(* ~a ~a)" f0 x0)
+ ; (let ([x0 (list-ref xlist w0)])
+ ; (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ ; )
+ ; )))
+ ; (define sum-a (r1cs:radd terms-a))
+ ; (define sum-b (r1cs:radd terms-b))
+ ; (define sum-c (r1cs:radd terms-c))
+ ; ; original form: A*B = C
+ ; (define ret-cnst (r1cs:rassert (r1cs:req
+ ; (r1cs:rmod (r1cs:rmul (list sum-a sum-b)) (r1cs:rint config:p))
+ ; (r1cs:rmod sum-c (r1cs:rint config:p))
+ ; )))
+
+ ; ======== parse into expanded form: A*B = C but expand A*B into ++terms ========
+ ; assemble symbolic terms
+ ; note that terms could be empty, in which case 0 is used
+ (define terms-a (for/list ([w0 wids-a] [f0 factors-a])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (cons f0 x0)
+ )
+ ))
+ (define terms-b (for/list ([w0 wids-b] [f0 factors-b])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (cons f0 x0)
+ )
+ ))
+ (define terms-c (for/list ([w0 wids-c] [f0 factors-c])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (cons f0 x0)
+ )
+ ))
+ ; A*B = C but expand A*B into ++terms
+ (define ret-cnst (r1cs:rassert (r1cs:req
+ ; A*B part
+ (if (or (empty? terms-a) (empty? terms-b))
+ ; A*B is empty
+ (r1cs:rint 0)
+ ; A*B is not empty
+ (r1cs:radd (for*/list ([va terms-a][vb terms-b])
+ (r1cs:rmul (list
+ (r1cs:rint (remainder (* (car va) (car vb)) config:p))
+ (r1cs:rvar (cdr va))
+ (r1cs:rvar (cdr vb))
+ ))
+ ))
+ )
+ ; C part
+ (if (empty? terms-c)
+ ; C is empty
+ (r1cs:rint 0)
+ ; C is not empty
+ (r1cs:radd (for/list ([v terms-c]) (r1cs:rmul (list (r1cs:rint (car v)) (r1cs:rvar (cdr v))))))
+ )
+ )))
+
+ ; return this assembled constraint
+ ret-cnst
+ ))
+
+ ; update smt with comments and fixed constraints
+ (set! raw-cmds (append
+ raw-cmds
+ sconstraints
+ (list (r1cs:rassert (r1cs:req
+ (r1cs:rint 1) (r1cs:rvar (format "~a" (list-ref xlist 0)))
+ )))
+ ))
+
+ (values
+ xlist
+ (r1cs:rcmds raw-options)
+ (r1cs:rcmds raw-declarations)
+ (r1cs:rcmds raw-cmds)
+ )
+)
diff --git a/picus/r1cs-grammar.rkt b/picus/r1cs/r1cs-grammar.rkt
similarity index 57%
rename from picus/r1cs-grammar.rkt
rename to picus/r1cs/r1cs-grammar.rkt
index 34e65c7..9d802e7 100644
--- a/picus/r1cs-grammar.rkt
+++ b/picus/r1cs/r1cs-grammar.rkt
@@ -1,8 +1,8 @@
-#lang rosette
+#lang racket
(require
- (prefix-in tokamak: "./tokamak.rkt")
- (prefix-in utils: "./utils.rkt")
- (prefix-in config: "./config.rkt")
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
)
(provide (all-defined-out))
@@ -11,6 +11,10 @@
; map back to field
(define (F x) (modulo x config:p))
+; ====================================
+; ======== utils for r1cs ast ========
+; ====================================
+
; r1cs commands (grammar)
; command level
(struct rcmds (vs) #:mutable #:transparent #:reflection-name 'r1cs:rcmds) ; vs: list
@@ -22,7 +26,6 @@
(struct rsolve () #:mutable #:transparent #:reflection-name 'r1cs:rsolve)
; sub-command level
(struct rint (v) #:mutable #:transparent #:reflection-name 'r1cs:rint) ; v: int
-(struct rstr (v) #:mutable #:transparent #:reflection-name 'r1cs:rstr) ; v: str
(struct rvar (v) #:mutable #:transparent #:reflection-name 'r1cs:rvar) ; v: str
(struct rtype (v) #:mutable #:transparent #:reflection-name 'r1cs:rtype) ; v: str
; sub-command level
@@ -45,16 +48,315 @@
(struct rneg (v) #:mutable #:transparent #:reflection-name 'r1cs:rneg) ; v: int
(struct rmod (v mod) #:mutable #:transparent #:reflection-name 'r1cs:rmod) ; v: int, mod: int
-(define (append-rcmds . obj)
+(define (rcmds-ref obj ind) (list-ref (rcmds-vs obj) ind))
+
+; concatenate multiple rcmd
+(define (rcmds-append . obj)
(if (null? obj)
(rcmds (list ))
(rcmds (append
(rcmds-vs (car obj))
- (rcmds-vs (apply append-rcmds (cdr obj)))
+ (rcmds-vs (apply rcmds-append (cdr obj)))
))
)
)
+; returns a human readable string of one specified equation
+; no mode is shown for better reading
+; this will skip the solver specific commands
+(define (rcmds->string arg-rcmds arg-id)
+ ; define print function
+ (define (do obj0)
+ (match obj0
+ [(rraw v) ""]
+ [(rlogic v) ""]
+ [(rdef v t) ""]
+ [(rassert v) (do v)]
+ [(rcmt v) ""]
+ [(rsolve ) ""]
+ [(req lhs rhs) (format "~a = ~a" (do lhs) (do rhs))]
+ [(rneq lhs rhs) (format "~a != ~a" (do lhs) (do rhs))]
+ [(rleq lhs rhs) (format "~a <= ~a" (do lhs) (do rhs))]
+ [(rlt lhs rhs) (format "~a < ~a" (do lhs) (do rhs))]
+ [(rgeq lhs rhs) (format "~a >= ~a" (do lhs) (do rhs))]
+ [(rgt lhs rhs) (format "~a > ~a" (do lhs) (do rhs))]
+ [(rand vs)
+ (string-join (for/list ([v vs]) (format "(~a)" (do v)))
+ " /\\ "
+ )
+ ]
+ [(rimp lhs rhs) (format "~a => ~a" (do lhs) (do rhs))]
+ [(ror vs)
+ (string-join (for/list ([v vs]) (format "(~a)" (do v)))
+ " \\/ "
+ )
+ ]
+ [(rint v) (format "~a" v)]
+ [(rvar v) (format "~a" v)]
+ [(radd vs)
+ (string-join (for/list ([v vs]) (format "~a" (do v)))
+ " + "
+ )
+ ]
+ [(rsub vs)
+ (string-join (for/list ([v vs]) (format "~a" (do v)))
+ " - "
+ )
+ ]
+ [(rmul vs)
+ (string-join (for/list ([v vs]) (format "~a" (do v)))
+ " * "
+ )
+ ]
+ [(rmod v mod) (do v)]
+ [else (tokamak:exit "not supported: ~a" obj0)]
+ )
+ )
+ ; call print function and return the printed string
+ (do (list-ref (rcmds-vs arg-rcmds) arg-id))
+)
+
+; return a set of all variables occuring in a (partial) r1cs ast
+; - arg-indexonly: whether to extract the indices instead of keeping the full variable name
+; (note) you should (had better) normalize the constraints before calling this method
+; to get the most precise results; e.g., 1*x would not otherwise be considered
+; in form of x0*x
+(define (get-assert-variables obj [arg-indexonly #f])
+ ; define internal function
+ (define (do obj0)
+ (match obj0
+ [(rcmds vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rraw v) (list )]
+ [(rlogic v) (list )]
+ [(rdef v t) (list )]
+ [(rassert v) (do v)]
+ [(rcmt v) (list )]
+ [(rsolve ) (list )]
+ [(req lhs rhs) (append (do lhs) (do rhs))]
+ [(rneq lhs rhs) (append (do lhs) (do rhs))]
+ [(rleq lhs rhs) (append (do lhs) (do rhs))]
+ [(rlt lhs rhs) (append (do lhs) (do rhs))]
+ [(rgeq lhs rhs) (append (do lhs) (do rhs))]
+ [(rgt lhs rhs) (append (do lhs) (do rhs))]
+ [(rand vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rimp lhs rhs) (append (do lhs) (do rhs))]
+ [(ror vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rint v) (list )]
+ [(rvar v)
+ ; (fixme) we here assume prefix is either "x" or "y"
+ (if (or (string-prefix? v "x") (string-prefix? v "y"))
+ ; starts with x or y, good
+ (if arg-indexonly
+ ; extracted variable index
+ (list (string->number (substring v 1)))
+ ; original string variable
+ (list v)
+ )
+ ; not starting with x or y, could be ps?, could be zero/one
+ ; don't include
+ (list )
+ )
+ ]
+ [(rtype v) (list )]
+ [(radd vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rsub vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rmul vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rmod v mod) (append (do v) (do mod))]
+ [else (tokamak:exit "not supported: ~a" obj0)]
+ )
+ )
+ ; then call it and remove duplicates, and return
+ (list->set (do obj))
+)
+
+; same as get-assert-variables, but limited to linear ones
+; linear meaning: variable that do not multiply with another variable (even itself)
+; a linear variable exists to a single constraints, not a constraint system
+; i.e., it could be linear in one constraint, while not in another
+; (note) you should normalize the constraints before calling this method
+; to get the most precise results; e.g., 1*x would not otherwise be considered
+; in form of x0*x
+; (important) one variable can simultaneously appear as linear and non-linear
+; in the interest of uniqueness, it should be marked as non-linear
+; but this method does not make the decision for the user
+; you need to determine by yourself
+(define (get-assert-variables/linear obj [arg-indexonly #f])
+ ; define internal function
+ (define (do obj0)
+ (match obj0
+ [(rcmds vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rraw v) (list )]
+ [(rlogic v) (list )]
+ [(rdef v t) (list )]
+ [(rassert v) (do v)]
+ [(rcmt v) (list )]
+ [(rsolve ) (list )]
+ [(req lhs rhs) (append (do lhs) (do rhs))]
+ [(rneq lhs rhs) (append (do lhs) (do rhs))]
+ [(rleq lhs rhs) (append (do lhs) (do rhs))]
+ [(rlt lhs rhs) (append (do lhs) (do rhs))]
+ [(rgeq lhs rhs) (append (do lhs) (do rhs))]
+ [(rgt lhs rhs) (append (do lhs) (do rhs))]
+ [(rand vs) (tokamak:exit "get-assert-variables/linear receives rand, which is not supported.")]
+ [(rimp lhs rhs) (append (do lhs) (do rhs))]
+ [(ror vs) (tokamak:exit "get-assert-variables/linear receives ror, which is not supported.")]
+ [(rint v) (list )]
+ [(rvar v)
+ (if arg-indexonly
+ ; extracted variable index
+ ; (fixme) we here assume prefix is either "x" or "y"
+ (list (string->number (substring v 1)))
+ ; original string variable
+ (list v)
+ )
+ ]
+ [(rtype v) (list )]
+ [(radd vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ [(rsub vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v))))
+ res
+ )
+ ]
+ ; (assumed optimized version)
+ ; - 1*x will be x, which will not be captured by rmul
+ ; - (fixme) this could be wrong, a*x is treated as linear,
+ ; since prime field has unique multiplicative inverse, so a*x=b
+ ; will have unique solution for x
+ ; others are not linear
+ [(rmul vs)
+ (let ([vv (filter (lambda (x) (rvar? x)) vs)])
+ (if (= 1 (length vv))
+ ; only 1 var, good as linear
+ (do (car vv))
+ ; no var or more than 1 var, not good for linear
+ (list )
+ )
+ )
+ ]
+ [(rmod v mod) (append (do v) (do mod))]
+ [else (tokamak:exit "not supported: ~a" obj0)]
+ )
+ )
+ ; then call it and remove duplicates, and return
+ (list->set (do obj))
+)
+
+(define (get-assert-variables/nonlinear obj [arg-indexonly #f])
+ ; define internal function
+ (define (do obj0 [include? #f])
+ (match obj0
+ [(rcmds vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v include?))))
+ res
+ )
+ ]
+ [(rraw v) (list )]
+ [(rlogic v) (list )]
+ [(rdef v t) (list )]
+ [(rassert v) (do v include?)]
+ [(rcmt v) (list )]
+ [(rsolve ) (list )]
+ [(req lhs rhs) (append (do lhs include?) (do rhs include?))]
+ [(rneq lhs rhs) (append (do lhs include?) (do rhs include?))]
+ [(rleq lhs rhs) (append (do lhs include?) (do rhs include?))]
+ [(rlt lhs rhs) (append (do lhs include?) (do rhs include?))]
+ [(rgeq lhs rhs) (append (do lhs include?) (do rhs include?))]
+ [(rgt lhs rhs) (append (do lhs include?) (do rhs include?))]
+ [(rand vs) (tokamak:exit "get-assert-variables/nonlinear receives rand, which is not supported.")]
+ [(rimp lhs rhs) (append (do lhs) (do rhs))]
+ [(ror vs) (tokamak:exit "get-assert-variables/nonlinear receives ror, which is not supported.")]
+ [(rint v) (list )]
+ [(rvar v)
+ ; only include when include? is #t
+ (if include?
+ (if arg-indexonly
+ ; extracted variable index
+ ; (fixme) we here assume prefix is either "x" or "y"
+ (list (string->number (substring v 1)))
+ ; original string variable
+ (list v)
+ )
+ (list)
+ )
+ ]
+ [(rtype v) (list )]
+ [(radd vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v include?))))
+ res
+ )
+ ]
+ [(rsub vs)
+ (let ([res (list )])
+ (for ([v vs]) (set! res (append res (do v include?))))
+ res
+ )
+ ]
+ [(rmul vs)
+ (let ([res (list )][vv (filter (lambda (x) (rvar? x)) vs)])
+ (if (<= (length vv) 1)
+ ; less than 1 var, this is just linear
+ (set! res (list ))
+ ; more than 1 var, all involved vars are non-linear
+ (for ([v vv]) (set! res (append res (do v #t))))
+ )
+ res
+ )
+ ]
+ [(rmod v mod) (append (do v include?) (do mod include?))]
+ [else (tokamak:exit "not supported: ~a" obj0)]
+ )
+ )
+ ; then call it and remove duplicates, and return
+ (list->set (do obj))
+)
+
+; =======================================
+; ======== utils for binary r1cs ========
+; =======================================
+
; r1cs structs for binary files (*.r1cs)
(struct r1cs (magic version nsec header constraint w2l inputs outputs) #:mutable #:transparent #:reflection-name 'r1cs)
(struct header-section (field-size prime-number nwires npubout npubin nprvin nlabels mconstraints) #:mutable #:transparent #:reflection-name 'header-section)
@@ -301,7 +603,7 @@
)
; returns a human readable string of one specified equation
-; original form is A*B-C=0, but we do A*B=C
+; no mode is shown for better reading
(define (r1cs->string arg-r1cs arg-id)
(define w2l (w2l-section-v (r1cs-w2l arg-r1cs))) ; w2l mapping, a list
(define clist (constraint-section-constraints (r1cs-constraint arg-r1cs))) ; a list of constraints
@@ -373,208 +675,4 @@
)
"")
-)
-
-; mathematica string
-(define (r1cs->mstring arg-r1cs arg-id)
- (define w2l (w2l-section-v (r1cs-w2l arg-r1cs))) ; w2l mapping, a list
- (define clist (constraint-section-constraints (r1cs-constraint arg-r1cs))) ; a list of constraints
-
- (define example-constraint (list-ref clist arg-id)) ; a constraint
- (define example-block-a (constraint-a example-constraint))
- (define example-block-b (constraint-b example-constraint))
- (define example-block-c (constraint-c example-constraint))
-
- ; process block a
- (define nnz-a (constraint-block-nnz example-block-a))
- (define wids-a (constraint-block-wids example-block-a))
- (define factors-a (constraint-block-factors example-block-a))
- (define str-a (string-join
- (for/list ([w0 wids-a] [f0 factors-a])
- (string-join (list
- "("
- (number->string f0)
- " * x"
- (number->string w0)
- ")"
- ) "")
- )
- " + "
- ))
-
- ; process block b
- (define nnz-b (constraint-block-nnz example-block-b))
- (define wids-b (constraint-block-wids example-block-b))
- (define factors-b (constraint-block-factors example-block-b))
- (define str-b (string-join
- (for/list ([w0 wids-b] [f0 factors-b])
- (string-join (list
- "("
- (number->string f0)
- " * x"
- (number->string w0)
- ")"
- ) "")
- )
- " + "
- ))
-
- ; process block c
- (define nnz-c (constraint-block-nnz example-block-c))
- (define wids-c (constraint-block-wids example-block-c))
- (define factors-c (constraint-block-factors example-block-c))
- (define str-c (string-join
- (for/list ([w0 wids-c] [f0 factors-c])
- (string-join (list
- "("
- (number->string f0)
- " * x"
- (number->string w0)
- ")"
- ) "")
- )
- " + "
- ))
-
- (string-join
- (list
- "(( "
- (if (zero? (string-length str-a)) "0" str-a)
- " ) * ( "
- (if (zero? (string-length str-b)) "0" str-b)
- " )) mod p == ("
- (if (zero? (string-length str-c)) "0" str-c)
- ") mod p"
- )
- "")
-
-)
-
-
-(define (extract-signals cnst)
- (define curr-block-a (constraint-a cnst))
- (define curr-block-b (constraint-b cnst))
- (define curr-block-c (constraint-c cnst))
-
- (define wids-a (constraint-block-wids curr-block-a))
- (define wids-b (constraint-block-wids curr-block-b))
- (define wids-c (constraint-block-wids curr-block-c))
-
- (utils:union (utils:union wids-a wids-b) wids-c)
-)
-
-(define (solve-eq value-1 value-2) ; returns c1/-c2
- (/ value-1 (- config:p value-2))
-)
-
-(define (pos-values signals factors)
- (if (= (length signals) 1)
- (if (= (car signals) 0)
- (list 0 1)
- (list (car signals) 0)
- )
- (if (= (car signals) 0) ; case length 2
- (list
- (car (cdr signals))
- (solve-eq (car factors) (car (cdr factors)))
- )
- (if (= (car (cdr signals)) 0)
- (list
- (car signals)
- (solve-eq (car (cdr factors)) (car factors))
- )
- (list 0 1)
- )
- )
- )
-)
-
-(define (extract-bounded-signals cnst)
- (define curr-block-a (constraint-a cnst))
- (define curr-block-b (constraint-b cnst))
- (define curr-block-c (constraint-c cnst))
-
- (define wids-a (constraint-block-wids curr-block-a))
- (define wids-b (constraint-block-wids curr-block-b))
- (define wids-c (constraint-block-wids curr-block-c))
-
- (define factors-a (constraint-block-factors curr-block-a))
- (define factors-b (constraint-block-factors curr-block-b))
- (define factors-c (constraint-block-factors curr-block-c))
-
- (cond
- [(and
- (= (length wids-c) 0)
- (<= (length wids-a) 2)
- (<= (length wids-b) 2)
- )
- (define bound-a (pos-values wids-a factors-a))
- (define bound-b (pos-values wids-b factors-b))
- (if (= (car bound-a) (car bound-b))
- (list (car bound-a) (max (list-ref bound-a 1)(list-ref bound-b 1)))
- (list 0 1)
- )
- ]
- [else (list 0 1)]
- )
-
-)
-
-(define (extract-solvable-signals cnst)
- (define curr-block-a (constraint-a cnst))
- (define curr-block-b (constraint-b cnst))
- (define curr-block-c (constraint-c cnst))
-
- (define wids-a (constraint-block-wids curr-block-a))
- (define wids-b (constraint-block-wids curr-block-b))
- (define wids-c (constraint-block-wids curr-block-c))
-
- (filter
- (lambda (signal)
- (and
- (not (utils:contains? wids-a signal))
- (not (utils:contains? wids-b signal))
- )
- )
- wids-c
- )
-)
-
-
-(define (compute-signal2constraints arg-r1cs)
- (define constraints (get-constraints arg-r1cs))
- (define mconstraints (get-mconstraints arg-r1cs))
- (define nwires (get-nwires arg-r1cs))
-
- (for/list ([signal nwires])
- (filter
- (lambda (cnst) (
- utils:contains?
- (extract-signals (list-ref constraints cnst))
- signal
- ))
- (range mconstraints)
- )
- )
-)
-
-(define (compute-constraint2signals arg-r1cs)
- (define constraints (get-constraints arg-r1cs))
- (define mconstraints (get-mconstraints arg-r1cs))
- (define nwires (get-nwires arg-r1cs))
-
- (for/list ([cnst mconstraints])
- (extract-signals (list-ref constraints cnst))
- )
-
-)
-
-(define (compute-constraint2solvablesignals arg-r1cs)
- (define constraints (get-constraints arg-r1cs))
- (define mconstraints (get-mconstraints arg-r1cs))
- (define nwires (get-nwires arg-r1cs))
-
- (for/list ([cnst mconstraints])
- (extract-solvable-signals (list-ref constraints cnst))
- )
)
\ No newline at end of file
diff --git a/picus/r1cs-z3-interpreter.rkt b/picus/r1cs/r1cs-z3-interpreter.rkt
similarity index 82%
rename from picus/r1cs-z3-interpreter.rkt
rename to picus/r1cs/r1cs-z3-interpreter.rkt
index ef5c9ba..820651a 100644
--- a/picus/r1cs-z3-interpreter.rkt
+++ b/picus/r1cs/r1cs-z3-interpreter.rkt
@@ -1,9 +1,9 @@
-#lang rosette
+#lang racket
; this interprets r1cs commands into z3 constraints
(require
- (prefix-in tokamak: "./tokamak.rkt")
- (prefix-in utils: "./utils.rkt")
- (prefix-in config: "./config.rkt")
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
(prefix-in r1cs: "./r1cs-grammar.rkt")
)
(provide (rename-out
@@ -13,8 +13,8 @@
(define (make-format-op op)
(define (format-op x y)
(cond
- ; [(&& (null? x) (null? y)) (tokamak:exit "x and y can't both be null")]
- [(&& (null? x) (null? y)) ""]
+ ; [(and (null? x) (null? y)) (tokamak:exit "x and y can't both be null")]
+ [(and (null? x) (null? y)) ""]
[(null? x) y]
[(null? y) x]
[else (format "(~a ~a ~a)" op x y)]
@@ -31,10 +31,10 @@
[(r1cs:rcmds vs) (for/list ([v vs]) (interpret-r1cs v))]
[(r1cs:rraw v) (format "~a" v)]
- [(r1cs:rlogic v) (format "(set-logic ~a)" (interpret-r1cs v))]
+ [(r1cs:rlogic v) (format "(set-logic ~a)" v)]
[(r1cs:rdef v t) (format "(declare-const ~a ~a)" (interpret-r1cs v) (interpret-r1cs t))]
[(r1cs:rassert v) (format "(assert ~a)" (interpret-r1cs v))]
- [(r1cs:rcmt v) (format "; ~a" (interpret-r1cs v))]
+ [(r1cs:rcmt v) (format "; ~a" v)]
[(r1cs:rsolve ) "(check-sat)\n(get-model)"]
; sub-command level
@@ -49,9 +49,7 @@
[(r1cs:ror vs) (foldr (make-format-op "or") null (for/list ([v vs]) (interpret-r1cs v)))]
[(r1cs:rimp lhs rhs) (format "(=> ~a ~a)" (interpret-r1cs lhs) (interpret-r1cs rhs))]
-
[(r1cs:rint v) (format "~a" v)]
- [(r1cs:rstr v) v]
[(r1cs:rvar v) (format "~a" v)]
[(r1cs:rtype v) (format "~a" v)]
@@ -59,7 +57,7 @@
[(r1cs:rsub vs) (foldr (make-format-op "-") null (for/list ([v vs]) (interpret-r1cs v)))]
[(r1cs:rmul vs) (foldr (make-format-op "*") null (for/list ([v vs]) (interpret-r1cs v)))]
[(r1cs:rneg v) (format "(- ~a)" (interpret-r1cs v))]
- [(r1cs:rmod v mod) (format "(mod ~a ~a)" (interpret-r1cs v) (interpret-r1cs mod))]
+ [(r1cs:rmod v mod) (format "(rem ~a ~a)" (interpret-r1cs v) (interpret-r1cs mod))]
[else (tokamak:exit "not supported: ~a" arg-r1cs)]
)
diff --git a/picus/r1cs/r1cs-z3-parser.rkt b/picus/r1cs/r1cs-z3-parser.rkt
new file mode 100644
index 0000000..f4ce615
--- /dev/null
+++ b/picus/r1cs/r1cs-z3-parser.rkt
@@ -0,0 +1,394 @@
+#lang racket
+; this interprets binary r1cs into its grammar representation
+(require
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in utils: "../utils.rkt")
+ (prefix-in config: "../config.rkt")
+ (prefix-in r1cs: "./r1cs-grammar.rkt")
+)
+(provide (rename-out
+ [parse-r1cs parse-r1cs]
+ [expand-r1cs expand-r1cs]
+ [parse-r1cs-old parse-r1cs-old]
+))
+
+; turns r1cs binary form into standard form
+; arguments:
+; - arg-r1cs: r1cs binary form instance using the struct r1cs grammar
+; - arg-xlist: symbols (in string) to use, usually in "x?" form
+; when parsing alt constraints, non-input symbols are replaced with "y?" series
+; returns:
+; - (values xlist options declarations constraints)
+(define (parse-r1cs arg-r1cs arg-xlist)
+
+ ; a list of options
+ (define raw-opts (list
+ (r1cs:rlogic "QF_NIA")
+ ))
+
+ (define raw-cnsts (list)) ; a list of commands
+ (define raw-decls (list)) ; a list of variable declarations
+
+ ; first create a list of all symbolic variables according to nwires
+ (define nwires (r1cs:get-nwires arg-r1cs))
+ ; strictly align with wid
+ (define xlist (if (null? arg-xlist)
+ ; create fresh new
+ (for/list ([i nwires]) (format "x~a" i))
+ ; use existing one
+ arg-xlist
+ ))
+
+ ; add declarations for variables
+ (set! raw-decls (append raw-decls
+ (list (r1cs:rcmt "======== declaration constraints ========"))
+ (for/list ([x xlist])
+ (if (and (not (null? arg-xlist)) (string-prefix? x "x"))
+ ; provided list with already defined x, skip
+ (r1cs:rcmt (format "~a: already defined" x))
+ ; otherwise you need to define this variable
+ (r1cs:rdef (r1cs:rvar (format "~a" x)) (r1cs:rtype "Int"))
+ )
+ )
+ ))
+
+ ; add range constraints for declared variables
+ (set! raw-decls (append raw-decls
+ (list (r1cs:rcmt "======== range constraints ========"))
+ (for/list ([x xlist])
+ (if (and (not (null? arg-xlist)) (string-prefix? x "x"))
+ ; provided list with already defined x, skip
+ (r1cs:rcmt (format "~a: already defined" x))
+ ; otherwise you need to define this variable
+ (r1cs:rassert (r1cs:rand (list
+ (r1cs:rleq (r1cs:rint 0) (r1cs:rvar (format "~a" x)))
+ (r1cs:rlt (r1cs:rvar (format "~a" x)) (r1cs:rint config:p))
+ )))
+ )
+ )
+ ))
+
+ ; then start creating constraints
+ (define m (r1cs:get-mconstraints arg-r1cs))
+ (define rconstraints (r1cs:get-constraints arg-r1cs)) ; r1cs constraints
+
+ ; symbolic constraints
+ (define sconstraints (for/list ([cnst rconstraints])
+
+ ; get block
+ (define curr-block-a (r1cs:constraint-a cnst))
+ (define curr-block-b (r1cs:constraint-b cnst))
+ (define curr-block-c (r1cs:constraint-c cnst))
+
+ ; process block a
+ (define nnz-a (r1cs:constraint-block-nnz curr-block-a))
+ (define wids-a (r1cs:constraint-block-wids curr-block-a))
+ (define factors-a (r1cs:constraint-block-factors curr-block-a))
+
+ ; process block b
+ (define nnz-b (r1cs:constraint-block-nnz curr-block-b))
+ (define wids-b (r1cs:constraint-block-wids curr-block-b))
+ (define factors-b (r1cs:constraint-block-factors curr-block-b))
+
+ ; process block c
+ (define nnz-c (r1cs:constraint-block-nnz curr-block-c))
+ (define wids-c (r1cs:constraint-block-wids curr-block-c))
+ (define factors-c (r1cs:constraint-block-factors curr-block-c))
+
+ ; ======== parse into original form: A*B = C ========
+ ; note that terms could be empty, in which case 0 is used
+ (define terms-a (cons (r1cs:rint 0) (for/list ([w0 wids-a] [f0 factors-a])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ )
+ )))
+ (define terms-b (cons (r1cs:rint 0) (for/list ([w0 wids-b] [f0 factors-b])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ )
+ )))
+ (define terms-c (cons (r1cs:rint 0) (for/list ([w0 wids-c] [f0 factors-c])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ )
+ )))
+ (define sum-a (r1cs:radd terms-a))
+ (define sum-b (r1cs:radd terms-b))
+ (define sum-c (r1cs:radd terms-c))
+ ; original form: A*B = C
+ (define ret-cnst (r1cs:rassert (r1cs:req
+ (r1cs:rmod (r1cs:rmul (list sum-a sum-b)) (r1cs:rint config:p))
+ (r1cs:rmod sum-c (r1cs:rint config:p))
+ )))
+
+ ret-cnst
+ ))
+
+ ; update smt with comments and fixed constraints
+ (set! raw-cnsts (append
+ raw-cnsts
+ (list (r1cs:rcmt "======== main constraints ========"))
+ sconstraints
+ (list (r1cs:rassert (r1cs:req
+ (r1cs:rint 1) (r1cs:rvar (format "~a" (list-ref xlist 0)))
+ )))
+ ))
+
+ (values
+ xlist
+ (r1cs:rcmds raw-opts)
+ (r1cs:rcmds raw-decls)
+ (r1cs:rcmds raw-cnsts)
+ )
+)
+
+
+; expands standard r1cs into terms++ form (sum of terms)
+; usually only the cnsts part is provided
+; arguments:
+; - arg-r1cs: r1cs standard form instance using the struct rcmds grammar
+; returns:
+; - expanded-r1cs
+(define (expand-r1cs arg-r1cs)
+ (define ret-cnsts (for/list ([v (r1cs:rcmds-vs arg-r1cs)])
+ (match v
+ ; match the standard form a*b=c
+ [(r1cs:rassert (r1cs:req
+ (r1cs:rmod
+ (r1cs:rmul (list
+ (r1cs:radd (list (r1cs:rint 0) (r1cs:rmul (list (r1cs:rint a0s) (r1cs:rvar a1s))) ...)) ; shape of A
+ (r1cs:radd (list (r1cs:rint 0) (r1cs:rmul (list (r1cs:rint b0s) (r1cs:rvar b1s))) ...)) ; shape of B
+ ))
+ p0
+ )
+ (r1cs:rmod
+ (r1cs:radd (list (r1cs:rint 0) (r1cs:rmul (list (r1cs:rint c0s) (r1cs:rvar c1s))) ...)) ; shape of C
+ p1
+ )
+ ))
+ ; start the expansion
+ (define terms-a (for/list ([a0 a0s][a1 a1s]) (cons a0 a1)))
+ (define terms-b (for/list ([b0 b0s][b1 b1s]) (cons b0 b1)))
+ (define terms-c (for/list ([c0 c0s][c1 c1s]) (cons c0 c1)))
+ ; A*B = C but expand A*B into ++terms
+ (r1cs:rassert (r1cs:req
+ ; A*B part
+ (if (or (empty? terms-a) (empty? terms-b))
+ ; A*B is empty
+ (r1cs:rint 0)
+ ; A*B is not empty
+ (r1cs:rmod
+ (r1cs:radd (for*/list ([va terms-a][vb terms-b])
+ (r1cs:rmul (list
+ (r1cs:rint (remainder (* (car va) (car vb)) config:p))
+ (r1cs:rvar (cdr va))
+ (r1cs:rvar (cdr vb))
+ ))
+ ))
+ (r1cs:rint config:p)
+ )
+ )
+ ; C part
+ (if (empty? terms-c)
+ ; C is empty
+ (r1cs:rint 0)
+ ; C is not empty
+ (r1cs:rmod
+ (r1cs:radd (for/list ([v terms-c]) (r1cs:rmul (list (r1cs:rint (car v)) (r1cs:rvar (cdr v))))))
+ (r1cs:rint config:p)
+ )
+ )
+ ))
+ ]
+ ; otherwise, just keep the form
+ [_
+ ; (tokamak:log "out of pattern: ~a" v)
+ v
+ ]
+ )
+ ))
+ ; return
+ (r1cs:rcmds ret-cnsts)
+)
+
+; to be deleted
+(define (parse-r1cs-old arg-r1cs arg-xlist)
+
+ ; a list of options
+ (define raw-options (list
+ (r1cs:rlogic "QF_NIA")
+ ))
+
+ (define raw-cmds (list)) ; a list of commands
+ (define raw-declarations (list)) ; a list of variable declarations
+
+ ; first create a list of all symbolic variables according to nwires
+ (define nwires (r1cs:get-nwires arg-r1cs))
+ ; strictly align with wid
+ (define xlist (if (null? arg-xlist)
+ ; create fresh new
+ (for/list ([i nwires]) (format "x~a" i))
+ ; use existing one
+ arg-xlist
+ ))
+
+ ; add declarations for variables
+ (set! raw-declarations (append raw-declarations
+ (list (r1cs:rcmt "======== declaration constraints ========"))
+ (for/list ([x xlist])
+ (if (and (not (null? arg-xlist)) (string-prefix? x "x"))
+ ; provided list with already defined x, skip
+ (r1cs:rcmt (format "~a: already defined" x))
+ ; otherwise you need to define this variable
+ (r1cs:rdef (r1cs:rvar (format "~a" x)) (r1cs:rtype "Int"))
+ )
+ )
+ ))
+
+ ; add range constraints for declared variables
+ (set! raw-declarations (append raw-declarations
+ (list (r1cs:rcmt "======== range constraints ========"))
+ (for/list ([x xlist])
+ (if (and (not (null? arg-xlist)) (string-prefix? x "x"))
+ ; provided list with already defined x, skip
+ (r1cs:rcmt (format "~a: already defined" x))
+ ; otherwise you need to define this variable
+ (r1cs:rassert (r1cs:rand (list
+ (r1cs:rleq (r1cs:rint 0) (r1cs:rvar (format "~a" x)))
+ (r1cs:rlt (r1cs:rvar (format "~a" x)) (r1cs:rint config:p))
+ )))
+ )
+ )
+ ))
+
+ ; then start creating constraints
+ (define m (r1cs:get-mconstraints arg-r1cs))
+ (define rconstraints (r1cs:get-constraints arg-r1cs)) ; r1cs constraints
+
+ ; symbolic constraints
+ (define sconstraints (for/list ([cnst rconstraints])
+
+ ; get block
+ (define curr-block-a (r1cs:constraint-a cnst))
+ (define curr-block-b (r1cs:constraint-b cnst))
+ (define curr-block-c (r1cs:constraint-c cnst))
+
+ ; process block a
+ (define nnz-a (r1cs:constraint-block-nnz curr-block-a))
+ (define wids-a (r1cs:constraint-block-wids curr-block-a))
+ (define factors-a (r1cs:constraint-block-factors curr-block-a))
+
+ ; process block b
+ (define nnz-b (r1cs:constraint-block-nnz curr-block-b))
+ (define wids-b (r1cs:constraint-block-wids curr-block-b))
+ (define factors-b (r1cs:constraint-block-factors curr-block-b))
+
+ ; process block c
+ (define nnz-c (r1cs:constraint-block-nnz curr-block-c))
+ (define wids-c (r1cs:constraint-block-wids curr-block-c))
+ (define factors-c (r1cs:constraint-block-factors curr-block-c))
+
+ ; ======== parse into original form: A*B = C ========
+ ; assemble symbolic terms
+ ; note that terms could be empty, in which case 0 is used
+ ; (define terms-a (cons (r1cs:rint 0) (for/list ([w0 wids-a] [f0 factors-a])
+ ; ; (format "(* ~a ~a)" f0 x0)
+ ; (let ([x0 (list-ref xlist w0)])
+ ; (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ ; )
+ ; )))
+ ; (define terms-b (cons (r1cs:rint 0) (for/list ([w0 wids-b] [f0 factors-b])
+ ; ; (format "(* ~a ~a)" f0 x0)
+ ; (let ([x0 (list-ref xlist w0)])
+ ; (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ ; )
+ ; )))
+ ; (define terms-c (cons (r1cs:rint 0) (for/list ([w0 wids-c] [f0 factors-c])
+ ; ; (format "(* ~a ~a)" f0 x0)
+ ; (let ([x0 (list-ref xlist w0)])
+ ; (r1cs:rmul (list (r1cs:rint f0) (r1cs:rvar x0)))
+ ; )
+ ; )))
+ ; (define sum-a (r1cs:radd terms-a))
+ ; (define sum-b (r1cs:radd terms-b))
+ ; (define sum-c (r1cs:radd terms-c))
+ ; ; original form: A*B = C
+ ; (define ret-cnst (r1cs:rassert (r1cs:req
+ ; (r1cs:rmod (r1cs:rmul (list sum-a sum-b)) (r1cs:rint config:p))
+ ; (r1cs:rmod sum-c (r1cs:rint config:p))
+ ; )))
+
+ ; ======== parse into expanded form: A*B = C but expand A*B into ++terms ========
+ ; assemble symbolic terms
+ ; note that terms could be empty, in which case 0 is used
+ (define terms-a (for/list ([w0 wids-a] [f0 factors-a])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (cons f0 x0)
+ )
+ ))
+ (define terms-b (for/list ([w0 wids-b] [f0 factors-b])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (cons f0 x0)
+ )
+ ))
+ (define terms-c (for/list ([w0 wids-c] [f0 factors-c])
+ ; (format "(* ~a ~a)" f0 x0)
+ (let ([x0 (list-ref xlist w0)])
+ (cons f0 x0)
+ )
+ ))
+ ; A*B = C but expand A*B into ++terms
+ (define ret-cnst (r1cs:rassert (r1cs:req
+ ; A*B part
+ (if (or (empty? terms-a) (empty? terms-b))
+ ; A*B is empty
+ (r1cs:rint 0)
+ ; A*B is not empty
+ (r1cs:rmod
+ (r1cs:radd (for*/list ([va terms-a][vb terms-b])
+ (r1cs:rmul (list
+ (r1cs:rint (remainder (* (car va) (car vb)) config:p))
+ (r1cs:rvar (cdr va))
+ (r1cs:rvar (cdr vb))
+ ))
+ ))
+ (r1cs:rint config:p)
+ )
+ )
+ ; C part
+ (if (empty? terms-c)
+ ; C is empty
+ (r1cs:rint 0)
+ ; C is not empty
+ (r1cs:rmod
+ (r1cs:radd (for/list ([v terms-c]) (r1cs:rmul (list (r1cs:rint (car v)) (r1cs:rvar (cdr v))))))
+ (r1cs:rint config:p)
+ )
+ )
+ )))
+
+ ; return this assembled constraint
+ ret-cnst
+ ))
+
+ ; update smt with comments and fixed constraints
+ (set! raw-cmds (append
+ raw-cmds
+ sconstraints
+ (list (r1cs:rassert (r1cs:req
+ (r1cs:rint 1) (r1cs:rvar (format "~a" (list-ref xlist 0)))
+ )))
+ ))
+
+ (values
+ xlist
+ (r1cs:rcmds raw-options)
+ (r1cs:rcmds raw-declarations)
+ (r1cs:rcmds raw-cmds)
+ )
+)
\ No newline at end of file
diff --git a/picus/solver.rkt b/picus/solver.rkt
new file mode 100644
index 0000000..03cc9e3
--- /dev/null
+++ b/picus/solver.rkt
@@ -0,0 +1,107 @@
+#lang racket
+; switcher for solver related components
+(require json racket/engine
+ (prefix-in tokamak: "./tokamak.rkt")
+)
+; z3 require
+(require
+ (prefix-in z3-solver: "./solvers/z3-solver.rkt")
+ (prefix-in z3-rint: "./r1cs/r1cs-z3-interpreter.rkt")
+ (prefix-in z3-parser: "./r1cs/r1cs-z3-parser.rkt")
+ ; optimizers
+ (prefix-in z3-simple: "./optimizers/r1cs-z3-simple-optimizer.rkt")
+ (prefix-in z3-subp: "./optimizers/r1cs-z3-subp-optimizer.rkt")
+ (prefix-in z3-ab0: "./optimizers/r1cs-z3-ab0-optimizer.rkt")
+)
+; cvc4 require (partly shared with z3)
+(require
+ (prefix-in cvc4-solver: "./solvers/cvc4-solver.rkt")
+ (prefix-in cvc4-rint: "./r1cs/r1cs-cvc4-interpreter.rkt")
+)
+; cvc5 require
+(require
+ (prefix-in cvc5-solver: "./solvers/cvc5-solver.rkt")
+ (prefix-in cvc5-rint: "./r1cs/r1cs-cvc5-interpreter.rkt")
+ (prefix-in cvc5-parser: "./r1cs/r1cs-cvc5-parser.rkt")
+ ; optimizers
+ (prefix-in cvc5-simple: "./optimizers/r1cs-cvc5-simple-optimizer.rkt")
+ (prefix-in cvc5-subp: "./optimizers/r1cs-cvc5-subp-optimizer.rkt")
+ (prefix-in cvc5-ab0: "./optimizers/r1cs-cvc5-ab0-optimizer.rkt")
+)
+(provide (rename-out
+ [state-smt-path state-smt-path]
+ [solve solve]
+ [parse-r1cs parse-r1cs]
+ [expand-r1cs expand-r1cs]
+ [normalize-r1cs normalize-r1cs]
+ [optimize-r1cs-p0 optimize-r1cs-p0]
+ [optimize-r1cs-p1 optimize-r1cs-p1]
+ [interpret-r1cs interpret-r1cs]
+))
+
+(define (state-smt-path arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) (lambda () z3-solver:state-smt-path)]
+ [(equal? "cvc4" arg-solver) (lambda () cvc4-solver:state-smt-path)]
+ [(equal? "cvc5" arg-solver) (lambda () cvc5-solver:state-smt-path)]
+ [else (tokamak:exit "you can't reach here")]
+ )
+)
+(define (solve arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) z3-solver:solve]
+ [(equal? "cvc4" arg-solver) cvc4-solver:solve]
+ [(equal? "cvc5" arg-solver) cvc5-solver:solve]
+ [else (tokamak:exit "you can't reach here")]
+ )
+)
+(define (parse-r1cs arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) z3-parser:parse-r1cs]
+ [(equal? "cvc4" arg-solver) z3-parser:parse-r1cs] ; share with z3
+ [(equal? "cvc5" arg-solver) cvc5-parser:parse-r1cs]
+ [else (tokamak:exit "you can't reach here")]
+ )
+)
+(define (expand-r1cs arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) z3-parser:expand-r1cs]
+ [(equal? "cvc4" arg-solver) z3-parser:expand-r1cs] ; shared with z3
+ [(equal? "cvc5" arg-solver) cvc5-parser:expand-r1cs]
+ )
+)
+(define (normalize-r1cs arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) (lambda (x) (z3-simple:optimize-r1cs x))]
+ [(equal? "cvc4" arg-solver) (lambda (x) (z3-simple:optimize-r1cs x))] ; shared with z3
+ [(equal? "cvc5" arg-solver) (lambda (x) (cvc5-simple:optimize-r1cs x))]
+ [else (tokamak:exit "you can't reach here")]
+ )
+)
+; phase 0 optimization, applies to standard form
+(define (optimize-r1cs-p0 arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) (lambda (x) (z3-ab0:optimize-r1cs x))]
+ [(equal? "cvc4" arg-solver) (lambda (x) (z3-ab0:optimize-r1cs x))] ; shared with z3
+ [(equal? "cvc5" arg-solver) (lambda (x) (cvc5-ab0:optimize-r1cs x))]
+ [else (tokamak:exit "you can't reach here")]
+ )
+)
+; phase 1 optimization, applies to normalized form
+; - pdecl?: whether or not to inlude declaration of p, usually alt- series should not include
+(define (optimize-r1cs-p1 arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) (lambda (x pdef?) (z3-subp:optimize-r1cs x pdef?))]
+ [(equal? "cvc4" arg-solver) (lambda (x pdef?) (z3-subp:optimize-r1cs x pdef?))] ; shared with z3
+ [(equal? "cvc5" arg-solver) (lambda (x pdef?) (cvc5-subp:optimize-r1cs x pdef?))]
+ [else (tokamak:exit "you can't reach here")]
+ )
+)
+(define (interpret-r1cs arg-solver)
+ (cond
+ [(equal? "z3" arg-solver) z3-rint:interpret-r1cs]
+ [(equal? "cvc4" arg-solver) cvc4-rint:interpret-r1cs]
+ [(equal? "cvc5" arg-solver) cvc5-rint:interpret-r1cs]
+ [else (tokamak:exit "you can't reach here")]
+ )
+)
\ No newline at end of file
diff --git a/picus/cvc5-utils.rkt b/picus/solvers/cvc4-solver.rkt
similarity index 50%
rename from picus/cvc5-utils.rkt
rename to picus/solvers/cvc4-solver.rkt
index 410fec0..d682ca6 100644
--- a/picus/cvc5-utils.rkt
+++ b/picus/solvers/cvc4-solver.rkt
@@ -1,5 +1,7 @@
-#lang rosette
-(require racket/engine)
+#lang racket
+(require racket/engine
+ (prefix-in tokamak: "../tokamak.rkt")
+)
(provide (all-defined-out))
; stateful variable that stores smt path
@@ -15,7 +17,7 @@
(define smt-file (open-output-file temp-path))
(display smt-str smt-file)
(close-output-port smt-file)
- (when (|| verbose? output-smt?)
+ (when (or verbose? output-smt?)
(printf "# written to: ~a\n" temp-path)
)
@@ -24,7 +26,8 @@
)
(define-values (sp out in err)
; (note) use `apply` to expand the last argument
- (apply subprocess #f #f #f (find-executable-path "cvc5") (list temp-path "--produce-models"))
+ ; (apply subprocess #f #f #f (find-executable-path "cvc4") (list temp-path))
+ (apply subprocess #f #f #f (find-executable-path "cvc4") (list temp-path "--produce-models"))
)
(define engine0 (engine (lambda (_)
(define out-str (port->string out))
@@ -38,7 +41,7 @@
(define eres (engine-run timeout engine0))
(define esol (engine-result engine0))
(cond
- [(! eres)
+ [(not eres)
; need to kill the process
(subprocess-kill sp #t)
(cons 'timeout "")
@@ -53,10 +56,49 @@
(cond
[(non-empty-string? err-str) (cons 'error err-str)] ; something wrong, not solved
[(string-prefix? out-str "unsat") (cons 'unsat out-str)]
- [(string-prefix? out-str "sat") (cons 'sat out-str)]
+ [(string-prefix? out-str "sat") (cons 'sat (parse-model out-str))]
[(string-prefix? out-str "unknown") (cons 'unknown out-str)]
[else (cons 'else out-str)]
)
]
)
+)
+
+; example string:
+; sat
+; (model
+; (define-fun x0 () Int 0)
+; (define-fun x1 () Int 1)
+; (define-fun x2 () Int 0)
+; (define-fun x3 () Int 1)
+; (define-fun x4 () Int 0)
+; (define-fun p () Int 21888242871839275222246405745257275088548364400416034343698204186575808495617)
+; (define-fun ps1 () Int 21888242871839275222246405745257275088548364400416034343698204186575808495616)
+; (define-fun ps2 () Int 21888242871839275222246405745257275088548364400416034343698204186575808495615)
+; (define-fun ps3 () Int 21888242871839275222246405745257275088548364400416034343698204186575808495614)
+; (define-fun ps4 () Int 21888242871839275222246405745257275088548364400416034343698204186575808495613)
+; (define-fun ps5 () Int 21888242871839275222246405745257275088548364400416034343698204186575808495612)
+; (define-fun zero () Int 0)
+; (define-fun one () Int 1)
+; (define-fun y1 () Int 0)
+; (define-fun y2 () Int 0)
+; (define-fun y3 () Int 0)
+; )
+; .
+(define (parse-model arg-str)
+ (define strlist (string-split arg-str "\n"))
+ (define model (make-hash))
+ (for ([s strlist])
+ (define res (regexp-match* #rx"define-fun (.*?) .* (.*?)\\)" s #:match-select cdr))
+ (when (not (empty? res))
+ (define var (list-ref (list-ref res 0) 0))
+ (define val (string->number (list-ref (list-ref res 0) 1)))
+ ; not a number
+ (when (boolean? val) (tokamak:exit "model parsing error, check: ~a" s))
+ ; update model
+ (hash-set! model var val)
+ )
+ )
+ ; return the model
+ model
)
\ No newline at end of file
diff --git a/picus/solvers/cvc5-solver.rkt b/picus/solvers/cvc5-solver.rkt
new file mode 100644
index 0000000..ca79e71
--- /dev/null
+++ b/picus/solvers/cvc5-solver.rkt
@@ -0,0 +1,104 @@
+#lang racket
+(require racket/engine
+ (prefix-in tokamak: "../tokamak.rkt")
+ (prefix-in config: "../config.rkt")
+)
+(provide (all-defined-out))
+
+; stateful variable that stores smt path
+(define state-smt-path null)
+
+; solving component
+(define (solve smt-str timeout #:verbose? [verbose? #f] #:output-smt? [output-smt? #f])
+ (define temp-folder (find-system-path 'temp-dir))
+ (define temp-file (format "picus~a.smt2"
+ (string-replace (format "~a" (current-inexact-milliseconds)) "." "")))
+ (define temp-path (build-path temp-folder temp-file))
+ (set! state-smt-path temp-path)
+ (define smt-file (open-output-file temp-path))
+ (display smt-str smt-file)
+ (close-output-port smt-file)
+ (when (or verbose? output-smt?)
+ (printf "(written to: ~a)\n" temp-path)
+ )
+
+ (when verbose?
+ (printf "# solving...\n")
+ )
+ (define-values (sp out in err)
+ ; (note) use `apply` to expand the last argument
+ ; (apply subprocess #f #f #f (find-executable-path "cvc5") (list temp-path))
+ (apply subprocess #f #f #f (find-executable-path "cvc5") (list temp-path "--produce-models"))
+ )
+ (define engine0 (engine (lambda (_)
+ (define out-str (port->string out))
+ (define err-str (port->string err))
+ (close-input-port out)
+ (close-output-port in)
+ (close-input-port err)
+ (subprocess-wait sp)
+ (cons out-str err-str)
+ )))
+ (define eres (engine-run timeout engine0))
+ (define esol (engine-result engine0))
+ (cond
+ [(not eres)
+ ; need to kill the process
+ (subprocess-kill sp #t)
+ (cons 'timeout "")
+ ]
+ [else
+ (define out-str (car esol))
+ (define err-str (cdr esol))
+ (when verbose?
+ (printf "# stdout:\n~a\n" out-str)
+ (printf "# stderr:\n~a\n" err-str)
+ )
+ (cond
+ [(non-empty-string? err-str) (cons 'error err-str)] ; something wrong, not solved
+ [(string-prefix? out-str "unsat") (cons 'unsat out-str)]
+ [(string-prefix? out-str "sat") (cons 'sat (parse-model out-str))]
+ [(string-prefix? out-str "unknown") (cons 'unknown out-str)]
+ [else (cons 'else out-str)]
+ )
+ ]
+ )
+)
+
+; example string:
+; sat
+; (
+; (define-fun x0 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 0)
+; (define-fun x1 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 0)
+; (define-fun x2 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) -1)
+; (define-fun x3 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 0)
+; (define-fun x4 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 0)
+; (define-fun p () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 0)
+; (define-fun ps1 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) -1)
+; (define-fun ps2 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) -2)
+; (define-fun ps3 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) -3)
+; (define-fun ps4 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) -4)
+; (define-fun ps5 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) -5)
+; (define-fun zero () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 0)
+; (define-fun one () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 1)
+; (define-fun y1 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) 1)
+; (define-fun y2 () (_ FiniteField 21888242871839275222246405745257275088548364400416034343698204186575808495617) -1)
+; )
+(define (parse-model arg-str)
+ (define strlist (string-split arg-str "\n"))
+ (define model (make-hash))
+ (for ([s strlist])
+ (define res (regexp-match* #rx"define-fun (.*?) .* (.*?)\\)" s #:match-select cdr))
+ (when (not (empty? res))
+ (define var (list-ref (list-ref res 0) 0))
+ (define val (string->number (list-ref (list-ref res 0) 1)))
+ (when (< val 0) (set! val (+ config:p val))) ; remap to field
+ ; not a number
+ (when (boolean? val) (tokamak:exit "model parsing error, check: ~a" s))
+ ; update model
+ (hash-set! model var val)
+ )
+ )
+ ; return the model
+ model
+)
\ No newline at end of file
diff --git a/picus/solvers/z3-solver.rkt b/picus/solvers/z3-solver.rkt
new file mode 100644
index 0000000..e7d0d7e
--- /dev/null
+++ b/picus/solvers/z3-solver.rkt
@@ -0,0 +1,121 @@
+#lang racket
+(require racket/engine
+ (prefix-in tokamak: "../tokamak.rkt")
+)
+(provide (all-defined-out))
+
+; stateful variable that stores smt path
+(define state-smt-path null)
+
+; solving component
+(define (solve smt-str timeout #:verbose? [verbose? #f] #:output-smt? [output-smt? #f])
+ (define temp-folder (find-system-path 'temp-dir))
+ (define temp-file (format "picus~a.smt2"
+ (string-replace (format "~a" (current-inexact-milliseconds)) "." "")))
+ (define temp-path (build-path temp-folder temp-file))
+ (set! state-smt-path temp-path)
+ (define smt-file (open-output-file temp-path))
+ (display smt-str smt-file)
+ (close-output-port smt-file)
+ (when (or verbose? output-smt?)
+ (printf "# written to: ~a\n" temp-path)
+ )
+
+ (when verbose?
+ (printf "# solving...\n")
+ )
+ (define-values (sp out in err)
+ ; (note) use `apply` to expand the last argument
+ (apply subprocess #f #f #f (find-executable-path "z3") (list temp-path))
+ ; (apply subprocess #f #f #f (find-executable-path "cvc4") (list temp-path))
+ ; (apply subprocess #f #f #f (find-executable-path "cvc5") (list temp-path))
+ )
+ (define engine0 (engine (lambda (_)
+ (define out-str (port->string out))
+ (define err-str (port->string err))
+ (close-input-port out)
+ (close-output-port in)
+ (close-input-port err)
+ (subprocess-wait sp)
+ (cons out-str err-str)
+ )))
+ (define eres (engine-run timeout engine0))
+ (define esol (engine-result engine0))
+ (cond
+ [(not eres)
+ ; need to kill the process
+ (subprocess-kill sp #t)
+ (cons 'timeout "")
+ ]
+ [else
+ (define out-str (car esol))
+ (define err-str (cdr esol))
+ (when verbose?
+ (printf "# stdout:\n~a\n" out-str)
+ (printf "# stderr:\n~a\n" err-str)
+ )
+ (cond
+ [(non-empty-string? err-str) (cons 'error err-str)] ; something wrong, not solved
+ [(string-prefix? out-str "unsat") (cons 'unsat out-str)]
+ [(string-prefix? out-str "sat") (cons 'sat (parse-model out-str))]
+ [(string-prefix? out-str "unknown") (cons 'unknown out-str)]
+ [else (cons 'else out-str)]
+ )
+ ]
+ )
+)
+
+; example
+; sat
+; (
+; (define-fun ps2 () Int
+; 21888242871839275222246405745257275088548364400416034343698204186575808495615)
+; (define-fun x2 () Int
+; 0)
+; (define-fun zero () Int
+; 0)
+; (define-fun y1 () Int
+; 1)
+; (define-fun ps3 () Int
+; 21888242871839275222246405745257275088548364400416034343698204186575808495614)
+; (define-fun x3 () Int
+; 0)
+; (define-fun x0 () Int
+; 0)
+; (define-fun one () Int
+; 1)
+; (define-fun p () Int
+; 21888242871839275222246405745257275088548364400416034343698204186575808495617)
+; (define-fun x4 () Int
+; 0)
+; (define-fun y2 () Int
+; 0)
+; (define-fun y3 () Int
+; 1)
+; (define-fun ps4 () Int
+; 21888242871839275222246405745257275088548364400416034343698204186575808495613)
+; (define-fun x1 () Int
+; 0)
+; (define-fun ps1 () Int
+; 21888242871839275222246405745257275088548364400416034343698204186575808495616)
+; (define-fun ps5 () Int
+; 21888242871839275222246405745257275088548364400416034343698204186575808495612)
+; )
+; .
+(define (parse-model arg-str)
+ (define strlist (string-split (string-replace arg-str "Int\n" "Int ") "\n"))
+ (define model (make-hash))
+ (for ([s strlist])
+ (define res (regexp-match* #rx"define-fun (.*?) .* (.*?)\\)" s #:match-select cdr))
+ (when (not (empty? res))
+ (define var (list-ref (list-ref res 0) 0))
+ (define val (string->number (list-ref (list-ref res 0) 1)))
+ ; not a number
+ (when (boolean? val) (tokamak:exit "model parsing error, check: ~a" s))
+ ; update model
+ (hash-set! model var val)
+ )
+ )
+ ; return the model
+ model
+)
\ No newline at end of file
diff --git a/picus/utils.rkt b/picus/utils.rkt
index 5083287..fd94869 100644
--- a/picus/utils.rkt
+++ b/picus/utils.rkt
@@ -1,4 +1,4 @@
-#lang rosette
+#lang racket
(provide (all-defined-out))
(define (contains? l e)
@@ -11,14 +11,6 @@
)
)
-; auxiliar function to check if the intersection of two sets is empty
-(define (empty_inter? l1 l2)
- (cond ((null? l1) #t)
- ((contains? l2 (car l1)) #f)
- (else (empty_inter? (cdr l1) l2))
- )
-)
-
(define (get-elem-map l x)
(if (null? l)
(values #f -1)
diff --git a/picus/z3-utils.rkt b/picus/z3-utils.rkt
deleted file mode 100644
index d610388..0000000
--- a/picus/z3-utils.rkt
+++ /dev/null
@@ -1,62 +0,0 @@
-#lang rosette
-(require racket/engine)
-(provide (all-defined-out))
-
-; stateful variable that stores smt path
-(define state-smt-path null)
-
-; solving component
-(define (solve smt-str timeout #:verbose? [verbose? #f] #:output-smt? [output-smt? #f])
- (define temp-folder (find-system-path 'temp-dir))
- (define temp-file (format "picus~a.smt2"
- (string-replace (format "~a" (current-inexact-milliseconds)) "." "")))
- (define temp-path (build-path temp-folder temp-file))
- (set! state-smt-path temp-path)
- (define smt-file (open-output-file temp-path))
- (display smt-str smt-file)
- (close-output-port smt-file)
- (when (|| verbose? output-smt?)
- (printf "# written to: ~a\n" temp-path)
- )
-
- (when verbose?
- (printf "# solving...\n")
- )
- (define-values (sp out in err)
- ; (note) use `apply` to expand the last argument
- (apply subprocess #f #f #f (find-executable-path "z3") (list temp-path))
- )
- (define engine0 (engine (lambda (_)
- (define out-str (port->string out))
- (define err-str (port->string err))
- (close-input-port out)
- (close-output-port in)
- (close-input-port err)
- (subprocess-wait sp)
- (cons out-str err-str)
- )))
- (define eres (engine-run timeout engine0))
- (define esol (engine-result engine0))
- (cond
- [(! eres)
- ; need to kill the process
- (subprocess-kill sp #t)
- (cons 'timeout "")
- ]
- [else
- (define out-str (car esol))
- (define err-str (cdr esol))
- (when verbose?
- (printf "# stdout:\n~a\n" out-str)
- (printf "# stderr:\n~a\n" err-str)
- )
- (cond
- [(non-empty-string? err-str) (cons 'error err-str)] ; something wrong, not solved
- [(string-prefix? out-str "unsat") (cons 'unsat out-str)]
- [(string-prefix? out-str "sat") (cons 'sat out-str)]
- [(string-prefix? out-str "unknown") (cons 'unknown out-str)]
- [else (cons 'else out-str)]
- )
- ]
- )
-)
\ No newline at end of file
diff --git a/resources/Dockerfile@base b/resources/Dockerfile@base
index a8d7f91..8a4a802 100644
--- a/resources/Dockerfile@base
+++ b/resources/Dockerfile@base
@@ -29,6 +29,8 @@ RUN add-apt-repository -y ppa:plt/racket && \
apt-get update && \
apt-get install -y racket libssl-dev curl && \
raco pkg install --auto rosette && \
+ raco pkg install --auto csv-reading && \
+ raco pkg install --auto graph && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
diff --git a/resources/docker_entrypoint.sh b/resources/docker_entrypoint.sh
old mode 100755
new mode 100644
index b75b0a6..9e6c17f
--- a/resources/docker_entrypoint.sh
+++ b/resources/docker_entrypoint.sh
@@ -4,9 +4,6 @@
# Instructions: set the following environment variables before calling this
# script, then run this script with no arguments.
-# example usage
-# CIRCOM_SRC_DIR=./tmp/circomlib-79d3034/ MAIN_FILES=test-mimcsponge.circom SOLVER=cvc5 VERSION=v2 CEXP=true CIRCOM_OUT_DIR=./tmp/circomlib-79d3034/ TIMEOUT=5000 ./resources/docker_entrypoint.sh
-
# The folder containing all source files, including libraries.
CIRCOM_SRC_DIR="${CIRCOM_SRC_DIR:-/src_files}"
@@ -17,30 +14,6 @@ MAIN_FILES="${MAIN_FILES:-${CIRCOM_SRC_DIR}}"
# The folder where the circom output and picus logs should be stored.
CIRCOM_OUT_DIR="${CIRCOM_OUT_DIR:-/artifact_dir}"
-# The backend solver that picus should use.
-SOLVER="${SOLVER:-cvc5}"
-
-# The picus version to use.
-VERSION="${VERSION:-v3}"
-
-# The timeout argument in milliseconds.
-# - For v0 it's the timeout for the whole solving.
-# - For other versions it's the timeout for each solver query.
-TIMEOUT="${TIMEOUT:-5000}"
-
-# Whether or not to print out counter-example. This only applies to version "v2".
-# If using other versions, CEXP will be forced to false.
-CEXP=${CEXP:-false}
-if [ "${VERSION}" != "v2" ]; then
- # forced to false
- CEXP=false
-fi
-# Reveal the corresponding argument
-ARGCEXP=""
-if [ "${CEXP}" = true ]; then
- ARGCEXP="--get-model"
-fi
-
set -e
mkdir -p "$CIRCOM_OUT_DIR"
@@ -52,7 +25,7 @@ for main_loc in $(xargs -n1 -d: <<< "$MAIN_FILES"); do
echo "Compile: $f"
out_dir=$(dirname $(realpath --relative-to="$CIRCOM_SRC_DIR" "$f"))
mkdir -p "${CIRCOM_OUT_DIR}"/"$out_dir"
- circom -o "${CIRCOM_OUT_DIR}"/"$out_dir" "$f" --r1cs --sym --O0 --json
+ circom -o "${CIRCOM_OUT_DIR}"/"$out_dir" "$f" --r1cs --sym --O0
done
done
echo "Done compiling."
@@ -65,7 +38,7 @@ for f in $(find "$CIRCOM_OUT_DIR" -type f -name '*.r1cs'); do
echo "Running picus on: $f"
fdir=$(dirname "$f")
logfile="$fdir"/"$(basename "$f")".picus.log
- racket test-${VERSION}-uniqueness.rkt --r1cs "$f" --solver cvc5 --timeout ${TIMEOUT} --weak ${ARGCEXP} |& tee "$logfile"
+ racket test-pp-uniqueness.rkt --r1cs "$f" --solver cvc5 --weak |& tee "$logfile"
echo "Log saved to $logfile"
echo "--------------------------------------------------------"
echo
diff --git a/scripts/batch-run-ecne-pre.sh b/scripts/batch-run-ecne-pre.sh
new file mode 100755
index 0000000..f3135d3
--- /dev/null
+++ b/scripts/batch-run-ecne-pre.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# usage: this.sh
+# example: ./batch-run-ecne.sh 600 ../Ecne/ ./logs/ecne-circomlib ./benchmarks/circomlib-cff5ab6/
+
+otime=$1
+ecnepath=$2
+logpath=$3
+targetfolder=$4
+
+mkdir -p ${logpath}
+
+for fp in ${targetfolder}/*.r1cs
+do
+ fn=$(basename ${fp})
+ bn="${fn%.*}"
+ bp="${fp%.*}"
+ echo "=================== checking: ${fn} ==================="
+ echo "==== start: $(date -u)"
+ st="$(date -u +%s)"
+
+ timeout ${otime} julia --project=${ecnepath} ${ecnepath}/src/Ecne.jl --r1cs ${fp} --name ooo --sym ${bp}.sym --compatible --silent --showunique > ${logpath}/${bn}.log 2>&1
+
+ et="$(date -u +%s)"
+ echo "==== end: $(date -u)"
+ ct="$(($et-$st))"
+ echo "==== elapsed: ${ct} seconds"
+done
\ No newline at end of file
diff --git a/batch-run-ecne.sh b/scripts/batch-run-ecne.sh
similarity index 51%
rename from batch-run-ecne.sh
rename to scripts/batch-run-ecne.sh
index 5e1f3cc..6bf5acf 100755
--- a/batch-run-ecne.sh
+++ b/scripts/batch-run-ecne.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# usage: this.sh
-# example: ./batch-run-ecne.sh 600 ../EcneProject/ ./logs/ecne-circomlib ./benchmarks/circomlib-cff5ab6/
+# example: ./batch-run-ecne.sh 600 ../Ecne/ ./logs/ecne-circomlib ./benchmarks/circomlib-cff5ab6/
otime=$1
ecnepath=$2
@@ -15,5 +15,13 @@ do
bn="${fn%.*}"
bp="${fp%.*}"
echo "=================== checking: ${fn} ==================="
- timeout ${otime} julia --project=${ecnepath} ${ecnepath}/src/Ecne.jl --r1cs ${fp} --name ooo --sym ${bp}.sym > ${logpath}/${bn}.log 2>&1
+ echo "==== start: $(date -u)"
+ st="$(date -u +%s)"
+
+ timeout ${otime} julia --project=${ecnepath} ${ecnepath}/src/Ecne.jl --r1cs ${fp} --name ooo --sym ${bp}.sym --compatible --silent > ${logpath}/${bn}.log 2>&1
+
+ et="$(date -u +%s)"
+ echo "==== end: $(date -u)"
+ ct="$(($et-$st))"
+ echo "==== elapsed: ${ct} seconds"
done
\ No newline at end of file
diff --git a/scripts/batch-run-picus-noprop.sh b/scripts/batch-run-picus-noprop.sh
new file mode 100755
index 0000000..21da812
--- /dev/null
+++ b/scripts/batch-run-picus-noprop.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# usage: this.sh
+# example: ./batch-run-picus.sh z3 600 ./logs/test/ ./benchmarks/circomlib-cff5ab6/
+
+solver=$1
+otime=$2
+logpath=$3
+targetfolder=$4
+
+mkdir -p ${logpath}
+
+for fp in ${targetfolder}/*.r1cs
+do
+ fn=$(basename ${fp})
+ bn="${fn%.*}"
+ bp="${fp%.*}"
+ echo "=================== checking: ${fn} ==================="
+ echo "==== start: $(date -u)"
+ st="$(date -u +%s)"
+
+ timeout ${otime} racket ./picus-dpvl-uniqueness.rkt --timeout 5000 --solver ${solver} --weak --noprop --r1cs ${fp} > ${logpath}/${bn}.log 2>&1
+
+ et="$(date -u +%s)"
+ echo "==== end: $(date -u)"
+ ct="$(($et-$st))"
+ echo "==== elapsed: ${ct} seconds"
+done
\ No newline at end of file
diff --git a/scripts/batch-run-picus-nosolve.sh b/scripts/batch-run-picus-nosolve.sh
new file mode 100755
index 0000000..c29c3d4
--- /dev/null
+++ b/scripts/batch-run-picus-nosolve.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# usage: this.sh
+# example: ./batch-run-picus.sh z3 600 ./logs/test/ ./benchmarks/circomlib-cff5ab6/
+
+solver=$1
+otime=$2
+logpath=$3
+targetfolder=$4
+
+mkdir -p ${logpath}
+
+for fp in ${targetfolder}/*.r1cs
+do
+ fn=$(basename ${fp})
+ bn="${fn%.*}"
+ bp="${fp%.*}"
+ echo "=================== checking: ${fn} ==================="
+ echo "==== start: $(date -u)"
+ st="$(date -u +%s)"
+
+ timeout ${otime} racket ./picus-dpvl-uniqueness.rkt --timeout 5000 --solver ${solver} --weak --nosolve --r1cs ${fp} > ${logpath}/${bn}.log 2>&1
+
+ et="$(date -u +%s)"
+ echo "==== end: $(date -u)"
+ ct="$(($et-$st))"
+ echo "==== elapsed: ${ct} seconds"
+done
\ No newline at end of file
diff --git a/scripts/batch-run-picus-pre.sh b/scripts/batch-run-picus-pre.sh
new file mode 100755
index 0000000..26fdc7f
--- /dev/null
+++ b/scripts/batch-run-picus-pre.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# usage: this.sh
+# example: ./batch-run-picus.sh z3 600 ./logs/test/ ./benchmarks/circomlib-cff5ab6/ ./tests/ecne-unique-set/circomlib-cff5ab6/
+
+solver=$1
+otime=$2
+logpath=$3
+targetfolder=$4
+prefolder=$5
+
+mkdir -p ${logpath}
+
+for fp in ${targetfolder}/*.r1cs
+do
+ fn=$(basename ${fp})
+ bn="${fn%.*}"
+ bp="${fp%.*}"
+ echo "=================== checking: ${fn} ==================="
+ echo "==== start: $(date -u)"
+ st="$(date -u +%s)"
+
+ timeout ${otime} racket ./picus-dpvl-uniqueness.rkt --timeout 5000 --solver ${solver} --weak --r1cs ${fp} --precondition ${prefolder}/${bn}.pre.json > ${logpath}/${bn}.log 2>&1
+
+ et="$(date -u +%s)"
+ echo "==== end: $(date -u)"
+ ct="$(($et-$st))"
+ echo "==== elapsed: ${ct} seconds"
+done
\ No newline at end of file
diff --git a/scripts/batch-run-picus.sh b/scripts/batch-run-picus.sh
new file mode 100755
index 0000000..aed9ce7
--- /dev/null
+++ b/scripts/batch-run-picus.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# usage: this.sh
+# example: ./batch-run-picus.sh z3 600 ./logs/test/ ./benchmarks/circomlib-cff5ab6/
+
+solver=$1
+otime=$2
+logpath=$3
+targetfolder=$4
+
+mkdir -p ${logpath}
+
+for fp in ${targetfolder}/*.r1cs
+do
+ fn=$(basename ${fp})
+ bn="${fn%.*}"
+ bp="${fp%.*}"
+ echo "=================== checking: ${fn} ==================="
+ echo "==== start: $(date -u)"
+ st="$(date -u +%s)"
+
+ timeout ${otime} racket ./picus-dpvl-uniqueness.rkt --timeout 5000 --solver ${solver} --weak --r1cs ${fp} > ${logpath}/${bn}.log 2>&1
+
+ et="$(date -u +%s)"
+ echo "==== end: $(date -u)"
+ ct="$(($et-$st))"
+ echo "==== elapsed: ${ct} seconds"
+done
\ No newline at end of file
diff --git a/scripts/parse-results.ipynb b/scripts/parse-results.ipynb
new file mode 100644
index 0000000..352b5b0
--- /dev/null
+++ b/scripts/parse-results.ipynb
@@ -0,0 +1,596 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "acc74ec8-9917-449a-a6ff-f26e9500ca73",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import re"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a9f60fb1-8959-494e-9db2-3b89b0aa5ce5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# choose between utils or core\n",
+ "# SERIES = \"utils\"\n",
+ "SERIES = \"core\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "223a4731-4194-4469-b7fb-28a6b0c33615",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "bmrks = None\n",
+ "if SERIES == \"utils\":\n",
+ " bmrks = [\n",
+ " \"AND@gates.circom\",\n",
+ " \"BabyAdd@babyjub.circom\",\n",
+ " \"BabyDbl@babyjub.circom\",\n",
+ " \"BabyPbk@babyjub.circom\",\n",
+ " \"BinSub@binsub.circom\",\n",
+ " \"BinSum@binsum.circom\",\n",
+ " \"BitElementMulAny@escalarmulany.circom\",\n",
+ " \"Bits2Num_strict@bitify.circom\",\n",
+ " \"Bits2Num@bitify.circom\",\n",
+ " \"Bits2Point_Strict@pointbits.circom\",\n",
+ " \"CompConstant@compconstant.circom\",\n",
+ " \"Decoder@multiplexer.circom\",\n",
+ " \"Edwards2Montgomery@montgomery.circom\",\n",
+ " \"EscalarMulAny@escalarmulany.circom\",\n",
+ " \"EscalarProduct@multiplexer.circom\",\n",
+ " \"GreaterEqThan@comparators.circom\",\n",
+ " \"GreaterThan@comparators.circom\",\n",
+ " \"IsEqual@comparators.circom\",\n",
+ " \"IsZero@comparators.circom\",\n",
+ " \"LessEqThan@comparators.circom\",\n",
+ " \"LessThan@comparators.circom\",\n",
+ " \"MiMC7@mimc.circom\",\n",
+ " \"MiMCFeistel@mimcsponge.circom\",\n",
+ " \"MiMCSponge@mimcsponge.circom\",\n",
+ " \"Montgomery2Edwards@montgomery.circom\",\n",
+ " \"MontgomeryAdd@montgomery.circom\",\n",
+ " \"MontgomeryDouble@montgomery.circom\",\n",
+ " \"MultiAND@gates.circom\",\n",
+ " \"MultiMiMC7@mimc.circom\",\n",
+ " \"MultiMux1@mux1.circom\",\n",
+ " \"MultiMux2@mux2.circom\",\n",
+ " \"MultiMux3@mux3.circom\",\n",
+ " \"MultiMux4@mux4.circom\",\n",
+ " \"Multiplexer@multiplexer.circom\",\n",
+ " \"Multiplexor2@escalarmulany.circom\",\n",
+ " \"Mux1@mux1.circom\",\n",
+ " \"Mux2@mux2.circom\",\n",
+ " \"Mux3@mux3.circom\",\n",
+ " \"Mux4@mux4.circom\",\n",
+ " \"NAND@gates.circom\",\n",
+ " \"NOR@gates.circom\",\n",
+ " \"NOT@gates.circom\",\n",
+ " \"Num2Bits_strict@bitify.circom\",\n",
+ " \"Num2Bits@bitify.circom\",\n",
+ " \"Num2BitsNeg@bitify.circom\",\n",
+ " \"OR@gates.circom\",\n",
+ " \"Pedersen@pedersen_old.circom\",\n",
+ " \"Pedersen@pedersen.circom\",\n",
+ " \"Point2Bits_Strict@pointbits.circom\",\n",
+ " \"Poseidon@poseidon.circom\",\n",
+ " \"Segment@pedersen.circom\",\n",
+ " \"SegmentMulAny@escalarmulany.circom\",\n",
+ " \"SegmentMulFix@escalarmulfix.circom\",\n",
+ " \"Sigma@poseidon.circom\",\n",
+ " \"Sign@sign.circom\",\n",
+ " \"Switcher@switcher.circom\",\n",
+ " \"Window4@pedersen.circom\",\n",
+ " \"WindowMulFix@escalarmulfix.circom\",\n",
+ " \"XOR@gates.circom\",\n",
+ " ]\n",
+ "else:\n",
+ " bmrks = [\n",
+ " \"AND@gates@circomlib.circom\",\n",
+ " \"BabyAdd@babyjub@circomlib.circom\",\n",
+ " \"BabyDbl@babyjub@circomlib.circom\",\n",
+ " \"BabyPbk@babyjub@circomlib.circom\",\n",
+ " \"BinSub@binsub@circomlib_16.circom\",\n",
+ " \"BinSum@binsum@circomlib_32_2.circom\",\n",
+ " \"BinSum@binsum@circomlib_32_5.circom\",\n",
+ " \"BitElementMulAny@escalarmulany@circomlib.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_1.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_128.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_16.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_253.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_254.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_256.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_32.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_64.circom\",\n",
+ " \"Bits2Num@bitify@circomlib_8.circom\",\n",
+ " \"Bits2Num_strict@bitify@circomlib.circom\",\n",
+ " \"Bits2Point@pointbits@circomlib.circom\",\n",
+ " \"Bits2Point_Strict@pointbits@circomlib.circom\",\n",
+ " \"Edwards2Montgomery@montgomery@circomlib.circom\",\n",
+ " \"GreaterEqThan@comparators@circomlib_16.circom\",\n",
+ " \"GreaterEqThan@comparators@circomlib_32.circom\",\n",
+ " \"GreaterEqThan@comparators@circomlib_8.circom\",\n",
+ " \"GreaterThan@comparators@circomlib_16.circom\",\n",
+ " \"GreaterThan@comparators@circomlib_32.circom\",\n",
+ " \"GreaterThan@comparators@circomlib_8.circom\",\n",
+ " \"IsEqual@comparators@circomlib.circom\",\n",
+ " \"IsZero@comparators@circomlib.circom\",\n",
+ " \"LessEqThan@comparators@circomlib_16.circom\",\n",
+ " \"LessEqThan@comparators@circomlib_32.circom\",\n",
+ " \"LessEqThan@comparators@circomlib_8.circom\",\n",
+ " \"Main@main@circomlib.circom\",\n",
+ " \"Montgomery2Edwards@montgomery@circomlib.circom\",\n",
+ " \"MontgomeryAdd@montgomery@circomlib.circom\",\n",
+ " \"MontgomeryDouble@montgomery@circomlib.circom\",\n",
+ " \"Multiplexor2@escalarmulany@circomlib.circom\",\n",
+ " \"Mux1@mux1@circomlib.circom\",\n",
+ " \"Mux2@mux2@circomlib.circom\",\n",
+ " \"Mux3@mux3@circomlib.circom\",\n",
+ " \"Mux4@mux4@circomlib.circom\",\n",
+ " \"NAND@gates@circomlib.circom\",\n",
+ " \"NOR@gates@circomlib.circom\",\n",
+ " \"NOT@gates@circomlib.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_1.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_128.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_16.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_253.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_254.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_256.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_32.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_64.circom\",\n",
+ " \"Num2Bits@bitify@circomlib_8.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_1.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_128.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_16.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_253.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_254.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_256.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_32.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_64.circom\",\n",
+ " \"Num2BitsNeg@bitify@circomlib_8.circom\",\n",
+ " \"Num2Bits_strict@bitify@circomlib.circom\",\n",
+ " \"OR@gates@circomlib.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_1.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_128.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_16.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_253.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_254.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_256.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_32.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_64.circom\",\n",
+ " \"Pedersen@pedersen@circomlib_8.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_1.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_128.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_16.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_253.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_254.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_256.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_32.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_64.circom\",\n",
+ " \"Pedersen@pedersen_old@circomlib_8.circom\",\n",
+ " \"Point2Bits@pointbits@circomlib.circom\",\n",
+ " \"Point2Bits_Strict@pointbits@circomlib.circom\",\n",
+ " \"SMTHash1@smthash_mimc@circomlib.circom\",\n",
+ " \"SMTHash1@smthash_poseidon@circomlib.circom\",\n",
+ " \"SMTHash2@smthash_mimc@circomlib.circom\",\n",
+ " \"SMTHash2@smthash_poseidon@circomlib.circom\",\n",
+ " \"SMTProcessorLevel@smtprocessorlevel@circomlib.circom\",\n",
+ " \"SMTProcessorSM@smtprocessorsm@circomlib.circom\",\n",
+ " \"SMTVerifierLevel@smtverifierlevel@circomlib.circom\",\n",
+ " \"SMTVerifierSM@smtverifiersm@circomlib.circom\",\n",
+ " \"Sha256_2@sha256_2@circomlib.circom\",\n",
+ " \"Sha256compression@sha256compression@circomlib.circom\",\n",
+ " \"Sigma@poseidon@circomlib.circom\",\n",
+ " \"Sigma@poseidon_old@circomlib.circom\",\n",
+ " \"SigmaPlus@sigmaplus@circomlib.circom\",\n",
+ " \"Sign@sign@circomlib.circom\",\n",
+ " \"Switcher@switcher@circomlib.circom\",\n",
+ " \"T1@t1@circomlib.circom\",\n",
+ " \"T2@t2@circomlib.circom\",\n",
+ " \"Window4@pedersen@circomlib.circom\",\n",
+ " \"WindowMulFix@escalarmulfix@circomlib.circom\",\n",
+ " \"XOR@gates@circomlib.circom\",\n",
+ " ]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cf438ce8-e7e1-48e1-9000-1aa123498977",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# parse stats\n",
+ "with open(\"../logs/compile-{}.log\".format(SERIES), \"r\") as f:\n",
+ " raw = f.read()\n",
+ " ll = raw.split(\"=================== \")\n",
+ " ll = list(filter(lambda p:len(p)>0, ll))\n",
+ "\n",
+ "stats = {}\n",
+ "for p in ll:\n",
+ " pname = p[:p.index(\":\")]\n",
+ " # print(\"# processing {}\".format(pname))\n",
+ " if pname not in bmrks:\n",
+ " # print(\"# skipping {}\".format(pname))\n",
+ " continue\n",
+ " re_nlcnst = int(re.search(r\"\\nnon-linear constraints: (.*)\\n\", p).group(1))\n",
+ " re_lcnst = int(re.search(r\"\\nlinear constraints: (.*)\\n\", p).group(1))\n",
+ " re_prvin = int(re.search(r\"\\nprivate inputs: (.*)\\n\", p).group(1))\n",
+ " re_pubin = int(re.search(r\"\\npublic inputs: (.*)\\n\", p).group(1))\n",
+ " re_prvout = int(re.search(r\"\\nprivate outputs: (.*)\\n\", p).group(1))\n",
+ " re_pubout = int(re.search(r\"\\npublic outputs: (.*)\\n\", p).group(1))\n",
+ " re_wires = int(re.search(r\"\\nwires: (.*)\\n\", p).group(1))\n",
+ " stats[pname] = {}\n",
+ " stats[pname][\"non-linear constraints\"] = re_nlcnst\n",
+ " stats[pname][\"linear constraints\"] = re_lcnst\n",
+ " stats[pname][\"total constraints\"] = re_nlcnst + re_lcnst\n",
+ " stats[pname][\"private inputs\"] = re_prvin\n",
+ " stats[pname][\"private inputs\"] = re_pubin\n",
+ " stats[pname][\"total inputs\"] = re_prvin + re_pubin\n",
+ " stats[pname][\"private outputs\"] = re_prvout\n",
+ " stats[pname][\"public outputs\"] = re_pubout\n",
+ " stats[pname][\"total outputs\"] = re_prvout + re_pubout\n",
+ " stats[pname][\"wires\"] = re_wires\n",
+ " stats[pname][\"witness\"] = re_wires - re_prvin - re_pubin - re_prvout - re_pubout\n",
+ " cat = None\n",
+ " if stats[pname][\"total constraints\"]<100:\n",
+ " cat = \"small\"\n",
+ " elif stats[pname][\"total constraints\"]>=100 and stats[pname][\"total constraints\"]<1000:\n",
+ " cat = \"medium\"\n",
+ " else:\n",
+ " cat = \"large\"\n",
+ " stats[pname][\"cat\"] = cat"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30d7580a-046b-4f13-b4e0-e83f6fe88029",
+ "metadata": {},
+ "source": [
+ "## print Table 1, \"circomlib-SERIES\" part"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "221c5156-c4d0-4e9b-93a7-db82be2980fa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# compute row \"circomlib-SERIES\" of Table 1\n",
+ "all_cnst = [stats[p][\"total constraints\"] for p in stats.keys()]\n",
+ "avg_cnst = round(sum(all_cnst)/len(all_cnst))\n",
+ "all_out = [stats[p][\"total outputs\"] for p in stats.keys()]\n",
+ "avg_out = round(sum(all_out)/len(all_out))\n",
+ "\n",
+ "print('Table 1, \"circomlib-{}\" part'.format(SERIES))\n",
+ "TEMPLATE = \"{:^15} | {:^10} | {:^20} | {:^20}\"\n",
+ "print(TEMPLATE.format(\"Benchmark Set\", \"# circuits\", \"Avg. # constraints\", \"Avg. # output signals\"))\n",
+ "print(TEMPLATE.format(\"circomlib-{}\".format(SERIES), len(stats), avg_cnst, avg_out))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b19eae8b-90e0-46a1-a263-b0c3f4cd217d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# parse time\n",
+ "with open(\"../logs/full-{}.log\".format(SERIES), \"r\") as f:\n",
+ " raw = f.read()\n",
+ " for fn in bmrks:\n",
+ " fn0 = fn.replace(\".circom\", \".r1cs\")\n",
+ " sp = raw.find(fn0)\n",
+ " s0 = raw.find(\"elapsed: \", sp)\n",
+ " ss = raw.find(\"seconds\", s0)\n",
+ " t = int(raw[s0+len(\"elapsed: \"):ss])\n",
+ " stats[fn][\"time\"] = t\n",
+ "\n",
+ "# self check\n",
+ "for p in stats.keys():\n",
+ " if \"time\" not in stats[p]:\n",
+ " print(\"# panic: time for {} doesn't exist, check your experiment again!\".format(p))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "36b75881-f73e-4a0e-91e6-741d6e182ede",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# parse result\n",
+ "for ff in bmrks:\n",
+ " with open(\"../logs/full-{}/{}.log\".format(SERIES, ff.replace(\".circom\",\"\")),\"r\") as f:\n",
+ " raw = f.read()\n",
+ " if \"# weak uniqueness: unsafe\" in raw:\n",
+ " stats[ff][\"res\"] = \"unsafe\"\n",
+ " elif \"# weak uniqueness: safe\" in raw:\n",
+ " stats[ff][\"res\"] = \"safe\"\n",
+ " elif \"# weak uniqueness: unknown\" in raw:\n",
+ " stats[ff][\"res\"] = \"unknown\"\n",
+ " else:\n",
+ " stats[ff][\"res\"] = \"unknown\"\n",
+ "\n",
+ "# self check\n",
+ "for p in stats.keys():\n",
+ " if \"res\" not in stats[p]:\n",
+ " print(\"# panic: result data for {} doesn't exist, check your experiment again!\".format(p))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "34ae5a3b-4038-4798-83f3-278abcbe6f8f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def compute_table2(cat):\n",
+ "\n",
+ " cat_in = [stats[p][\"total inputs\"] for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ " avg_cat_in = round(sum(cat_in)/len(cat_in))\n",
+ "\n",
+ " cat_out = [stats[p][\"total outputs\"] for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ " avg_cat_out = round(sum(cat_out)/len(cat_out))\n",
+ "\n",
+ " cat_witness = [stats[p][\"witness\"] for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ " avg_cat_witness = round(sum(cat_witness)/len(cat_witness))\n",
+ "\n",
+ " cat_wires = [stats[p][\"wires\"] for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ " avg_cat_wires = round(sum(cat_wires)/len(cat_wires))\n",
+ "\n",
+ " cat_lcnst = [stats[p][\"linear constraints\"] for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ " avg_cat_lcnst = round(sum(cat_lcnst)/len(cat_lcnst))\n",
+ "\n",
+ " cat_nlcnst = [stats[p][\"non-linear constraints\"] for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ " avg_cat_nlcnst = round(sum(cat_nlcnst)/len(cat_nlcnst))\n",
+ "\n",
+ " cat_cnst = [stats[p][\"total constraints\"] for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ " avg_cat_cnst = round(sum(cat_cnst)/len(cat_cnst))\n",
+ "\n",
+ " subkeys = [p for p in stats.keys() if cat == \"overall\" or stats[p][\"cat\"] == cat]\n",
+ "\n",
+ " # need to exclude timeouts\n",
+ " cat_time = [stats[p][\"time\"] for p in stats.keys() if (cat == \"overall\" or stats[p][\"cat\"] == cat) and (stats[p][\"res\"] == \"safe\" or stats[p][\"res\"] == \"unsafe\") and stats[p][\"time\"] < 600]\n",
+ " avg_cat_time = round(sum(cat_time)/len(cat_time))\n",
+ "\n",
+ " cat_check = [stats[p][\"res\"] for p in stats.keys() if (cat == \"overall\" or stats[p][\"cat\"] == cat) and stats[p][\"res\"] == \"safe\"]\n",
+ "\n",
+ " cat_cross = [stats[p][\"res\"] for p in stats.keys() if (cat == \"overall\" or stats[p][\"cat\"] == cat) and stats[p][\"res\"] == \"unsafe\"]\n",
+ " if cat == \"overall\" or cat == \"small\":\n",
+ " # +1 for the additional \"BitElementMulAny@escalarmulany.r1cs\" solved by counter-example procedure\n",
+ " if SERIES == \"utils\":\n",
+ " cat_cross.append(stats[\"BitElementMulAny@escalarmulany.circom\"])\n",
+ " if SERIES == \"core\":\n",
+ " cat_cross.append(stats[\"BitElementMulAny@escalarmulany@circomlib.circom\"])\n",
+ "\n",
+ " TEMPLATE = \"{:^20} | {:^5}\"\n",
+ " print(TEMPLATE.format(\"in\", avg_cat_in))\n",
+ " print(TEMPLATE.format(\"out\", avg_cat_out))\n",
+ " print(TEMPLATE.format(\"witness\", avg_cat_witness))\n",
+ " print(TEMPLATE.format(\"total (variables)\", avg_cat_wires))\n",
+ " print()\n",
+ " print(TEMPLATE.format(\"linear\", avg_cat_lcnst))\n",
+ " print(TEMPLATE.format(\"non-linear\", avg_cat_nlcnst))\n",
+ " print(TEMPLATE.format(\"total (constraints)\", avg_cat_cnst))\n",
+ " print()\n",
+ " print(TEMPLATE.format(\"Total (#)\", len(subkeys)))\n",
+ " print(TEMPLATE.format(\"Avg. Time (s)\", avg_cat_time))\n",
+ " print(TEMPLATE.format(\"check (#)\", len(cat_check)))\n",
+ " print(TEMPLATE.format(\"cross (#)\", len(cat_cross)))\n",
+ " print(TEMPLATE.format(\"Solved (%)\", (len(cat_check) + len(cat_cross)) / len(subkeys)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3bf8061-5a5b-458a-9895-e3c91416a005",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "## print Table 2, \"circomlib-SERIES\" part"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e4ce7974-ed66-468b-967d-8f1af4e43600",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# compute column of \"circomlib-SERIES\" - \"small\" in Table 2\n",
+ "print('------> Table 2, \"circomlib-{}\" part, \"small\"'.format(SERIES))\n",
+ "compute_table2(\"small\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9e356396-f845-4613-8883-86abea19de75",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# compute column of \"circomlib-SERIES\" - \"medium\" in Table 2\n",
+ "print('------> Table 2, \"circomlib-{}\" part, \"medium\"'.format(SERIES))\n",
+ "compute_table2(\"medium\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a4224c77-4c4f-4d86-91a2-e45e600ccde2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# compute column of \"circomlib-SERIES\" - \"large\" in Table 2\n",
+ "print('------> Table 2, \"circomlib-{}\" part, \"large\"'.format(SERIES))\n",
+ "compute_table2(\"large\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7dd4387b-f56c-45ff-a91e-bf485cfddff2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# compute column of \"circomlib-SERIES\" - \"overall\" in Table 2\n",
+ "print('------> Table 2, \"circomlib-{}\" part, \"overall\"'.format(SERIES))\n",
+ "compute_table2(\"overall\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a1c82272-f3e0-44df-873e-991a376747c1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# parse result for ucp-SERIES\n",
+ "for ff in bmrks:\n",
+ " with open(\"../logs/ucp-{}/{}.log\".format(SERIES, ff.replace(\".circom\",\"\")),\"r\") as f:\n",
+ " raw = f.read()\n",
+ " if \"# weak uniqueness: unsafe\" in raw:\n",
+ " stats[ff][\"ucp_res\"] = \"unsafe\"\n",
+ " elif \"# weak uniqueness: safe\" in raw:\n",
+ " stats[ff][\"ucp_res\"] = \"safe\"\n",
+ " elif \"# weak uniqueness: unknown\" in raw:\n",
+ " stats[ff][\"ucp_res\"] = \"unknown\"\n",
+ " else:\n",
+ " stats[ff][\"ucp_res\"] = \"unknown\"\n",
+ "\n",
+ "# self check\n",
+ "for p in stats.keys():\n",
+ " if \"ucp_res\" not in stats[p]:\n",
+ " print(\"# panic: ucp result data for {} doesn't exist, check your experiment again!\".format(p))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "206e1712-b2ca-4566-863d-61c366cfa79f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# parse result for smt-SERIES\n",
+ "for ff in bmrks:\n",
+ " with open(\"../logs/smt-{}/{}.log\".format(SERIES, ff.replace(\".circom\",\"\")),\"r\") as f:\n",
+ " raw = f.read()\n",
+ " if \"# weak uniqueness: unsafe\" in raw:\n",
+ " stats[ff][\"smt_res\"] = \"unsafe\"\n",
+ " elif \"# weak uniqueness: safe\" in raw:\n",
+ " stats[ff][\"smt_res\"] = \"safe\"\n",
+ " elif \"# weak uniqueness: unknown\" in raw:\n",
+ " stats[ff][\"smt_res\"] = \"unknown\"\n",
+ " else:\n",
+ " stats[ff][\"smt_res\"] = \"unknown\"\n",
+ "\n",
+ "# self check\n",
+ "for p in stats.keys():\n",
+ " if \"smt_res\" not in stats[p]:\n",
+ " print(\"# panic: smt result data for {} doesn't exist, check your experiment again!\".format(p))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a723b1b2-428d-491b-963c-7aaf9968a112",
+ "metadata": {},
+ "source": [
+ "## print Figure 11, \"circomlib-SERIES\" part"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9872f6a4-f46e-4485-89be-a96d3176c91e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# compute solved% for full-SERIES\n",
+ "full_check = [stats[p][\"res\"] for p in stats.keys() if stats[p][\"res\"] == \"safe\"]\n",
+ "full_cross = [stats[p][\"res\"] for p in stats.keys() if stats[p][\"res\"] == \"unsafe\"]\n",
+ "# +1 for the additional \"BitElementMulAny@escalarmulany.r1cs\" solved by counter-example procedure\n",
+ "if SERIES == \"utils\":\n",
+ " full_cross.append(stats[\"BitElementMulAny@escalarmulany.circom\"])\n",
+ "if SERIES == \"core\":\n",
+ " full_cross.append(stats[\"BitElementMulAny@escalarmulany@circomlib.circom\"])\n",
+ "full_percentage = (len(full_check) + len(full_cross)) / len(stats)\n",
+ "\n",
+ "# compute solved% for ucp-SERIES\n",
+ "ucp_check = [stats[p][\"ucp_res\"] for p in stats.keys() if stats[p][\"ucp_res\"] == \"safe\"]\n",
+ "ucp_cross = [stats[p][\"ucp_res\"] for p in stats.keys() if stats[p][\"ucp_res\"] == \"unsafe\"]\n",
+ "ucp_percentage = (len(ucp_check) + len(ucp_cross)) / len(stats)\n",
+ "\n",
+ "# compute solved% for smt-SERIES\n",
+ "smt_check = [stats[p][\"smt_res\"] for p in stats.keys() if stats[p][\"smt_res\"] == \"safe\"]\n",
+ "smt_cross = [stats[p][\"smt_res\"] for p in stats.keys() if stats[p][\"smt_res\"] == \"unsafe\"]\n",
+ "smt_percentage = (len(smt_check) + len(smt_cross)) / len(stats)\n",
+ "\n",
+ "print('------> Figure 11, \"circomlib-{}\" part'.format(SERIES))\n",
+ "print(\"FULL: {:.2}\\nUCP: {:.2}\\nSMT: {:.2}\".format(full_percentage, ucp_percentage, smt_percentage))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7beaba17-ee8e-4d8b-bf3d-c34b231a3a31",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ee61eb3c-65e0-411b-934c-a1ac6a8ef285",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "258c6610-54a7-46ce-a28c-2ab0bc12fb6f",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8c27cf2e-39ee-4405-aaeb-22d84a1a33da",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "base",
+ "language": "python",
+ "name": "base"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/scripts/parse-results.py b/scripts/parse-results.py
new file mode 100644
index 0000000..a86c7e0
--- /dev/null
+++ b/scripts/parse-results.py
@@ -0,0 +1,487 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+# In[ ]:
+
+
+import re
+import sys
+
+
+# In[ ]:
+
+
+# choose between utils or core
+# SERIES = "utils"
+# SERIES = "core"
+SERIES = sys.argv[1]
+
+
+# In[ ]:
+
+
+bmrks = None
+if SERIES == "utils":
+ bmrks = [
+ "AND@gates.circom",
+ "BabyAdd@babyjub.circom",
+ "BabyDbl@babyjub.circom",
+ "BabyPbk@babyjub.circom",
+ "BinSub@binsub.circom",
+ "BinSum@binsum.circom",
+ "BitElementMulAny@escalarmulany.circom",
+ "Bits2Num_strict@bitify.circom",
+ "Bits2Num@bitify.circom",
+ "Bits2Point_Strict@pointbits.circom",
+ "CompConstant@compconstant.circom",
+ "Decoder@multiplexer.circom",
+ "Edwards2Montgomery@montgomery.circom",
+ "EscalarMulAny@escalarmulany.circom",
+ "EscalarProduct@multiplexer.circom",
+ "GreaterEqThan@comparators.circom",
+ "GreaterThan@comparators.circom",
+ "IsEqual@comparators.circom",
+ "IsZero@comparators.circom",
+ "LessEqThan@comparators.circom",
+ "LessThan@comparators.circom",
+ "MiMC7@mimc.circom",
+ "MiMCFeistel@mimcsponge.circom",
+ "MiMCSponge@mimcsponge.circom",
+ "Montgomery2Edwards@montgomery.circom",
+ "MontgomeryAdd@montgomery.circom",
+ "MontgomeryDouble@montgomery.circom",
+ "MultiAND@gates.circom",
+ "MultiMiMC7@mimc.circom",
+ "MultiMux1@mux1.circom",
+ "MultiMux2@mux2.circom",
+ "MultiMux3@mux3.circom",
+ "MultiMux4@mux4.circom",
+ "Multiplexer@multiplexer.circom",
+ "Multiplexor2@escalarmulany.circom",
+ "Mux1@mux1.circom",
+ "Mux2@mux2.circom",
+ "Mux3@mux3.circom",
+ "Mux4@mux4.circom",
+ "NAND@gates.circom",
+ "NOR@gates.circom",
+ "NOT@gates.circom",
+ "Num2Bits_strict@bitify.circom",
+ "Num2Bits@bitify.circom",
+ "Num2BitsNeg@bitify.circom",
+ "OR@gates.circom",
+ "Pedersen@pedersen_old.circom",
+ "Pedersen@pedersen.circom",
+ "Point2Bits_Strict@pointbits.circom",
+ "Poseidon@poseidon.circom",
+ "Segment@pedersen.circom",
+ "SegmentMulAny@escalarmulany.circom",
+ "SegmentMulFix@escalarmulfix.circom",
+ "Sigma@poseidon.circom",
+ "Sign@sign.circom",
+ "Switcher@switcher.circom",
+ "Window4@pedersen.circom",
+ "WindowMulFix@escalarmulfix.circom",
+ "XOR@gates.circom",
+ ]
+else:
+ bmrks = [
+ "AND@gates@circomlib.circom",
+ "BabyAdd@babyjub@circomlib.circom",
+ "BabyDbl@babyjub@circomlib.circom",
+ "BabyPbk@babyjub@circomlib.circom",
+ "BinSub@binsub@circomlib_16.circom",
+ "BinSum@binsum@circomlib_32_2.circom",
+ "BinSum@binsum@circomlib_32_5.circom",
+ "BitElementMulAny@escalarmulany@circomlib.circom",
+ "Bits2Num@bitify@circomlib_1.circom",
+ "Bits2Num@bitify@circomlib_128.circom",
+ "Bits2Num@bitify@circomlib_16.circom",
+ "Bits2Num@bitify@circomlib_253.circom",
+ "Bits2Num@bitify@circomlib_254.circom",
+ "Bits2Num@bitify@circomlib_256.circom",
+ "Bits2Num@bitify@circomlib_32.circom",
+ "Bits2Num@bitify@circomlib_64.circom",
+ "Bits2Num@bitify@circomlib_8.circom",
+ "Bits2Num_strict@bitify@circomlib.circom",
+ "Bits2Point@pointbits@circomlib.circom",
+ "Bits2Point_Strict@pointbits@circomlib.circom",
+ "Edwards2Montgomery@montgomery@circomlib.circom",
+ "GreaterEqThan@comparators@circomlib_16.circom",
+ "GreaterEqThan@comparators@circomlib_32.circom",
+ "GreaterEqThan@comparators@circomlib_8.circom",
+ "GreaterThan@comparators@circomlib_16.circom",
+ "GreaterThan@comparators@circomlib_32.circom",
+ "GreaterThan@comparators@circomlib_8.circom",
+ "IsEqual@comparators@circomlib.circom",
+ "IsZero@comparators@circomlib.circom",
+ "LessEqThan@comparators@circomlib_16.circom",
+ "LessEqThan@comparators@circomlib_32.circom",
+ "LessEqThan@comparators@circomlib_8.circom",
+ "Main@main@circomlib.circom",
+ "Montgomery2Edwards@montgomery@circomlib.circom",
+ "MontgomeryAdd@montgomery@circomlib.circom",
+ "MontgomeryDouble@montgomery@circomlib.circom",
+ "Multiplexor2@escalarmulany@circomlib.circom",
+ "Mux1@mux1@circomlib.circom",
+ "Mux2@mux2@circomlib.circom",
+ "Mux3@mux3@circomlib.circom",
+ "Mux4@mux4@circomlib.circom",
+ "NAND@gates@circomlib.circom",
+ "NOR@gates@circomlib.circom",
+ "NOT@gates@circomlib.circom",
+ "Num2Bits@bitify@circomlib_1.circom",
+ "Num2Bits@bitify@circomlib_128.circom",
+ "Num2Bits@bitify@circomlib_16.circom",
+ "Num2Bits@bitify@circomlib_253.circom",
+ "Num2Bits@bitify@circomlib_254.circom",
+ "Num2Bits@bitify@circomlib_256.circom",
+ "Num2Bits@bitify@circomlib_32.circom",
+ "Num2Bits@bitify@circomlib_64.circom",
+ "Num2Bits@bitify@circomlib_8.circom",
+ "Num2BitsNeg@bitify@circomlib_1.circom",
+ "Num2BitsNeg@bitify@circomlib_128.circom",
+ "Num2BitsNeg@bitify@circomlib_16.circom",
+ "Num2BitsNeg@bitify@circomlib_253.circom",
+ "Num2BitsNeg@bitify@circomlib_254.circom",
+ "Num2BitsNeg@bitify@circomlib_256.circom",
+ "Num2BitsNeg@bitify@circomlib_32.circom",
+ "Num2BitsNeg@bitify@circomlib_64.circom",
+ "Num2BitsNeg@bitify@circomlib_8.circom",
+ "Num2Bits_strict@bitify@circomlib.circom",
+ "OR@gates@circomlib.circom",
+ "Pedersen@pedersen@circomlib_1.circom",
+ "Pedersen@pedersen@circomlib_128.circom",
+ "Pedersen@pedersen@circomlib_16.circom",
+ "Pedersen@pedersen@circomlib_253.circom",
+ "Pedersen@pedersen@circomlib_254.circom",
+ "Pedersen@pedersen@circomlib_256.circom",
+ "Pedersen@pedersen@circomlib_32.circom",
+ "Pedersen@pedersen@circomlib_64.circom",
+ "Pedersen@pedersen@circomlib_8.circom",
+ "Pedersen@pedersen_old@circomlib_1.circom",
+ "Pedersen@pedersen_old@circomlib_128.circom",
+ "Pedersen@pedersen_old@circomlib_16.circom",
+ "Pedersen@pedersen_old@circomlib_253.circom",
+ "Pedersen@pedersen_old@circomlib_254.circom",
+ "Pedersen@pedersen_old@circomlib_256.circom",
+ "Pedersen@pedersen_old@circomlib_32.circom",
+ "Pedersen@pedersen_old@circomlib_64.circom",
+ "Pedersen@pedersen_old@circomlib_8.circom",
+ "Point2Bits@pointbits@circomlib.circom",
+ "Point2Bits_Strict@pointbits@circomlib.circom",
+ "SMTHash1@smthash_mimc@circomlib.circom",
+ "SMTHash1@smthash_poseidon@circomlib.circom",
+ "SMTHash2@smthash_mimc@circomlib.circom",
+ "SMTHash2@smthash_poseidon@circomlib.circom",
+ "SMTProcessorLevel@smtprocessorlevel@circomlib.circom",
+ "SMTProcessorSM@smtprocessorsm@circomlib.circom",
+ "SMTVerifierLevel@smtverifierlevel@circomlib.circom",
+ "SMTVerifierSM@smtverifiersm@circomlib.circom",
+ "Sha256_2@sha256_2@circomlib.circom",
+ "Sha256compression@sha256compression@circomlib.circom",
+ "Sigma@poseidon@circomlib.circom",
+ "Sigma@poseidon_old@circomlib.circom",
+ "SigmaPlus@sigmaplus@circomlib.circom",
+ "Sign@sign@circomlib.circom",
+ "Switcher@switcher@circomlib.circom",
+ "T1@t1@circomlib.circom",
+ "T2@t2@circomlib.circom",
+ "Window4@pedersen@circomlib.circom",
+ "WindowMulFix@escalarmulfix@circomlib.circom",
+ "XOR@gates@circomlib.circom",
+ ]
+
+
+# In[ ]:
+
+
+# parse stats
+with open("../logs/compile-{}.log".format(SERIES), "r") as f:
+ raw = f.read()
+ ll = raw.split("=================== ")
+ ll = list(filter(lambda p:len(p)>0, ll))
+
+stats = {}
+for p in ll:
+ pname = p[:p.index(":")]
+ # print("# processing {}".format(pname))
+ if pname not in bmrks:
+ # print("# skipping {}".format(pname))
+ continue
+ re_nlcnst = int(re.search(r"\nnon-linear constraints: (.*)\n", p).group(1))
+ re_lcnst = int(re.search(r"\nlinear constraints: (.*)\n", p).group(1))
+ re_prvin = int(re.search(r"\nprivate inputs: (.*)\n", p).group(1))
+ re_pubin = int(re.search(r"\npublic inputs: (.*)\n", p).group(1))
+ re_prvout = int(re.search(r"\nprivate outputs: (.*)\n", p).group(1))
+ re_pubout = int(re.search(r"\npublic outputs: (.*)\n", p).group(1))
+ re_wires = int(re.search(r"\nwires: (.*)\n", p).group(1))
+ stats[pname] = {}
+ stats[pname]["non-linear constraints"] = re_nlcnst
+ stats[pname]["linear constraints"] = re_lcnst
+ stats[pname]["total constraints"] = re_nlcnst + re_lcnst
+ stats[pname]["private inputs"] = re_prvin
+ stats[pname]["private inputs"] = re_pubin
+ stats[pname]["total inputs"] = re_prvin + re_pubin
+ stats[pname]["private outputs"] = re_prvout
+ stats[pname]["public outputs"] = re_pubout
+ stats[pname]["total outputs"] = re_prvout + re_pubout
+ stats[pname]["wires"] = re_wires
+ stats[pname]["witness"] = re_wires - re_prvin - re_pubin - re_prvout - re_pubout
+ cat = None
+ if stats[pname]["total constraints"]<100:
+ cat = "small"
+ elif stats[pname]["total constraints"]>=100 and stats[pname]["total constraints"]<1000:
+ cat = "medium"
+ else:
+ cat = "large"
+ stats[pname]["cat"] = cat
+
+
+# ## print Table 1, "circomlib-SERIES" part
+
+# In[ ]:
+
+
+# compute row "circomlib-SERIES" of Table 1
+all_cnst = [stats[p]["total constraints"] for p in stats.keys()]
+avg_cnst = round(sum(all_cnst)/len(all_cnst))
+all_out = [stats[p]["total outputs"] for p in stats.keys()]
+avg_out = round(sum(all_out)/len(all_out))
+
+print('Table 1, "circomlib-{}" part'.format(SERIES))
+TEMPLATE = "{:^15} | {:^10} | {:^20} | {:^20}"
+print(TEMPLATE.format("Benchmark Set", "# circuits", "Avg. # constraints", "Avg. # output signals"))
+print(TEMPLATE.format("circomlib-{}".format(SERIES), len(stats), avg_cnst, avg_out))
+
+
+# In[ ]:
+
+
+# parse time
+with open("../logs/full-{}.log".format(SERIES), "r") as f:
+ raw = f.read()
+ for fn in bmrks:
+ fn0 = fn.replace(".circom", ".r1cs")
+ sp = raw.find(fn0)
+ s0 = raw.find("elapsed: ", sp)
+ ss = raw.find("seconds", s0)
+ t = int(raw[s0+len("elapsed: "):ss])
+ stats[fn]["time"] = t
+
+# self check
+for p in stats.keys():
+ if "time" not in stats[p]:
+ print("# panic: time for {} doesn't exist, check your experiment again!".format(p))
+
+
+# In[ ]:
+
+
+# parse result
+for ff in bmrks:
+ with open("../logs/full-{}/{}.log".format(SERIES, ff.replace(".circom","")),"r") as f:
+ raw = f.read()
+ if "# weak uniqueness: unsafe" in raw:
+ stats[ff]["res"] = "unsafe"
+ elif "# weak uniqueness: safe" in raw:
+ stats[ff]["res"] = "safe"
+ elif "# weak uniqueness: unknown" in raw:
+ stats[ff]["res"] = "unknown"
+ else:
+ stats[ff]["res"] = "unknown"
+
+# self check
+for p in stats.keys():
+ if "res" not in stats[p]:
+ print("# panic: result data for {} doesn't exist, check your experiment again!".format(p))
+
+
+# In[ ]:
+
+
+def compute_table2(cat):
+
+ cat_in = [stats[p]["total inputs"] for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+ avg_cat_in = round(sum(cat_in)/len(cat_in))
+
+ cat_out = [stats[p]["total outputs"] for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+ avg_cat_out = round(sum(cat_out)/len(cat_out))
+
+ cat_witness = [stats[p]["witness"] for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+ avg_cat_witness = round(sum(cat_witness)/len(cat_witness))
+
+ cat_wires = [stats[p]["wires"] for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+ avg_cat_wires = round(sum(cat_wires)/len(cat_wires))
+
+ cat_lcnst = [stats[p]["linear constraints"] for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+ avg_cat_lcnst = round(sum(cat_lcnst)/len(cat_lcnst))
+
+ cat_nlcnst = [stats[p]["non-linear constraints"] for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+ avg_cat_nlcnst = round(sum(cat_nlcnst)/len(cat_nlcnst))
+
+ cat_cnst = [stats[p]["total constraints"] for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+ avg_cat_cnst = round(sum(cat_cnst)/len(cat_cnst))
+
+ subkeys = [p for p in stats.keys() if cat == "overall" or stats[p]["cat"] == cat]
+
+ # need to exclude timeouts
+ cat_time = [stats[p]["time"] for p in stats.keys() if (cat == "overall" or stats[p]["cat"] == cat) and (stats[p]["res"] == "safe" or stats[p]["res"] == "unsafe") and stats[p]["time"] < 600]
+ avg_cat_time = round(sum(cat_time)/len(cat_time))
+
+ cat_check = [stats[p]["res"] for p in stats.keys() if (cat == "overall" or stats[p]["cat"] == cat) and stats[p]["res"] == "safe"]
+
+ cat_cross = [stats[p]["res"] for p in stats.keys() if (cat == "overall" or stats[p]["cat"] == cat) and stats[p]["res"] == "unsafe"]
+ if cat == "overall" or cat == "small":
+ # +1 for the additional "BitElementMulAny@escalarmulany.r1cs" solved by counter-example procedure
+ if SERIES == "utils":
+ cat_cross.append(stats["BitElementMulAny@escalarmulany.circom"])
+ if SERIES == "core":
+ cat_cross.append(stats["BitElementMulAny@escalarmulany@circomlib.circom"])
+
+ TEMPLATE = "{:^20} | {:^5}"
+ print(TEMPLATE.format("in", avg_cat_in))
+ print(TEMPLATE.format("out", avg_cat_out))
+ print(TEMPLATE.format("witness", avg_cat_witness))
+ print(TEMPLATE.format("total (variables)", avg_cat_wires))
+ print()
+ print(TEMPLATE.format("linear", avg_cat_lcnst))
+ print(TEMPLATE.format("non-linear", avg_cat_nlcnst))
+ print(TEMPLATE.format("total (constraints)", avg_cat_cnst))
+ print()
+ print(TEMPLATE.format("Total (#)", len(subkeys)))
+ print(TEMPLATE.format("Avg. Time (s)", avg_cat_time))
+ print(TEMPLATE.format("check (#)", len(cat_check)))
+ print(TEMPLATE.format("cross (#)", len(cat_cross)))
+ print(TEMPLATE.format("Solved (%)", (len(cat_check) + len(cat_cross)) / len(subkeys)))
+
+
+# ## print Table 2, "circomlib-SERIES" part
+
+# In[ ]:
+
+
+# compute column of "circomlib-SERIES" - "small" in Table 2
+print('------> Table 2, "circomlib-{}" part, "small"'.format(SERIES))
+compute_table2("small")
+
+
+# In[ ]:
+
+
+# compute column of "circomlib-SERIES" - "medium" in Table 2
+print('------> Table 2, "circomlib-{}" part, "medium"'.format(SERIES))
+compute_table2("medium")
+
+
+# In[ ]:
+
+
+# compute column of "circomlib-SERIES" - "large" in Table 2
+print('------> Table 2, "circomlib-{}" part, "large"'.format(SERIES))
+compute_table2("large")
+
+
+# In[ ]:
+
+
+# compute column of "circomlib-SERIES" - "overall" in Table 2
+print('------> Table 2, "circomlib-{}" part, "overall"'.format(SERIES))
+compute_table2("overall")
+
+
+# In[ ]:
+
+
+# parse result for ucp-SERIES
+for ff in bmrks:
+ with open("../logs/ucp-{}/{}.log".format(SERIES, ff.replace(".circom","")),"r") as f:
+ raw = f.read()
+ if "# weak uniqueness: unsafe" in raw:
+ stats[ff]["ucp_res"] = "unsafe"
+ elif "# weak uniqueness: safe" in raw:
+ stats[ff]["ucp_res"] = "safe"
+ elif "# weak uniqueness: unknown" in raw:
+ stats[ff]["ucp_res"] = "unknown"
+ else:
+ stats[ff]["ucp_res"] = "unknown"
+
+# self check
+for p in stats.keys():
+ if "ucp_res" not in stats[p]:
+ print("# panic: ucp result data for {} doesn't exist, check your experiment again!".format(p))
+
+
+# In[ ]:
+
+
+# parse result for smt-SERIES
+for ff in bmrks:
+ with open("../logs/smt-{}/{}.log".format(SERIES, ff.replace(".circom","")),"r") as f:
+ raw = f.read()
+ if "# weak uniqueness: unsafe" in raw:
+ stats[ff]["smt_res"] = "unsafe"
+ elif "# weak uniqueness: safe" in raw:
+ stats[ff]["smt_res"] = "safe"
+ elif "# weak uniqueness: unknown" in raw:
+ stats[ff]["smt_res"] = "unknown"
+ else:
+ stats[ff]["smt_res"] = "unknown"
+
+# self check
+for p in stats.keys():
+ if "smt_res" not in stats[p]:
+ print("# panic: smt result data for {} doesn't exist, check your experiment again!".format(p))
+
+
+# ## print Figure 11, "circomlib-SERIES" part
+
+# In[ ]:
+
+
+# compute solved% for full-SERIES
+full_check = [stats[p]["res"] for p in stats.keys() if stats[p]["res"] == "safe"]
+full_cross = [stats[p]["res"] for p in stats.keys() if stats[p]["res"] == "unsafe"]
+# +1 for the additional "BitElementMulAny@escalarmulany.r1cs" solved by counter-example procedure
+if SERIES == "utils":
+ full_cross.append(stats["BitElementMulAny@escalarmulany.circom"])
+if SERIES == "core":
+ full_cross.append(stats["BitElementMulAny@escalarmulany@circomlib.circom"])
+full_percentage = (len(full_check) + len(full_cross)) / len(stats)
+
+# compute solved% for ucp-SERIES
+ucp_check = [stats[p]["ucp_res"] for p in stats.keys() if stats[p]["ucp_res"] == "safe"]
+ucp_cross = [stats[p]["ucp_res"] for p in stats.keys() if stats[p]["ucp_res"] == "unsafe"]
+ucp_percentage = (len(ucp_check) + len(ucp_cross)) / len(stats)
+
+# compute solved% for smt-SERIES
+smt_check = [stats[p]["smt_res"] for p in stats.keys() if stats[p]["smt_res"] == "safe"]
+smt_cross = [stats[p]["smt_res"] for p in stats.keys() if stats[p]["smt_res"] == "unsafe"]
+smt_percentage = (len(smt_check) + len(smt_cross)) / len(stats)
+
+print('------> Figure 11, "circomlib-{}" part'.format(SERIES))
+print("FULL: {:.2}\nUCP: {:.2}\nSMT: {:.2}".format(full_percentage, ucp_percentage, smt_percentage))
+
+
+# In[ ]:
+
+
+
+
+
+# In[ ]:
+
+
+
+
+
+# In[ ]:
+
+
+
+
+
+# In[ ]:
+
+
+
+
diff --git a/scripts/prepare-buggy-mix.sh b/scripts/prepare-buggy-mix.sh
index 33ed538..174dbe4 100755
--- a/scripts/prepare-buggy-mix.sh
+++ b/scripts/prepare-buggy-mix.sh
@@ -4,10 +4,10 @@ declare -a arr=(
# "buggy-mix/circom-ecdsa-436665b/test-bigmod22.circom"
# "buggy-mix/hermez-network-971c89f/test-rollup-main-L1.circom"
# "buggy-mix/iden3-core-3a3a300/credentialAtomicQuerySigTest.circom"
-"buggy-mix/circomlib-79d3034/test-mimcsponge.circom"
+# "buggy-mix/circomlib-79d3034/test-mimcsponge.circom"
# "buggy-mix/tornado-core-ce97895/withdraw.circom"
# "buggy-mix/re-tornado-core-ce97895/withdraw.circom"
-# "buggy-mix/min0-tornado-core-ce97895/withdraw.circom"
+"buggy-mix/min0-tornado-core-ce97895/withdraw.circom"
)
for fn in "${arr[@]}"
diff --git a/scripts/prepare-circom-pairing-ext.sh b/scripts/prepare-circom-pairing-ext.sh
new file mode 100755
index 0000000..db31536
--- /dev/null
+++ b/scripts/prepare-circom-pairing-ext.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+for fp in ./benchmarks/circom-pairing-ext-743d761/*.circom
+do
+ fn=$(basename ${fp})
+ bn="${fn%.*}"
+ echo "=================== ${fn}: ${bn} ==================="
+ echo " compiling..."
+ circom -o ./benchmarks/circom-pairing-ext-743d761/ ./benchmarks/circom-pairing-ext-743d761/${fn} --r1cs --sym --O0
+
+done
\ No newline at end of file
diff --git a/scripts/prepare-circomlib.sh b/scripts/prepare-circomlib.sh
index 01c62a8..d36ba19 100755
--- a/scripts/prepare-circomlib.sh
+++ b/scripts/prepare-circomlib.sh
@@ -2,72 +2,71 @@
declare -a arr=(
"AliasCheck@aliascheck.circom"
-"BabyDbl@babyjub.circom"
+"AND@gates.circom"
"BabyAdd@babyjub.circom"
"BabyCheck@babyjub.circom"
+"BabyDbl@babyjub.circom"
"BabyPbk@babyjub.circom"
"BinSub@binsub.circom"
"BinSum@binsum.circom"
-"Num2BitsNeg@bitify.circom"
-"Num2Bits_strict@bitify.circom"
-"Bits2Num@bitify.circom"
+"BitElementMulAny@escalarmulany.circom"
"Bits2Num_strict@bitify.circom"
-"Num2Bits@bitify.circom"
-"IsZero@comparators.circom"
-"LessEqThan@comparators.circom"
-"LessThan@comparators.circom"
-"GreaterThan@comparators.circom"
-"ForceEqualIfEnabled@comparators.circom"
-"IsEqual@comparators.circom"
-"GreaterEqThan@comparators.circom"
+"Bits2Num@bitify.circom"
+"Bits2Point_Strict@pointbits.circom"
"CompConstant@compconstant.circom"
-"EdDSAVerifier@eddsa.circom"
-"EdDSAMiMCVerifier@eddsamimc.circom"
+"Decoder@multiplexer.circom"
"EdDSAMiMCSpongeVerifier@eddsamimcsponge.circom"
+"EdDSAMiMCVerifier@eddsamimc.circom"
"EdDSAPoseidonVerifier@eddsaposeidon.circom"
-"BitElementMulAny@escalarmulany.circom"
-"Multiplexor2@escalarmulany.circom"
+"EdDSAVerifier@eddsa.circom"
+"Edwards2Montgomery@montgomery.circom"
"EscalarMulAny@escalarmulany.circom"
-"SegmentMulAny@escalarmulany.circom"
-"SegmentMulFix@escalarmulfix.circom"
-"WindowMulFix@escalarmulfix.circom"
-"NOR@gates.circom"
-"MultiAND@gates.circom"
-"NOT@gates.circom"
-"NAND@gates.circom"
-"OR@gates.circom"
-"XOR@gates.circom"
-"AND@gates.circom"
-# "IsZero@isZero.circom" # isZero.circom is not in latest circomlib
+"EscalarProduct@multiplexer.circom"
+"ForceEqualIfEnabled@comparators.circom"
+"GreaterEqThan@comparators.circom"
+"GreaterThan@comparators.circom"
+"IsEqual@comparators.circom"
+"IsZero@comparators.circom"
+"LessEqThan@comparators.circom"
+"LessThan@comparators.circom"
"MiMC7@mimc.circom"
-"MultiMiMC7@mimc.circom"
"MiMCFeistel@mimcsponge.circom"
"MiMCSponge@mimcsponge.circom"
-"Edwards2Montgomery@montgomery.circom"
"Montgomery2Edwards@montgomery.circom"
-"MontgomeryDouble@montgomery.circom"
"MontgomeryAdd@montgomery.circom"
-"Multiplexer@multiplexer.circom"
-"EscalarProduct@multiplexer.circom"
-"Decoder@multiplexer.circom"
-"Mux1@mux1.circom"
+"MontgomeryDouble@montgomery.circom"
+"MultiAND@gates.circom"
+"MultiMiMC7@mimc.circom"
"MultiMux1@mux1.circom"
"MultiMux2@mux2.circom"
-"Mux2@mux2.circom"
"MultiMux3@mux3.circom"
-"Mux3@mux3.circom"
"MultiMux4@mux4.circom"
+"Multiplexer@multiplexer.circom"
+"Multiplexor2@escalarmulany.circom"
+"Mux1@mux1.circom"
+"Mux2@mux2.circom"
+"Mux3@mux3.circom"
"Mux4@mux4.circom"
+"NAND@gates.circom"
+"NOR@gates.circom"
+"NOT@gates.circom"
+"Num2Bits_strict@bitify.circom"
+"Num2Bits@bitify.circom"
+"Num2BitsNeg@bitify.circom"
+"OR@gates.circom"
"Pedersen@pedersen_old.circom"
"Pedersen@pedersen.circom"
-"Window4@pedersen.circom"
-"Segment@pedersen.circom"
-"Bits2Point_Strict@pointbits.circom"
"Point2Bits_Strict@pointbits.circom"
"Poseidon@poseidon.circom"
+"Segment@pedersen.circom"
+"SegmentMulAny@escalarmulany.circom"
+"SegmentMulFix@escalarmulfix.circom"
"Sigma@poseidon.circom"
"Sign@sign.circom"
"Switcher@switcher.circom"
+"Window4@pedersen.circom"
+"WindowMulFix@escalarmulfix.circom"
+"XOR@gates.circom"
)
# for fp in ./benchmarks/circomlib/*.circom
@@ -79,7 +78,7 @@ do
# circom -o ./benchmarks/circomlib/ ./benchmarks/circomlib/${fn} --r1cs --sym
# to compare with Ecne, you need --O0 to disable optimization
# /home/clara/circom/iden3_circom_now/target/release/circom -o ../benchmarks/circomlib-cff5ab6/ ../benchmarks/circomlib-cff5ab6/${fn} --r1cs --sym --O0 --json
- circom -o ./benchmarks/circomlib-cff5ab6/ ./benchmarks/circomlib-cff5ab6/${fn} --r1cs --sym --O0 --json
+ circom -o ./benchmarks/circomlib-cff5ab6/ ./benchmarks/circomlib-cff5ab6/${fn} --r1cs --sym --O0
# echo " parsing..."
# ./circom-parser/target/debug/parser ./benchmarks/circomlib/${fn} > ./benchmarks/circomlib/${bn}.json
diff --git a/scripts/prepare-circomlibex.sh b/scripts/prepare-circomlibex.sh
index 8a6d73a..6923211 100755
--- a/scripts/prepare-circomlibex.sh
+++ b/scripts/prepare-circomlibex.sh
@@ -119,5 +119,5 @@ do
echo "=================== ${fn}: ${bn} ==================="
echo " compiling..."
# to compare with Ecne, you need --O0 to disable optimization
- circom -o ./benchmarks/circomlibex-cff5ab6/ ./benchmarks/circomlibex-cff5ab6/${fn} --r1cs --sym --O0 --json
+ circom -o ./benchmarks/circomlibex-cff5ab6/ ./benchmarks/circomlibex-cff5ab6/${fn} --r1cs --sym --O0
done
diff --git a/scripts/prepare-motivating.sh b/scripts/prepare-motivating.sh
new file mode 100755
index 0000000..8085e52
--- /dev/null
+++ b/scripts/prepare-motivating.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+declare -a arr=(
+# "ValidateDecodingFixed.circom"
+# "ValidateDecodingBuggy.circom"
+"VDBuggy.circom"
+"VDFixed.circom"
+"adder.circom"
+)
+
+# for fp in ./benchmarks/circomlib/*.circom
+for fn in "${arr[@]}"
+do
+ bn="${fn%.*}"
+ echo "=================== ${fn}: ${bn} ==================="
+ echo " compiling..."
+ # circom -o ./benchmarks/circomlib/ ./benchmarks/circomlib/${fn} --r1cs --sym
+ # to compare with Ecne, you need --O0 to disable optimization
+ # /home/clara/circom/iden3_circom_now/target/release/circom -o ../benchmarks/circomlib-cff5ab6/ ../benchmarks/circomlib-cff5ab6/${fn} --r1cs --sym --O0 --json
+ circom -o ./benchmarks/motivating/ ./benchmarks/motivating/${fn} --r1cs --sym --O0
+ # echo " parsing..."
+ # ./circom-parser/target/debug/parser ./benchmarks/circomlib/${fn} > ./benchmarks/circomlib/${bn}.json
+
+ # echo " reading..."
+ # racket ./test-read-r1cs.rkt --r1cs ./benchmarks/circomlib/${bn}.r1cs > ./benchmarks/circomlib/${bn}.r1cs.log
+
+ # echo " testing..."
+ # racket ./test-functionality.rkt --cname ${bn}
+done
diff --git a/scripts/prepare-net-circomlib.sh b/scripts/prepare-net-circomlib.sh
new file mode 100755
index 0000000..9914c8e
--- /dev/null
+++ b/scripts/prepare-net-circomlib.sh
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+# this only prepares the net benchmarks (i.e. those with output signals)
+
+declare -a arr=(
+# "AliasCheck@aliascheck.circom"
+"AND@gates.circom"
+"BabyAdd@babyjub.circom"
+# "BabyCheck@babyjub.circom"
+"BabyDbl@babyjub.circom"
+"BabyPbk@babyjub.circom"
+"BinSub@binsub.circom"
+"BinSum@binsum.circom"
+"BitElementMulAny@escalarmulany.circom"
+"Bits2Num_strict@bitify.circom"
+"Bits2Num@bitify.circom"
+"Bits2Point_Strict@pointbits.circom"
+"CompConstant@compconstant.circom"
+"Decoder@multiplexer.circom"
+# "EdDSAMiMCSpongeVerifier@eddsamimcsponge.circom"
+# "EdDSAMiMCVerifier@eddsamimc.circom"
+# "EdDSAPoseidonVerifier@eddsaposeidon.circom"
+# "EdDSAVerifier@eddsa.circom"
+"Edwards2Montgomery@montgomery.circom"
+"EscalarMulAny@escalarmulany.circom"
+"EscalarProduct@multiplexer.circom"
+# "ForceEqualIfEnabled@comparators.circom"
+"GreaterEqThan@comparators.circom"
+"GreaterThan@comparators.circom"
+"IsEqual@comparators.circom"
+"IsZero@comparators.circom"
+"LessEqThan@comparators.circom"
+"LessThan@comparators.circom"
+"MiMC7@mimc.circom"
+"MiMCFeistel@mimcsponge.circom"
+"MiMCSponge@mimcsponge.circom"
+"Montgomery2Edwards@montgomery.circom"
+"MontgomeryAdd@montgomery.circom"
+"MontgomeryDouble@montgomery.circom"
+"MultiAND@gates.circom"
+"MultiMiMC7@mimc.circom"
+"MultiMux1@mux1.circom"
+"MultiMux2@mux2.circom"
+"MultiMux3@mux3.circom"
+"MultiMux4@mux4.circom"
+"Multiplexer@multiplexer.circom"
+"Multiplexor2@escalarmulany.circom"
+"Mux1@mux1.circom"
+"Mux2@mux2.circom"
+"Mux3@mux3.circom"
+"Mux4@mux4.circom"
+"NAND@gates.circom"
+"NOR@gates.circom"
+"NOT@gates.circom"
+"Num2Bits_strict@bitify.circom"
+"Num2Bits@bitify.circom"
+"Num2BitsNeg@bitify.circom"
+"OR@gates.circom"
+"Pedersen@pedersen_old.circom"
+"Pedersen@pedersen.circom"
+"Point2Bits_Strict@pointbits.circom"
+"Poseidon@poseidon.circom"
+"Segment@pedersen.circom"
+"SegmentMulAny@escalarmulany.circom"
+"SegmentMulFix@escalarmulfix.circom"
+"Sigma@poseidon.circom"
+"Sign@sign.circom"
+"Switcher@switcher.circom"
+"Window4@pedersen.circom"
+"WindowMulFix@escalarmulfix.circom"
+"XOR@gates.circom"
+)
+
+# for fp in ./benchmarks/circomlib/*.circom
+for fn in "${arr[@]}"
+do
+ bn="${fn%.*}"
+ echo "=================== ${fn}: ${bn} ==================="
+ echo " compiling..."
+ # circom -o ./benchmarks/circomlib/ ./benchmarks/circomlib/${fn} --r1cs --sym
+ # to compare with Ecne, you need --O0 to disable optimization
+ # /home/clara/circom/iden3_circom_now/target/release/circom -o ../benchmarks/circomlib-cff5ab6/ ../benchmarks/circomlib-cff5ab6/${fn} --r1cs --sym --O0 --json
+ circom -o ./benchmarks/circomlib-cff5ab6/ ./benchmarks/circomlib-cff5ab6/${fn} --r1cs --sym --O0
+ # echo " parsing..."
+ # ./circom-parser/target/debug/parser ./benchmarks/circomlib/${fn} > ./benchmarks/circomlib/${bn}.json
+
+ # echo " reading..."
+ # racket ./test-read-r1cs.rkt --r1cs ./benchmarks/circomlib/${bn}.r1cs > ./benchmarks/circomlib/${bn}.r1cs.log
+
+ # echo " testing..."
+ # racket ./test-functionality.rkt --cname ${bn}
+done
diff --git a/scripts/prepare-pre-circomlib.sh b/scripts/prepare-pre-circomlib.sh
new file mode 100755
index 0000000..c9d2750
--- /dev/null
+++ b/scripts/prepare-pre-circomlib.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+declare -a arr=(
+"AliasCheck@aliascheck.circom"
+"BabyDbl@babyjub.circom"
+"BabyAdd@babyjub.circom"
+"BabyCheck@babyjub.circom"
+"BabyPbk@babyjub.circom"
+"BinSub@binsub.circom"
+"BinSum@binsum.circom"
+"Num2BitsNeg@bitify.circom"
+"Num2Bits_strict@bitify.circom"
+"Bits2Num@bitify.circom"
+"Bits2Num_strict@bitify.circom"
+"Num2Bits@bitify.circom"
+"IsZero@comparators.circom"
+"LessEqThan@comparators.circom"
+"LessThan@comparators.circom"
+"GreaterThan@comparators.circom"
+"ForceEqualIfEnabled@comparators.circom"
+"IsEqual@comparators.circom"
+"GreaterEqThan@comparators.circom"
+"CompConstant@compconstant.circom"
+"EdDSAVerifier@eddsa.circom"
+"EdDSAMiMCVerifier@eddsamimc.circom"
+"EdDSAMiMCSpongeVerifier@eddsamimcsponge.circom"
+"EdDSAPoseidonVerifier@eddsaposeidon.circom"
+"BitElementMulAny@escalarmulany.circom"
+"Multiplexor2@escalarmulany.circom"
+"EscalarMulAny@escalarmulany.circom"
+"SegmentMulAny@escalarmulany.circom"
+"SegmentMulFix@escalarmulfix.circom"
+"WindowMulFix@escalarmulfix.circom"
+"NOR@gates.circom"
+"MultiAND@gates.circom"
+"NOT@gates.circom"
+"NAND@gates.circom"
+"OR@gates.circom"
+"XOR@gates.circom"
+"AND@gates.circom"
+# "IsZero@isZero.circom" # isZero.circom is not in latest circomlib
+"MiMC7@mimc.circom"
+"MultiMiMC7@mimc.circom"
+"MiMCFeistel@mimcsponge.circom"
+"MiMCSponge@mimcsponge.circom"
+"Edwards2Montgomery@montgomery.circom"
+"Montgomery2Edwards@montgomery.circom"
+"MontgomeryDouble@montgomery.circom"
+"MontgomeryAdd@montgomery.circom"
+"Multiplexer@multiplexer.circom"
+"EscalarProduct@multiplexer.circom"
+"Decoder@multiplexer.circom"
+"Mux1@mux1.circom"
+"MultiMux1@mux1.circom"
+"MultiMux2@mux2.circom"
+"Mux2@mux2.circom"
+"MultiMux3@mux3.circom"
+"Mux3@mux3.circom"
+"MultiMux4@mux4.circom"
+"Mux4@mux4.circom"
+"Pedersen@pedersen_old.circom"
+"Pedersen@pedersen.circom"
+"Window4@pedersen.circom"
+"Segment@pedersen.circom"
+"Bits2Point_Strict@pointbits.circom"
+"Point2Bits_Strict@pointbits.circom"
+"Poseidon@poseidon.circom"
+"Sigma@poseidon.circom"
+"Sign@sign.circom"
+"Switcher@switcher.circom"
+)
+
+# for fp in ./benchmarks/circomlib/*.circom
+for fn in "${arr[@]}"
+do
+ bn="${fn%.*}"
+ echo "=================== ${fn}: ${bn} ==================="
+ echo " compiling..."
+ # circom -o ./benchmarks/circomlib/ ./benchmarks/circomlib/${fn} --r1cs --sym
+ # to compare with Ecne, you need --O0 to disable optimization
+ # /home/clara/circom/iden3_circom_now/target/release/circom -o ../benchmarks/circomlib-cff5ab6/ ../benchmarks/circomlib-cff5ab6/${fn} --r1cs --sym --O0 --json
+ circom -o ./benchmarks/pre-circomlib-cff5ab6/ ./benchmarks/pre-circomlib-cff5ab6/${fn} --r1cs --sym --O0
+ # echo " parsing..."
+ # ./circom-parser/target/debug/parser ./benchmarks/circomlib/${fn} > ./benchmarks/circomlib/${bn}.json
+
+ # echo " reading..."
+ # racket ./test-read-r1cs.rkt --r1cs ./benchmarks/circomlib/${bn}.r1cs > ./benchmarks/circomlib/${bn}.r1cs.log
+
+ # echo " testing..."
+ # racket ./test-functionality.rkt --cname ${bn}
+done
diff --git a/test-v0-uniqueness.rkt b/test-v0-uniqueness.rkt
deleted file mode 100644
index 8b8e3d5..0000000
--- a/test-v0-uniqueness.rkt
+++ /dev/null
@@ -1,187 +0,0 @@
-#lang rosette
-; common require
-(require json racket/engine
- (prefix-in tokamak: "./picus/tokamak.rkt")
- (prefix-in utils: "./picus/utils.rkt")
- (prefix-in config: "./picus/config.rkt")
- (prefix-in r1cs: "./picus/r1cs-grammar.rkt")
-)
-; z3 require
-(require
- (prefix-in z3-solver: "./picus/z3-utils.rkt")
- (prefix-in z3-rint: "./picus/r1cs-z3-interpreter.rkt")
- (prefix-in z3-parser: "./picus/r1cs-z3-parser.rkt")
- (prefix-in z3-osimp: "./picus/optimizers/r1cs-z3-simple-optimizer.rkt")
- (prefix-in z3-oab0: "./picus/optimizers/r1cs-z3-AB0-optimizer.rkt")
-)
-; cvc5 require
-(require
- (prefix-in cvc5-solver: "./picus/cvc5-utils.rkt")
- (prefix-in cvc5-rint: "./picus/r1cs-cvc5-interpreter.rkt")
- (prefix-in cvc5-parser: "./picus/r1cs-cvc5-parser.rkt")
- (prefix-in cvc5-osimp: "./picus/optimizers/r1cs-cvc5-simple-optimizer.rkt")
- ; note: cvc5 doesn't have AB0 optimizer, use template instead
-)
-
-; =====================================
-; ======== commandline parsing ========
-; =====================================
-; stateful variable
-(define state-smt-path null)
-; parse command line arguments
-(define arg-r1cs null)
-(define arg-solver "z3")
-(define arg-timeout 5000)
-(define arg-smt #f)
-(command-line
- #:once-each
- [("--r1cs") p-r1cs "path to target r1cs"
- (begin
- (set! arg-r1cs p-r1cs)
- (when (! (string-suffix? arg-r1cs ".r1cs"))
- (tokamak:exit "file needs to be *.r1cs")
- )
- )
- ]
- [("--solver") p-solver "solver to use: z3 | cvc5 (default: z3)"
- (cond
- [(|| (equal? "z3" p-solver) (equal? "cvc5" p-solver)) (set! arg-solver p-solver)]
- [else (tokamak:exit "solver needs to be either z3 or cvc5")]
- )
- ]
- [("--timeout") p-timeout "timeout for every small query (default: 5000ms)"
- (begin
- (set! arg-timeout (string->number p-timeout))
- )
- ]
- [("--smt") "show path to generated smt files (default: false)"
- (begin
- (set! arg-smt #t)
- )
- ]
-)
-(printf "# r1cs file: ~a\n" arg-r1cs)
-(printf "# timeout: ~a\n" arg-timeout)
-(printf "# solver: ~a\n" arg-solver)
-
-; =========================================
-; ======== solver specific methods ========
-; =========================================
-(define (solver:get-theory)
- (cond
- [(equal? "z3" arg-solver) "QF_NIA"]
- [(equal? "cvc5" arg-solver) "QF_FF"]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (solver:solve)
- (cond
- [(equal? "z3" arg-solver) z3-solver:solve]
- [(equal? "cvc5" arg-solver) cvc5-solver:solve]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (parser:parse-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-parser:parse-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-parser:parse-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (optimizer:optimize)
- (cond
- [(equal? "z3" arg-solver) (lambda (x) (z3-oab0:optimize-r1cs (z3-osimp:optimize-r1cs x)))]
- [(equal? "cvc5" arg-solver) (lambda (x) (cvc5-osimp:optimize-r1cs x))]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (rint:interpret-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-rint:interpret-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-rint:interpret-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-
-; ======================
-; ======== main ========
-; ======================
-; load r1cs binary
-(define r0 (r1cs:read-r1cs arg-r1cs))
-(define nwires (r1cs:get-nwires r0))
-(printf "# number of wires: ~a\n" nwires)
-(printf "# number of constraints: ~a\n" (r1cs:get-mconstraints r0))
-(printf "# field size (how many bytes): ~a\n" (r1cs:get-field-size r0))
-
-; parse original r1cs
-(printf "# parsing original r1cs...\n")
-(define-values (xlist original-definitions original-cnsts) ((parser:parse-r1cs) r0 null)) ; interpret the constraint system
-(define input-list (r1cs:r1cs-inputs r0))
-(define output-list (r1cs:r1cs-outputs r0))
-(printf "# inputs: ~a.\n" input-list)
-(printf "# outputs: ~a.\n" output-list)
-(printf "# xlist: ~a.\n" xlist)
-
-; parse alternative r1cs
-(define xlist0 (for/list ([i (range nwires)])
- (if (not (utils:contains? input-list i))
- (format "y~a" i)
- (list-ref xlist i)
- )
-))
-(printf "# xlist0: ~a.\n" xlist0)
-(printf "# parsing alternative r1cs...\n")
-(define-values (_ alternative-definitions alternative-cnsts) ((parser:parse-r1cs) r0 xlist0))
-
-; assemble solve query
-(printf "# assembling query...\n")
-(define tmp0 (r1cs:rassert (r1cs:ror
- (filter (lambda (x) (! (null? x))) (for/list ([i (range nwires)])
- (if (utils:contains? output-list i)
- (r1cs:rneq (r1cs:rvar (list-ref xlist i)) (r1cs:rvar (list-ref xlist0 i)))
- null
- )
- ))
-)))
-(define query-cmds (r1cs:rcmds (list tmp0)))
-
-(printf "# assembling final smt...\n")
-(define final-cmds (r1cs:append-rcmds
- (r1cs:rcmds (list
- ; (note) setlogic needs to go first so optimizer can detect it
- (r1cs:rlogic (r1cs:rstr (solver:get-theory)))
- ))
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "================================"))
- (r1cs:rcmt (r1cs:rstr "======== original block ========"))
- (r1cs:rcmt (r1cs:rstr "================================"))
- ))
- original-definitions
- original-cnsts
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "==================================="))
- (r1cs:rcmt (r1cs:rstr "======== alternative block ========"))
- (r1cs:rcmt (r1cs:rstr "==================================="))
- ))
- alternative-definitions
- alternative-cnsts
- (r1cs:rcmds (list
- (r1cs:rcmt (r1cs:rstr "============================="))
- (r1cs:rcmt (r1cs:rstr "======== query block ========"))
- (r1cs:rcmt (r1cs:rstr "============================="))
- ))
- query-cmds
- (r1cs:rcmds (list (r1cs:rsolve )))
-))
-
-; perform optimization
-(define optimized-cmds ((optimizer:optimize) final-cmds))
-(define final-str (string-join ((rint:interpret-r1cs) optimized-cmds) "\n"))
-; (printf "# final str is:\n~a\n" final-str)
-
-; solve!
-(define res ((solver:solve) final-str arg-timeout #:output-smt? arg-smt))
-(if (equal? 'unsat (car res))
- (printf "# weak uniqueness: safe.\n")
- (printf "# weak uniqueness: unsafe or unknown / reason: ~a\n" res)
-)
\ No newline at end of file
diff --git a/test-v1-uniqueness.rkt b/test-v1-uniqueness.rkt
deleted file mode 100644
index 2f216ae..0000000
--- a/test-v1-uniqueness.rkt
+++ /dev/null
@@ -1,169 +0,0 @@
-#lang rosette
-; common require
-(require json racket/engine
- (prefix-in tokamak: "./picus/tokamak.rkt")
- (prefix-in utils: "./picus/utils.rkt")
- (prefix-in config: "./picus/config.rkt")
- (prefix-in r1cs: "./picus/r1cs-grammar.rkt")
- (prefix-in inc: "./picus/algorithms/inc.rkt")
-)
-; z3 require
-(require
- (prefix-in z3-solver: "./picus/z3-utils.rkt")
- (prefix-in z3-rint: "./picus/r1cs-z3-interpreter.rkt")
- (prefix-in z3-parser: "./picus/r1cs-z3-parser.rkt")
- (prefix-in z3-osimp: "./picus/optimizers/r1cs-z3-simple-optimizer.rkt")
- (prefix-in z3-oab0: "./picus/optimizers/r1cs-z3-AB0-optimizer.rkt")
-)
-; cvc5 require
-(require
- (prefix-in cvc5-solver: "./picus/cvc5-utils.rkt")
- (prefix-in cvc5-rint: "./picus/r1cs-cvc5-interpreter.rkt")
- (prefix-in cvc5-parser: "./picus/r1cs-cvc5-parser.rkt")
- (prefix-in cvc5-osimp: "./picus/optimizers/r1cs-cvc5-simple-optimizer.rkt")
- ; note: cvc5 doesn't have AB0 optimizer, use template instead
-)
-
-; =====================================
-; ======== commandline parsing ========
-; =====================================
-; stateful variable
-(define state-smt-path null)
-; parse command line arguments
-(define arg-r1cs null)
-(define arg-solver "z3")
-(define arg-timeout 5000)
-(define arg-smt #f)
-(command-line
- #:once-each
- [("--r1cs") p-r1cs "path to target r1cs"
- (begin
- (set! arg-r1cs p-r1cs)
- (when (! (string-suffix? arg-r1cs ".r1cs"))
- (tokamak:exit "file needs to be *.r1cs")
- )
- )
- ]
- [("--solver") p-solver "solver to use: z3 | cvc5 (default: z3)"
- (cond
- [(|| (equal? "z3" p-solver) (equal? "cvc5" p-solver)) (set! arg-solver p-solver)]
- [else (tokamak:exit "solver needs to be either z3 or cvc5")]
- )
- ]
- [("--timeout") p-timeout "timeout for every small query (default: 5000ms)"
- (begin
- (set! arg-timeout (string->number p-timeout))
- )
- ]
- [("--smt") "show path to generated smt files (default: false)"
- (begin
- (set! arg-smt #t)
- )
- ]
-)
-(printf "# r1cs file: ~a\n" arg-r1cs)
-(printf "# timeout: ~a\n" arg-timeout)
-(printf "# solver: ~a\n" arg-solver)
-
-; =========================================
-; ======== solver specific methods ========
-; =========================================
-(define (solver:get-theory)
- (cond
- [(equal? "z3" arg-solver) "QF_NIA"]
- [(equal? "cvc5" arg-solver) "QF_FF"]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (solver:solve)
- (cond
- [(equal? "z3" arg-solver) z3-solver:solve]
- [(equal? "cvc5" arg-solver) cvc5-solver:solve]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (solver:state-smt-path)
- (cond
- [(equal? "z3" arg-solver) z3-solver:state-smt-path]
- [(equal? "cvc5" arg-solver) cvc5-solver:state-smt-path]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (parser:parse-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-parser:parse-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-parser:parse-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (optimizer:optimize)
- (cond
- [(equal? "z3" arg-solver) (lambda (x) (z3-oab0:optimize-r1cs (z3-osimp:optimize-r1cs x)))]
- [(equal? "cvc5" arg-solver) (lambda (x) (cvc5-osimp:optimize-r1cs x))]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (rint:interpret-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-rint:interpret-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-rint:interpret-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-
-; ==================================
-; ======== main preparation ========
-; ==================================
-(define r0 (r1cs:read-r1cs arg-r1cs))
-(define nwires (r1cs:get-nwires r0))
-(define mconstraints (r1cs:get-mconstraints r0))
-(printf "# number of wires: ~a\n" nwires)
-(printf "# number of constraints: ~a\n" mconstraints)
-(printf "# field size (how many bytes): ~a\n" (r1cs:get-field-size r0))
-
-; parse original r1cs
-(printf "# parsing original r1cs...\n")
-(define-values (xlist original-definitions original-cnsts) ((parser:parse-r1cs) r0 null)) ; interpret the constraint system
-(define input-list (r1cs:r1cs-inputs r0))
-(define output-list (r1cs:r1cs-outputs r0))
-(printf "# inputs: ~a.\n" input-list)
-(printf "# outputs: ~a.\n" output-list)
-(printf "# xlist: ~a.\n" xlist)
-
-; parse alternative r1cs
-(define xlist0 (for/list ([i (range nwires)])
- (if (not (utils:contains? input-list i))
- (format "y~a" i)
- (list-ref xlist i)
- )
-))
-(printf "# xlist0: ~a.\n" xlist0)
-(printf "# parsing alternative r1cs...\n")
-(define-values (_ alternative-definitions alternative-cnsts) ((parser:parse-r1cs) r0 xlist0))
-
-; ============================
-; ======== main solve ========
-; ============================
-(define-values (res-ul round-has-unknown) (inc:apply-inc
- r0 nwires mconstraints input-list output-list
- xlist original-definitions original-cnsts
- xlist0 alternative-definitions alternative-cnsts
- arg-timeout arg-smt
- solver:get-theory solver:solve solver:state-smt-path parser:parse-r1cs optimizer:optimize rint:interpret-r1cs
-))
-(printf "# final unknown list: ~a\n" res-ul)
-(if (empty? res-ul)
- (printf "# strong uniqueness: safe.\n")
- (if round-has-unknown
- (printf "# strong uniqueness: unknown.\n")
- (printf "# strong uniqueness: unsafe.\n")
- )
-)
-
-(if (utils:empty_inter? res-ul output-list)
- (printf "# weak uniqueness: safe.\n")
- (if round-has-unknown
- (printf "# weak uniqueness: unknown.\n")
- (printf "# weak uniqueness: unsafe.\n")
- )
-)
\ No newline at end of file
diff --git a/test-v2-uniqueness.rkt b/test-v2-uniqueness.rkt
deleted file mode 100644
index 3a002fd..0000000
--- a/test-v2-uniqueness.rkt
+++ /dev/null
@@ -1,186 +0,0 @@
-#lang rosette
-; common require
-(require json racket/engine
- (prefix-in tokamak: "./picus/tokamak.rkt")
- (prefix-in utils: "./picus/utils.rkt")
- (prefix-in config: "./picus/config.rkt")
- (prefix-in r1cs: "./picus/r1cs-grammar.rkt")
- (prefix-in pp: "./picus/algorithms/clara-pp.rkt")
-)
-; z3 require
-(require
- (prefix-in z3-solver: "./picus/z3-utils.rkt")
- (prefix-in z3-rint: "./picus/r1cs-z3-interpreter.rkt")
- (prefix-in z3-parser: "./picus/r1cs-z3-parser.rkt")
- (prefix-in z3-osimp: "./picus/optimizers/r1cs-z3-simple-optimizer.rkt")
- (prefix-in z3-oab0: "./picus/optimizers/r1cs-z3-AB0-optimizer.rkt")
- ;(prefix-in z3-bounds: "./picus/optimizers/r1cs-z3-Bounds-optimizer.rkt")
-)
-; cvc5 require
-(require
- (prefix-in cvc5-solver: "./picus/cvc5-utils.rkt")
- (prefix-in cvc5-rint: "./picus/r1cs-cvc5-interpreter.rkt")
- (prefix-in cvc5-parser: "./picus/r1cs-cvc5-parser.rkt")
- (prefix-in cvc5-osimp: "./picus/optimizers/r1cs-cvc5-simple-optimizer.rkt")
- ; note: cvc5 doesn't have AB0 optimizer, use template instead
-)
-
-; =====================================
-; ======== commandline parsing ========
-; =====================================
-; stateful variable
-(define state-smt-path null)
-; parse command line arguments
-(define arg-r1cs null)
-(define arg-solver "z3")
-(define arg-timeout 5000)
-(define arg-smt #f)
-(define arg-weak #f)
-(define arg-model #f)
-(command-line
- #:once-each
- [("--r1cs") p-r1cs "path to target r1cs"
- (begin
- (set! arg-r1cs p-r1cs)
- (when (! (string-suffix? arg-r1cs ".r1cs"))
- (tokamak:exit "file needs to be *.r1cs")
- )
- )
- ]
- [("--solver") p-solver "solver to use: z3 | cvc5 (default: z3)"
- (cond
- [(|| (equal? "z3" p-solver) (equal? "cvc5" p-solver)) (set! arg-solver p-solver)]
- [else (tokamak:exit "solver needs to be either z3 or cvc5")]
- )
- ]
- [("--timeout") p-timeout "timeout for every small query (default: 5000ms)"
- (begin
- (set! arg-timeout (string->number p-timeout))
- )
- ]
- [("--smt") "show path to generated smt files (default: false)"
- (begin
- (set! arg-smt #t)
- )
- ]
- [("--weak") "only check weak safety, not strong safety (default: false)"
- (begin
- (set! arg-weak #t)
- )
- ]
- [("--get-model") "produce and print out counter example for every query (default: false)"
- (begin
- (set! arg-model #t)
- )
- ]
-)
-(printf "# r1cs file: ~a\n" arg-r1cs)
-(printf "# timeout: ~a\n" arg-timeout)
-(printf "# solver: ~a\n" arg-solver)
-
-; =========================================
-; ======== solver specific methods ========
-; =========================================
-(define (solver:get-theory)
- (cond
- [(equal? "z3" arg-solver) "QF_NIA"]
- [(equal? "cvc5" arg-solver) "QF_FF"]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (solver:solve)
- (cond
- [(equal? "z3" arg-solver) z3-solver:solve]
- [(equal? "cvc5" arg-solver) cvc5-solver:solve]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (solver:state-smt-path)
- (cond
- [(equal? "z3" arg-solver) z3-solver:state-smt-path]
- [(equal? "cvc5" arg-solver) cvc5-solver:state-smt-path]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (parser:parse-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-parser:parse-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-parser:parse-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (optimizer:optimize)
- (cond
- [(equal? "z3" arg-solver) (lambda (x) (
- z3-oab0:optimize-r1cs (z3-osimp:optimize-r1cs x)
- ))]
- [(equal? "cvc5" arg-solver) (lambda (x)
- (cvc5-osimp:optimize-r1cs x)
- )]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (rint:interpret-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-rint:interpret-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-rint:interpret-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-
-; ======================
-; ======== main ========
-; ======================
-(define r0 (r1cs:read-r1cs arg-r1cs))
-(define nwires (r1cs:get-nwires r0))
-(define mconstraints (r1cs:get-mconstraints r0))
-(printf "# number of wires: ~a\n" nwires)
-(printf "# number of constraints: ~a\n" mconstraints)
-(printf "# field size (how many bytes): ~a\n" (r1cs:get-field-size r0))
-
-; parse original r1cs
-(printf "# parsing original r1cs...\n")
-(define-values (xlist original-definitions original-cnsts) ((parser:parse-r1cs) r0 null)) ; interpret the constraint system
-(define input-list (r1cs:r1cs-inputs r0))
-(define output-list (r1cs:r1cs-outputs r0))
-(printf "# inputs: ~a.\n" input-list)
-(printf "# outputs: ~a.\n" output-list)
-;(printf "# xlist: ~a.\n" xlist)
-
-; parse alternative r1cs
-(define xlist0 (for/list ([i (range nwires)])
- (if (not (utils:contains? input-list i))
- (format "y~a" i)
- (list-ref xlist i)
- )
-))
-;(printf "# xlist0: ~a.\n" xlist0)
-(printf "# parsing alternative r1cs...\n")
-(define-values (_ alternative-definitions alternative-cnsts) ((parser:parse-r1cs) r0 xlist0))
-
-(define-values (res-ul round-has-unknown) (pp:apply-pp
- r0 nwires mconstraints input-list output-list
- xlist original-definitions original-cnsts
- xlist0 alternative-definitions alternative-cnsts
- arg-weak arg-timeout arg-smt arg-model
- solver:get-theory solver:solve solver:state-smt-path parser:parse-r1cs optimizer:optimize rint:interpret-r1cs
-))
-(printf "# final unknown list: ~a\n" res-ul)
-(if (not arg-weak)
- (if (empty? res-ul)
- (printf "# strong uniqueness: safe.\n")
- (if round-has-unknown
- (printf "# strong uniqueness: unknown.\n")
- (printf "# strong uniqueness: unsafe.\n")
- )
- )
- (printf "# strong uniqueness: skipped (--weak)\n")
-)
-
-(if (utils:empty_inter? res-ul output-list)
- (printf "# weak uniqueness: safe.\n")
- (if round-has-unknown
- (printf "# weak uniqueness: unknown.\n")
- (printf "# weak uniqueness: unsafe.\n")
- )
-)
diff --git a/test-v3-uniqueness.rkt b/test-v3-uniqueness.rkt
deleted file mode 100644
index 7dc1ec5..0000000
--- a/test-v3-uniqueness.rkt
+++ /dev/null
@@ -1,189 +0,0 @@
-#lang rosette
-; common require
-(require json racket/engine
- (prefix-in tokamak: "./picus/tokamak.rkt")
- (prefix-in utils: "./picus/utils.rkt")
- (prefix-in config: "./picus/config.rkt")
- (prefix-in r1cs: "./picus/r1cs-grammar.rkt")
- (prefix-in nb: "./picus/algorithms/clara-nb.rkt")
-)
-; z3 require
-(require
- (prefix-in z3-solver: "./picus/z3-utils.rkt")
- (prefix-in z3-rint: "./picus/r1cs-z3-interpreter.rkt")
- (prefix-in z3-parser: "./picus/r1cs-z3-parser.rkt")
- (prefix-in z3-osimp: "./picus/optimizers/r1cs-z3-simple-optimizer.rkt")
- (prefix-in z3-oab0: "./picus/optimizers/r1cs-z3-AB0-optimizer.rkt")
- ;(prefix-in z3-bounds: "./picus/optimizers/r1cs-z3-Bounds-optimizer.rkt")
-)
-; cvc5 require
-(require
- (prefix-in cvc5-solver: "./picus/cvc5-utils.rkt")
- (prefix-in cvc5-rint: "./picus/r1cs-cvc5-interpreter.rkt")
- (prefix-in cvc5-parser: "./picus/r1cs-cvc5-parser.rkt")
- (prefix-in cvc5-osimp: "./picus/optimizers/r1cs-cvc5-simple-optimizer.rkt")
- ; note: cvc5 doesn't have AB0 optimizer, use template instead
-)
-
-; =====================================
-; ======== commandline parsing ========
-; =====================================
-; stateful variable
-(define state-smt-path null)
-; parse command line arguments
-(define arg-r1cs null)
-(define arg-solver "z3")
-(define arg-timeout 5000)
-(define arg-smt #f)
-(define arg-weak #f)
-(define arg-initlvl 0)
-(command-line
- #:once-each
- [("--r1cs") p-r1cs "path to target r1cs"
- (begin
- (set! arg-r1cs p-r1cs)
- (when (! (string-suffix? arg-r1cs ".r1cs"))
- (tokamak:exit "file needs to be *.r1cs")
- )
- )
- ]
- [("--solver") p-solver "solver to use: z3 | cvc5 (default: z3)"
- (cond
- [(|| (equal? "z3" p-solver) (equal? "cvc5" p-solver)) (set! arg-solver p-solver)]
- [else (tokamak:exit "solver needs to be either z3 or cvc5")]
- )
- ]
- [("--timeout") p-timeout "timeout for every small query (default: 5000ms)"
- (begin
- (set! arg-timeout (string->number p-timeout))
- )
- ]
- [("--initlvl") p-initlvl "initial level of neighboring method: 0 - full nb | 1 | 2 - disable nb (default:0)"
- (begin
- (when (! (|| (equal? "0" p-initlvl) (equal? "1" p-initlvl) (equal? "2" p-initlvl)))
- (tokamak:exit "initial level should be 0, 1 or 2")
- )
- (set! arg-initlvl (string->number p-initlvl))
- )
- ]
- [("--smt") "show path to generated smt files (default: false)"
- (begin
- (set! arg-smt #t)
- )
- ]
- [("--weak") "only check weak safety, not strong safety (default: false)"
- (begin
- (set! arg-weak #t)
- )
- ]
-)
-(printf "# r1cs file: ~a\n" arg-r1cs)
-(printf "# timeout: ~a\n" arg-timeout)
-(printf "# solver: ~a\n" arg-solver)
-
-; =========================================
-; ======== solver specific methods ========
-; =========================================
-(define (solver:get-theory)
- (cond
- [(equal? "z3" arg-solver) "QF_NIA"]
- [(equal? "cvc5" arg-solver) "QF_FF"]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (solver:solve)
- (cond
- [(equal? "z3" arg-solver) z3-solver:solve]
- [(equal? "cvc5" arg-solver) cvc5-solver:solve]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (solver:state-smt-path)
- (cond
- [(equal? "z3" arg-solver) z3-solver:state-smt-path]
- [(equal? "cvc5" arg-solver) cvc5-solver:state-smt-path]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (parser:parse-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-parser:parse-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-parser:parse-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (optimizer:optimize)
- (cond
- [(equal? "z3" arg-solver) (lambda (x) (
- z3-oab0:optimize-r1cs (z3-osimp:optimize-r1cs x)
- ))]
- [(equal? "cvc5" arg-solver) (lambda (x)
- (cvc5-osimp:optimize-r1cs x)
- )]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-(define (rint:interpret-r1cs)
- (cond
- [(equal? "z3" arg-solver) z3-rint:interpret-r1cs]
- [(equal? "cvc5" arg-solver) cvc5-rint:interpret-r1cs]
- [else (tokamak:exit "you can't reach here")]
- )
-)
-
-; ======================
-; ======== main ========
-; ======================
-(define r0 (r1cs:read-r1cs arg-r1cs))
-(define nwires (r1cs:get-nwires r0))
-(define mconstraints (r1cs:get-mconstraints r0))
-(printf "# number of wires: ~a\n" nwires)
-(printf "# number of constraints: ~a\n" mconstraints)
-(printf "# field size (how many bytes): ~a\n" (r1cs:get-field-size r0))
-
-; parse original r1cs
-(printf "# parsing original r1cs...\n")
-(define-values (xlist original-definitions original-cnsts) ((parser:parse-r1cs) r0 null)) ; interpret the constraint system
-(define input-list (r1cs:r1cs-inputs r0))
-(define output-list (r1cs:r1cs-outputs r0))
-(printf "# inputs: ~a.\n" input-list)
-(printf "# outputs: ~a.\n" output-list)
-;(printf "# xlist: ~a.\n" xlist)
-
-; parse alternative r1cs
-(define xlist0 (for/list ([i (range nwires)])
- (if (not (utils:contains? input-list i))
- (format "y~a" i)
- (list-ref xlist i)
- )
-))
-;(printf "# xlist0: ~a.\n" xlist0)
-(printf "# parsing alternative r1cs...\n")
-(define-values (_ alternative-definitions alternative-cnsts) ((parser:parse-r1cs) r0 xlist0))
-
-(define-values (res-ul round-has-unknown) (nb:apply-nb
- r0 nwires mconstraints input-list output-list
- xlist original-definitions original-cnsts
- xlist0 alternative-definitions alternative-cnsts
- arg-weak arg-timeout arg-smt arg-initlvl
- solver:get-theory solver:solve solver:state-smt-path parser:parse-r1cs optimizer:optimize rint:interpret-r1cs
-))
-(printf "# final unknown list: ~a\n" res-ul)
-(if (not arg-weak)
- (if (empty? res-ul)
- (printf "# strong uniqueness: safe.\n")
- (if round-has-unknown
- (printf "# strong uniqueness: unknown.\n")
- (printf "# strong uniqueness: unsafe.\n")
- )
- )
- (printf "# strong uniqueness: skipped (--weak)\n")
-)
-
-(if (utils:empty_inter? res-ul output-list)
- (printf "# weak uniqueness: safe.\n")
- (if round-has-unknown
- (printf "# weak uniqueness: unknown.\n")
- (printf "# weak uniqueness: unsafe.\n")
- )
-)
diff --git a/tests/.keep b/tests/.keep
deleted file mode 100644
index e69de29..0000000