Compare commits

..

40 Commits

Author SHA1 Message Date
Jordi Baylina
8fc6e3f1c6 0.5.12 2020-07-02 06:00:10 +02:00
Jordi Baylina
c32d303d27 deps 2020-07-02 05:59:00 +02:00
Jordi Baylina
744d3b241c deps and verbos 2020-07-02 05:33:31 +02:00
Jordi Baylina
1a5f7d1a2b 0.5.11 2020-04-27 12:03:38 +02:00
Jordi Baylina
434e7ac498 deps 2020-04-27 12:03:29 +02:00
Jordi Baylina
99afb4312e Fix negative short composition 2020-04-27 11:57:32 +02:00
Jordi Baylina
67ec7c5d5b 0.5.10 2020-04-19 19:29:06 +02:00
Jordi Baylina
a76f3b5988 deps 2020-04-19 19:28:57 +02:00
Jordi Baylina
bc9d395e70 0.5.9 2020-04-19 18:38:19 +02:00
Jordi Baylina
7fc457ac90 fastfile 2020-04-19 18:38:10 +02:00
Jordi Baylina
8c4980c3f9 0.5.8 2020-04-18 20:53:21 +02:00
Jordi Baylina
767ca60008 Use native big int 2020-04-18 20:53:13 +02:00
Jordi Baylina
f25842f67c 0.5.7 2020-04-07 13:02:51 +02:00
Jordi Baylina
92399017df FIX: c tester in linux 2020-04-07 13:02:39 +02:00
Jordi Baylina
1463685b11 Merge pull request #57 from iden3/feature/c-tester-linux
add `-pthread` for linux g++ command
2020-04-07 13:00:51 +02:00
Jordi Baylina
a1ae6e4a44 0.5.6 2020-04-07 12:54:30 +02:00
Jordi Baylina
c7c6b799ad FIX: Error in wasm generation of big circuits 2020-04-07 12:53:58 +02:00
krlosMata
b107a11432 add -pthread for linux 2020-04-07 11:51:48 +02:00
Jordi Baylina
96776d2374 0.5.5 2020-03-31 15:36:55 +02:00
Jordi Baylina
ca7379995e Error reporting fixes 2020-03-31 15:36:26 +02:00
Jordi Baylina
f604c31e0d 0.5.4 2020-03-28 21:33:04 +01:00
Jordi Baylina
a9c0593ec0 deps 2020-03-28 21:32:56 +01:00
Jordi Baylina
80cce0ccbb deps 2020-03-28 21:26:43 +01:00
Jordi Baylina
fcef4f5f32 .DS_Store banished! 2020-03-27 20:39:21 +01:00
Jordi Baylina
3ef303593b Merge branch 'master' of github.com:iden3/circom 2020-03-27 17:05:24 +01:00
Marta Bellés
16cf75c94b Update TUTORIAL.md 2020-03-27 15:59:49 +01:00
Jordi Baylina
d79d59416d Fix tutorial 2020-03-27 15:47:06 +01:00
Jordi Baylina
eae13a94fa Fix TUTORIAL 2020-03-27 14:38:43 +01:00
Marta Bellés
7e41508860 Update TUTORIAL.md 2020-03-27 13:17:09 +01:00
Jordi Baylina
5d374237e1 Fix tutorial 2020-03-27 09:54:14 +01:00
Jordi Baylina
a18b603b22 0.5.3 2020-03-26 22:36:57 +01:00
Jordi Baylina
f261992689 deps and compatible with node10 2020-03-26 22:36:47 +01:00
Jordi Baylina
45e359aa35 0.5.2 2020-03-26 19:05:36 +01:00
Jordi Baylina
da6cff2335 Resolve right path for circom_runtime in tester 2020-03-26 19:05:23 +01:00
Jordi Baylina
38b4a7a8b3 0.5.1 2020-03-26 18:41:05 +01:00
Jordi Baylina
825f31b420 deps and sanitycheck in tester 2020-03-26 18:40:52 +01:00
Jordi Baylina
b9b384681b 0.5.0 2020-03-26 17:47:18 +01:00
Jordi Baylina
eb8cb0af74 Almost ready for 0.5.0 2020-03-26 17:42:25 +01:00
Jordi Baylina
ef899e618b Wasm generation finished 2020-03-16 20:37:08 +01:00
Jordi Baylina
8f63d18ff4 Begining of wasm 2020-03-09 21:16:56 +01:00
77 changed files with 3941 additions and 13022 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1,7 +1,4 @@
module.exports = { module.exports = {
"plugins": [
"mocha"
],
"env": { "env": {
"es6": true, "es6": true,
"node": true, "node": true,
@@ -27,7 +24,6 @@ module.exports = {
"semi": [ "semi": [
"error", "error",
"always" "always"
], ]
"mocha/no-exclusive-tests": "error"
} }
}; };

View File

@@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Copyright (C) 2020 0Kims Association <https://0kims.org>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.

View File

@@ -1,14 +1,14 @@
# circom and snarkjs tutorial # circom and snarkjs tutorial
This tutorial will guide you in creating your first Zero Knowledge zkSnark circuit. It will take you through the various techniques to write circuits, and will show you how to create proofs and verify them off-chain and on-chain on Ethereum. This tutorial will guide you in creating your first zero-knowledge SNARK circuit. It will take you through the various techniques to write circuits and show you how to create and verify proofs off-chain and on-chain on Ethereum.
## 1. Installing the tools ## 1. Installing the tools
### 1.1 Pre-requisites ### 1.1 Pre-requisites
If you don't have it installed yet, you need to install `Node.js`. If you don't have it installed yet, you need to install `Node.js`.
The last stable version of `Node.js` (or 8.12.0) works just fine, but if you install the latest current version `Node.js` (10.12.0) you will see a significant increase in performance. This is because last versions of node includes Big Integer Libraries nativelly. The `snarkjs` library makes use of this feature if available, and this improves the performance x10 (!). You should install at least version 10 of node. It's important to note here that the latests versions of javascript, includes big integer support and web assembly compilers that make the code run fast.
### 1.2 Install **circom** and **snarkjs** ### 1.2 Install **circom** and **snarkjs**
@@ -22,7 +22,7 @@ npm install -g snarkjs
## 2. Working with a circuit ## 2. Working with a circuit
Let's create a circuit that tries to prove that you are able to factor a number! Let's create a circuit that will allow you to prove that you are able to factor a number!
### 2.1 Create a circuit in a new directory ### 2.1 Create a circuit in a new directory
@@ -42,7 +42,7 @@ template Multiplier() {
signal private input a; signal private input a;
signal private input b; signal private input b;
signal output c; signal output c;
c <== a*b; c <== a*b;
} }
@@ -62,10 +62,14 @@ Note: When compiling a circuit, a component named `main` must always exist.
We are now ready to compile the circuit. Run the following command: We are now ready to compile the circuit. Run the following command:
```sh ```sh
circom circuit.circom -o circuit.json circom circuit.circom --r1cs --wasm --sym
``` ```
to compile the circuit to a file named `circuit.json` The `--r1cs` option will generate `circuit.r1cs` (the r1cs constraint system of the circuit in binary format).
The `--wasm` option will generate `circuit.wasm` (the wasm code to generate the witness).
The `--sym` option will generate `circuit.sym` (a symbols file required for debugging or if you want to print the constraint system in an annotated mode).
## 3. Taking the compiled circuit to *snarkjs* ## 3. Taking the compiled circuit to *snarkjs*
@@ -74,7 +78,7 @@ Now that the circuit is compiled, we will continue with `snarkjs`.
Please note that you can always access the help of `snarkjs` by typing: Please note that you can always access the help of `snarkjs` by typing:
```sh ```sh
snarkjs --help snarkjs --help
``` ```
### 3.1 View information and stats regarding a circuit ### 3.1 View information and stats regarding a circuit
@@ -82,13 +86,13 @@ snarkjs --help
To show general statistics of this circuit, you can run: To show general statistics of this circuit, you can run:
```sh ```sh
snarkjs info -c circuit.json snarkjs info -r circuit.r1cs
``` ```
You can also print the constraints of the circuit by running: You can also print the constraints of the circuit by running:
```sh ```sh
snarkjs printconstraints -c circuit.json snarkjs printconstraints -r circuit.r1cs -s circuit.sym
``` ```
@@ -98,24 +102,24 @@ snarkjs printconstraints -c circuit.json
Ok, let's run a setup for our circuit: Ok, let's run a setup for our circuit:
```sh ```sh
snarkjs setup snarkjs setup
``` ```
> By default `snarkjs` will look for and use `circuit.json`. You can always specify a different circuit file by adding `-c <circuit JSON file name>` > By default `snarkjs` will look for and use `circuit.r1cs`. You can always specify a different circuit file by adding `-r <circuit R1CS file name>`.
The output of the setup will in the form of 2 files: `proving_key.json` and `verification_key.json` The output of the setup will be in the form of 2 files: `proving_key.json` and `verification_key.json`.
### 3.3. Calculating a witness ### 3.3. Calculating a witness
Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constrains of the circuit. Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constraints of the circuit.
`snarkjs` calculates those for you. You need to provide a file with the inputs and it will execute the circuit and calculate all the intermediate signals and the output. This set of signals is the *witness*. `circom` generates a wasm module that calculates those for you. You need to provide a file with the inputs and it will execute the circuit and calculate all the intermediate signals and the output. This set of signals is the *witness*.
The zero knowledge proofs prove that you know a set of signals (witness) that match all the constraints, without revealing any of the signals except the public inputs plus the outputs. The zero-knowledge proofs prove that you know a set of signals (witness) that match all the constraints without revealing any of the signals except the public inputs and the outputs.
For example, imagine you want to prove you are able to factor 33. It means that you know two numbers `a` and `b` and when you multiply them, it results in 33. For example, imagine you want to prove you are able to factor the number 33. It means that you know two numbers `a` and `b` that when you multiply them, it results in 33.
> Of course you can always use one and the same number as `a` and `b`. We will deal with this problem later. > Of course you can always use the number one and the same number as `a` or `b`. We will deal with this problem later.
So you want to prove that you know 3 and 11. So you want to prove that you know 3 and 11.
@@ -128,7 +132,7 @@ Let's create a file named `input.json`
Now let's calculate the witness: Now let's calculate the witness:
```sh ```sh
snarkjs calculatewitness snarkjs calculatewitness --wasm circuit.wasm --input input.json --witness witness.json
``` ```
You may want to take a look at `witness.json` file with all the signals. You may want to take a look at `witness.json` file with all the signals.
@@ -143,7 +147,7 @@ snarkjs proof
This command will use the `proving_key.json` and the `witness.json` files by default to generate `proof.json` and `public.json` This command will use the `proving_key.json` and the `witness.json` files by default to generate `proof.json` and `public.json`
The `proof.json` file will contain the actual proof. And the `public.json` file will contain just the values of the public inputs and the outputs. The `proof.json` file will contain the actual proof and the `public.json` file will contain just the values of the public inputs and the outputs.
### Verifying the proof ### Verifying the proof
@@ -173,7 +177,7 @@ You can take the code in `verifier.sol` and cut and paste it in remix.
This code contains two contracts: Pairings and Verifier. You only need to deploy the `Verifier` contract. This code contains two contracts: Pairings and Verifier. You only need to deploy the `Verifier` contract.
> You may want to use a test net like Rinkeby, Kovan or Ropsten. You can also use the Javascript VM, but in some browsers, the verification takes long and it may hang the page. > You may want to use a test net like Rinkeby, Kovan or Ropsten. You can also use the Javascript VM, but in some browsers the verification takes long and it may hang the page.
### Verifying the proof on-chain ### Verifying the proof on-chain
@@ -182,7 +186,7 @@ The verifier contract deployed in the last step has a `view` function called `ve
This function will return true if the proof and the inputs are valid. This function will return true if the proof and the inputs are valid.
To facilitate the call, you can use snarkjs to generate the parameters of the call by typing: To facilitate the call, you can use `snarkjs` to generate the parameters of the call by typing:
```sh ```sh
snarkjs generatecall snarkjs generatecall
@@ -197,15 +201,15 @@ If you change any bit in the parameters, the result will be verifiably false.
## Bonus track ## Bonus track
We can fix the circuit to not accept one as any of the values by adding some extra constraints. We can fix the circuit to not accept the number 1 as any of the input values by adding some extra constraints.
Here the trick is that we use the property that 0 has no inverse. So `(a-1)` should not have an inverse. Here, the trick is that we use the property that 0 has no inverse. So `(a-1)` should not have an inverse.
That means that `(a-1)*inv = 1` will be inpossible to match if `a` is 1. That means that `(a-1)*inv = 1` will be inpossible to match if `a` is 1.
We just calculate inv by `1/(a-1)` We just calculate inv by `1/(a-1)`.
So let's modify the circuit: So, let's modify the circuit:
``` ```
template Multiplier() { template Multiplier() {
@@ -214,35 +218,35 @@ template Multiplier() {
signal output c; signal output c;
signal inva; signal inva;
signal invb; signal invb;
inva <-- 1/(a-1); inva <-- 1/(a-1);
(a-1)*inva === 1; (a-1)*inva === 1;
invb <-- 1/(b-1); invb <-- 1/(b-1);
(b-1)*invb === 1; (b-1)*invb === 1;
c <== a*b; c <== a*b;
} }
component main = Multiplier(); component main = Multiplier();
``` ```
A nice thing of the circom language is that you can split a <== into two independent actions: <-- and === A nice thing of the circom language is that you can split a `<==` into two independent actions: `<--` and `===`.
The <-- and --> operators assign a value to a signal without creating any constraints. The `<--` and `-->` operators assign a value to a signal without creating any constraints.
The === operator adds a constraint without assigning any value to any signal. The `===` operator adds a constraint without assigning any value to a signal.
The circuit also has another problem: the operation works in Zr, so we need to guarantee the multiplication does not overflow. This can be done by converting the inputs to binary and checking the ranges, but we will reserve it for future tutorials. The circuit also has another problem: the operation works in `Z_r`, so we need to guarantee the multiplication does not overflow. This can be done by converting the inputs to binary and checking the ranges, but we will reserve it for future tutorials.
## Where to go from here: ## Where to go from here
You may want to read the [README](https://github.com/iden3/circom) to learn more features about circom. You may want to read the [README](https://github.com/iden3/circom) to learn more features about `circom`.
You can also check a library with many basic circuits lib binarizations, comparators, eddsa, hashes, merkle trees etc [here](https://github.com/iden3/circomlib) (Work in progress). You can also check a library with many basic circuits lib binarizations, comparators, eddsa, hashes, merkle trees etc [here](https://github.com/iden3/circomlib) (Work in progress).
Or a exponentiation in the Baby Jub curve [here](https://github.com/iden3/circomlib) (Work in progress). Or a exponentiation in the Baby Jubjub curve [here](https://github.com/iden3/circomlib) (Work in progress).
# Final note # Final note
@@ -251,4 +255,4 @@ There is nothing worse for a dev than working with a buggy compiler. This is a
And please contact us for any isue you have. In general, a github issue with a small piece of code with the bug is very useful to us. And please contact us for any isue you have. In general, a github issue with a small piece of code with the bug is very useful to us.
Enjoy zero knowledge proving! Enjoy zero-knowledge proving!

View File

@@ -1,245 +0,0 @@
<% function addS1S2() { %>
xor rdx, rdx
mov edx, eax
add edx, ecx
jo add_manageOverflow ; rsi already is the 64bits result
mov [rdi], rdx ; not necessary to adjust so just save and return
ret
add_manageOverflow: ; Do the operation in 64 bits
push rsi
movsx rsi, eax
movsx rdx, ecx
add rsi, rdx
call rawCopyS2L
pop rsi
ret
<% } %>
<% function addL1S2() { %>
add rsi, 8
movsx rdx, ecx
add rdi, 8
cmp rdx, 0
<% const rawAddLabel = global.tmpLabel() %>
jns <%= rawAddLabel %>
neg rdx
call rawSubLS
sub rdi, 8
sub rsi, 8
ret
<%= rawAddLabel %>:
call rawAddLS
sub rdi, 8
sub rsi, 8
ret
<% } %>
<% function addS1L2() { %>
lea rsi, [rdx + 8]
movsx rdx, eax
add rdi, 8
cmp rdx, 0
<% const rawAddLabel = global.tmpLabel() %>
jns <%= rawAddLabel %>
neg rdx
call rawSubLS
sub rdi, 8
sub rsi, 8
ret
<%= rawAddLabel %>:
call rawAddLS
sub rdi, 8
sub rsi, 8
ret
<% } %>
<% function addL1L2() { %>
add rdi, 8
add rsi, 8
add rdx, 8
call rawAddLL
sub rdi, 8
sub rsi, 8
ret
<% } %>
;;;;;;;;;;;;;;;;;;;;;;
; add
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of any kind
; Params:
; rsi <= Pointer to element 1
; rdx <= Pointer to element 2
; rdi <= Pointer to result
; Modified Registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_add:
mov rax, [rsi]
mov rcx, [rdx]
bt rax, 63 ; Check if is short first operand
jc add_l1
bt rcx, 63 ; Check if is short second operand
jc add_s1l2
add_s1s2: ; Both operands are short
<%= addS1S2() %>
add_l1:
bt rcx, 63 ; Check if is short second operand
jc add_l1l2
;;;;;;;;
add_l1s2:
bt rax, 62 ; check if montgomery first
jc add_l1ms2
add_l1ns2:
<%= global.setTypeDest("0x80"); %>
<%= addL1S2(); %>
add_l1ms2:
bt rcx, 62 ; check if montgomery second
jc add_l1ms2m
add_l1ms2n:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_b() %>
<%= addL1L2() %>
add_l1ms2m:
<%= global.setTypeDest("0xC0"); %>
<%= addL1L2() %>
;;;;;;;;
add_s1l2:
bt rcx, 62 ; check if montgomery first
jc add_s1l2m
add_s1l2n:
<%= global.setTypeDest("0x80"); %>
<%= addS1L2(); %>
add_s1l2m:
bt rax, 62 ; check if montgomery second
jc add_s1ml2m
add_s1nl2m:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_a() %>
<%= addL1L2() %>
add_s1ml2m:
<%= global.setTypeDest("0xC0"); %>
<%= addL1L2() %>
;;;;
add_l1l2:
bt rax, 62 ; check if montgomery first
jc add_l1ml2
add_l1nl2:
bt rcx, 62 ; check if montgomery second
jc add_l1nl2m
add_l1nl2n:
<%= global.setTypeDest("0x80"); %>
<%= addL1L2() %>
add_l1nl2m:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_a(); %>
<%= addL1L2() %>
add_l1ml2:
bt rcx, 62 ; check if montgomery seconf
jc add_l1ml2m
add_l1ml2n:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_b(); %>
<%= addL1L2() %>
add_l1ml2m:
<%= global.setTypeDest("0xC0"); %>
<%= addL1L2() %>
;;;;;;;;;;;;;;;;;;;;;;
; rawAddLL
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of type long
; Params:
; rsi <= Pointer to the long data of element 1
; rdx <= Pointer to the long data of element 2
; rdi <= Pointer to the long data of result
; Modified Registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;
rawAddLL:
; Add component by component with carry
<% for (let i=0; i<n64; i++) { %>
mov rax, [rsi + <%=i*8%>]
<%= i==0 ? "add" : "adc" %> rax, [rdx + <%=i*8%>]
mov [rdi + <%=i*8%>], rax
<% } %>
jc rawAddLL_sq ; if overflow, substract q
; Compare with q
<% for (let i=0; i<n64; i++) { %>
<% if (i>0) { %>
mov rax, [rdi + <%= (n64-i-1)*8 %>]
<% } %>
cmp rax, [q + <%= (n64-i-1)*8 %>]
jc rawAddLL_done ; q is bigget so done.
jnz rawAddLL_sq ; q is lower
<% } %>
; If equal substract q
rawAddLL_sq:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax
<% } %>
rawAddLL_done:
ret
;;;;;;;;;;;;;;;;;;;;;;
; rawAddLS
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of type long
; Params:
; rdi <= Pointer to the long data of result
; rsi <= Pointer to the long data of element 1
; rdx <= Value to be added
;;;;;;;;;;;;;;;;;;;;;;
rawAddLS:
; Add component by component with carry
add rdx, [rsi]
mov [rdi] ,rdx
<% for (let i=1; i<n64; i++) { %>
mov rdx, 0
adc rdx, [rsi + <%=i*8%>]
mov [rdi + <%=i*8%>], rdx
<% } %>
jc rawAddLS_sq ; if overflow, substract q
; Compare with q
<% for (let i=0; i<n64; i++) { %>
mov rax, [rdi + <%= (n64-i-1)*8 %>]
cmp rax, [q + <%= (n64-i-1)*8 %>]
jc rawAddLS_done ; q is bigget so done.
jnz rawAddLS_sq ; q is lower
<% } %>
; If equal substract q
rawAddLS_sq:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax
<% } %>
rawAddLS_done:
ret

View File

@@ -1,217 +0,0 @@
<% function binOpS1S2(op) { %>
cmp r8d, 0
<% const s1s2_solveNeg = global.tmpLabel() %>
js <%=s1s2_solveNeg%>
cmp r9d, 0
js <%=s1s2_solveNeg%>
xor rdx, rdx ; both ops are positive so do the op and return
mov edx, r8d
<%=op%> edx, r9d
mov [rdi], rdx ; not necessary to adjust so just save and return
ret
<%=s1s2_solveNeg%>:
<%= global.setTypeDest("0x80"); %>
<%= global.toLong_b() %>
<%= global.toLong_a() %>
<%= binOpL1L2(op) %>
<% } %>
<% function binOpS1L2(op) { %>
cmp r8d, 0
<% const s1l2_solveNeg = global.tmpLabel() %>
js <%=s1l2_solveNeg%>
movsx rax, r8d
<%=op%> rax, [rdx +8]
mov [rdi+8], rax
<% for (let i=1; i<n64; i++) { %>
xor rax, rax
<%=op%> rax, [rdx + <%= (i*8)+8 %>]
<% if (i== n64-1) { %>
and rax, [lboMask]
<% } %>
mov [rdi + <%= (i*8)+8 %> ], rax
<% } %>
ret
<%=s1l2_solveNeg%>:
<%= global.toLong_a() %>
<%= global.setTypeDest("0x80"); %>
<%= binOpL1L2(op) %>
<% } %>
<% function binOpL1S2(op) { %>
cmp r9d, 0
<% const l1s2_solveNeg = global.tmpLabel() %>
js <%=l1s2_solveNeg%>
movsx rax, r9d
<%=op%> rax, [rsi +8]
mov [rdi+8], rax
<% for (let i=1; i<n64; i++) { %>
xor rax, rax
<%=op%> rax, [rsi + <%= (i*8)+8 %>];
<% if (i== n64-1) { %>
and rax, [lboMask] ;
<% } %>
mov [rdi + <%= (i*8)+8 %> ], rax;
<% } %>
ret
<%=l1s2_solveNeg%>:
<%= global.toLong_b() %>
<%= global.setTypeDest("0x80"); %>
<%= binOpL1L2(op) %>
<% } %>
<% function binOpL1L2(op) { %>
<% for (let i=0; i<n64; i++) { %>
mov rax, [rsi + <%= (i*8)+8 %>]
<%=op%> rax, [rdx + <%= (i*8)+8 %>]
<% if (i== n64-1) { %>
and rax, [lboMask]
<% } %>
mov [rdi + <%= (i*8)+8 %> ], rax
<% } %>
ret
<% } %>
<% function binOp(op) { %>
;;;;;;;;;;;;;;;;;;;;;;
; b<%= op %>
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of any kind
; Params:
; rsi <= Pointer to element 1
; rdx <= Pointer to element 2
; rdi <= Pointer to result
; Modified Registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_b<%=op%>:
mov r8, [rsi]
mov r9, [rdx]
bt r8, 63 ; Check if is short first operand
jc <%=op%>_l1
bt r9, 63 ; Check if is short second operand
jc <%=op%>_s1l2
<%=op%>_s1s2:
<%= binOpS1S2(op) %>
<%=op%>_l1:
bt r9, 63 ; Check if is short second operand
jc <%=op%>_l1l2
<%=op%>_l1s2:
bt r8, 62 ; check if montgomery first
jc <%=op%>_l1ms2
<%=op%>_l1ns2:
<%= global.setTypeDest("0x80"); %>
<%= binOpL1S2(op) %>
<%=op%>_l1ms2:
<%= global.setTypeDest("0x80"); %>
push r9 ; r9 is used in montgomery so we need to save it
<%= global.fromMont_a() %>
pop r9
<%= binOpL1S2(op) %>
<%=op%>_s1l2:
bt r9, 62 ; check if montgomery first
jc <%=op%>_s1l2m
<%=op%>_s1l2n:
<%= global.setTypeDest("0x80"); %>
<%= binOpS1L2(op) %>
<%=op%>_s1l2m:
<%= global.setTypeDest("0x80"); %>
push r8 ; r8 is used in montgomery so we need to save it
<%= global.fromMont_b() %>
pop r8
<%= binOpS1L2(op) %>
<%=op%>_l1l2:
bt r8, 62 ; check if montgomery first
jc <%=op%>_l1ml2
bt r9, 62 ; check if montgomery first
jc <%=op%>_l1nl2m
<%=op%>_l1nl2n:
<%= global.setTypeDest("0x80"); %>
<%= binOpL1L2(op) %>
<%=op%>_l1nl2m:
<%= global.setTypeDest("0x80"); %>
<%= global.fromMont_b() %>
<%= binOpL1L2(op) %>
<%=op%>_l1ml2:
bt r9, 62 ; check if montgomery first
jc <%=op%>_l1ml2m
<%=op%>_l1ml2n:
<%= global.setTypeDest("0x80"); %>
<%= global.fromMont_a() %>
<%= binOpL1L2(op) %>
<%=op%>_l1ml2m:
<%= global.setTypeDest("0x80"); %>
<%= global.fromMont_a() %>
<%= global.fromMont_b() %>
<%= binOpL1L2(op) %>
<% } %>
<%= binOp("and") %>
<%= binOp("or") %>
<%= binOp("xor") %>
;;;;;;;;;;;;;;;;;;;;;;
; bnot
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of any kind
; Params:
; rsi <= Pointer to element 1
; rdi <= Pointer to result
; Modified Registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_bnot:
<%= global.setTypeDest("0x80"); %>
mov r8, [rsi]
bt r8, 63 ; Check if is long operand
jc bnot_l1
bnot_s:
<%= global.toLong_a() %>
jmp bnot_l1n
bnot_l1:
bt r8, 62 ; check if montgomery first
jnc bnot_l1n
bnot_l1m:
<%= global.fromMont_a() %>
bnot_l1n:
<% for (let i=0; i<n64; i++) { %>
mov rax, [rsi + <%= i*8 + 8 %>]
not rax
<% if (i== n64-1) { %>
and rax, [lboMask]
<% } %>
mov [rdi + <%= i*8 + 8 %>], rax
<% } %>
ret

View File

@@ -1,72 +0,0 @@
const bigInt=require("big-integer");
const path = require("path");
const util = require("util");
const renderFile = util.promisify(require("ejs").renderFile);
const runningAsScript = !module.parent;
class ZqBuilder {
constructor(q, name) {
const self = this;
this.q=bigInt(q);
this.n64 = Math.floor((this.q.bitLength() - 1) / 64)+1;
this.name = name;
this.bigInt = bigInt;
this.lastTmp=0;
this.global = {};
this.global.tmpLabel = function(label) {
self.lastTmp++;
label = label || "tmp";
return label+"_"+self.lastTmp;
};
}
constantElement(v) {
let S = "";
const mask = bigInt("FFFFFFFFFFFFFFFF", 16);
for (let i=0; i<this.n64; i++) {
if (i>0) S = S+",";
let shex = v.shiftRight(i*64).and(mask).toString(16);
while (shex.length <16) shex = "0" + shex;
S = S + "0x" + shex;
}
return S;
}
}
async function buildField(q, name) {
const builder = new ZqBuilder(q, name);
const asm = await renderFile(path.join(__dirname, "fr.asm.ejs"), builder);
const c = await renderFile(path.join(__dirname, "fr.c.ejs"), builder);
const h = await renderFile(path.join(__dirname, "fr.h.ejs"), builder);
return {asm: asm, h: h, c: c};
}
if (runningAsScript) {
const fs = require("fs");
var argv = require("yargs")
.usage("Usage: $0 -q [primeNum] -n [name] -oc [out .c file] -oh [out .h file]")
.demandOption(["q","n"])
.alias("q", "prime")
.alias("n", "name")
.argv;
const q = bigInt(argv.q);
const asmFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".asm";
const hFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".h";
const cFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".c";
buildField(q, argv.name).then( (res) => {
fs.writeFileSync(asmFileName, res.asm, "utf8");
fs.writeFileSync(hFileName, res.h, "utf8");
fs.writeFileSync(cFileName, res.c, "utf8");
});
} else {
module.exports = buildField;
}

View File

@@ -1,75 +0,0 @@
const chai = require("chai");
const assert = chai.assert;
const fs = require("fs");
var tmp = require("tmp-promise");
const path = require("path");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const BuildZqField = require("./buildzqfield");
module.exports = testField;
async function testField(prime, test) {
tmp.setGracefulCleanup();
const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
const source = await BuildZqField(prime, "Fr");
// console.log(dir.path);
await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8");
await fs.promises.writeFile(path.join(dir.path, "fr.h"), source.h, "utf8");
await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8");
await exec(`cp ${path.join(__dirname, "tester.cpp")} ${dir.path}`);
await exec("nasm -fmacho64 --prefix _ " +
` ${path.join(dir.path, "fr.asm")}`
);
await exec("g++" +
` ${path.join(dir.path, "tester.cpp")}` +
` ${path.join(dir.path, "fr.o")}` +
` ${path.join(dir.path, "fr.c")}` +
` -o ${path.join(dir.path, "tester")}` +
" -lgmp -g"
);
const inLines = [];
for (let i=0; i<test.length; i++) {
for (let j=0; j<test[i][0].length; j++) {
inLines.push(test[i][0][j]);
}
}
inLines.push("");
await fs.promises.writeFile(path.join(dir.path, "in.tst"), inLines.join("\n"), "utf8");
await exec(`${path.join(dir.path, "tester")}` +
` <${path.join(dir.path, "in.tst")}` +
` >${path.join(dir.path, "out.tst")}`);
const res = await fs.promises.readFile(path.join(dir.path, "out.tst"), "utf8");
const resLines = res.split("\n");
for (let i=0; i<test.length; i++) {
const expected = test[i][1].toString();
const calculated = resLines[i];
if (calculated != expected) {
console.log("FAILED");
for (let j=0; j<test[i][0].length; j++) {
console.log(test[i][0][j]);
}
console.log("Should Return: " + expected);
console.log("But Returns: " + calculated);
}
assert.equal(calculated, expected);
}
}

View File

@@ -1,108 +0,0 @@
<% function retOne() { %>
mov qword [rdi], 1
add rsp, <%= (n64+1)*8 %>
ret
<% } %>
<% function retZero() { %>
mov qword [rdi], 0
add rsp, <%= (n64+1)*8 %>
ret
<% } %>
<% function cmpLong(op, eq) { %>
<%
if (eq==true) {
if (["leq","geq"].indexOf(op) >= 0) retOne();
if (["lt","gt"].indexOf(op) >= 0) retZero();
}
%>
<% const label_gt = global.tmpLabel() %>
<% const label_lt = global.tmpLabel() %>
<% for (let i=n64-1; i>=0; i--) { %>
mov rax, [rsp + <%= 8+(i*8) %>]
cmp [half + <%= (i*8) %>], rax ; comare with (q-1)/2
jc <%=label_lt%> ; half<rax => e1-e2 is neg => e1 < e2
jnz <%=label_gt%> ; half>rax => e1 -e2 is pos => e1 > e2
<% } %>
; half == rax => e1-e2 is pos => e1 > e2
<%=label_gt%>:
<% if (["geq","gt"].indexOf(op) >= 0) retOne(); else retZero(); %>
<%=label_lt%>:
<% if (["leq","lt"].indexOf(op) >= 0) retOne(); else retZero(); %>
<% } // cmpLong%>
<% function cmpOp(op) { %>
;;;;;;;;;;;;;;;;;;;;;;
; <%= op %>
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of any kind
; Params:
; rsi <= Pointer to element 1
; rdx <= Pointer to element 2
; rdi <= Pointer to result can be zero or one.
; Modified Registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_<%=op%>:
sub rsp, <%= (n64+1)*8 %> ; Save space for the result of the substraction
push rdi ; Save rdi
lea rdi, [rsp+8] ; We pushed rdi so we need to add 8
call <%=name%>_sub ; Do a substraction
call <%=name%>_toNormal ; Convert it to normal
pop rdi
mov rax, [rsp] ; We already poped do no need to add 8
bt rax, 63 ; check is result is long
jc <%=op%>_longCmp
<%=op%>_shortCmp:
cmp eax, 0
je <%=op%>_s_eq
js <%=op%>_s_lt
<%=op%>_s_gt:
<% if (["geq","gt", "neq"].indexOf(op) >= 0) retOne(); else retZero(); %>
<%=op%>_s_lt:
<% if (["leq","lt", "neq"].indexOf(op) >= 0) retOne(); else retZero(); %>
<%=op%>_s_eq:
<% if (["eq","geq", "leq"].indexOf(op) >= 0) retOne(); else retZero(); %>
<%=op%>_longCmp:
<% for (let i=n64-1; i>=0; i--) { %>
cmp qword [rsp + <%= 8+(i*8) %>], 0
jnz <%=op%>_neq
<% } %>
<%=op%>_eq:
<% if (op == "eq") {
retOne();
} else if (op == "neq") {
retZero();
} else {
cmpLong(op, true);
}
%>
<%=op%>_neq:
<% if (op == "neq") {
retOne();
} else if (op == "eq") {
retZero();
} else {
cmpLong(op, false);
}
%>
<% } %>
<%= cmpOp("eq") %>
<%= cmpOp("neq") %>
<%= cmpOp("lt") %>
<%= cmpOp("gt") %>
<%= cmpOp("leq") %>
<%= cmpOp("geq") %>

View File

@@ -1,133 +0,0 @@
;;;;;;;;;;;;;;;;;;;;;;
; copy
;;;;;;;;;;;;;;;;;;;;;;
; Copies
; Params:
; rsi <= the src
; rdi <= the dest
;
; Nidified registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_copy:
<% for (let i=0; i<=n64; i++) { %>
mov rax, [rsi + <%= i*8 %>]
mov [rdi + <%= i*8 %>], rax
<% } %>
ret
;;;;;;;;;;;;;;;;;;;;;;
; copy an array of integers
;;;;;;;;;;;;;;;;;;;;;;
; Copies
; Params:
; rsi <= the src
; rdi <= the dest
; rdx <= number of integers to copy
;
; Nidified registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_copyn:
<%=name%>_copyn_loop:
mov r8, rsi
mov r9, rdi
mov rax, <%= n64+1 %>
mul rdx
mov rcx, rax
cld
rep movsq
mov rsi, r8
mov rdi, r9
ret
;;;;;;;;;;;;;;;;;;;;;;
; rawCopyS2L
;;;;;;;;;;;;;;;;;;;;;;
; Convert a 64 bit integer to a long format field element
; Params:
; rsi <= the integer
; rdi <= Pointer to the overwritted element
;
; Nidified registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;;
rawCopyS2L:
mov al, 0x80
shl rax, 56
mov [rdi], rax ; set the result to LONG normal
cmp rsi, 0
js u64toLong_adjust_neg
mov [rdi + 8], rsi
xor rax, rax
<% for (let i=1; i<n64; i++) { %>
mov [rdi + <%= 8+i*8 %>], rax
<% } %>
ret
u64toLong_adjust_neg:
add rsi, [q] ; Set the first digit
mov [rdi + 8], rsi ;
mov rsi, -1 ; all ones
<% for (let i=1; i<n64; i++) { %>
mov rax, rsi ; Add to q
adc rax, [q + <%= i*8 %> ]
mov [rdi + <%= (i+1)*8 %>], rax
<% } %>
ret
;;;;;;;;;;;;;;;;;;;;;;
; toInt
;;;;;;;;;;;;;;;;;;;;;;
; Convert a 64 bit integer to a long format field element
; Params:
; rsi <= Pointer to the element
; Returs:
; rax <= The value
;;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_toInt:
mov rax, [rdi]
bt rax, 63
jc <%=name%>_long
movsx rax, eax
ret
<%=name%>_long:
mov rax, [rdi + 8]
mov rcx, rax
shr rcx, 31
jnz <%=name%>_longNeg
<% for (let i=1; i< n64; i++) { %>
mov rcx, [rdi + <%= i*8+8 %>]
test rcx, rcx
jnz <%=name%>_longNeg
<% } %>
ret
<%=name%>_longNeg:
mov rax, [rdi + 8]
sub rax, [q]
jnc <%=name%>_longErr
<% for (let i=1; i<n64; i++) { %>
mov rcx, [rdi + <%= i*8+8 %>]
sbb rcx, [q + <%= i*8 %>]
jnc <%=name%>_longErr
<% } %>
mov rcx, rax
sar rcx, 31
add rcx, 1
jnz <%=name%>_longErr
ret
<%=name%>_longErr:
push rdi
mov rdi, 0
call <%=name%>_fail
pop rdi

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +0,0 @@
global <%=name%>_copy
global <%=name%>_copyn
global <%=name%>_add
global <%=name%>_sub
global <%=name%>_neg
global <%=name%>_mul
global <%=name%>_square
global <%=name%>_band
global <%=name%>_bor
global <%=name%>_bxor
global <%=name%>_bnot
global <%=name%>_eq
global <%=name%>_neq
global <%=name%>_lt
global <%=name%>_gt
global <%=name%>_leq
global <%=name%>_geq
global <%=name%>_land
global <%=name%>_lor
global <%=name%>_lnot
global <%=name%>_toNormal
global <%=name%>_toLongNormal
global <%=name%>_toMontgomery
global <%=name%>_toInt
global <%=name%>_isTrue
global <%=name%>_q
extern <%=name%>_fail
DEFAULT REL
section .text
<%- include('utils.asm.ejs'); %>
<%- include('copy.asm.ejs'); %>
<%- include('montgomery.asm.ejs'); %>
<%- include('add.asm.ejs'); %>
<%- include('sub.asm.ejs'); %>
<%- include('neg.asm.ejs'); %>
<%- include('mul.asm.ejs'); %>
<%- include('binops.asm.ejs'); %>
<%- include('cmpops.asm.ejs'); %>
<%- include('logicalops.asm.ejs'); %>
section .data
<%=name%>_q:
dd 0
dd 0x80000000
q dq <%= constantElement(q) %>
half dq <%= constantElement(q.shiftRight(1)) %>
R2 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*2).mod(q)) %>
R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %>
lboMask dq 0x<%= bigInt("8000000000000000",16).shiftRight(n64*64 - q.bitLength()).minus(bigInt.one).toString(16) %>

View File

@@ -1,185 +0,0 @@
#include "fr.h"
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <assert.h>
mpz_t q;
mpz_t zero;
mpz_t one;
mpz_t mask;
size_t nBits;
void Fr_toMpz(mpz_t r, PFrElement pE) {
Fr_toNormal(pE);
if (!(pE->type & Fr_LONG)) {
mpz_set_si(r, pE->shortVal);
if (pE->shortVal<0) {
mpz_add(r, r, q);
}
} else {
mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal);
}
}
void Fr_fromMpz(PFrElement pE, mpz_t v) {
if (mpz_fits_sint_p(v)) {
pE->type = Fr_SHORT;
pE->shortVal = mpz_get_si(v);
} else {
pE->type = Fr_LONG;
for (int i=0; i<Fr_N64; i++) pE->longVal[i] = 0;
mpz_export((void *)(pE->longVal), NULL, -1, 8, -1, 0, v);
}
}
void Fr_init() {
mpz_init(q);
mpz_import(q, Fr_N64, -1, 8, -1, 0, (const void *)Fr_q.longVal);
mpz_init_set_ui(zero, 0);
mpz_init_set_ui(one, 1);
nBits = mpz_sizeinbase (q, 2);
mpz_init(mask);
mpz_mul_2exp(mask, one, nBits-1);
mpz_sub(mask, mask, one);
}
void Fr_str2element(PFrElement pE, char const *s) {
mpz_t mr;
mpz_init_set_str(mr, s, 10);
Fr_fromMpz(pE, mr);
}
char *Fr_element2str(PFrElement pE) {
mpz_t r;
if (!(pE->type & Fr_LONG)) {
if (pE->shortVal>=0) {
char *r = new char[32];
sprintf(r, "%d", pE->shortVal);
return r;
} else {
mpz_init_set_si(r, pE->shortVal);
mpz_add(r, r, q);
mpz_clear(q);
}
} else {
Fr_toNormal(pE);
mpz_init(r);
mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal);
}
char *res = mpz_get_str (0, 10, r);
mpz_clear(r);
return res;
}
void Fr_idiv(PFrElement r, PFrElement a, PFrElement b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
Fr_toMpz(ma, a);
// char *s1 = mpz_get_str (0, 10, ma);
// printf("s1 %s\n", s1);
Fr_toMpz(mb, b);
// char *s2 = mpz_get_str (0, 10, mb);
// printf("s2 %s\n", s2);
mpz_fdiv_q(mr, ma, mb);
// char *sr = mpz_get_str (0, 10, mr);
// printf("r %s\n", sr);
Fr_fromMpz(r, mr);
}
void Fr_mod(PFrElement r, PFrElement a, PFrElement b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
Fr_toMpz(ma, a);
Fr_toMpz(mb, b);
mpz_fdiv_r(mr, ma, mb);
Fr_fromMpz(r, mr);
}
void Fr_shl(PFrElement r, PFrElement a, PFrElement b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
Fr_toMpz(ma, a);
Fr_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
mpz_mul_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
}
Fr_fromMpz(r, mr);
}
void Fr_shr(PFrElement r, PFrElement a, PFrElement b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
Fr_toMpz(ma, a);
Fr_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
}
Fr_fromMpz(r, mr);
}
void Fr_pow(PFrElement r, PFrElement a, PFrElement b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
Fr_toMpz(ma, a);
Fr_toMpz(mb, b);
mpz_powm(mr, ma, mb, q);
Fr_fromMpz(r, mr);
}
void Fr_inv(PFrElement r, PFrElement a) {
mpz_t ma;
mpz_t mr;
mpz_init(ma);
mpz_init(mr);
Fr_toMpz(ma, a);
mpz_invert(mr, ma, q);
Fr_fromMpz(r, mr);
}
void Fr_div(PFrElement r, PFrElement a, PFrElement b) {
FrElement tmp;
Fr_inv(&tmp, b);
Fr_mul(r, a, &tmp);
}
void Fr_fail() {
assert(false);
}

View File

@@ -1,184 +0,0 @@
#include "<%=name.toLowerCase()+".h"%>"
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <assert.h>
mpz_t q;
mpz_t zero;
mpz_t one;
mpz_t mask;
size_t nBits;
void <%=name%>_toMpz(mpz_t r, P<%=name%>Element pE) {
<%=name%>_toNormal(pE);
if (!(pE->type & <%=name%>_LONG)) {
mpz_set_si(r, pE->shortVal);
if (pE->shortVal<0) {
mpz_add(r, r, q);
}
} else {
mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal);
}
}
void <%=name%>_fromMpz(P<%=name%>Element pE, mpz_t v) {
if (mpz_fits_sint_p(v)) {
pE->type = <%=name%>_SHORT;
pE->shortVal = mpz_get_si(v);
} else {
pE->type = <%=name%>_LONG;
for (int i=0; i<<%=name%>_N64; i++) pE->longVal[i] = 0;
mpz_export((void *)(pE->longVal), NULL, -1, 8, -1, 0, v);
}
}
void <%=name%>_init() {
mpz_init(q);
mpz_import(q, <%=name%>_N64, -1, 8, -1, 0, (const void *)Fr_q.longVal);
mpz_init_set_ui(zero, 0);
mpz_init_set_ui(one, 1);
nBits = mpz_sizeinbase (q, 2);
mpz_init(mask);
mpz_mul_2exp(mask, one, nBits-1);
mpz_sub(mask, mask, one);
}
void <%=name%>_str2element(P<%=name%>Element pE, char const *s) {
mpz_t mr;
mpz_init_set_str(mr, s, 10);
<%=name%>_fromMpz(pE, mr);
}
char *<%=name%>_element2str(P<%=name%>Element pE) {
mpz_t r;
if (!(pE->type & <%=name%>_LONG)) {
if (pE->shortVal>=0) {
char *r = new char[32];
sprintf(r, "%d", pE->shortVal);
return r;
} else {
mpz_init_set_si(r, pE->shortVal);
mpz_add(r, r, q);
}
} else {
<%=name%>_toNormal(pE);
mpz_init(r);
mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal);
}
char *res = mpz_get_str (0, 10, r);
mpz_clear(r);
return res;
}
void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
<%=name%>_toMpz(ma, a);
// char *s1 = mpz_get_str (0, 10, ma);
// printf("s1 %s\n", s1);
<%=name%>_toMpz(mb, b);
// char *s2 = mpz_get_str (0, 10, mb);
// printf("s2 %s\n", s2);
mpz_fdiv_q(mr, ma, mb);
// char *sr = mpz_get_str (0, 10, mr);
// printf("r %s\n", sr);
<%=name%>_fromMpz(r, mr);
}
void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
<%=name%>_toMpz(ma, a);
<%=name%>_toMpz(mb, b);
mpz_fdiv_r(mr, ma, mb);
<%=name%>_fromMpz(r, mr);
}
void <%=name%>_shl(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
<%=name%>_toMpz(ma, a);
<%=name%>_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
mpz_mul_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
}
<%=name%>_fromMpz(r, mr);
}
void <%=name%>_shr(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
<%=name%>_toMpz(ma, a);
<%=name%>_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
}
<%=name%>_fromMpz(r, mr);
}
void <%=name%>_pow(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) {
mpz_t ma;
mpz_t mb;
mpz_t mr;
mpz_init(ma);
mpz_init(mb);
mpz_init(mr);
<%=name%>_toMpz(ma, a);
<%=name%>_toMpz(mb, b);
mpz_powm(mr, ma, mb, q);
<%=name%>_fromMpz(r, mr);
}
void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a) {
mpz_t ma;
mpz_t mr;
mpz_init(ma);
mpz_init(mr);
<%=name%>_toMpz(ma, a);
mpz_invert(mr, ma, q);
<%=name%>_fromMpz(r, mr);
}
void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) {
<%=name%>Element tmp;
<%=name%>_inv(&tmp, b);
<%=name%>_mul(r, a, &tmp);
}
void <%=name%>_fail() {
assert(false);
}

View File

@@ -1,67 +0,0 @@
#ifndef __FR_H
#define __FR_H
#include <stdint.h>
#define Fr_N64 4
#define Fr_SHORT 0x00000000
#define Fr_LONG 0x80000000
#define Fr_LONGMONTGOMERY 0xC0000000
typedef struct __attribute__((__packed__)) {
int32_t shortVal;
uint32_t type;
uint64_t longVal[Fr_N64];
} FrElement;
typedef FrElement *PFrElement;
extern FrElement Fr_q;
extern "C" void Fr_copy(PFrElement r, PFrElement a);
extern "C" void Fr_copyn(PFrElement r, PFrElement a, int n);
extern "C" void Fr_add(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_sub(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_neg(PFrElement r, PFrElement a);
extern "C" void Fr_mul(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_square(PFrElement r, PFrElement a);
extern "C" void Fr_band(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_bor(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_bxor(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_bnot(PFrElement r, PFrElement a);
extern "C" void Fr_eq(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_neq(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_lt(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_gt(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_leq(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_geq(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_land(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_lor(PFrElement r, PFrElement a, PFrElement b);
extern "C" void Fr_lnot(PFrElement r, PFrElement a);
extern "C" void Fr_toNormal(PFrElement pE);
extern "C" void Fr_toLongNormal(PFrElement pE);
extern "C" void Fr_toMontgomery(PFrElement pE);
extern "C" int Fr_isTrue(PFrElement pE);
extern "C" int Fr_toInt(PFrElement pE);
extern "C" void Fr_fail();
extern FrElement Fr_q;
// Pending functions to convert
void Fr_str2element(PFrElement pE, char const*s);
char *Fr_element2str(PFrElement pE);
void Fr_idiv(PFrElement r, PFrElement a, PFrElement b);
void Fr_mod(PFrElement r, PFrElement a, PFrElement b);
void Fr_inv(PFrElement r, PFrElement a);
void Fr_div(PFrElement r, PFrElement a, PFrElement b);
void Fr_shl(PFrElement r, PFrElement a, PFrElement b);
void Fr_shr(PFrElement r, PFrElement a, PFrElement b);
void Fr_pow(PFrElement r, PFrElement a, PFrElement b);
void Fr_init();
#endif // __FR_H

View File

@@ -1,67 +0,0 @@
#ifndef __<%=name.toUpperCase()%>_H
#define __<%=name.toUpperCase()%>_H
#include <stdint.h>
#define <%=name%>_N64 <%= n64 %>
#define <%=name%>_SHORT 0x00000000
#define <%=name%>_LONG 0x80000000
#define <%=name%>_LONGMONTGOMERY 0xC0000000
typedef struct __attribute__((__packed__)) {
int32_t shortVal;
uint32_t type;
uint64_t longVal[<%=name%>_N64];
} <%=name%>Element;
typedef <%=name%>Element *P<%=name%>Element;
extern <%=name%>Element <%=name%>_q;
extern "C" void <%=name%>_copy(P<%=name%>Element r, P<%=name%>Element a);
extern "C" void <%=name%>_copyn(P<%=name%>Element r, P<%=name%>Element a, int n);
extern "C" void <%=name%>_add(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_sub(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_neg(P<%=name%>Element r, P<%=name%>Element a);
extern "C" void <%=name%>_mul(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_square(P<%=name%>Element r, P<%=name%>Element a);
extern "C" void <%=name%>_band(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_bor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_bxor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_bnot(P<%=name%>Element r, P<%=name%>Element a);
extern "C" void <%=name%>_eq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_neq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_lt(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_gt(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_leq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_geq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_land(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_lor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
extern "C" void <%=name%>_lnot(P<%=name%>Element r, P<%=name%>Element a);
extern "C" void <%=name%>_toNormal(P<%=name%>Element pE);
extern "C" void <%=name%>_toLongNormal(P<%=name%>Element pE);
extern "C" void <%=name%>_toMontgomery(P<%=name%>Element pE);
extern "C" int <%=name%>_isTrue(P<%=name%>Element pE);
extern "C" int <%=name%>_toInt(P<%=name%>Element pE);
extern "C" void <%=name%>_fail();
extern <%=name%>Element <%=name%>_q;
// Pending functions to convert
void <%=name%>_str2element(P<%=name%>Element pE, char const*s);
char *<%=name%>_element2str(P<%=name%>Element pE);
void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a);
void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
void <%=name%>_shl(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
void <%=name%>_shr(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
void <%=name%>_pow(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b);
void <%=name%>_init();
#endif // __<%=name.toUpperCase()%>_H

Binary file not shown.

View File

@@ -1,97 +0,0 @@
<% function isTrue(resReg, srcPtrReg) { %>
<% const longIsZero = global.tmpLabel() %>
<% const retOne = global.tmpLabel("retOne") %>
<% const retZero = global.tmpLabel("retZero") %>
<% const done = global.tmpLabel("done") %>
mov rax, [<%=srcPtrReg%>]
bt rax, 63
jc <%= longIsZero %>
test eax, eax
jz <%= retZero %>
jmp <%= retOne %>
<%= longIsZero %>:
<% for (let i=0; i<n64; i++) { %>
mov rax, [<%= srcPtrReg + " + " +(i*8+8) %>]
test rax, rax
jnz <%= retOne %>
<% } %>
<%= retZero %>:
mov qword <%=resReg%>, 0
jmp <%= done %>
<%= retOne %>:
mov qword <%=resReg%>, 1
<%= done %>:
<% } %>
<% function logicalOp(op) { %>
;;;;;;;;;;;;;;;;;;;;;;
; l<%= op %>
;;;;;;;;;;;;;;;;;;;;;;
; Logical <%= op %> between two elements
; Params:
; rsi <= Pointer to element 1
; rdx <= Pointer to element 2
; rdi <= Pointer to result zero or one
; Modified Registers:
; rax, rcx, r8
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_l<%=op%>:
<%= isTrue("r8", "rsi") %>
<%= isTrue("rcx", "rdx") %>
<%=op%> rcx, r8
mov [rdi], rcx
ret
<% } %>
<% logicalOp("and"); %>
<% logicalOp("or"); %>
;;;;;;;;;;;;;;;;;;;;;;
; lnot
;;;;;;;;;;;;;;;;;;;;;;
; Do the logical not of an element
; Params:
; rsi <= Pointer to element to be tested
; rdi <= Pointer to result one if element1 is zero and zero otherwise
; Modified Registers:
; rax, rax, r8
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_lnot:
<%= isTrue("rcx", "rsi") %>
test rcx, rcx
jz lnot_retOne
lnot_retZero:
mov qword [rdi], 0
ret
lnot_retOne:
mov qword [rdi], 1
ret
;;;;;;;;;;;;;;;;;;;;;;
; isTrue
;;;;;;;;;;;;;;;;;;;;;;
; Convert a 64 bit integer to a long format field element
; Params:
; rsi <= Pointer to the element
; Returs:
; rax <= 1 if true 0 if false
;;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_isTrue:
<%= isTrue("rax", "rdi") %>
ret

View File

@@ -1,64 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "fr.h"
int main() {
Fr_init();
/*
FrElement a = { 0, Fr_LONGMONTGOMERY, {1,1,1,1}};
FrElement b = { 0, Fr_LONGMONTGOMERY, {2,2,2,2}};
FrElement a={0x43e1f593f0000000ULL,0x2833e84879b97091ULL,0xb85045b68181585dULL,0x30644e72e131a029ULL};
FrElement b = {3,0,0,0};
FrElement c;
*/
// Fr_add(&(c[0]), a, a);
// Fr_add(&(c[0]), c, b);
/*
for (int i=0; i<1000000000; i++) {
Fr_mul(&c, &a, &b);
}
Fr_mul(&c,&a, &b);
*/
/*
FrElement a1[10];
FrElement a2[10];
for (int i=0; i<10; i++) {
a1[i].type = Fr_LONGMONTGOMERY;
a1[i].shortVal =0;
for (int j=0; j<Fr_N64; j++) {
a2[i].longVal[j] = i;
}
}
Fr_copyn(a2, a1, 10);
for (int i=0; i<10; i++) {
char *c1 = Fr_element2str(&a1[i]);
char *c2 = Fr_element2str(&a2[i]);
printf("%s\n%s\n\n", c1, c2);
free(c1);
free(c2);
}
*/
int tests[7] = { 0, 1, 2, -1, -2, 0x7FFFFFFF, (int)0x80000000};
for (int i=0; i<7;i++) {
FrElement a = { tests[i], Fr_SHORT, {0,0,0,0}};
Fr_toLongNormal(&a);
int b = Fr_toInt(&a);
int c = Fr_isTrue(&a);
printf("%d, %d, %d\n", tests[i], b, c);
}
FrElement err = { 0, Fr_LONGMONTGOMERY, {1,1,1,1}};
Fr_toInt(&err);
// printf("%llu, %llu, %llu, %llu\n", c.longVal[0], c.longVal[1], c.longVal[2], c.longVal[3]);
}

View File

@@ -1,342 +0,0 @@
<%
//////////////////////
// montgomeryTemplate
//////////////////////
// This function creates functions with the montgomery transformation
// applied
// the round hook allows to add diferent code in the iteration
//
// All the montgomery functions modifies:
// r8, r9, 10, r11, rax, rcx
//////////////////////
function montgomeryTemplate(fnName, round) {
let r0, r1, r2;
function setR(step) {
if ((step % 3) == 0) {
r0 = "r8";
r1 = "r9";
r2 = "r10";
} else if ((step % 3) == 1) {
r0 = "r9";
r1 = "r10";
r2 = "r8";
} else {
r0 = "r10";
r1 = "r8";
r2 = "r9";
}
}
const base = bigInt.one.shiftLeft(64);
const np64 = base.minus(q.modInv(base));
%>
<%=fnName%>:
sub rsp, <%= n64*8 %> ; Reserve space for ms
mov rcx, rdx ; rdx is needed for multiplications so keep it in cx
mov r11, 0x<%= np64.toString(16) %> ; np
xor r8,r8
xor r9,r9
xor r10,r10
<%
// Main loop
for (let i=0; i<n64*2; i++) {
setR(i);
round(i, r0, r1, r2);
%>
<%
for (let j=i-1; j>=0; j--) { // All ms
if (((i-j)<n64)&&(j<n64)) {
%>
mov rax, [rsp + <%= j*8 %>]
mul qword [q + <%= (i-j)*8 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
}
} // ms
%>
<%
if (i<n64) {
%>
mov rax, <%= r0 %>
mul r11
mov [rsp + <%= i*8 %>], rax
mul qword [q]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} else {
%>
mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %>
xor <%= r0 %>,<%= r0 %>
<%
}
%>
<%
} // Main Loop
%>
test <%= r1 %>, <%= r1 %>
jnz <%=fnName%>_mulM_sq
; Compare with q
<%
for (let i=0; i<n64; i++) {
%>
mov rax, [rdi + <%= (n64-i-1)*8 %>]
cmp rax, [q + <%= (n64-i-1)*8 %>]
jc <%=fnName%>_mulM_done ; q is bigget so done.
jnz <%=fnName%>_mulM_sq ; q is lower
<%
}
%>
; If equal substract q
<%=fnName%>_mulM_sq:
<%
for (let i=0; i<n64; i++) {
%>
mov rax, [q + <%= i*8 %>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax
<%
}
%>
<%=fnName%>_mulM_done:
mov rdx, rcx ; recover rdx to its original place.
add rsp, <%= n64*8 %> ; recover rsp
ret
<%
} // Template
%>
;;;;;;;;;;;;;;;;;;;;;;
; rawMontgomeryMul
;;;;;;;;;;;;;;;;;;;;;;
; Multiply two elements in montgomery form
; Params:
; rsi <= Pointer to the long data of element 1
; rdx <= Pointer to the long data of element 2
; rdi <= Pointer to the long data of result
; Modified registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%
montgomeryTemplate("rawMontgomeryMul", function(i, r0, r1, r2) {
// Same Digit
for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1<n64); o1++) {
const o2= i-o1;
%>
mov rax, [rsi + <%= 8*o1 %>]
mul qword [rcx + <%= 8*o2 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} // Same digit
})
%>
;;;;;;;;;;;;;;;;;;;;;;
; rawMontgomerySquare
;;;;;;;;;;;;;;;;;;;;;;
; Square an element
; Params:
; rsi <= Pointer to the long data of element 1
; rdi <= Pointer to the long data of result
; Modified registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%
montgomeryTemplate("rawMontgomerySquare", function(i, r0, r1, r2) {
// Same Digit
for (let o1=Math.max(0, i-n64+1); (o1<((i+1)>>1) )&&(o1<n64); o1++) {
const o2= i-o1;
%>
mov rax, [rsi + <%= 8*o1 %>]
mul qword [rsi + <%= 8*o2 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} // Same digit
%>
<% if (i%2 == 0) { %>
mov rax, [rsi + <%= 8*(i/2) %>]
mul rax
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<% } %>
<%
})
%>
;;;;;;;;;;;;;;;;;;;;;;
; rawMontgomeryMul1
;;;;;;;;;;;;;;;;;;;;;;
; Multiply two elements in montgomery form
; Params:
; rsi <= Pointer to the long data of element 1
; rdx <= second operand
; rdi <= Pointer to the long data of result
; Modified registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%
montgomeryTemplate("rawMontgomeryMul1", function(i, r0, r1, r2) {
// Same Digit
if (i<n64) {
%>
mov rax, [rsi + <%= 8*i %>]
mul rcx
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} // Same digit
})
%>
;;;;;;;;;;;;;;;;;;;;;;
; rawFromMontgomery
;;;;;;;;;;;;;;;;;;;;;;
; Multiply two elements in montgomery form
; Params:
; rsi <= Pointer to the long data of element 1
; rdi <= Pointer to the long data of result
; Modified registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%
montgomeryTemplate("rawFromMontgomery", function(i, r0, r1, r2) {
// Same Digit
if (i<n64) {
%>
add <%= r0 %>, [rdi + <%= 8*i %>]
adc <%= r1 %>, 0x0
adc <%= r2 %>, 0x0
<%
} // Same digit
})
%>
;;;;;;;;;;;;;;;;;;;;;;
; toMontgomery
;;;;;;;;;;;;;;;;;;;;;;
; Convert a number to Montgomery
; rdi <= Pointer element to convert
; Modified registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;
<%=name%>_toMontgomery:
mov rax, [rdi]
bts rax, 62 ; check if montgomery
jc toMontgomery_doNothing
bts rax, 63
jc toMontgomeryLong
toMontgomeryShort:
mov [rdi], rax
add rdi, 8
push rsi
lea rsi, [R2]
movsx rdx, eax
cmp rdx, 0
js negMontgomeryShort
posMontgomeryShort:
call rawMontgomeryMul1
pop rsi
sub rdi, 8
ret
negMontgomeryShort:
neg rdx ; Do the multiplication positive and then negate the result.
call rawMontgomeryMul1
mov rsi, rdi
call rawNegL
pop rsi
sub rdi, 8
ret
toMontgomeryLong:
mov [rdi], rax
add rdi, 8
push rsi
mov rdx, rdi
lea rsi, [R2]
call rawMontgomeryMul
pop rsi
sub rdi, 8
toMontgomery_doNothing:
ret
;;;;;;;;;;;;;;;;;;;;;;
; toNormal
;;;;;;;;;;;;;;;;;;;;;;
; Convert a number from Montgomery
; rdi <= Pointer element to convert
; Modified registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;
<%=name%>_toNormal:
mov rax, [rdi]
btc rax, 62 ; check if montgomery
jnc toNormal_doNothing
bt rax, 63 ; if short, it means it's converted
jnc toNormal_doNothing
toNormalLong:
mov [rdi], rax
add rdi, 8
call rawFromMontgomery
sub rdi, 8
toNormal_doNothing:
ret
;;;;;;;;;;;;;;;;;;;;;;
; toLongNormal
;;;;;;;;;;;;;;;;;;;;;;
; Convert a number to long normal
; rdi <= Pointer element to convert
; Modified registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;
<%=name%>_toLongNormal:
mov rax, [rdi]
bt rax, 62 ; check if montgomery
jc toLongNormal_fromMontgomery
bt rax, 63 ; check if long
jnc toLongNormal_fromShort
ret ; It is already long
toLongNormal_fromMontgomery:
add rdi, 8
call rawFromMontgomery
sub rdi, 8
ret
toLongNormal_fromShort:
mov r8, rsi ; save rsi
movsx rsi, eax
call rawCopyS2L
mov rsi, r8 ; recover rsi
ret

View File

@@ -1,275 +0,0 @@
<% function mulS1S2() { %>
xor rax, rax
mov eax, r8d
imul r9d
jo mul_manageOverflow ; rsi already is the 64bits result
mov [rdi], rax ; not necessary to adjust so just save and return
mul_manageOverflow: ; Do the operation in 64 bits
push rsi
movsx rax, r8d
movsx rcx, r9d
imul rcx
mov rsi, rax
call rawCopyS2L
pop rsi
<% } %>
<% function squareS1() { %>
xor rax, rax
mov eax, r8d
imul eax
jo square_manageOverflow ; rsi already is the 64bits result
mov [rdi], rax ; not necessary to adjust so just save and return
square_manageOverflow: ; Do the operation in 64 bits
push rsi
movsx rax, r8d
imul rax
mov rsi, rax
call rawCopyS2L
pop rsi
<% } %>
<% function mulL1S2(t) { %>
push rsi
add rsi, 8
movsx rdx, r9d
add rdi, 8
cmp rdx, 0
<% const rawPositiveLabel = global.tmpLabel() %>
jns <%= rawPositiveLabel %>
neg rdx
call rawMontgomeryMul1
mov rsi, rdi
call rawNegL
sub rdi, 8
pop rsi
<% const done = global.tmpLabel() %>
jmp <%= done %>
<%= rawPositiveLabel %>:
call rawMontgomeryMul1
sub rdi, 8
pop rsi
<%= done %>:
<% } %>
<% function mulS1L2() { %>
push rsi
lea rsi, [rdx + 8]
movsx rdx, r8d
add rdi, 8
cmp rdx, 0
<% const rawPositiveLabel = global.tmpLabel() %>
jns <%= rawPositiveLabel %>
neg rdx
call rawMontgomeryMul1
mov rsi, rdi
call rawNegL
sub rdi, 8
pop rsi
<% const done = global.tmpLabel() %>
jmp <%= done %>
<%= rawPositiveLabel %>:
call rawMontgomeryMul1
sub rdi, 8
pop rsi
<%= done %>:
<% } %>
<% function mulL1L2() { %>
add rdi, 8
add rsi, 8
add rdx, 8
call rawMontgomeryMul
sub rdi, 8
sub rsi, 8
<% } %>
<% function squareL1() { %>
add rdi, 8
add rsi, 8
call rawMontgomerySquare
sub rdi, 8
sub rsi, 8
<% } %>
<% function mulR3() { %>
push rsi
add rdi, 8
mov rsi, rdi
lea rdx, [R3]
call rawMontgomeryMul
sub rdi, 8
pop rsi
<% } %>
;;;;;;;;;;;;;;;;;;;;;;
; square
;;;;;;;;;;;;;;;;;;;;;;
; Squares a field element
; Params:
; rsi <= Pointer to element 1
; rdi <= Pointer to result
; [rdi] = [rsi] * [rsi]
; Modified Registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_square:
mov r8, [rsi]
bt r8, 63 ; Check if is short first operand
jc square_l1
square_s1: ; Both operands are short
<%= squareS1() %>
ret
square_l1:
bt r8, 62 ; check if montgomery first
jc square_l1m
square_l1n:
<%= global.setTypeDest("0xC0"); %>
<%= squareL1() %>
<%= mulR3() %>
ret
square_l1m:
<%= global.setTypeDest("0xC0"); %>
<%= squareL1() %>
ret
;;;;;;;;;;;;;;;;;;;;;;
; mul
;;;;;;;;;;;;;;;;;;;;;;
; Multiplies two elements of any kind
; Params:
; rsi <= Pointer to element 1
; rdx <= Pointer to element 2
; rdi <= Pointer to result
; [rdi] = [rsi] * [rdi]
; Modified Registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_mul:
mov r8, [rsi]
mov r9, [rdx]
bt r8, 63 ; Check if is short first operand
jc mul_l1
bt r9, 63 ; Check if is short second operand
jc mul_s1l2
mul_s1s2: ; Both operands are short
<%= mulS1S2() %>
ret
mul_l1:
bt r9, 63 ; Check if is short second operand
jc mul_l1l2
;;;;;;;;
mul_l1s2:
bt r8, 62 ; check if montgomery first
jc mul_l1ms2
mul_l1ns2:
bt r9, 62 ; check if montgomery first
jc mul_l1ns2m
mul_l1ns2n:
<%= global.setTypeDest("0xC0"); %>
<%= mulL1S2() %>
<%= mulR3() %>
ret
mul_l1ns2m:
<%= global.setTypeDest("0x80"); %>
<%= mulL1L2() %>
ret
mul_l1ms2:
bt r9, 62 ; check if montgomery second
jc mul_l1ms2m
mul_l1ms2n:
<%= global.setTypeDest("0x80"); %>
<%= mulL1S2() %>
ret
mul_l1ms2m:
<%= global.setTypeDest("0xC0"); %>
<%= mulL1L2() %>
ret
;;;;;;;;
mul_s1l2:
bt r8, 62 ; check if montgomery first
jc mul_s1ml2
mul_s1nl2:
bt r9, 62 ; check if montgomery first
jc mul_s1nl2m
mul_s1nl2n:
<%= global.setTypeDest("0xC0"); %>
<%= mulS1L2() %>
<%= mulR3() %>
ret
mul_s1nl2m:
<%= global.setTypeDest("0x80"); %>
<%= mulS1L2(); %>
ret
mul_s1ml2:
bt r9, 62 ; check if montgomery first
jc mul_s1ml2m
mul_s1ml2n:
<%= global.setTypeDest("0x80"); %>
<%= mulL1L2() %>
ret
mul_s1ml2m:
<%= global.setTypeDest("0xC0"); %>
<%= mulL1L2() %>
ret
;;;;
mul_l1l2:
bt r8, 62 ; check if montgomery first
jc mul_l1ml2
mul_l1nl2:
bt r9, 62 ; check if montgomery second
jc mul_l1nl2m
mul_l1nl2n:
<%= global.setTypeDest("0xC0"); %>
<%= mulL1L2() %>
<%= mulR3() %>
ret
mul_l1nl2m:
<%= global.setTypeDest("0x80"); %>
<%= mulL1L2() %>
ret
mul_l1ml2:
bt r9, 62 ; check if montgomery seconf
jc mul_l1ml2m
mul_l1ml2n:
<%= global.setTypeDest("0x80"); %>
<%= mulL1L2() %>
ret
mul_l1ml2m:
<%= global.setTypeDest("0xC0"); %>
<%= mulL1L2() %>
ret

View File

@@ -1,78 +0,0 @@
<% function negS() { %>
neg eax
jo neg_manageOverflow ; Check if overflow. (0x80000000 is the only case)
mov [rdi], rax ; not necessary to adjust so just save and return
ret
neg_manageOverflow: ; Do the operation in 64 bits
push rsi
movsx rsi, eax
neg rsi
call rawCopyS2L
pop rsi
ret
<% } %>
<% function negL() { %>
add rdi, 8
add rsi, 8
call rawNegL
sub rdi, 8
sub rsi, 8
ret
<% } %>
;;;;;;;;;;;;;;;;;;;;;;
; neg
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of any kind
; Params:
; rsi <= Pointer to element to be negated
; rdi <= Pointer to result
; [rdi] = -[rsi]
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_neg:
mov rax, [rsi]
bt rax, 63 ; Check if is short first operand
jc neg_l
neg_s: ; Operand is short
<%= negS() %>
neg_l:
mov [rdi], rax ; Copy the type
<%= negL() %>
;;;;;;;;;;;;;;;;;;;;;;
; rawNeg
;;;;;;;;;;;;;;;;;;;;;;
; Negates a value
; Params:
; rdi <= Pointer to the long data of result
; rsi <= Pointer to the long data of element 1
;
; [rdi] = - [rsi]
;;;;;;;;;;;;;;;;;;;;;;
rawNegL:
; Compare is zero
xor rax, rax
<% for (let i=0; i<n64; i++) { %>
cmp [rsi + <%=i*8%>], rax
jnz doNegate
<% } %>
; it's zero so just set to zero
<% for (let i=0; i<n64; i++) { %>
mov [rdi + <%=i*8%>], rax
<% } %>
ret
doNegate:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> rax, [rsi + <%=i*8%>]
mov [rdi + <%=i*8%>], rax
<% } %>
ret

View File

@@ -1,33 +0,0 @@
const tester = require("../c/buildasm/buildzqfieldtester2.js");
const bigInt = require("big-integer");
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
describe("basic cases", function () {
this.timeout(100000);
it("should do basic tests", async () => {
await tester(__P__, [
["add", 0, 0],
["add", 0, 1],
["add", 1, 0],
["add", 1, 1],
["add", 2, 1],
["add", 2, 10],
["add", -1, -1],
["add", -20, -10],
["add", "10604728079509999371218483608188593244163417117449316147628604036713980815027", "10604728079509999371218483608188593244163417117449316147628604036713980815027"],
["mul", 0, 0],
["mul", 0, 1],
["mul", 1, 0],
["mul", 1, 1],
["mul", 2, 1],
["mul", 2, 10],
["mul", -1, -1],
["mul", -20, -10],
["mul", "10604728079509999371218483608188593244163417117449316147628604036713980815027", "10604728079509999371218483608188593244163417117449316147628604036713980815027"],
]);
});
});

View File

@@ -1,209 +0,0 @@
const bigInt=require("big-integer");
class ZqBuilder {
constructor(q, name) {
this.q=bigInt(q);
this.h = [];
this.c = [];
this.name = name;
}
build() {
this._buildHeaders();
this._buildAdd();
this._buildMul();
this.c.push(""); this.h.push("");
return [this.h.join("\n"), this.c.join("\n")];
}
_buildHeaders() {
this.n64 = Math.floor((this.q.bitLength() - 1) / 64)+1;
this.h.push("typedef unsigned long long u64;");
this.h.push(`typedef u64 ${this.name}Element[${this.n64}];`);
this.h.push(`typedef u64 *P${this.name}Element;`);
this.h.push(`extern ${this.name}Element ${this.name}_q;`);
this.h.push(`#define ${this.name}_N64 ${this.n64}`);
this.c.push(`#include "${this.name.toLowerCase()}.h"`);
this._defineConstant(`${this.name}_q`, this.q);
this.c.push(""); this.h.push("");
}
_defineConstant(n, v) {
let S = `${this.name}Element ${n}={`;
const mask = bigInt("FFFFFFFFFFFFFFFF", 16);
for (let i=0; i<this.n64; i++) {
if (i>0) S = S+",";
let shex = v.shiftRight(i*64).and(mask).toString(16);
while (shex <16) shex = "0" + shex;
S = S + "0x" + shex + "ULL";
}
S += "};";
this.c.push(S);
}
_buildAdd() {
this.h.push(`void ${this.name}_add(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b);`);
this.c.push(`void ${this.name}_add(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b) {`);
this.c.push(" __asm__ __volatile__ (");
for (let i=0; i<this.n64; i++) {
this.c.push(` "movq ${i*8}(%2), %%rax;"`);
this.c.push(` "${i==0 ? "addq" : "adcq"} ${i*8}(%1), %%rax;"`);
this.c.push(` "movq %%rax, ${i*8}(%0);"`);
}
this.c.push(" \"jc SQ;\"");
for (let i=0; i<this.n64; i++) {
if (i>0) {
this.c.push(` "movq ${(this.n64 - i-1)*8}(%0), %%rax;"`);
}
this.c.push(` "cmp ${(this.n64 - i-1)*8}(%3), %%rax;"`);
this.c.push(" \"jg SQ;\"");
this.c.push(" \"jl DONE;\"");
}
this.c.push(" \"SQ:\"");
for (let i=0; i<this.n64; i++) {
this.c.push(` "movq ${i*8}(%3), %%rax;"`);
this.c.push(` "${i==0 ? "subq" : "sbbq"} %%rax, ${i*8}(%0);"`);
}
this.c.push(" \"DONE:\"");
this.c.push(` :: "r" (r), "r" (a), "r" (b), "r" (${this.name}_q) : "%rax", "memory");`);
this.c.push("}\n");
}
_buildMul() {
let r0, r1, r2;
function setR(step) {
if ((step % 3) == 0) {
r0 = "%%r8";
r1 = "%%r9";
r2 = "%%r10";
} else if ((step % 3) == 1) {
r0 = "%%r9";
r1 = "%%r10";
r2 = "%%r8";
} else {
r0 = "%%r10";
r1 = "%%r8";
r2 = "%%r9";
}
}
const base = bigInt.one.shiftLeft(64);
const np64 = base.minus(this.q.modInv(base));
this.h.push(`void ${this.name}_mul(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b);`);
this.c.push(`void ${this.name}_mul(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b) {`);
this.c.push(" __asm__ __volatile__ (");
this.c.push(` "subq $${this.n64*8}, %%rsp;"`);
this.c.push(` "movq $0x${np64.toString(16)}, %%r11;"`);
this.c.push(" \"movq $0x0, %%r8;\"");
this.c.push(" \"movq $0x0, %%r9;\"");
this.c.push(" \"movq $0x0, %%r10;\"");
for (let i=0; i<this.n64*2; i++) {
setR(i);
for (let o1=Math.max(0, i-this.n64+1); (o1<=i)&&(o1<this.n64); o1++) {
const o2= i-o1;
this.c.push(` "movq ${o1*8}(%1), %%rax;"`);
this.c.push(` "mulq ${o2*8}(%2);"`);
this.c.push(` "addq %%rax, ${r0};"`);
this.c.push(` "adcq %%rdx, ${r1};"`);
this.c.push(` "adcq $0x0, ${r2};"`);
}
for (let j=i-1; j>=0; j--) {
if (((i-j)<this.n64)&&(j<this.n64)) {
this.c.push(` "movq ${j*8}(%%rsp), %%rax;"`);
this.c.push(` "mulq ${(i-j)*8}(%3);"`);
this.c.push(` "addq %%rax, ${r0};"`);
this.c.push(` "adcq %%rdx, ${r1};"`);
this.c.push(` "adcq $0x0, ${r2};"`);
}
}
if (i<this.n64) {
this.c.push(` "movq ${r0}, %%rax;"`);
this.c.push(" \"mulq %%r11;\"");
this.c.push(` "movq %%rax, ${i*8}(%%rsp);"`);
this.c.push(" \"mulq (%3);\"");
this.c.push(` "addq %%rax, ${r0};"`);
this.c.push(` "adcq %%rdx, ${r1};"`);
this.c.push(` "adcq $0x0, ${r2};"`);
} else {
this.c.push(` "movq ${r0}, ${(i-this.n64)*8}(%0);"`);
this.c.push(` "movq $0, ${r0};"`);
}
}
this.c.push(` "cmp $0, ${r1};"`);
this.c.push(" \"jne SQ2;\"");
for (let i=0; i<this.n64; i++) {
this.c.push(` "movq ${(this.n64 - i-1)*8}(%0), %%rax;"`);
this.c.push(` "cmp ${(this.n64 - i-1)*8}(%3), %%rax;"`);
this.c.push(" \"jg SQ2;\"");
this.c.push(" \"jl DONE2;\"");
}
this.c.push(" \"SQ2:\"");
for (let i=0; i<this.n64; i++) {
this.c.push(` "movq ${i*8}(%3), %%rax;"`);
this.c.push(` "${i==0 ? "subq" : "sbbq"} %%rax, ${i*8}(%0);"`);
}
this.c.push(" \"DONE2:\"");
this.c.push(` "addq $${this.n64*8}, %%rsp;"`);
this.c.push(` :: "r" (r), "r" (a), "r" (b), "r" (${this.name}_q) : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "memory");`);
this.c.push("}\n");
}
_buildIDiv() {
this.h.push(`void ${this.name}_idiv(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b);`);
this.c.push(`void ${this.name}_idiv(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b) {`);
this.c.push(" __asm__ __volatile__ (");
this.c.push(" \"pxor %%xmm0, %%xmm0;\""); // Comparison Register
if (this.n64 == 1) {
this.c.push(` "mov %%rax, $${this.n64 - 8};"`);
} else {
this.c.push(` "mov %%rax, $${this.n64 -16};"`);
}
this.c.push(` :: "r" (r), "r" (a), "r" (b), "r" (${this.name}_q) : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "memory");`);
this.c.push("}\n");
}
}
var runningAsScript = !module.parent;
if (runningAsScript) {
const fs = require("fs");
var argv = require("yargs")
.usage("Usage: $0 -q [primeNum] -n [name] -oc [out .c file] -oh [out .h file]")
.demandOption(["q","n"])
.alias("q", "prime")
.alias("n", "name")
.argv;
const q = bigInt(argv.q);
const cFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".c";
const hFileName = (argv.oh) ? argv.oh : argv.name.toLowerCase() + ".h";
const builder = new ZqBuilder(q, argv.name);
const res = builder.build();
fs.writeFileSync(hFileName, res[0], "utf8");
fs.writeFileSync(cFileName, res[1], "utf8");
} else {
module.exports = function(q, name) {
const builder = new ZqBuilder(q, name);
return builder.build();
};
}

View File

@@ -1,68 +0,0 @@
const chai = require("chai");
const assert = chai.assert;
const fs = require("fs");
var tmp = require("tmp-promise");
const path = require("path");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const bigInt = require("big-integer");
const BuildZqField = require("./buildzqfield");
const ZqField = require("fflib").ZqField;
module.exports = testField;
function toMontgomeryStr(a, prime) {
const n64 = Math.floor((prime.bitLength() - 1) / 64)+1;
return a.shiftLeft(n64*64).mod(prime).toString(10);
}
function fromMontgomeryStr(a, prime) {
const n64 = Math.floor((prime.bitLength() - 1) / 64)+1;
const R = bigInt.one.shiftLeft(n64*64).mod(prime);
const RI = R.modInv(prime);
return bigInt(a).times(RI).mod(prime);
}
async function testField(prime, test) {
tmp.setGracefulCleanup();
const F = new ZqField(prime);
const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
const [hSource, cSource] = BuildZqField(prime, "Fr");
await fs.promises.writeFile(path.join(dir.path, "fr.h"), hSource, "utf8");
await fs.promises.writeFile(path.join(dir.path, "fr.c"), cSource, "utf8");
await exec("g++" +
` ${path.join(__dirname, "tester.c")}` +
` ${path.join(dir.path, "fr.c")}` +
` -o ${path.join(dir.path, "tester")}` +
" -lgmp"
);
for (let i=0; i<test.length; i++) {
let a = bigInt(test[i][1]).mod(prime);
if (a.isNegative()) a = prime.add(a);
let b = bigInt(test[i][2]).mod(prime);
if (b.isNegative()) b = prime.add(b);
const ec = F[test[i][0]](a,b);
// console.log(toMontgomeryStr(a, prime));
// console.log(toMontgomeryStr(b, prime));
const res = await exec(`${path.join(dir.path, "tester")}` +
` ${test[i][0]}` +
` ${toMontgomeryStr(a, prime)}` +
` ${toMontgomeryStr(b, prime)}`
);
// console.log(res.stdout);
const c=fromMontgomeryStr(res.stdout, prime);
assert.equal(ec.toString(), c.toString());
}
}

View File

@@ -1,302 +0,0 @@
global <%=name%>_add
global <%=name%>_mul
global <%=name%>_q
DEFAULT REL
section .text
;;;;;;;;;;;;;;;;;;;;;;
; add
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_add:
; Add component by component with carry
<% for (let i=0; i<n64; i++) { %>
mov rax, [rsi + <%=i*8%>]
<%= i==0 ? "add" : "adc" %> rax, [rdx + <%=i*8%>]
mov [rdi + <%=i*8%>], rax
<% } %>
jc add_sq ; if overflow, substract q
; Compare with q
<% for (let i=0; i<n64; i++) { %>
<% if (i>0) { %>
mov rax, [rdi + <%= (n64-i-1)*8 %>]
<% } %>
cmp rax, [q + <%= (n64-i-1)*8 %>]
jg add_sq
jl add_done
<% } %>
; If equal substract q
add_sq:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax
mov [rdx + <%=i*8%>], rax
<% } %>
add_done:
ret
;;;;;;;;;;;;;;;;;;;;;;
; mul Montgomery
;;;;;;;;;;;;;;;;;;;;;;
mulM:
<%
let r0, r1, r2;
function setR(step) {
if ((step % 3) == 0) {
r0 = "r8";
r1 = "r9";
r2 = "r10";
} else if ((step % 3) == 1) {
r0 = "r9";
r1 = "r10";
r2 = "r8";
} else {
r0 = "r10";
r1 = "r8";
r2 = "r9";
}
}
const base = bigInt.one.shiftLeft(64);
const np64 = base.minus(q.modInv(base));
%>
sub rsp, <%= n64*8 %> ; Reserve space for ms
mov rcx, rdx ; rdx is needed for multiplications so keep it in cx
mov r11, 0x<%= np64.toString(16) %> ; np
xor r8,r8
xor r9,r9
xor r10,r10
<%
// Main loop
for (let i=0; i<n64*2; i++) {
setR(i);
%>
<%
// Same Digit
for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1<n64); o1++) {
const o2= i-o1;
%>
mov rax, [rsi + <%= 8*o1 %>]
mul qword [rcx + <%= 8*o2 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} // Same digit
%>
<%
for (let j=i-1; j>=0; j--) { // All ms
if (((i-j)<n64)&&(j<n64)) {
%>
mov rax, [rsp + <%= j*8 %>]
mul qword [q + <%= (i-j)*8 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
}
} // ms
%>
<%
if (i<n64) {
%>
mov rax, <%= r0 %>
mul r11
mov [rsp + <%= i*8 %>], rax
mul qword [q]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} else {
%>
mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %>
xor <%= r0 %>,<%= r0 %>
<%
}
%>
<%
} // Main Loop
%>
cmp <%= r1 %>, 0x0
jne mulM_sq
; Compare with q
<%
for (let i=0; i<n64; i++) {
%>
mov rax, [rdi + <%= (n64-i-1)*8 %>]
cmp rax, [q + <%= (n64-i-1)*8 %>]
jg mulM_sq
jl mulM_done
<%
}
%>
; If equal substract q
mulM_sq:
<%
for (let i=0; i<n64; i++) {
%>
mov rax, [q + <%= i*8 %>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax
mov [rdx + <%= i*8 %>], rax
<%
}
%>
mulM_done:
add rsp, <%= n64*8 %> ; recover rsp
ret
;;;;;;;;;;;;;;;;;;;;;;
; mul MontgomeryShort
;;;;;;;;;;;;;;;;;;;;;;
mulSM:
;;;;;;;;;;;;;;;;;;;;;;
; mul
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_mul:
mov rax, [rsi]
bt rax, 63
jc l1
mov rcx, [rdx]
bt rcx, 63
jc s1l2
s1s2: ; short first and second
mul ecx
jc rs2l ; If if doesn't feed in 32 bits convert the result to long
; The shorts multiplication is done. copy the val to destination and return
mov [rdi], rax
ret
rs2l: ; The result in the multiplication doen't feed
; we have the result in edx:eax we need to convert it to long
shl rdx, 32
mov edx, eax ; pack edx:eax to rdx
xor rax, rax ; Set the format to long
bts rax, 63
mov [rdi], rax ; move the first digit
cmp rdx, 0 ; check if redx is negative.
jl rs2ln
; edx is positive.
mov [rdi + 8], rdx ; Set the firs digit
xor rax, rax ; Set the remaining digits to 0
<% for (let i=1; i<n64; i++) { %>
mov [rdi + <%= (i+1)*8 %>], rax
<% } %>
ret
; edx is negative.
rs2ln:
add rdx, [q] ; Set the firs digit
mov [rdi + 8], rdx ;
mov rdx, -1 ; all ones
<% for (let i=1; i<n64; i++) { %>
mov rax, rdx ; Add to q
adc rax, [q + <%= i*8 %> ]
mov [rdi + <%= (i+1)*8 %>], rax
<% } %>
ret
l1:
mov rcx, [rdx]
bt rcx, 63
jc ll
l1s2:
xor rdx, rdx
mov edx, ecx
bt rax, 62
jc lsM
jmp lsN
s1l2:
mov rsi, rdx
xor rdx, rdx
mov edx, eax
bt rcx, 62
jc lsM
jmp lsN
lsN:
mov byte [rdi + 3], 0xC0 ; set the result to montgomery
add rsi, 8
add rdi, 8
call mulSM
mov rdx, R3
call mulM
ret
lsM:
mov byte [rdi + 3], 0x80 ; set the result to long normal
add rsi, 8
add rdi, 8
call mulSM
ret
ll:
bt rax, 62
jc lml
bt rcx, 62
jc lnlm
lnln:
mov byte [rdi + 3], 0xC0 ; set the result to long montgomery
add rsi, 8
add rdi, 8
add rdx, 8
call mulM
mov rdi, rsi
mov rdx, R3
call mulM
ret
lml:
bt rcx, 62
jc lmlm
lnlm:
mov byte [rdi + 3], 0x80 ; set the result to long normal
add rsi, 8
add rdi, 8
add rdx, 8
call mulM
ret
lmlm:
mov byte [rdi + 3], 0xC0 ; set the result to long montgomery
add rsi, 8
add rdi, 8
add rdx, 8
call mulM
ret
section .data
<%=name%>_q:
dd 0
dd 0x80000000
q dq <%= constantElement(q) %>
R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %>

View File

@@ -1,251 +0,0 @@
;;;;;;;;;;;;;;;;;;;;;;
; mul Montgomery
;;;;;;;;;;;;;;;;;;;;;;
mulM:
<%
let r0, r1, r2;
function setR(step) {
if ((step % 3) == 0) {
r0 = "r8";
r1 = "r9";
r2 = "r10";
} else if ((step % 3) == 1) {
r0 = "r9";
r1 = "r10";
r2 = "r8";
} else {
r0 = "r10";
r1 = "r8";
r2 = "r9";
}
}
const base = bigInt.one.shiftLeft(64);
const np64 = base.minus(q.modInv(base));
%>
sub rsp, <%= n64*8 %> ; Reserve space for ms
mov rcx, rdx ; rdx is needed for multiplications so keep it in cx
mov r11, 0x<%= np64.toString(16) %> ; np
xor r8,r8
xor r9,r9
xor r10,r10
<%
// Main loop
for (let i=0; i<n64*2; i++) {
setR(i);
%>
<%
// Same Digit
for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1<n64); o1++) {
const o2= i-o1;
%>
mov rax, [rsi + <%= 8*o1 %>]
mul qword [rcx + <%= 8*o2 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} // Same digit
%>
<%
for (let j=i-1; j>=0; j--) { // All ms
if (((i-j)<n64)&&(j<n64)) {
%>
mov rax, [rsp + <%= j*8 %>]
mul qword [q + <%= (i-j)*8 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
}
} // ms
%>
<%
if (i<n64) {
%>
mov rax, <%= r0 %>
mul r11
mov [rsp + <%= i*8 %>], rax
mul qword [q]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
} else {
%>
mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %>
xor <%= r0 %>,<%= r0 %>
<%
}
%>
<%
} // Main Loop
%>
cmp <%= r1 %>, 0x0
jne mulM_sq
; Compare with q
<%
for (let i=0; i<n64; i++) {
%>
mov rax, [rdi + <%= (n64-i-1)*8 %>]
cmp rax, [q + <%= (n64-i-1)*8 %>]
jg mulM_sq
jl mulM_done
<%
}
%>
; If equal substract q
mulM_sq:
<%
for (let i=0; i<n64; i++) {
%>
mov rax, [q + <%= i*8 %>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax
<%
}
%>
mulM_done:
add rsp, <%= n64*8 %> ; recover rsp
ret
;;;;;;;;;;;;;;;;;;;;;;
; mul MontgomeryShort
;;;;;;;;;;;;;;;;;;;;;;
mulSM:
;;;;;;;;;;;;;;;;;;;;;;
; mul
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_mul:
mov rax, [rsi]
bt rax, 63
jc l1
mov rcx, [rdx]
bt rcx, 63
jc s1l2
s1s2: ; short first and second
mul ecx
jc rs2l ; If if doesn't feed in 32 bits convert the result to long
; The shorts multiplication is done. copy the val to destination and return
mov [rdi], rax
ret
rs2l: ; The result in the multiplication doen't feed
; we have the result in edx:eax we need to convert it to long
shl rdx, 32
mov edx, eax ; pack edx:eax to rdx
xor rax, rax ; Set the format to long
bts rax, 63
mov [rdi], rax ; move the first digit
cmp rdx, 0 ; check if redx is negative.
jl rs2ln
; edx is positive.
mov [rdi + 8], rdx ; Set the firs digit
xor rax, rax ; Set the remaining digits to 0
<% for (let i=1; i<n64; i++) { %>
mov [rdi + <%= (i+1)*8 %>], rax
<% } %>
ret
; edx is negative.
rs2ln:
add rdx, [q] ; Set the firs digit
mov [rdi + 8], rdx ;
mov rdx, -1 ; all ones
<% for (let i=1; i<n64; i++) { %>
mov rax, rdx ; Add to q
adc rax, [q + <%= i*8 %> ]
mov [rdi + <%= (i+1)*8 %>], rax
<% } %>
ret
l1:
mov rcx, [rdx]
bt rcx, 63
jc ll
l1s2:
xor rdx, rdx
mov edx, ecx
bt rax, 62
jc lsM
jmp lsN
s1l2:
mov rsi, rdx
xor rdx, rdx
mov edx, eax
bt rcx, 62
jc lsM
jmp lsN
lsN:
mov byte [rdi + 7], 0xC0 ; set the result to montgomery
add rsi, 8
add rdi, 8
call mulSM
mov rsi, rdi
lea rdx, [R3]
call mulM
ret
lsM:
mov byte [rdi + 7], 0x80 ; set the result to long normal
add rsi, 8
add rdi, 8
call mulSM
ret
ll:
bt rax, 62
jc lml
bt rcx, 62
jc lnlm
lnln:
mov byte [rdi + 7], 0xC0 ; set the result to long montgomery
add rsi, 8
add rdi, 8
add rdx, 8
call mulM
mov rsi, rdi
lea rdx, [R3]
call mulM
ret
lml:
bt rcx, 62
jc lmlm
lnlm:
mov byte [rdi + 7], 0x80 ; set the result to long normal
add rsi, 8
add rdi, 8
add rdx, 8
call mulM
ret
lmlm:
mov byte [rdi + 7], 0xC0 ; set the result to long montgomery
add rsi, 8
add rdi, 8
add rdx, 8
call mulM
ret

View File

@@ -1,317 +0,0 @@
<% function subS1S2() { %>
xor rdx, rdx
mov edx, eax
sub edx, ecx
jo sub_manageOverflow ; rsi already is the 64bits result
mov [rdi], rdx ; not necessary to adjust so just save and return
ret
sub_manageOverflow: ; Do the operation in 64 bits
push rsi
movsx rsi, eax
movsx rdx, ecx
sub rsi, rdx
call rawCopyS2L
pop rsi
ret
<% } %>
<% function subL1S2(t) { %>
add rsi, 8
movsx rdx, ecx
add rdi, 8
cmp rdx, 0
<% const rawSubLabel = global.tmpLabel() %>
jns <%= rawSubLabel %>
neg rdx
call rawAddLS
sub rdi, 8
sub rsi, 8
ret
<%= rawSubLabel %>:
call rawSubLS
sub rdi, 8
sub rsi, 8
ret
<% } %>
<% function subS1L2(t) { %>
cmp eax, 0
<% const s1NegLabel = global.tmpLabel() %>
js <%= s1NegLabel %>
; First Operand is positive
push rsi
add rdi, 8
movsx rsi, eax
add rdx, 8
call rawSubSL
sub rdi, 8
pop rsi
ret
<%= s1NegLabel %>: ; First operand is negative
push rsi
lea rsi, [rdx + 8]
movsx rdx, eax
add rdi, 8
neg rdx
call rawNegLS
sub rdi, 8
pop rsi
ret
<% } %>
<% function subL1L2(t) { %>
add rdi, 8
add rsi, 8
add rdx, 8
call rawSubLL
sub rdi, 8
sub rsi, 8
ret
<% } %>
;;;;;;;;;;;;;;;;;;;;;;
; sub
;;;;;;;;;;;;;;;;;;;;;;
; Substracts two elements of any kind
; Params:
; rsi <= Pointer to element 1
; rdx <= Pointer to element 2
; rdi <= Pointer to result
; Modified Registers:
; r8, r9, 10, r11, rax, rcx
;;;;;;;;;;;;;;;;;;;;;;
<%=name%>_sub:
mov rax, [rsi]
mov rcx, [rdx]
bt rax, 63 ; Check if is long first operand
jc sub_l1
bt rcx, 63 ; Check if is long second operand
jc sub_s1l2
sub_s1s2: ; Both operands are short
<%= subS1S2() %>
sub_l1:
bt rcx, 63 ; Check if is short second operand
jc sub_l1l2
;;;;;;;;
sub_l1s2:
bt rax, 62 ; check if montgomery first
jc sub_l1ms2
sub_l1ns2:
<%= global.setTypeDest("0x80"); %>
<%= subL1S2(); %>
sub_l1ms2:
bt rcx, 62 ; check if montgomery second
jc sub_l1ms2m
sub_l1ms2n:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_b() %>
<%= subL1L2() %>
sub_l1ms2m:
<%= global.setTypeDest("0xC0"); %>
<%= subL1L2() %>
;;;;;;;;
sub_s1l2:
bt rcx, 62 ; check if montgomery first
jc sub_s1l2m
sub_s1l2n:
<%= global.setTypeDest("0x80"); %>
<%= subS1L2(); %>
sub_s1l2m:
bt rax, 62 ; check if montgomery second
jc sub_s1ml2m
sub_s1nl2m:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_a() %>
<%= subL1L2() %>
sub_s1ml2m:
<%= global.setTypeDest("0xC0"); %>
<%= subL1L2() %>
;;;;
sub_l1l2:
bt rax, 62 ; check if montgomery first
jc sub_l1ml2
sub_l1nl2:
bt rcx, 62 ; check if montgomery second
jc sub_l1nl2m
sub_l1nl2n:
<%= global.setTypeDest("0x80"); %>
<%= subL1L2() %>
sub_l1nl2m:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_a(); %>
<%= subL1L2() %>
sub_l1ml2:
bt rcx, 62 ; check if montgomery seconf
jc sub_l1ml2m
sub_l1ml2n:
<%= global.setTypeDest("0xC0"); %>
<%= global.toMont_b(); %>
<%= subL1L2() %>
sub_l1ml2m:
<%= global.setTypeDest("0xC0"); %>
<%= subL1L2() %>
;;;;;;;;;;;;;;;;;;;;;;
; rawSubLS
;;;;;;;;;;;;;;;;;;;;;;
; Substracts a short element from the long element
; Params:
; rdi <= Pointer to the long data of result
; rsi <= Pointer to the long data of element 1 where will be substracted
; rdx <= Value to be substracted
; [rdi] = [rsi] - rdx
; Modified Registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;
rawSubLS:
; Substract first digit
mov rax, [rsi]
sub rax, rdx
mov [rdi] ,rax
mov rdx, 0
<% for (let i=1; i<n64; i++) { %>
mov rax, [rsi + <%=i*8%>]
sbb rax, rdx
mov [rdi + <%=i*8%>], rax
<% } %>
jnc rawSubLS_done ; if overflow, add q
; Add q
rawSubLS_aq:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax
<% } %>
rawSubLS_done:
ret
;;;;;;;;;;;;;;;;;;;;;;
; rawSubSL
;;;;;;;;;;;;;;;;;;;;;;
; Substracts a long element from a short element
; Params:
; rdi <= Pointer to the long data of result
; rsi <= Value from where will bo substracted
; rdx <= Pointer to long of the value to be substracted
;
; [rdi] = rsi - [rdx]
; Modified Registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;
rawSubSL:
; Substract first digit
sub rsi, [rdx]
mov [rdi] ,rsi
<% for (let i=1; i<n64; i++) { %>
mov rax, 0
sbb rax, [rdx + <%=i*8%>]
mov [rdi + <%=i*8%>], rax
<% } %>
jnc rawSubSL_done ; if overflow, add q
; Add q
rawSubSL_aq:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax
<% } %>
rawSubSL_done:
ret
;;;;;;;;;;;;;;;;;;;;;;
; rawSubLL
;;;;;;;;;;;;;;;;;;;;;;
; Substracts a long element from a short element
; Params:
; rdi <= Pointer to the long data of result
; rsi <= Pointer to long from where substracted
; rdx <= Pointer to long of the value to be substracted
;
; [rdi] = [rsi] - [rdx]
; Modified Registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;
rawSubLL:
; Substract first digit
<% for (let i=0; i<n64; i++) { %>
mov rax, [rsi + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> rax, [rdx + <%=i*8%>]
mov [rdi + <%=i*8%>], rax
<% } %>
jnc rawSubLL_done ; if overflow, add q
; Add q
rawSubLL_aq:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax
<% } %>
rawSubLL_done:
ret
;;;;;;;;;;;;;;;;;;;;;;
; rawNegLS
;;;;;;;;;;;;;;;;;;;;;;
; Substracts a long element and a short element form 0
; Params:
; rdi <= Pointer to the long data of result
; rsi <= Pointer to long from where substracted
; rdx <= short value to be substracted too
;
; [rdi] = -[rsi] - rdx
; Modified Registers:
; rax
;;;;;;;;;;;;;;;;;;;;;;
rawNegLS:
mov rax, [q]
sub rax, rdx
mov [rdi], rax
<% for (let i=1; i<n64; i++) { %>
mov rax, [q + <%=i*8%> ]
sbb rax, 0
mov [rdi + <%=i*8%>], rax
<% } %>
setc dl
<% for (let i=0; i<n64; i++) { %>
mov rax, [rdi + <%=i*8%> ]
<%= i==0 ? "sub" : "sbb" %> rax, [rsi + <%=i*8%>]
mov [rdi + <%=i*8%>], rax
<% } %>
setc dh
or dl, dh
jz rawNegSL_done
; it is a negative value, so add q
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax
<% } %>
rawNegSL_done:
ret

View File

@@ -1,218 +0,0 @@
#include <string>
#include <iostream>
#include <regex>
#include <string>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <stdio.h> /* printf, NULL */
#include <stdlib.h>
#include <cassert>
#include "fr.h"
typedef void (*Func1)(PFrElement, PFrElement);
typedef void (*Func2)(PFrElement, PFrElement, PFrElement);
typedef void *FuncAny;
typedef struct {
FuncAny fn;
int nOps;
} FunctionSpec;
std::map<std::string, FunctionSpec> functions;
std::vector<FrElement> stack;
void addFunction(std::string name, FuncAny f, int nOps) {
FunctionSpec fs;
fs.fn = f;
fs.nOps = nOps;
functions[name] = fs;
}
void fillMap() {
addFunction("add", (FuncAny)Fr_add, 2);
addFunction("sub", (FuncAny)Fr_sub, 2);
addFunction("neg", (FuncAny)Fr_neg, 1);
addFunction("mul", (FuncAny)Fr_mul, 2);
addFunction("square", (FuncAny)Fr_square, 1);
addFunction("idiv", (FuncAny)Fr_idiv, 2);
addFunction("inv", (FuncAny)Fr_inv, 1);
addFunction("div", (FuncAny)Fr_div, 2);
addFunction("band", (FuncAny)Fr_band, 2);
addFunction("bor", (FuncAny)Fr_bor, 2);
addFunction("bxor", (FuncAny)Fr_bxor, 2);
addFunction("bnot", (FuncAny)Fr_bnot, 1);
addFunction("eq", (FuncAny)Fr_eq, 2);
addFunction("neq", (FuncAny)Fr_neq, 2);
addFunction("lt", (FuncAny)Fr_lt, 2);
addFunction("gt", (FuncAny)Fr_gt, 2);
addFunction("leq", (FuncAny)Fr_leq, 2);
addFunction("geq", (FuncAny)Fr_geq, 2);
addFunction("land", (FuncAny)Fr_land, 2);
addFunction("lor", (FuncAny)Fr_lor, 2);
addFunction("lnot", (FuncAny)Fr_lnot, 1);
}
u_int64_t readInt(std::string &s) {
if (s.rfind("0x", 0) == 0) {
return std::stoull(s.substr(2), 0, 16);
} else {
return std::stoull(s, 0, 10);
}
}
void pushNumber(std::vector<std::string> &v) {
u_int64_t a;
if ((v.size()<1) || (v.size() > (Fr_N64+1))) {
printf("Invalid Size: %d - %d \n", v.size(), Fr_N64);
throw std::runtime_error("Invalid number of parameters for number");
}
FrElement e;
a = readInt(v[0]);
*(u_int64_t *)(&e) = a;
for (int i=0; i<Fr_N64; i++) {
if (i+1 < v.size()) {
a = readInt(v[i+1]);
} else {
a = 0;
}
e.longVal[i] = a;
}
stack.push_back(e);
}
void callFunction(FunctionSpec fs) {
if (stack.size() < fs.nOps) {
throw new std::runtime_error("Not enough elements in stack");
}
if (fs.nOps == 1) {
FrElement a = stack.back();
stack.pop_back();
FrElement c;
(*(Func1)fs.fn)(&c, &a);
stack.push_back(c);
} else if (fs.nOps == 2) {
FrElement b = stack.back();
stack.pop_back();
FrElement a = stack.back();
stack.pop_back();
FrElement c;
(*(Func2)fs.fn)(&c, &a, &b);
stack.push_back(c);
} else {
assert(false);
}
}
void processLine(std::string &line) {
std::regex re("(\\s*[,;]\\s*)|\\s+"); // whitespace
std::sregex_token_iterator begin( line.begin(), line.end(), re ,-1);
std::sregex_token_iterator end;
std::vector<std::string> tokens;
std::copy(begin, end, std::back_inserter(tokens));
// Remove initial empty tokens
while ((tokens.size() > 0)&&(tokens[0] == "")) {
tokens.erase(tokens.begin());
}
// Empty lines are valid but are not processed
if (tokens.size() == 0) return;
auto search = functions.find(tokens[0]);
if (search == functions.end()) {
pushNumber(tokens);
} else {
if (tokens.size() != 1) {
throw std::runtime_error("Functions does not accept parameters");
}
callFunction(search->second);
}
}
int main(void)
{
Fr_init();
fillMap();
std::string line;
int i=0;
while (std::getline(std::cin, line)) {
processLine(line);
// if (i%1000 == 0) printf("%d\n", i);
// printf("%d\n", i);
i++;
}
// Print the elements in the stack
//
for (int i=0; i<stack.size(); i++) {
char *s;
s = Fr_element2str(&stack[i]);
printf("%s\n", s);
free(s);
}
return EXIT_SUCCESS;
}
/*
#include <stdlib.h>
#include <string.h>
#include "fr.h"
typedef void (*Func2)(PFrElement, PFrElement, PFrElement);
typedef struct {
const char *fnName;
Func2 fn;
} FN;
#define NFN 2
FN fns[NFN] = {
{"add", Fr_add},
{"mul", Fr_mul},
};
int main(int argc, char **argv) {
if (argc <= 1) {
fprintf( stderr, "invalid number of parameters");
return 1;
}
for (int i=0; i< NFN;i++) {
if (strcmp(argv[1], fns[i].fnName) == 0) {
if (argc != 4) {
fprintf( stderr, "invalid number of parameters");
return 1;
}
FrElement a;
FrElement b;
Fr_str2element(&a, argv[2]);
Fr_str2element(&b, argv[3]);
FrElement c;
fns[i].fn(&c, &a, &b);
char *s;
s = Fr_element2str(&c);
printf("%s", s);
free(s);
return 0;
}
}
fprintf( stderr, "invalid operation %s", argv[1]);
return 1;
}
*/

View File

@@ -1,73 +0,0 @@
<% global.setTypeDest = function (t) {
return (
` mov r11b, ${t}
shl r11, 56
mov [rdi], r11`);
} %>
<% global.toMont_a = function () {
return (
` push rdi
mov rdi, rsi
mov rsi, rdx
call ${name}_toMontgomery
mov rdx, rsi
mov rsi, rdi
pop rdi`);
} %>
<% global.toMont_b = function() {
return (
` push rdi
mov rdi, rdx
call ${name}_toMontgomery
mov rdx, rdi
pop rdi`);
} %>
<% global.fromMont_a = function () {
return (
` push rdi
mov rdi, rsi
mov rsi, rdx
call ${name}_toNormal
mov rdx, rsi
mov rsi, rdi
pop rdi`);
} %>
<% global.fromMont_b = function() {
return (
` push rdi
mov rdi, rdx
call ${name}_toNormal
mov rdx, rdi
pop rdi`);
} %>
<% global.toLong_a = function () {
return (
` push rdi
push rdx
mov rdi, rsi
movsx rsi, r8d
call rawCopyS2L
mov rsi, rdi
pop rdx
pop rdi`);
} %>
<% global.toLong_b = function() {
return (
` push rdi
push rsi
mov rdi, rdx
movsx rsi, r9d
call rawCopyS2L
mov rdx, rdi
pop rsi
pop rdi`);
} %>

View File

@@ -1,229 +0,0 @@
#include <string>
#include <stdexcept>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#include <thread>
#include "calcwit.h"
#include "utils.h"
Circom_CalcWit::Circom_CalcWit(Circom_Circuit *aCircuit) {
circuit = aCircuit;
#ifdef SANITY_CHECK
signalAssigned = new bool[circuit->NSignals];
signalAssigned[0] = true;
#endif
mutexes = new std::mutex[NMUTEXES];
cvs = new std::condition_variable[NMUTEXES];
inputSignalsToTrigger = new int[circuit->NComponents];
signalValues = new FrElement[circuit->NSignals];
// Set one signal
Fr_copy(&signalValues[0], circuit->constants + 1);
reset();
}
Circom_CalcWit::~Circom_CalcWit() {
#ifdef SANITY_CHECK
delete signalAssigned;
#endif
delete[] cvs;
delete[] mutexes;
delete[] signalValues;
delete[] inputSignalsToTrigger;
}
void Circom_CalcWit::syncPrintf(const char *format, ...) {
va_list args;
va_start(args, format);
printf_mutex.lock();
vprintf(format, args);
printf_mutex.unlock();
va_end(args);
}
void Circom_CalcWit::reset() {
#ifdef SANITY_CHECK
for (int i=1; i<circuit->NComponents; i++) signalAssigned[i] = false;
#endif
for (int i=0; i<circuit->NComponents; i++) {
inputSignalsToTrigger[i] = circuit->components[i].inputSignals;
if (inputSignalsToTrigger[i] == 0) triggerComponent(i);
}
}
int Circom_CalcWit::getSubComponentOffset(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].offset;
}
Circom_Sizes Circom_CalcWit::getSubComponentSizes(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].sizes;
}
int Circom_CalcWit::getSignalOffset(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].offset;
}
Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].sizes;
}
void Circom_CalcWit::getSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value) {
// syncPrintf("getSignal: %d\n", sIdx);
if ((circuit->components[cIdx].newThread)&&(currentComponentIdx != cIdx)) {
std::unique_lock<std::mutex> lk(mutexes[cIdx % NMUTEXES]);
while (inputSignalsToTrigger[cIdx] != -1) {
cvs[cIdx % NMUTEXES].wait(lk);
}
// cvs[cIdx % NMUTEXES].wait(lk, [&]{return inputSignalsToTrigger[cIdx] == -1;});
lk.unlock();
}
#ifdef SANITY_CHECK
if (signalAssigned[sIdx] == false) {
fprintf(stderr, "Accessing a not assigned signal: %d\n", sIdx);
assert(false);
}
#endif
Fr_copy(value, signalValues + sIdx);
/*
char *valueStr = mpz_get_str(0, 10, *value);
syncPrintf("%d, Get %d --> %s\n", currentComponentIdx, sIdx, valueStr);
free(valueStr);
*/
}
void Circom_CalcWit::finished(int cIdx) {
{
std::lock_guard<std::mutex> lk(mutexes[cIdx % NMUTEXES]);
inputSignalsToTrigger[cIdx] = -1;
}
// syncPrintf("Finished: %d\n", cIdx);
cvs[cIdx % NMUTEXES].notify_all();
}
void Circom_CalcWit::setSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value) {
// syncPrintf("setSignal: %d\n", sIdx);
#ifdef SANITY_CHECK
if (signalAssigned[sIdx] == true) {
fprintf(stderr, "Signal assigned twice: %d\n", sIdx);
assert(false);
}
signalAssigned[sIdx] = true;
#endif
// Log assignement
/*
char *valueStr = mpz_get_str(0, 10, *value);
syncPrintf("%d, Set %d --> %s\n", currentComponentIdx, sIdx, valueStr);
free(valueStr);
*/
Fr_copy(signalValues + sIdx, value);
if ( BITMAP_ISSET(circuit->mapIsInput, sIdx) ) {
if (inputSignalsToTrigger[cIdx]>0) {
inputSignalsToTrigger[cIdx]--;
if (inputSignalsToTrigger[cIdx] == 0) triggerComponent(cIdx);
}
}
}
void Circom_CalcWit::checkConstraint(int currentComponentIdx, PFrElement value1, PFrElement value2, char const *err) {
#ifdef SANITY_CHECK
FrElement tmp;
Fr_eq(&tmp, value1, value2);
if (!Fr_isTrue(&tmp)) {
char *pcV1 = Fr_element2str(value1);
char *pcV2 = Fr_element2str(value2);
// throw std::runtime_error(std::to_string(currentComponentIdx) + std::string(", Constraint doesn't match, ") + err + ". " + sV1 + " != " + sV2 );
fprintf(stderr, "Constraint doesn't match, %s: %s != %s", err, pcV1, pcV2);
free(pcV1);
free(pcV2);
assert(false);
}
#endif
}
void Circom_CalcWit::triggerComponent(int newCIdx) {
//int oldCIdx = cIdx;
// cIdx = newCIdx;
if (circuit->components[newCIdx].newThread) {
// syncPrintf("Triggered: %d\n", newCIdx);
std::thread t(circuit->components[newCIdx].fn, this, newCIdx);
// t.join();
t.detach();
} else {
(*(circuit->components[newCIdx].fn))(this, newCIdx);
}
// cIdx = oldCIdx;
}
void Circom_CalcWit::log(PFrElement value) {
char *pcV = Fr_element2str(value);
syncPrintf("Log: %s\n", pcV);
free(pcV);
}
void Circom_CalcWit::join() {
for (int i=0; i<circuit->NComponents; i++) {
std::unique_lock<std::mutex> lk(mutexes[i % NMUTEXES]);
while (inputSignalsToTrigger[i] != -1) {
cvs[i % NMUTEXES].wait(lk);
}
// cvs[i % NMUTEXES].wait(lk, [&]{return inputSignalsToTrigger[i] == -1;});
lk.unlock();
// syncPrintf("Joined: %d\n", i);
}
}

View File

@@ -1,73 +0,0 @@
#ifndef CIRCOM_CALCWIT_H
#define CIRCOM_CALCWIT_H
#include "circom.h"
#include "fr.h"
#include <mutex>
#include <condition_variable>
#define NMUTEXES 128
class Circom_CalcWit {
#ifdef SANITY_CHECK
bool *signalAssigned;
#endif
// componentStatus -> For each component
// >0 Signals required to trigger
// == 0 Component triggered
// == -1 Component finished
int *inputSignalsToTrigger;
std::mutex *mutexes;
std::condition_variable *cvs;
std::mutex printf_mutex;
FrElement *signalValues;
void triggerComponent(int newCIdx);
void calculateWitness(void *input, void *output);
void syncPrintf(const char *format, ...);
public:
Circom_Circuit *circuit;
// Functions called by the circuit
Circom_CalcWit(Circom_Circuit *aCircuit);
~Circom_CalcWit();
int getSubComponentOffset(int cIdx, u64 hash);
Circom_Sizes getSubComponentSizes(int cIdx, u64 hash);
int getSignalOffset(int cIdx, u64 hash);
Circom_Sizes getSignalSizes(int cIdx, u64 hash);
void getSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value);
void setSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value);
void checkConstraint(int currentComponentIdx, PFrElement value1, PFrElement value2, char const *err);
void log(PFrElement value);
void finished(int cIdx);
void join();
// Public functions
inline void setInput(int idx, PFrElement val) {
setSignal(0, 0, circuit->wit2sig[idx], val);
}
inline void getWitness(int idx, PFrElement val) {
Fr_copy(val, &signalValues[circuit->wit2sig[idx]]);
}
void reset();
};
#endif // CIRCOM_CALCWIT_H

View File

@@ -1,58 +0,0 @@
#ifndef __CIRCOM_H
#define __CIRCOM_H
#include <gmp.h>
#include <stdint.h>
#include "fr.h"
class Circom_CalcWit;
typedef unsigned long long u64;
typedef uint32_t u32;
typedef uint8_t u8;
typedef int Circom_Size;
typedef Circom_Size *Circom_Sizes;
struct Circom_HashEntry {
u64 hash;
int pos;
};
typedef Circom_HashEntry *Circom_HashTable;
typedef enum { _typeSignal, _typeComponent} Circom_EntryType;
struct Circom_ComponentEntry {
int offset;
Circom_Sizes sizes;
Circom_EntryType type;
};
typedef Circom_ComponentEntry *Circom_ComponentEntries;
typedef void (*Circom_ComponentFunction)(Circom_CalcWit *ctx, int __cIdx);
struct Circom_Component {
Circom_HashTable hashTable;
Circom_ComponentEntries entries;
Circom_ComponentFunction fn;
int inputSignals;
bool newThread;
};
class Circom_Circuit {
public:
int NSignals;
int NComponents;
int NInputs;
int NOutputs;
int NVars;
int *wit2sig;
Circom_Component *components;
u32 *mapIsInput;
PFrElement constants;
const char *P;
};
#define BITMAP_ISSET(m, b) (m[b>>5] & (1 << (b&0x1F)))
extern struct Circom_Circuit _circuit;
#endif

1
c/fr.c
View File

@@ -1 +0,0 @@
buildasm/fr.c

1
c/fr.h
View File

@@ -1 +0,0 @@
buildasm/fr.h

1
c/fr.o
View File

@@ -1 +0,0 @@
buildasm/fr.o

View File

@@ -1,214 +0,0 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#include "calcwit.h"
#include "circom.h"
#include "utils.h"
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
void loadBin(Circom_CalcWit *ctx, std::string filename) {
int fd;
struct stat sb;
// map input
fd = open(filename.c_str(), O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
u8 *in;
in = (u8 *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (in == MAP_FAILED)
handle_error("mmap");
close(fd);
FrElement v;
u8 *p = in;
for (int i=0; i<_circuit.NInputs; i++) {
v.type = Fr_LONG;
for (int j=0; j<Fr_N64; j++) {
v.longVal[j] = *(u64 *)p;
}
p += 8;
ctx->setSignal(0, 0, _circuit.wit2sig[1 + _circuit.NOutputs + i], &v);
}
}
typedef void (*ItFunc)(Circom_CalcWit *ctx, int idx, json val);
void iterateArr(Circom_CalcWit *ctx, int o, Circom_Sizes sizes, json jarr, ItFunc f) {
if (!jarr.is_array()) {
assert((sizes[0] == 1)&&(sizes[1] == 0));
f(ctx, o, jarr);
} else {
int n = sizes[0] / sizes[1];
for (int i=0; i<n; i++) {
iterateArr(ctx, o + i*sizes[1], sizes+1, jarr[i], f);
}
}
}
void itFunc(Circom_CalcWit *ctx, int o, json val) {
FrElement v;
std::string s;
if (val.is_string()) {
s = val.get<std::string>();
} else if (val.is_number()) {
double vd = val.get<double>();
std::stringstream stream;
stream << std::fixed << std::setprecision(0) << vd;
s = stream.str();
} else {
handle_error("Invalid JSON type");
}
Fr_str2element (&v, s.c_str());
ctx->setSignal(0, 0, o, &v);
}
void loadJson(Circom_CalcWit *ctx, std::string filename) {
std::ifstream inStream(filename);
json j;
inStream >> j;
for (json::iterator it = j.begin(); it != j.end(); ++it) {
// std::cout << it.key() << " => " << it.value() << '\n';
u64 h = fnv1a(it.key());
int o;
try {
o = ctx->getSignalOffset(0, h);
} catch (std::runtime_error e) {
std::ostringstream errStrStream;
errStrStream << "Error loadin variable: " << it.key() << "\n" << e.what();
throw std::runtime_error(errStrStream.str() );
}
Circom_Sizes sizes = ctx->getSignalSizes(0, h);
iterateArr(ctx, o, sizes, it.value(), itFunc);
}
}
void writeOutBin(Circom_CalcWit *ctx, std::string filename) {
FILE *write_ptr;
write_ptr = fopen(filename.c_str(),"wb");
// Add header
// 4 bytes --> total number of constraints
uint32_t witnessLength = _circuit.NVars;
// 4 bytes --> witness element size (measured in number of 32bit words)
uint32_t witnessSize = 8; // witness size = 8*32 = 256 bits
// 8bytes --> empty
uint64_t otherField = 0;
fwrite(&witnessLength, 4, 1, write_ptr);
fwrite(&witnessSize, 4, 1, write_ptr);
fwrite(&otherField, 8, 1, write_ptr);
FrElement v;
u8 buffOut[256];
for (int i=0;i<_circuit.NVars;i++) {
size_t size=256;
ctx->getWitness(i, &v);
Fr_toLongNormal(&v);
fwrite(v.longVal, Fr_N64*8, 1, write_ptr);
}
fclose(write_ptr);
}
void writeOutJson(Circom_CalcWit *ctx, std::string filename) {
std::ofstream outFile;
outFile.open (filename);
outFile << "[\n";
FrElement v;
for (int i=0;i<_circuit.NVars;i++) {
ctx->getWitness(i, &v);
char *pcV = Fr_element2str(&v);
std::string sV = std::string(pcV);
outFile << (i ? "," : " ") << "\"" << sV << "\"\n";
free(pcV);
}
outFile << "]\n";
outFile.close();
}
bool hasEnding (std::string const &fullString, std::string const &ending) {
if (fullString.length() >= ending.length()) {
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
} else {
return false;
}
}
int main(int argc, char *argv[]) {
Fr_init();
if (argc!=3) {
std::string cl = argv[0];
std::string base_filename = cl.substr(cl.find_last_of("/\\") + 1);
std::cout << "Usage: " << base_filename << " <input.<bin|json>> <output.<bin|json>>\n";
} else {
// open output
Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit);
std::string infilename = argv[1];
if (hasEnding(infilename, std::string(".bin"))) {
loadBin(ctx, infilename);
} else if (hasEnding(infilename, std::string(".json"))) {
loadJson(ctx, infilename);
} else {
handle_error("Invalid input extension (.bin / .json)");
}
ctx->join();
printf("Finished!\n");
std::string outfilename = argv[2];
if (hasEnding(outfilename, std::string(".bin"))) {
writeOutBin(ctx, outfilename);
} else if (hasEnding(outfilename, std::string(".json"))) {
writeOutJson(ctx, outfilename);
} else {
handle_error("Invalid output extension (.bin / .json)");
}
delete ctx;
exit(EXIT_SUCCESS);
}
}

Binary file not shown.

View File

@@ -1,47 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#include "utils.h"
#include "circom.h"
#include "calcwit.h"
auto j = R"(
{
"in": "314"
}
)"_json;
typedef void (*ItFunc)(int idx, json val);
void iterateArr(int o, Circom_Sizes sizes, json jarr, ItFunc f) {
if (!jarr.is_array()) {
assert((sizes[0] == 1)&&(sizes[1] == 0));
f(o, jarr);
} else {
int n = sizes[0] / sizes[1];
for (int i=0; i<n; i++) {
iterateArr(o + i*sizes[1], sizes+1, jarr[i], f);
}
}
}
void itFunc(int o, json v) {
std::cout << o << " <-- " << v << '\n';
}
int main(int argc, char **argv) {
Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit);
for (json::iterator it = j.begin(); it != j.end(); ++it) {
// std::cout << it.key() << " => " << it.value() << '\n';
u64 h = fnv1a(it.key());
int o = ctx->getSignalOffset(0, h);
Circom_Sizes sizes = ctx->getSignalSizes(0, h);
iterateArr(o, sizes, it.value(), itFunc);
}
}

View File

@@ -1,25 +0,0 @@
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include "utils.h"
std::string int_to_hex( u64 i )
{
std::stringstream stream;
stream << "0x"
<< std::setfill ('0') << std::setw(16)
<< std::hex << i;
return stream.str();
}
u64 fnv1a(std::string s) {
u64 hash = 0xCBF29CE484222325LL;
for(char& c : s) {
hash ^= u64(c);
hash *= 0x100000001B3LL;
}
return hash;
}

View File

@@ -1,10 +0,0 @@
#ifndef __UTILS_H
#define __UTILS_H
#include "circom.h"
std::string int_to_hex( u64 i );
u64 fnv1a(std::string s);
#endif // __UTILS_H

View File

@@ -1,199 +0,0 @@
#include "zqfield.h"
ZqField::ZqField(PBigInt ap) {
mpz_init_set(p, *ap);
mpz_init_set_ui(zero, 0);
mpz_init_set_ui(one, 1);
nBits = mpz_sizeinbase (p, 2);
mpz_init(mask);
mpz_mul_2exp(mask, one, nBits-1);
mpz_sub(mask, mask, one);
}
ZqField::~ZqField() {
mpz_clear(p);
mpz_clear(zero);
mpz_clear(one);
}
void ZqField::add(PBigInt r, PBigInt a, PBigInt b) {
mpz_add(*r,*a,*b);
if (mpz_cmp(*r, p) >= 0) {
mpz_sub(*r, *r, p);
}
}
void ZqField::sub(PBigInt r, PBigInt a, PBigInt b) {
if (mpz_cmp(*a, *b) >= 0) {
mpz_sub(*r, *a, *b);
} else {
mpz_sub(*r, *b, *a);
mpz_sub(*r, p, *r);
}
}
void ZqField::neg(PBigInt r, PBigInt a) {
if (mpz_sgn(*a) > 0) {
mpz_sub(*r, p, *a);
} else {
mpz_set(*r, *a);
}
}
void ZqField::mul(PBigInt r, PBigInt a, PBigInt b) {
mpz_t tmp;
mpz_init(tmp);
mpz_mul(tmp,*a,*b);
mpz_fdiv_r(*r, tmp, p);
mpz_clear(tmp);
}
void ZqField::div(PBigInt r, PBigInt a, PBigInt b) {
mpz_t tmp;
mpz_init(tmp);
mpz_invert(tmp, *b, p);
mpz_mul(tmp,*a,tmp);
mpz_fdiv_r(*r, tmp, p);
mpz_clear(tmp);
}
void ZqField::idiv(PBigInt r, PBigInt a, PBigInt b) {
mpz_fdiv_q(*r, *a, *b);
}
void ZqField::mod(PBigInt r, PBigInt a, PBigInt b) {
mpz_fdiv_r(*r, *a, *b);
}
void ZqField::pow(PBigInt r, PBigInt a, PBigInt b) {
mpz_powm(*r, *a, *b, p);
}
void ZqField::lt(PBigInt r, PBigInt a, PBigInt b) {
int c = mpz_cmp(*a, *b);
if (c<0) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::eq(PBigInt r, PBigInt a, PBigInt b) {
int c = mpz_cmp(*a, *b);
if (c==0) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::gt(PBigInt r, PBigInt a, PBigInt b) {
int c = mpz_cmp(*a, *b);
if (c>0) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::leq(PBigInt r, PBigInt a, PBigInt b) {
int c = mpz_cmp(*a, *b);
if (c<=0) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::geq(PBigInt r, PBigInt a, PBigInt b) {
int c = mpz_cmp(*a, *b);
if (c>=0) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::neq(PBigInt r, PBigInt a, PBigInt b) {
int c = mpz_cmp(*a, *b);
if (c!=0) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::land(PBigInt r, PBigInt a, PBigInt b) {
if (mpz_sgn(*a) && mpz_sgn(*b)) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::lor(PBigInt r, PBigInt a, PBigInt b) {
if (mpz_sgn(*a) || mpz_sgn(*b)) {
mpz_set(*r, one);
} else {
mpz_set(*r, zero);
}
}
void ZqField::lnot(PBigInt r, PBigInt a) {
if (mpz_sgn(*a)) {
mpz_set(*r, zero);
} else {
mpz_set(*r, one);
}
}
int ZqField::isTrue(PBigInt a) {
return mpz_sgn(*a);
}
void ZqField::copyn(PBigInt a, PBigInt b, int n) {
for (int i=0;i<n; i++) mpz_set(a[i], b[i]);
}
void ZqField::band(PBigInt r, PBigInt a, PBigInt b) {
mpz_and(*r, *a, *b);
mpz_and(*r, *r, mask);
}
void ZqField::bor(PBigInt r, PBigInt a, PBigInt b) {
mpz_ior(*r, *a, *b);
mpz_and(*r, *r, mask);
}
void ZqField::bxor(PBigInt r, PBigInt a, PBigInt b) {
mpz_xor(*r, *a, *b);
mpz_and(*r, *r, mask);
}
void ZqField::bnot(PBigInt r, PBigInt a) {
mpz_xor(*r, *a, mask);
mpz_and(*r, *r, mask);
}
void ZqField::shl(PBigInt r, PBigInt a, PBigInt b) {
if (mpz_cmp_ui(*b, nBits) >= 0) {
mpz_set(*r, zero);
} else {
mpz_mul_2exp(*r, *a, mpz_get_ui(*b));
mpz_and(*r, *r, mask);
}
}
void ZqField::shr(PBigInt r, PBigInt a, PBigInt b) {
if (mpz_cmp_ui(*b, nBits) >= 0) {
mpz_set(*r, zero);
} else {
mpz_tdiv_q_2exp(*r, *a, mpz_get_ui(*b));
mpz_and(*r, *r, mask);
}
}
int ZqField::toInt(PBigInt a) {
return mpz_get_si (*a);
}

View File

@@ -1,49 +0,0 @@
#ifndef ZQFIELD_H
#define ZQFIELD_H
#include "circom.h"
class ZqField {
public:
BigInt p;
BigInt one;
BigInt zero;
size_t nBits;
BigInt mask;
ZqField(PBigInt ap);
~ZqField();
void copyn(PBigInt a, PBigInt b, int n);
void add(PBigInt r,PBigInt a, PBigInt b);
void sub(PBigInt r,PBigInt a, PBigInt b);
void neg(PBigInt r,PBigInt a);
void mul(PBigInt r,PBigInt a, PBigInt b);
void div(PBigInt r,PBigInt a, PBigInt b);
void idiv(PBigInt r,PBigInt a, PBigInt b);
void mod(PBigInt r,PBigInt a, PBigInt b);
void pow(PBigInt r,PBigInt a, PBigInt b);
void lt(PBigInt r, PBigInt a, PBigInt b);
void eq(PBigInt r, PBigInt a, PBigInt b);
void gt(PBigInt r, PBigInt a, PBigInt b);
void leq(PBigInt r, PBigInt a, PBigInt b);
void geq(PBigInt r, PBigInt a, PBigInt b);
void neq(PBigInt r, PBigInt a, PBigInt b);
void land(PBigInt r, PBigInt a, PBigInt b);
void lor(PBigInt r, PBigInt a, PBigInt b);
void lnot(PBigInt r, PBigInt a);
void band(PBigInt r, PBigInt a, PBigInt b);
void bor(PBigInt r, PBigInt a, PBigInt b);
void bxor(PBigInt r, PBigInt a, PBigInt b);
void bnot(PBigInt r, PBigInt a);
void shl(PBigInt r, PBigInt a, PBigInt b);
void shr(PBigInt r, PBigInt a, PBigInt b);
int isTrue(PBigInt a);
int toInt(PBigInt a);
};
#endif // ZQFIELD_H

32
cli.js
View File

@@ -23,6 +23,7 @@
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const Scalar = require("ffjavascript").Scalar;
const compiler = require("./src/compiler"); const compiler = require("./src/compiler");
@@ -30,12 +31,14 @@ const version = require("./package").version;
const argv = require("yargs") const argv = require("yargs")
.version(version) .version(version)
.usage("circom [input source circuit file] -o [output definition circuit file] -c [output c file]") .usage("circom [input source circuit file] -r [output r1cs file] -c [output c file] -w [output wasm file] -t [output wat file] -s [output sym file]")
.alias("o", "output") .alias("o", "output")
.alias("c", "csource") .alias("c", "csource")
.alias("w", "wasm") .alias("w", "wasm")
.alias("t", "wat")
.alias("s", "sym") .alias("s", "sym")
.alias("r", "r1cs") .alias("r", "r1cs")
.alias("p", "prime")
.alias("n", "newThreadTemplates") .alias("n", "newThreadTemplates")
.help("h") .help("h")
.alias("h", "help") .alias("h", "help")
@@ -71,18 +74,24 @@ const fullFileName = path.resolve(process.cwd(), inputFile);
const fileName = path.basename(fullFileName, ".circom"); const fileName = path.basename(fullFileName, ".circom");
const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp"; const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp";
const wasmName = typeof(argv.wasm) === "string" ? argv.wasm : fileName + ".wasm"; const wasmName = typeof(argv.wasm) === "string" ? argv.wasm : fileName + ".wasm";
const watName = typeof(argv.wat) === "string" ? argv.wat : fileName + ".wat";
const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs"; const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs";
const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym"; const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym";
const options = {}; const options = {};
options.reduceConstraints = !argv.fast; options.reduceConstraints = !argv.fast;
options.verbose = argv.verbose || false; options.verbose = argv.verbose || false;
options.sanityCheck = argv.sanitycheck;
if (argv.csource) { if (argv.csource) {
options.cSourceWriteStream = fs.createWriteStream(cSourceName); options.cSourceWriteStream = fs.createWriteStream(cSourceName);
} }
if (argv.wasm) { if (argv.wasm) {
options.wasmWriteStream = fs.createWriteStream(wasmName); options.wasmWriteStream = fs.createWriteStream(wasmName);
} }
if (argv.wat) {
options.watWriteStream = fs.createWriteStream(watName);
}
if (argv.r1cs) { if (argv.r1cs) {
options.r1csFileName = r1csName; options.r1csFileName = r1csName;
} }
@@ -92,11 +101,22 @@ if (argv.sym) {
if (argv.newThreadTemplates) { if (argv.newThreadTemplates) {
options.newThreadTemplates = new RegExp(argv.newThreadTemplates); options.newThreadTemplates = new RegExp(argv.newThreadTemplates);
} }
if (!argv.prime) {
options.prime = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
} else if (["BLS12-381", "BLS12381"]. indexOf(argv.prime.toUpperCase()) >=0) {
options.prime = Scalar.fromString("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001",16);
} else if (["BN-128", "BN128", "BN254", "BN-254"]. indexOf(argv.prime.toUpperCase()) >=0) {
options.prime = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
} else {
options.prime = Scalar.fromString(argv.prime);
}
compiler(fullFileName, options).then( () => { compiler(fullFileName, options).then( () => {
let cSourceDone = false; let cSourceDone = false;
let wasmDone = false; let wasmDone = false;
let symDone = false; let symDone = false;
let watDone = false;
if (options.cSourceWriteStream) { if (options.cSourceWriteStream) {
options.cSourceWriteStream.on("finish", () => { options.cSourceWriteStream.on("finish", () => {
cSourceDone = true; cSourceDone = true;
@@ -113,6 +133,14 @@ compiler(fullFileName, options).then( () => {
} else { } else {
wasmDone = true; wasmDone = true;
} }
if (options.watWriteStream) {
options.watWriteStream.on("finish", () => {
watDone = true;
finishIfDone();
});
} else {
watDone = true;
}
if (options.symWriteStream) { if (options.symWriteStream) {
options.symWriteStream.on("finish", () => { options.symWriteStream.on("finish", () => {
symDone = true; symDone = true;
@@ -122,7 +150,7 @@ compiler(fullFileName, options).then( () => {
symDone = true; symDone = true;
} }
function finishIfDone() { function finishIfDone() {
if ((cSourceDone)&&(symDone)&&(wasmDone)) { if ((cSourceDone)&&(symDone)&&(wasmDone)&&(watDone)) {
setTimeout(() => { setTimeout(() => {
process.exit(0); process.exit(0);
}, 300); }, 300);

View File

@@ -152,114 +152,93 @@ Size in bytes of the section
Section Type: 0x01 Section Type: 0x01
```` ````
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 4 │ FieldDefSize ┃ FieldDef ┃ field Id
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 4 │ 00 00 00 00 ┃ bigInt Format ┃ 4 │ 20 00 00 00 ┃ Field Size in bytes (fs)
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ fs │ 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 ┃ Prime size
┗━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 32 │ 01 00 00 00 ┃ nWires
┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓
4 is Id size ( Normally 4 (32bits)) 3201 00 00 00 nPubOut
┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓
is │ 01 00 00 00 ┃ nWires 32 │ 01 00 00 00 ┃ nPubIn
┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓
is │ 01 00 00 00 ┃ nPubOut 32 │ 01 00 00 00 ┃ nPrvIn
┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 64 │ 01 00 00 00 00 00 00 00 ┃ nLabels
┗━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓
is │ 01 00 00 00 ┃ nPubIn 32 │ 01 00 00 00 ┃ mConstraints
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ nPrvIn
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ nLabels
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ mConstraints
┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┛
```` ````
#### fieldDefSize #### field Size (fs)
Size: 4 bytes Size: 4 bytes
Format: Little-Endian Format: Little-Endian
Size of the field Definition Size in bytes of a field element. Mast be a multiple of 8.
Example: Example:
``` ```
0x00 0x0 0x00 0x00 0x00 0x0 0x00 0x00
``` ```
#### fieldDef #### Prime
Field dfinition the first 4 bytes are the type in LE. 0x0000001 Ar prime fields. Prime Number of the field
For the prime fields, the next bytes are the prime in variable length LE base 256 format.
NOTE: This number is independent of the bigInt Format defined next
#### bigInt Format
Size: 4 bytes
Format: Little-Endian
0 Means that the Big Int are variable size LE.
That is the First byte indicates the size and the remaining bytes are the number in little enfian (LSB first) base 256.
Numbers from 1 to 16383 are fixed size Litle endian format base 256.
Example: Example:
``` ```
0x00 0x00 0x00 0x00 0x010000f0_93f5e143_9170b979_48e83328_5d588181_b64550b8_29a031e1_724e6430
``` ```
#### Id Size (is)
Size: 4 bytes
Format: Little-Endian
Size of the identifiers for wires, labels and constraints. In small circuits this is going to be 4 (32 bits)
but can be increaset to 8 for bigger circiuits.
The only possible numbers are 4 or 8
#### Number of wires #### Number of wires
Size: `is` bytes Size: 4 bytes
Format: Little-Endian Format: Little-Endian
Total Number of wires including ONE signal (Index 0). Total Number of wires including ONE signal (Index 0).
#### Number of public outputs #### Number of public outputs
Size: `is` bytes Size: 4 bytes
Format: Little-Endian Format: Little-Endian
Total Number of wires public output wires. They should be starting at idx 1 Total Number of wires public output wires. They should be starting at idx 1
#### Number of public inputs #### Number of public inputs
Size: `is` bytes Size: 4 bytes
Format: Little-Endian Format: Little-Endian
Total Number of wires public input wires. They should be starting just after the public output Total Number of wires public input wires. They should be starting just after the public output
#### Number of private inputs #### Number of private inputs
Size: `is` bytes Size: 4 bytes
Format: Little-Endian
Total Number of wires private input wires. They should be starting just after the public inputs
#### Number of Labels
Size: 8 bytes
Format: Little-Endian Format: Little-Endian
Total Number of wires private input wires. They should be starting just after the public inputs Total Number of wires private input wires. They should be starting just after the public inputs
#### Number of constraints (m) #### Number of constraints (m)
Size: `ìs` bytes Size: 4 bytes
Format: Little-Endian Format: Little-Endian
Total Number of constraints Total Number of constraints
@@ -269,115 +248,115 @@ Total Number of constraints
Section Type: 0x02 Section Type: 0x02
```` ````
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
is │ nA ┃ 32 │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
is │ wireId_1 ┃ V │ a_{0,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ a_{0,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
is │ wireId_2 ┃ V │ a_{0,wireId_2} ┃ │ 32 │ wireId_2 ┃ fs │ a_{0,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │ ... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nA ┃ V │ a_{0,wireId_nA} ┃ │ 32 │ wireId_nA ┃ fs │ a_{0,wireId_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
is │ nB ┃ 32 │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_1 ┃ V │ b_{0,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ b_{0,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
is │ wireId_2 ┃ V │ b_{0,wireId_2} ┃ ╲ 32 │ wireId_2 ┃ fs │ b_{0,wireId_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_0 ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_0
... ... ... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nB ┃ V │ b_{0,wireId_nB} ┃ │ 32 │ wireId_nB ┃ fs │ b_{0,wireId_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
is │ nC ┃ 32 │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_1 ┃ V │ c_{0,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ c_{0,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
is │ wireId_2 ┃ V │ c_{0,wireId_2} ┃ │ 32 │ wireId_2 ┃ fs │ c_{0,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │ ... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nC ┃ V │ c_{0,wireId_nC} ┃ 32 │ wireId_nC ┃ fs │ c_{0,wireId_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
is │ nA ┃ 32 │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
is │ wireId_1 ┃ V │ a_{1,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ a_{1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
is │ wireId_2 ┃ V │ a_{1,wireId_2} ┃ │ 32 │ wireId_2 ┃ fs │ a_{1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │ ... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nA ┃ V │ a_{1,wireId_nA} ┃ │ 32 │ wireId_nA ┃ fs │ a_{1,wireId_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
is │ nB ┃ 32 │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_1 ┃ V │ b_{1,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ b_{1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
is │ wireId_2 ┃ V │ b_{1,wireId_2} ┃ ╲ 32 │ wireId_2 ┃ fs │ b_{1,wireId_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_1 ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_1
... ... ... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nB ┃ V │ b_{1,wireId_nB} ┃ │ 32 │ wireId_nB ┃ fs │ b_{1,wireId_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
is │ nC ┃ 32 │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_1 ┃ V │ c_{1,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ c_{1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
is │ wireId_2 ┃ V │ c_{1,wireId_2} ┃ │ 32 │ wireId_2 ┃ fs │ c_{1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │ ... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nC ┃ V │ c_{1,wireId_nC} ┃ 32 │ wireId_nC ┃ fs │ c_{1,wireId_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
... ...
... ...
... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
is │ nA ┃ 32 │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
is │ wireId_1 ┃ V │ a_{m-1,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ a_{m-1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
is │ wireId_2 ┃ V │ a_{m-1,wireId_2} ┃ │ 32 │ wireId_2 ┃ fs │ a_{m-1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │ ... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nA ┃ V │ a_{m-1,wireId_nA} ┃ │ 32 │ wireId_nA ┃ fs │ a_{m-1,wireId_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
is │ nB ┃ 32 │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_1 ┃ V │ b_{m-1,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ b_{m-1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
is │ wireId_2 ┃ V │ b_{m-1,wireId_2} ┃ ╲ 32 │ wireId_2 ┃ fs │ b_{m-1,wireId_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_{m-1} ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_{m-1}
... ... ... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nB ┃ V │ b_{m-1,wireId_nB} ┃ │ 32 │ wireId_nB ┃ fs │ b_{m-1,wireId_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
is │ nC ┃ 32 │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_1 ┃ V │ c_{m-1,wireId_1} ┃ │ 32 │ wireId_1 ┃ fs │ c_{m-1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
is │ wireId_2 ┃ V │ c_{m-1,wireId_2} ┃ │ 32 │ wireId_2 ┃ fs │ c_{m-1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │ ... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
is │ wireId_nC ┃ V │ c_{m-1,wireId_nC} ┃ 32 │ wireId_nC ┃ fs │ c_{m-1,wireId_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
```` ````
@@ -401,7 +380,7 @@ $$
#### Number of nonZero Factors #### Number of nonZero Factors
Size: `ìs` bytes Size: 4 bytes
Format: Little-Endian Format: Little-Endian
Total number of non Zero factors in the linear compination. Total number of non Zero factors in the linear compination.
@@ -414,16 +393,14 @@ For each factor we have the index of the factor and the value of the factor.
#### WireId of the factor #### WireId of the factor
Size: `is` bytes Size: 4 bytes
Format: Little-Endian Format: Little-Endian
WireId of the nonZero Factor WireId of the nonZero Factor
#### Value of the factor #### Value of the factor
The first byte indicate the length N in bytes of the number in the upcoming bytes. This is the factor that multiplies the associated wire in the linear convination.
The next N bytes represent the value in Little Endian format.
For example, to represent the linear combination: For example, to represent the linear combination:
@@ -436,13 +413,13 @@ The linear combination would be represented as:
```` ````
┏━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━┓
┃ 03 00 00 00 ┃ ┃ 03 00 00 00 ┃
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ 04 00 00 00 ┃ 01 05 ┃ 04 00 00 00 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ 05 00 00 00 ┃ 01 08 ┃ 05 00 00 00 ┃ 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ 76 03 00 00 ┃ 02 04 01 ┃ 76 03 00 00 ┃ 04010000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```` ````
@@ -452,7 +429,7 @@ Section Type: 0x03
```` ````
┏━━┳━━━━━━━━━━━━━━━━━━━┳━━┳━━━━━━━━━━━━━━━━━━━┓ ┏━━┳━━━━━━━━━━━━━━━━━━━┓ ┏━━┳━━━━━━━━━━━━━━━━━━━┳━━┳━━━━━━━━━━━━━━━━━━━┓ ┏━━┳━━━━━━━━━━━━━━━━━━━┓
is│ labelId of Wire_0 ┃is│ labelId of Wire_1 ┃ ... ┃is│ labelId of Wire_n ┃ 64│ labelId of Wire_0 ┃64│ labelId of Wire_1 ┃ ... ┃64│ labelId of Wire_n ┃
┗━━┻━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━━━━━━━━━━━━━━━┛ ┗━━┻━━━━━━━━━━━━━━━━━━━┛ ┗━━┻━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━━━━━━━━━━━━━━━┛ ┗━━┻━━━━━━━━━━━━━━━━━━━┛
```` ````
@@ -500,176 +477,170 @@ $$
The format will be: The format will be:
```` ````
┏━━━━━━━━━━━━━━ ┏━━━━━━━━━━┓
┃ 72 31 63 77 Magic ┃ 72316377 Magic
┣━━━━━━━━━━━━━━ ┣━━━━━━━━━━┫
┃ 01 00 00 00 ┃ Version ┃ 01000000 ┃ Version
┣━━━━━━━━━━━━━━ ┣━━━━━━━━━━┫
┃ 03 00 00 00 ┃ nSections ┃ 03000000 ┃ nSections
┗━━━━━━━━━━━━━━ ┗━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ 01 00 00 00 ┃ 49 00 00 00 ┃ SectionType: Header ┃ 01000000 ┃ 40000000 00000000 ┃ SectionType: Header
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━ ┏━━━━━━━━━━┓
┃ 25 00 00 00 10 00 00 00 ┃ FieldDefSize FieldDef ┃ 20000000 Field Size
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430┃ ┃ 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
┣━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┣━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ 00 00 00 00 Big Int format ┃ 07000000# of wires
┣━━━━━━━━━━━━━━ ┣━━━━━━━━━━┫
┃ 04 00 00 00 Id Size ┃ 01000000 ┃ # Public Outs
┣━━━━━━━━━━━━━━ ┣━━━━━━━━━━┫
┃ 07 00 00 00 ┃ # of wires ┃ 02000000 ┃ # Public Ins
┣━━━━━━━━━━━━━━ ┣━━━━━━━━━━┫
┃ 01 00 00 00 ┃ # Public Outs ┃ 03000000 ┃ # Private Ins
┣━━━━━━━━━━━━━━ ┣━━━━━━━━━━┻━━━━━━━━┓
02 00 00 00 ┃ # Public Ins e8030000 00000000 ┃ # Labels
┣━━━━━━━━━━━━━━ ┣━━━━━━━━━━┳━━━━━━━━┛
┃ 03 00 00 00 ┃ # Private Ins ┃ 03000000 ┃ # Constraints
┣━━━━━━━━━━━━━━ ━━━━━━━━━━
┃ e8 03 00 00 ┃ # Labels ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┣━━━━━━━━━━━━━━┫ ┃ 02000000 ┃ 88200000 00000000 ┃ SectionType: Constraints
┃ 03 00 00 00 ┃ # Constraints ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛
━━━━━━━━━━━━━━┛ ━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓ ┃ 02000000 ┃
┃ 02 00 00 00 ┃ 8b 00 00 00 ┃ SectionType: Constraints ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛ ┃ 05000000 ┃ 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
┏━━━━━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0 ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 02 00 00 00 ┃ 06000000 ┃ 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
━━━━━━━━━━━━━━╋━━━━━━━━┓ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ 05 00 00 00 ┃ 01 03 ┃ ┏━━━━━━━━━━┓
┣━━━━━━━━━━━━━━╋━━━━━━━━┫ ┃ 03000000 ┃
┃ 06 00 00 00 ┃ 01 08 ┃ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┗━━━━━━━━━━━━━━┻━━━━━━━━┛ ┃ 00000000 ┃ 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
┏━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 03 00 00 00 ┃ 02000000 ┃ 01140000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━╋━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 00 00 00 00 ┃ 01 02 ┃ 03000000 ┃ 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
━━━━━━━━━━━━━━╋━━━━━━━━┫ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ 02 00 00 00 ┃ 01 14 ┃ ┏━━━━━━━━━━┓
┣━━━━━━━━━━━━━━╋━━━━━━━━┫ ┃ 02000000 ┃
┃ 03 00 00 00 ┃ 01 0C ┃ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┗━━━━━━━━━━━━━━┻━━━━━━━━┛ ┃ 00000000 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
┏━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 02 00 00 00 ┃ 02000000 ┃ 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
━━━━━━━━━━━━━━╋━━━━━━━━┓ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ 00 00 00 00 ┃ 01 05 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
┃ 02 00 00 00 ┃ 01 07 ┃
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
┏━━━━━━━━━━━━━━┓ Constraint 1: (4w_1 + 8w_4 + 3w_5) * (6w_6 + 44w_3) = 0 ┏━━━━━━━━━━┓ Constraint 1: (4w_1 + 8w_4 + 3w_5) * (6w_6 + 44w_3) = 0
┃ 03 00 00 00 ┃ 03000000 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 01 00 00 00 ┃ 01 04 ┃ 01000000 ┃ 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 04 00 00 00 ┃ 01 08 ┃ 04000000 ┃ 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 05 00 00 00 ┃ 01 03 ┃ 05000000 ┃ 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┗━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━ ┏━━━━━━━━━━┓
┃ 02 00 00 00 ┃ 02000000 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 03 00 00 00 ┃ 01 2C ┃ 03000000 ┃ 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 06 00 00 00 ┃ 01 06 ┃ 06000000 ┃ 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┗━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━ ┏━━━━━━━━━━┓
┃ 00 00 00 00 ┃ 00000000 ┃
┗━━━━━━━━━━━━━━ ┗━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┓ Constraint 2: (4w_6) * (6w_0 + 5w_3 + 11w_2) - (600w_6) = 0 ┏━━━━━━━━━━┓ Constraint 2: (4w_6) * (6w_0 + 5w_3 + 11w_2) - (600w_6) = 0
┃ 01 00 00 00 ┃ 01000000 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 06 00 00 00 ┃ 01 04 ┃ 06000000 ┃ 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┗━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━ ┏━━━━━━━━━━┓
┃ 03 00 00 00 ┃ 03000000 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 00 00 00 00 ┃ 01 06 ┃ 00000000 ┃ 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 02 00 00 00 ┃ 01 0B ┃ 02000000 ┃ 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┣━━━━━━━━━━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ 03 00 00 00 ┃ 01 05 ┃ 03000000 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┗━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━ ┏━━━━━━━━━━┓
┃ 01 00 00 00 ┃ 01000000 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 06 00 00 00 02 58 02 ┃ 06000000 ┃ 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ 03 00 00 00 1c 00 00 00 ┃ Wire to Label Map ┃ 03000000 ┃ 38000000 00000000 ┃ Wire to Label Map
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━
┃ 00 00 00 00 ┃ 00000000 00000000 ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━━━
┃ 03 00 00 00 ┃ 03000000 00000000 ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━━━
┃ 0a 00 00 00 ┃ 0a000000 00000000 ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━━━
┃ 0b 00 00 00 ┃ 0b000000 00000000 ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━━━
┃ 0c 00 00 00 ┃ 0c000000 00000000 ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━━━
┃ 0f 00 00 00 ┃ 0f000000 00000000 ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━━━━━━━━━
┃ 44 01 00 00 ┃ 44010000 00000000 ┃
┗━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━
```` ````
And the binary representation in Hex: And the binary representation in Hex:
```` ````
72 31 63 77 72316377
01 00 00 00 01000000
03 00 00 00 03000000
01 00 00 00 49 00 00 00 01000000 40000000 00000000
25 00 00 00 10 00 00 00 20000000
20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
00 00 00 00 07000000
04 00 00 00 01000000
07 00 00 00 02000000
01 00 00 00 03000000
02 00 00 00 e8030000 00000000
03 00 00 00 03000000
e8 03 00 00 02000000 88200000 00000000
03 00 00 00 02000000
02 00 00 00 8b 00 00 00 05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
02 00 00 00 06000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
05 00 00 00 01 03 03000000
06 00 00 00 01 08 00000000 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
03 00 00 00 02000000 01140000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00 00 00 00 01 02 03000000 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
02 00 00 00 01 14 02000000
03 00 00 00 01 0C 00000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
02 00 00 00 02000000 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00 00 00 00 01 05 03000000
02 00 00 00 01 07 01000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
03 00 00 00 04000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
01 00 00 00 01 04 05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
04 00 00 00 01 08 02000000
05 00 00 00 01 03 03000000 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
02 00 00 00 06000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
03 00 00 00 01 2C 00000000
06 00 00 00 01 06 01000000
00 00 00 00 06000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
01 00 00 00 03000000
06 00 00 00 01 04 00000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
03 00 00 00 02000000 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00 00 00 00 01 06 03000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
02 00 00 00 01 0B 01000000
03 00 00 00 01 05 06000000 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
01 00 00 00 03000000 38000000 00000000
06 00 00 00 02 58 02 00000000 00000000
03 00 00 00 1c 00 00 00 03000000 00000000
00 00 00 00 0a000000 00000000
03 00 00 00 0b000000 00000000
0a 00 00 00 0c000000 00000000
0b 00 00 00 0f000000 00000000
0c 00 00 00 44010000 00000000
0f 00 00 00
44 01 00 00
```` ````

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +1,4 @@
module.exports.compiler = require("./src/compiler.js"); module.exports.compiler = require("./src/compiler.js");
module.exports.c_tester = require("./src/c_tester.js"); module.exports.c_tester = require("./ports/c/tester.js");
module.exports.tester = require("./src/c_tester.js"); module.exports.wasm_tester = require("./ports/wasm/tester.js");
module.exports.tester = module.exports.wasm_tester;

1174
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.0.35", "version": "0.5.12",
"description": "Language to generate logic circuits", "description": "Language to generate logic circuits",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@@ -29,20 +29,20 @@
"url": "https://github.com/iden3/circom.git" "url": "https://github.com/iden3/circom.git"
}, },
"dependencies": { "dependencies": {
"big-integer": "^1.6.32", "chai": "^4.2.0",
"ejs": "^3.0.1", "circom_runtime": "0.0.6",
"fflib": "0.0.2", "fastfile": "0.0.2",
"ffiasm": "0.0.2",
"ffjavascript": "0.1.2",
"ffwasm": "0.0.7",
"fnv-plus": "^1.3.1", "fnv-plus": "^1.3.1",
"optimist": "^0.6.1", "r1csfile": "0.0.5",
"rimraf-promise": "^2.0.0",
"tmp-promise": "^2.0.2", "tmp-promise": "^2.0.2",
"yargs": "^12.0.2" "wasmbuilder": "0.0.10"
}, },
"devDependencies": { "devDependencies": {
"chai": "^4.2.0", "eslint": "^6.8.0",
"eslint": "^5.16.0",
"eslint-plugin-mocha": "^5.3.0",
"jison": "^0.4.18", "jison": "^0.4.18",
"snarkjs": "0.1.14" "yargs": "^15.3.1"
} }
} }

View File

@@ -132,10 +132,8 @@ include { return 'include'; }
%{ %{
const bigInt = require('big-integer'); const Scalar = require('ffjavascript').Scalar;
const util = require('util'); const util = require('util');
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const __MASK__ = new bigInt(2).pow(253).minus(1);
function setLines(dst, first, last) { function setLines(dst, first, last) {
last = last || first; last = last || first;
@@ -266,20 +264,12 @@ identifierList
ifStatment ifStatment
: 'if' '(' expression ')' statment 'else' statment : 'if' '(' expression ')' statment 'else' statment
{ {
if ($3.type == "NUMBER") { $$ = { type: "IF", condition: $3, then: $5, else: $7 };
$$ = !$3.value.eq(0) ? $5 : $7;
} else {
$$ = { type: "IF", condition: $3, then: $5, else: $7 };
}
setLines($$, @1, @7); setLines($$, @1, @7);
} }
| 'if' '(' expression ')' statment | 'if' '(' expression ')' statment
{ {
if ($3.type == "NUMBER") { $$ = { type: "IF", condition: $3, then: $5 };
$$ = !$3.value.eq(0) ? $5 : { type: "NUMBER", value: bigInt(0) };
} else {
$$ = { type: "IF", condition: $3, then: $5 };
}
setLines($$, @1, @5); setLines($$, @1, @5);
} }
; ;
@@ -451,11 +441,7 @@ e17
} }
| e17 '?' e17 ':' e17 %prec TERCOND | e17 '?' e17 ':' e17 %prec TERCOND
{ {
if ($1.type == "NUMBER") { $$ = { type: "OP", op: "?", values: [$1, $3, $5] };
$$ = !$1.value.eq(0) ? $3 : $5;
} else {
$$ = { type: "OP", op: "?", values: [$1, $3, $5] };
}
setLines($$, @1, @5); setLines($$, @1, @5);
} }
| e16 %prec EMPTY | e16 %prec EMPTY
@@ -478,11 +464,7 @@ e16
e15 e15
: e15 '||' e14 : e15 '||' e14
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "||", values: [$1, $3] };
$$ = { type: "NUMBER", value: !$1.value.eq(0) || !$3.value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "||", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e14 %prec EMPTY | e14 %prec EMPTY
@@ -494,11 +476,7 @@ e15
e14 e14
: e14 '&&' e13 : e14 '&&' e13
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "&&", values: [$1, $3] };
$$ = { type: "NUMBER", value: !$1.value.eq(0) && !$3.value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "&&", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e13 %prec EMPTY | e13 %prec EMPTY
@@ -510,11 +488,7 @@ e14
e13 e13
: e13 '|' e12 : e13 '|' e12
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "|", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.or($3.value).and(__MASK__) };
} else {
$$ = { type: "OP", op: "|", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e12 %prec EMPTY | e12 %prec EMPTY
@@ -527,11 +501,7 @@ e13
e12 e12
: e12 '^' e11 : e12 '^' e11
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "^", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.xor($3.value).and(__MASK__) };
} else {
$$ = { type: "OP", op: "^", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e11 %prec EMPTY | e11 %prec EMPTY
@@ -543,11 +513,7 @@ e12
e11 e11
: e11 '&' e10 : e11 '&' e10
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "&", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.and($3.value).and(__MASK__) };
} else {
$$ = { type: "OP", op: "&", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e10 %prec EMPTY | e10 %prec EMPTY
@@ -562,20 +528,12 @@ e11
e10 e10
: e10 '==' e9 : e10 '==' e9
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "==", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.equals($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "==", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e10 '!=' e9 | e10 '!=' e9
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "!=", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.eq($3.value) ? bigInt(0) : bigInt(1) };
} else {
$$ = { type: "OP", op: "!=", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 %prec EMPTY | e9 %prec EMPTY
@@ -587,38 +545,22 @@ e10
e9 e9
: e9 '<=' e7 : e9 '<=' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "<=", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.lesserOrEquals($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "<=", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 '>=' e7 | e9 '>=' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: ">=", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.greaterOrEquals($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: ">=", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 '<' e7 | e9 '<' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "<", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.lesser($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "<", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 '>' e7 | e9 '>' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: ">", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.greater($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: ">", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e7 %prec EMPTY | e7 %prec EMPTY
@@ -630,22 +572,12 @@ e9
e7 e7
: e7 '<<' e6 : e7 '<<' e6
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "<<", values: [$1, $3] };
let v = $3.value.greater(256) ? 256 : $3.value.value;
$$ = { type: "NUMBER", value: $1.value.shiftLeft(v).and(__MASK__) };
} else {
$$ = { type: "OP", op: "<<", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e7 '>>' e6 | e7 '>>' e6
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: ">>", values: [$1, $3] };
let v = $3.value.greater(256) ? 256 : $3.value.value;
$$ = {type: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) };
} else {
$$ = { type: "OP", op: ">>", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e6 %prec EMPTY | e6 %prec EMPTY
@@ -657,20 +589,12 @@ e7
e6 e6
: e6 '+' e5 : e6 '+' e5
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "+", values: [$1, $3] };
$$ = { type: "NUMBER", value: ($1.value.plus($3.value)).mod(__P__) };
} else {
$$ = { type: "OP", op: "+", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e6 '-' e5 | e6 '-' e5
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "-", values: [$1, $3] };
$$ = { type: "NUMBER", value: ($1.value.plus(__P__).minus($3.value)).mod(__P__) };
} else {
$$ = { type: "OP", op: "-", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 %prec EMPTY | e5 %prec EMPTY
@@ -683,38 +607,22 @@ e6
e5 e5
: e5 '*' e4 : e5 '*' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "*", values: [$1, $3] };
$$ = { type: "NUMBER", value: ($1.value.times($3.value)).mod(__P__) };
} else {
$$ = { type: "OP", op: "*", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 '/' e4 | e5 '/' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "/", values: [$1, $3] };
$$ = { type: "NUMBER", value: ($1.value.times($3.value.modInv(__P__))).mod(__P__) };
} else {
$$ = { type: "OP", op: "/", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 '\\' e4 | e5 '\\' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "\\", values: [$1, $3] };
$$ = { type: "NUMBER", value: ($1.value.divide($3.value)) };
} else {
$$ = { type: "OP", op: "\\", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 '%' e4 | e5 '%' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "%", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.mod($3.value) };
} else {
$$ = { type: "OP", op: "%", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e4 %prec EMPTY | e4 %prec EMPTY
@@ -726,11 +634,7 @@ e5
e4 e4
: e4 '**' e3 : e4 '**' e3
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) { $$ = { type: "OP", op: "**", values: [$1, $3] };
$$ = { type: "NUMBER", value: $1.value.modPow($3.value, __P__) };
} else {
$$ = { type: "OP", op: "**", values: [$1, $3] };
}
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e3 %prec EMPTY | e3 %prec EMPTY
@@ -758,29 +662,17 @@ e3
} }
| '-' e3 %prec UMINUS | '-' e3 %prec UMINUS
{ {
if ($2.type == "NUMBER") { $$ = { type: "OP", op: "UMINUS", values: [$2] };
$$ = { type: "NUMBER", value: __P__.minus($2.value).mod(__P__) };
} else {
$$ = { type: "OP", op: "UMINUS", values: [$2] };
}
setLines($$, @1, @2); setLines($$, @1, @2);
} }
| '!' e3 | '!' e3
{ {
if ($2.type == "NUMBER") { $$ = { type: "OP", op: "!", values: [$2] };
$$ = { type: "NUMBER", value: $2.value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "!", values: [$2] };
}
setLines($$, @1, @2); setLines($$, @1, @2);
} }
| '~' e3 | '~' e3
{ {
if ($2.type == "NUMBER") { $$ = { type: "OP", op: "~", values: [$2] };
$$ = { type: "NUMBER", value: $2.value.xor(__MASK__) };
} else {
$$ = { type: "OP", op: "~", values: [$2] };
}
setLines($$, @1, @2); setLines($$, @1, @2);
} }
| e2 %prec EMPTY | e2 %prec EMPTY
@@ -817,12 +709,12 @@ e0
} }
| DECNUMBER | DECNUMBER
{ {
$$ = {type: "NUMBER", value: bigInt($1).mod(__P__) } $$ = {type: "NUMBER", value: Scalar.fromString($1) }
setLines($$, @1); setLines($$, @1);
} }
| HEXNUMBER | HEXNUMBER
{ {
$$ = {type: "NUMBER", value: bigInt($1.substr(2).toUpperCase(), 16).mod(__P__) } $$ = {type: "NUMBER", value: Scalar.fromString($1.substr(2).toUpperCase(), 16) }
setLines($$, @1); setLines($$, @1);
} }
| '(' expression ')' %prec EMPTY | '(' expression ')' %prec EMPTY

View File

@@ -146,21 +146,13 @@ case 20:
break; break;
case 21: case 21:
if ($$[$0-4].type == "NUMBER") { this.$ = { type: "IF", condition: $$[$0-4], then: $$[$0-2], else: $$[$0] };
this.$ = !$$[$0-4].value.eq(0) ? $$[$0-2] : $$[$0];
} else {
this.$ = { type: "IF", condition: $$[$0-4], then: $$[$0-2], else: $$[$0] };
}
setLines(this.$, _$[$0-6], _$[$0]); setLines(this.$, _$[$0-6], _$[$0]);
break; break;
case 22: case 22:
if ($$[$0-2].type == "NUMBER") { this.$ = { type: "IF", condition: $$[$0-2], then: $$[$0] };
this.$ = !$$[$0-2].value.eq(0) ? $$[$0] : { type: "NUMBER", value: bigInt(0) };
} else {
this.$ = { type: "IF", condition: $$[$0-2], then: $$[$0] };
}
setLines(this.$, _$[$0-4], _$[$0]); setLines(this.$, _$[$0-4], _$[$0]);
break; break;
@@ -321,11 +313,7 @@ case 50:
break; break;
case 51: case 51:
if ($$[$0-4].type == "NUMBER") { this.$ = { type: "OP", op: "?", values: [$$[$0-4], $$[$0-2], $$[$0]] };
this.$ = !$$[$0-4].value.eq(0) ? $$[$0-2] : $$[$0];
} else {
this.$ = { type: "OP", op: "?", values: [$$[$0-4], $$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-4], _$[$0]); setLines(this.$, _$[$0-4], _$[$0]);
break; break;
@@ -336,71 +324,43 @@ case 52: case 53: case 54: case 56: case 58: case 60:
break; break;
case 55: case 55:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "||", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: !$$[$0-2].value.eq(0) || !$$[$0].value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "||", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 57: case 57:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "&&", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: !$$[$0-2].value.eq(0) && !$$[$0].value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "&&", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 59: case 59:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "|", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.or($$[$0].value).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "|", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 61: case 61:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "^", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.xor($$[$0].value).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "^", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 63: case 63:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "&", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.and($$[$0].value).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "&", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 65: case 65:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "==", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.equals($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "==", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 66: case 66:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "!=", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.eq($$[$0].value) ? bigInt(0) : bigInt(1) };
} else {
this.$ = { type: "OP", op: "!=", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
@@ -411,63 +371,37 @@ case 67: case 72:
break; break;
case 68: case 68:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "<=", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.lesserOrEquals($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "<=", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 69: case 69:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: ">=", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.greaterOrEquals($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: ">=", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 70: case 70:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "<", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.lesser($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "<", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 71: case 71:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: ">", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.greater($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: ">", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 73: case 73:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "<<", values: [$$[$0-2], $$[$0]] };
let v = $$[$0].value.greater(256) ? 256 : $$[$0].value.value;
this.$ = { type: "NUMBER", value: $$[$0-2].value.shiftLeft(v).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "<<", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 74: case 74:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: ">>", values: [$$[$0-2], $$[$0]] };
let v = $$[$0].value.greater(256) ? 256 : $$[$0].value.value;
this.$ = {type: "NUMBER", value: $$[$0-2].value.shiftRight(v).and(__MASK__) };
} else {
this.$ = { type: "OP", op: ">>", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
@@ -478,71 +412,43 @@ case 75:
break; break;
case 76: case 76:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "+", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: ($$[$0-2].value.plus($$[$0].value)).mod(__P__) };
} else {
this.$ = { type: "OP", op: "+", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 77: case 77:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "-", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: ($$[$0-2].value.plus(__P__).minus($$[$0].value)).mod(__P__) };
} else {
this.$ = { type: "OP", op: "-", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 79: case 79:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "*", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: ($$[$0-2].value.times($$[$0].value)).mod(__P__) };
} else {
this.$ = { type: "OP", op: "*", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 80: case 80:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "/", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: ($$[$0-2].value.times($$[$0].value.modInv(__P__))).mod(__P__) };
} else {
this.$ = { type: "OP", op: "/", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 81: case 81:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "\\", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: ($$[$0-2].value.divide($$[$0].value)) };
} else {
this.$ = { type: "OP", op: "\\", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 82: case 82:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "%", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.mod($$[$0].value) };
} else {
this.$ = { type: "OP", op: "%", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 84: case 84:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) { this.$ = { type: "OP", op: "**", values: [$$[$0-2], $$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0-2].value.modPow($$[$0].value, __P__) };
} else {
this.$ = { type: "OP", op: "**", values: [$$[$0-2], $$[$0]] };
}
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
@@ -566,31 +472,19 @@ case 88:
break; break;
case 89: case 89:
if ($$[$0].type == "NUMBER") { this.$ = { type: "OP", op: "UMINUS", values: [$$[$0]] };
this.$ = { type: "NUMBER", value: __P__.minus($$[$0].value).mod(__P__) };
} else {
this.$ = { type: "OP", op: "UMINUS", values: [$$[$0]] };
}
setLines(this.$, _$[$0-1], _$[$0]); setLines(this.$, _$[$0-1], _$[$0]);
break; break;
case 90: case 90:
if ($$[$0].type == "NUMBER") { this.$ = { type: "OP", op: "!", values: [$$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0].value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "!", values: [$$[$0]] };
}
setLines(this.$, _$[$0-1], _$[$0]); setLines(this.$, _$[$0-1], _$[$0]);
break; break;
case 91: case 91:
if ($$[$0].type == "NUMBER") { this.$ = { type: "OP", op: "~", values: [$$[$0]] };
this.$ = { type: "NUMBER", value: $$[$0].value.xor(__MASK__) };
} else {
this.$ = { type: "OP", op: "~", values: [$$[$0]] };
}
setLines(this.$, _$[$0-1], _$[$0]); setLines(this.$, _$[$0-1], _$[$0]);
break; break;
@@ -613,13 +507,13 @@ case 97: case 102: case 103:
break; break;
case 98: case 98:
this.$ = {type: "NUMBER", value: bigInt($$[$0]).mod(__P__) } this.$ = {type: "NUMBER", value: Scalar.fromString($$[$0]) }
setLines(this.$, _$[$0]); setLines(this.$, _$[$0]);
break; break;
case 99: case 99:
this.$ = {type: "NUMBER", value: bigInt($$[$0].substr(2).toUpperCase(), 16).mod(__P__) } this.$ = {type: "NUMBER", value: Scalar.fromString($$[$0].substr(2).toUpperCase(), 16) }
setLines(this.$, _$[$0]); setLines(this.$, _$[$0]);
break; break;
@@ -866,10 +760,8 @@ parse: function parse(input) {
return true; return true;
}}; }};
const bigInt = require('big-integer'); const Scalar = require('ffjavascript').Scalar;
const util = require('util'); const util = require('util');
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const __MASK__ = new bigInt(2).pow(253).minus(1);
function setLines(dst, first, last) { function setLines(dst, first, last) {
last = last || first; last = last || first;
@@ -1365,7 +1257,7 @@ case 77: console.log("INVALID: " + yy_.yytext); return 'INVALID'
break; break;
} }
}, },
rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:~)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/], rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:~)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/],
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],"inclusive":true}} conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],"inclusive":true}}
}); });
return lexer; return lexer;

View File

@@ -1,10 +1,11 @@
const streamFromMultiArray = require("./stream_from_multiarray"); const streamFromMultiArray = require("../../src/streamfromarray_txt.js");
const bigInt = require("big-integer"); const utils = require("../../src/utils");
const utils = require("./utils");
const assert = require("assert"); const assert = require("assert");
const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field;
function ref2src(c) { function ref2src(c) {
if (c[0] == "R") { if ((c[0] == "R")||(c[0] == "RI")) {
return c[1]; return c[1];
} else if (c[0] == "V") { } else if (c[0] == "V") {
return c[1].toString(); return c[1].toString();
@@ -94,6 +95,9 @@ class CodeBuilderC {
this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr}); this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
} }
log(val) {
this.ops.push({op: "LOG", val});
}
concat(cb) { concat(cb) {
this.ops.push(...cb.ops); this.ops.push(...cb.ops);
@@ -211,6 +215,8 @@ class CodeBuilderC {
code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`); code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`);
} else if (o.op == "CHECKCONSTRAINT") { } else if (o.op == "CHECKCONSTRAINT") {
code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`); code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`);
} else if (o.op == "LOG") {
code.push(`ctx->log(${ref2src(o.val)});`);
} }
}); });
} }
@@ -335,13 +341,16 @@ class FunctionBuilderC {
} }
class BuilderC { class BuilderC {
constructor() { constructor(p) {
this.F = new F1Field(p);
this.hashMaps={}; this.hashMaps={};
this.componentEntriesTables={}; this.componentEntriesTables={};
this.sizes ={}; this.sizes ={};
this.constants = []; this.constants = [];
this.functions = []; this.functions = [];
this.components = []; this.components = [];
this.usedConstants = {};
} }
setHeader(header) { setHeader(header) {
@@ -362,7 +371,11 @@ class BuilderC {
} }
addConstant(c) { addConstant(c) {
c = this.F.e(c);
const cS = c.toString();
if (typeof this.usedConstants[cS] != "undefined") return this.usedConstants[cS];
this.constants.push(c); this.constants.push(c);
this.usedConstants[cS] = this.constants.length - 1;
return this.constants.length - 1; return this.constants.length - 1;
} }
@@ -460,8 +473,6 @@ class BuilderC {
_buildConstants(code) { _buildConstants(code) {
const self = this; const self = this;
const n64 = Math.floor((self.header.P.bitLength() - 1) / 64)+1;
const R = bigInt.one.shiftLeft(n64*64);
code.push("// Constants"); code.push("// Constants");
code.push(`FrElement _constants[${self.constants.length}] = {`); code.push(`FrElement _constants[${self.constants.length}] = {`);
@@ -471,12 +482,19 @@ class BuilderC {
code.push("};"); code.push("};");
function number2Code(n) { function number2Code(n) {
if (n.lt(bigInt("80000000", 16)) ) { const minShort = self.F.neg(self.F.e("80000000"));
return addShortMontgomeryPositive(n); const maxShort = self.F.e("7FFFFFFF", 16);
}
if (n.geq(self.header.P.minus(bigInt("80000000", 16))) ) { if ( (self.F.geq(n, minShort))
return addShortMontgomeryNegative(n); &&(self.F.leq(n, maxShort)))
{
if (self.F.geq(n, self.F.zero)) {
return addShortMontgomeryPositive(n);
} else {
return addShortMontgomeryNegative(n);
}
} }
return addLongMontgomery(n); return addLongMontgomery(n);
@@ -486,7 +504,7 @@ class BuilderC {
function addShortMontgomeryNegative(a) { function addShortMontgomeryNegative(a) {
const b = a.minus(self.header.P); const b = -Scalar.toNumber(self.F.neg(a));
return `${b.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`; return `${b.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`;
} }
@@ -495,25 +513,31 @@ class BuilderC {
} }
function getLongString(a) { function getLongString(a) {
let r = bigInt(a);
let S = ""; let S = "";
let i = 0; const arr = Scalar.toArray(a, 0x100000000);
while (!r.isZero()) { for (let i=0; i<self.F.n64*2; i+=2) {
if (S!= "") S = S+","; const idx = arr.length-2-i;
S += "0x" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16) + "LL";
i++; if (i>0) S = S + ",";
r = r.shiftRight(64);
} if ( idx >=0) {
while (i<n64) { let msb = arr[idx].toString(16);
if (S!= "") S = S+","; while (msb.length<8) msb = "0" + msb;
S += "0LL";
i++; let lsb = arr[idx+1].toString(16);
while (lsb.length<8) lsb = "0" + lsb;
S += "0x" + msb + lsb + "LL";
} else {
S += "0LL";
}
} }
return S; return S;
} }
function toMontgomery(a) { function toMontgomery(a) {
return a.times(R).mod(self.header.P); return self.F.mul(a, self.F.R);
} }
} }

View File

@@ -4,16 +4,17 @@ const assert = chai.assert;
const fs = require("fs"); const fs = require("fs");
var tmp = require("tmp-promise"); var tmp = require("tmp-promise");
const path = require("path"); const path = require("path");
const compiler = require("./compiler"); const compiler = require("../../src/compiler");
const util = require("util"); const util = require("util");
const exec = util.promisify(require("child_process").exec); const exec = util.promisify(require("child_process").exec);
const stringifyBigInts = require("./utils").stringifyBigInts; const Scalar = require("ffjavascript").Scalar;
const unstringifyBigInts = require("./utils").unstringifyBigInts; const utils = require("../../src/utils");
const bigInt = require("big-integer"); const loadR1cs = require("r1csfile").load;
const utils = require("./utils"); const ZqField = require("ffjavascript").ZqField;
const loadR1cs = require("./r1csfile").loadR1cs; const buildZqField = require("ffiasm").buildZqField;
const ZqField = require("fflib").ZqField;
const {stringifyBigInts, unstringifyBigInts } = require("ffjavascript").utils;
module.exports = c_tester; module.exports = c_tester;
@@ -31,23 +32,43 @@ async function c_tester(circomFile, _options) {
options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp")); options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp"));
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym")); options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
options.r1csFileName = path.join(dir.path, baseName + ".r1cs"); options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
options.p = options.p || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
await compiler(circomFile, options); await compiler(circomFile, options);
const cdir = path.join(__dirname, "..", "c"); const source = await buildZqField(options.p, "Fr");
await exec("cp" +
` ${path.join(dir.path, baseName + ".cpp")}` + // console.log(dir.path);
" /tmp/circuit.cpp"
); await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8");
await exec("g++" + await fs.promises.writeFile(path.join(dir.path, "fr.h"), source.h, "utf8");
await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8");
let pThread = "";
if (process.platform === "darwin") {
await exec("nasm -fmacho64 --prefix _ " +
` ${path.join(dir.path, "fr.asm")}`
);
} else if (process.platform === "linux") {
pThread = "-pthread";
await exec("nasm -felf64 " +
` ${path.join(dir.path, "fr.asm")}`
);
} else throw("Unsupported platform");
const cdir = path.join(path.dirname(require.resolve("circom_runtime")), "c");
await exec("g++" + ` ${pThread}` +
` ${path.join(cdir, "main.cpp")}` + ` ${path.join(cdir, "main.cpp")}` +
` ${path.join(cdir, "calcwit.cpp")}` + ` ${path.join(cdir, "calcwit.cpp")}` +
` ${path.join(cdir, "utils.cpp")}` + ` ${path.join(cdir, "utils.cpp")}` +
` ${path.join(cdir, "fr.c")}` + ` ${path.join(dir.path, "fr.c")}` +
` ${path.join(cdir, "fr.o")}` + ` ${path.join(dir.path, "fr.o")}` +
` ${path.join(dir.path, baseName + ".cpp")} ` + ` ${path.join(dir.path, baseName + ".cpp")} ` +
` -o ${path.join(dir.path, baseName)}` + ` -o ${path.join(dir.path, baseName)}` +
` -I ${cdir}` + ` -I ${dir.path} -I${cdir}` +
" -lgmp -std=c++11 -DSANITY_CHECK" " -lgmp -std=c++11 -DSANITY_CHECK -g"
); );
// console.log(dir.path); // console.log(dir.path);
@@ -70,10 +91,13 @@ class CTester {
path.join(this.dir.path, "in.json"), path.join(this.dir.path, "in.json"),
JSON.stringify(stringifyBigInts(input), null, 1) JSON.stringify(stringifyBigInts(input), null, 1)
); );
await exec(`${path.join(this.dir.path, this.baseName)}` + const r = await exec(`${path.join(this.dir.path, this.baseName)}` +
` ${path.join(this.dir.path, "in.json")}` + ` ${path.join(this.dir.path, "in.json")}` +
` ${path.join(this.dir.path, "out.json")}` ` ${path.join(this.dir.path, "out.json")}`
); );
if (r.stdout) {
console.log(r.stdout);
}
const resStr = await fs.promises.readFile( const resStr = await fs.promises.readFile(
path.join(this.dir.path, "out.json") path.join(this.dir.path, "out.json")
); );
@@ -92,10 +116,11 @@ class CTester {
const lines = symsStr.split("\n"); const lines = symsStr.split("\n");
for (let i=0; i<lines.length; i++) { for (let i=0; i<lines.length; i++) {
const arr = lines[i].split(","); const arr = lines[i].split(",");
if (arr.length!=3) continue; if (arr.length!=4) continue;
this.symbols[arr[2]] = { this.symbols[arr[3]] = {
idx: Number(arr[0]), labelIdx: Number(arr[0]),
idxWit: Number(arr[1]) varIdx: Number(arr[1]),
componentIdx: Number(arr[2]),
}; };
} }
} }
@@ -104,8 +129,8 @@ class CTester {
const self = this; const self = this;
if (this.constraints) return; if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false); const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.field = new ZqField(r1cs.prime); self.F = new ZqField(r1cs.prime);
self.nWires = r1cs.nWires; self.nVars = r1cs.nVars;
self.constraints = r1cs.constraints; self.constraints = r1cs.constraints;
} }
@@ -129,8 +154,8 @@ class CTester {
if (typeof self.symbols[prefix] == "undefined") { if (typeof self.symbols[prefix] == "undefined") {
assert(false, "Output variable not defined: "+ prefix); assert(false, "Output variable not defined: "+ prefix);
} }
const ba = bigInt(actualOut[self.symbols[prefix].idxWit]).toString(); const ba = actualOut[self.symbols[prefix].varIdx].toString();
const be = bigInt(eOut).toString(); const be = eOut.toString();
assert.strictEqual(ba, be, prefix); assert.strictEqual(ba, be, prefix);
} }
} }
@@ -142,8 +167,8 @@ class CTester {
if (!self.symbols) await self.loadSymbols(); if (!self.symbols) await self.loadSymbols();
for (let n in self.symbols) { for (let n in self.symbols) {
let v; let v;
if (utils.isDefined(witness[self.symbols[n].idxWit])) { if (utils.isDefined(witness[self.symbols[n].varIdx])) {
v = witness[self.symbols[n].idxWit].toString(); v = witness[self.symbols[n].varIdx].toString();
} else { } else {
v = "undefined"; v = "undefined";
} }
@@ -160,16 +185,16 @@ class CTester {
} }
function checkConstraint(constraint) { function checkConstraint(constraint) {
const F = self.field; const F = self.F;
const a = evalLC(constraint.a); const a = evalLC(constraint[0]);
const b = evalLC(constraint.b); const b = evalLC(constraint[1]);
const c = evalLC(constraint.c); const c = evalLC(constraint[2]);
assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match"); assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match");
} }
function evalLC(lc) { function evalLC(lc) {
const F = self.field; const F = self.F;
let v = F.zero; let v = F.zero;
for (let w in lc) { for (let w in lc) {
v = F.add( v = F.add(

845
ports/wasm/build_runtime.js Normal file
View File

@@ -0,0 +1,845 @@
const errs = require("./errs");
const buildWasmFf = require("ffwasm").buildWasmFf;
module.exports = function buildRuntime(module, builder) {
const pSanityCheck = module.alloc(4);
function buildInit() {
const f = module.addFunction("init");
f.addParam("sanityCheck", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
// Set the stack to current memory
f.addCode(
c.i32_store(
c.i32_const(4),
c.i32_shl(
c.i32_and(
c.current_memory(),
c.i32_const(0xFFFFFFF8)
),
c.i32_const(16)
)
)
);
// Save Sanity check flag
f.addCode(
c.i32_store(
c.i32_const(pSanityCheck),
c.getLocal("sanityCheck")
)
);
f.addCode(
// i=0
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
// if (i==NComponents) break
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
// inputSignalsToTrigger[i] = components[i].nInputSignals
c.i32_store(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("i"),
c.i32_const(4)
)
),
c.i32_load(
c.i32_add(
c.i32_load(c.i32_const(builder.ppComponents)),
c.i32_mul(
c.getLocal("i"),
c.i32_const(builder.sizeofComponent) // Sizeof component
)
),
builder.offsetComponentNInputSignals
)
),
// i=i+1
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
);
f.addCode(ifSanityCheck(c,
// i=0
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
// if (i==NSignals) break
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NSignals))),
// signalsAssigned[i] = false
c.i32_store(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("i"),
c.i32_const(4)
)
),
c.i32_const(0)
),
// i=i+1
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
));
f.addCode(
c.call(
"Fr_copy",
c.i32_const(builder.pSignals),
c.i32_add(
c.i32_load(c.i32_const(builder.ppConstants)),
c.i32_const(builder.addConstant(1) * builder.sizeFr)
)
)
);
f.addCode(ifSanityCheck(c,
c.i32_store(
c.i32_const(builder.pSignalsAssigned),
c.i32_const(1)
)
));
f.addCode(
// i=0
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
// if (i==NComponents) break
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
// if (inputSignalsToTrigger[i] == 0) triggerComponent(i)
c.if(
c.i32_eqz(
c.i32_load(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("i"),
c.i32_const(4)
)
)
)
),
c.call(
"triggerComponent",
c.getLocal("i")
)
),
// i=i+1
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
);
}
function ifSanityCheck(c, ...args) {
return c.if(
c.i32_load(c.i32_const(pSanityCheck)),
[].concat(...[...args])
);
}
function buildTriggerComponent() {
const f = module.addFunction("triggerComponent");
f.addParam("component", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.call_indirect(
c.getLocal("component"), // Idx in table
c.getLocal("component") // Parameter
)
);
}
function buildHash2ComponentEntry() {
const f = module.addFunction("hash2ComponentEntry");
f.addParam("component", "i32");
f.addParam("hash", "i64");
f.setReturnType("i32");
f.addLocal("pComponent", "i32");
f.addLocal("pHashTable", "i32");
f.addLocal("hIdx", "i32");
f.addLocal("h", "i64");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"pComponent",
c.i32_add(
c.i32_load(c.i32_const(builder.ppComponents)), // pComponents
c.i32_mul(
c.getLocal("component"),
c.i32_const(20) // sizeof(Component)
)
)
),
c.setLocal(
"pHashTable",
c.i32_load(c.getLocal("pComponent"))
),
c.setLocal(
"hIdx",
c.i32_and(
c.i32_wrap_i64(c.getLocal("hash")),
c.i32_const(0xFF)
)
),
c.block(c.loop(
c.setLocal(
"h",
c.i64_load(
c.i32_add(
c.getLocal("pHashTable"),
c.i32_mul(
c.getLocal("hIdx"),
c.i32_const(12)
)
)
)
),
c.br_if(1, c.i64_eq(c.getLocal("h"), c.getLocal("hash"))),
c.if(
c.i64_eqz(c.getLocal("h")),
c.call(
"error",
c.i32_const(errs.HASH_NOT_FOUND.code),
c.i32_const(errs.HASH_NOT_FOUND.pointer),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0)
)
),
c.setLocal(
"hIdx",
c.i32_and(
c.i32_add(
c.getLocal("hIdx"),
c.i32_const(1)
),
c.i32_const(0xFF)
)
),
c.br(0)
)),
c.i32_add( // pComponentEntry
c.i32_load( // pComponentEntryTable
c.i32_add(
c.getLocal("pComponent"),
c.i32_const(4)
)
),
c.i32_mul(
c.i32_load( // idx to the componentEntry
c.i32_add(
c.getLocal("pHashTable"),
c.i32_mul(
c.getLocal("hIdx"),
c.i32_const(12)
)
),
8
),
c.i32_const(12)
)
)
);
}
function buildGetFromComponentEntry(fnName, offset, type) {
const f = module.addFunction(fnName);
f.addParam("pR", "i32");
f.addParam("component", "i32");
f.addParam("hash", "i64");
f.addLocal("pComponentEntry", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"pComponentEntry",
c.call(
"hash2ComponentEntry",
c.getLocal("component"),
c.getLocal("hash")
)
),
c.if( // If type is not signal
c.i32_ne(
c.i32_load(
c.getLocal("pComponentEntry"),
8 // type offset
),
c.i32_const(type)
),
c.call(
"error",
c.i32_const(errs.INVALID_TYPE.code),
c.i32_const(errs.INVALID_TYPE.pointer),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0)
)
),
c.i32_store(
c.getLocal("pR"),
c.i32_load(
c.getLocal("pComponentEntry"),
offset
)
)
);
const f2 = module.addFunction(fnName + "32");
f2.addParam("pR", "i32");
f2.addParam("component", "i32");
f2.addParam("hashMSB", "i32");
f2.addParam("hashLSB", "i32");
const c2 = f2.getCodeBuilder();
f2.addCode(
c2.call(
fnName,
c2.getLocal("pR"),
c2.getLocal("component"),
c2.i64_or(
c2.i64_shl(
c2.i64_extend_i32_u(c2.getLocal("hashMSB")),
c2.i64_const(32)
),
c2.i64_extend_i32_u(c2.getLocal("hashLSB"))
)
)
);
}
function buildGetSignal() {
const f = module.addFunction("getSignal");
f.addParam("cIdx", "i32");
f.addParam("pR", "i32");
f.addParam("component", "i32");
f.addParam("signal", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c,
c.if(
c.i32_eqz(
c.i32_load(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
)
),
c.call(
"error",
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0)
)
)
));
f.addCode(
c.call(
"Fr_copy",
c.getLocal("pR"),
c.i32_add(
c.i32_const(builder.pSignals),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(builder.sizeFr)
)
)
)
);
f.addCode(ifSanityCheck(c,
c.call("logGetSignal", c.getLocal("signal"), c.getLocal("pR") )
));
}
function buildSetSignal() {
const f = module.addFunction("setSignal");
f.addParam("cIdx", "i32");
f.addParam("component", "i32");
f.addParam("signal", "i32");
f.addParam("pVal", "i32");
f.addLocal("signalsToTrigger", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c,
c.call("logSetSignal", c.getLocal("signal"), c.getLocal("pVal") ),
c.if(
c.i32_load(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
),
c.call(
"error",
c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code),
c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0)
)
),
c.i32_store(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
c.i32_const(1)
),
));
f.addCode(
c.call(
"Fr_copy",
c.i32_add(
c.i32_const(builder.pSignals),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(builder.sizeFr)
)
),
c.getLocal("pVal"),
)
);
f.addCode(
c.if( // If ( mapIsInput[s >> 5] & 1 << (s & 0x1f) )
c.i32_and(
c.i32_load(
c.i32_add(
c.i32_load(c.i32_const(builder.ppMapIsInput)),
c.i32_shl(
c.i32_shr_u(
c.getLocal("signal"),
c.i32_const(5)
),
c.i32_const(2)
)
)
),
c.i32_shl(
c.i32_const(1),
c.i32_and(
c.getLocal("signal"),
c.i32_const(0x1F)
)
)
),
[
...c.setLocal(
"signalsToTrigger",
c.i32_load(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("component"),
c.i32_const(4)
)
)
)
),
...c.if( // if (signalsToTrigger > 0)
c.i32_gt_u(
c.getLocal("signalsToTrigger"),
c.i32_const(0)
),
[
...c.setLocal( // signalsToTrigger--
"signalsToTrigger",
c.i32_sub(
c.getLocal("signalsToTrigger"),
c.i32_const(1)
)
),
...c.i32_store(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("component"),
c.i32_const(4)
)
),
c.getLocal("signalsToTrigger"),
),
...c.if( // if (signalsToTrigger==0) triggerCompomnent(component)
c.i32_eqz(c.getLocal("signalsToTrigger")),
c.call(
"triggerComponent",
c.getLocal("component")
)
)
],
c.call(
"error",
c.i32_const(errs.MAPISINPUT_DONT_MATCH.code),
c.i32_const(errs.MAPISINPUT_DONT_MATCH.pointer),
c.getLocal("component"),
c.getLocal("signal"),
c.i32_const(0),
c.i32_const(0)
)
)
]
)
);
}
function buildComponentFinished() {
const f = module.addFunction("componentFinished");
f.addParam("cIdx", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c,
c.call("logFinishComponent", c.getLocal("cIdx"))
));
f.addCode(c.ret([]));
}
function buildComponentStarted() {
const f = module.addFunction("componentStarted");
f.addParam("cIdx", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c,
c.call("logStartComponent", c.getLocal("cIdx"))
));
f.addCode(c.ret([]));
}
function buildCheckConstraint() {
const pTmp = module.alloc(builder.sizeFr);
const f = module.addFunction("checkConstraint");
f.addParam("cIdx", "i32");
f.addParam("pA", "i32");
f.addParam("pB", "i32");
f.addParam("pStr", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c,
c.call(
"Fr_eq",
c.i32_const(pTmp),
c.getLocal("pA"),
c.getLocal("pB")
),
c.if (
c.i32_eqz(
c.call(
"Fr_isTrue",
c.i32_const(pTmp),
)
),
c.call(
"error",
c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.code),
c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.pointer),
c.getLocal("cIdx"),
c.getLocal("pA"),
c.getLocal("pB"),
c.getLocal("pStr"),
)
)
));
}
function buildGetNVars() {
const f = module.addFunction("getNVars");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(c.i32_const(builder.header.NVars));
}
function buildGetFrLen() {
const f = module.addFunction("getFrLen");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.i32_const(builder.sizeFr));
}
function buildGetPRawPrime() {
const f = module.addFunction("getPRawPrime");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.i32_const(module.modules["Fr_F1m"].pq));
}
function buildGetPWitness() {
const f = module.addFunction("getPWitness");
f.addParam("w", "i32");
f.addLocal("signal", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"signal",
c.i32_load( // wit2sig[w]
c.i32_add(
c.i32_load( c.i32_const(builder.ppWit2sig)),
c.i32_mul(
c.getLocal("w"),
c.i32_const(4)
)
)
)
)
);
if (builder.sanityCheck) {
f.addCode(
c.if(
c.i32_eqz(
c.i32_load(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
)
),
c.call(
"error",
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0),
c.i32_const(0)
)
)
);
}
f.addCode(
c.i32_add(
c.i32_const(builder.pSignals),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(builder.sizeFr)
)
)
);
}
function buildGetWitnessBuffer() {
const f = module.addFunction("getWitnessBuffer");
f.setReturnType("i32");
f.addLocal("i", "i32");
f.addLocal("pSrc", "i32");
f.addLocal("pDst", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
// if (i==NComponents) break
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NVars))),
c.setLocal(
"pSrc",
c.call(
"getPWitness",
c.getLocal("i"),
)
),
c.call(
"Fr_toLongNormal",
c.getLocal("pSrc")
),
c.setLocal(
"pDst",
c.i32_add(
c.i32_const(builder.pOutput),
c.i32_mul(
c.getLocal("i"),
c.i32_const(builder.sizeFr-8)
)
)
),
c.call(
"Fr_F1m_copy",
c.i32_add(c.getLocal("pSrc"), c.i32_const(8)),
c.getLocal("pDst")
),
// i=i+1
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
)),
c.i32_const(builder.pOutput)
);
}
const fError = module.addIimportFunction("error", "runtime");
fError.addParam("code", "i32");
fError.addParam("pStr", "i32");
fError.addParam("param1", "i32");
fError.addParam("param2", "i32");
fError.addParam("param3", "i32");
fError.addParam("param4", "i32");
const fLogSetSignal = module.addIimportFunction("logSetSignal", "runtime");
fLogSetSignal.addParam("signal", "i32");
fLogSetSignal.addParam("val", "i32");
const fLogGetSignal = module.addIimportFunction("logGetSignal", "runtime");
fLogGetSignal.addParam("signal", "i32");
fLogGetSignal.addParam("val", "i32");
const fLogFinishComponent = module.addIimportFunction("logFinishComponent", "runtime");
fLogFinishComponent.addParam("cIdx", "i32");
const fLogStartComponent = module.addIimportFunction("logStartComponent", "runtime");
fLogStartComponent.addParam("cIdx", "i32");
const fLog = module.addIimportFunction("log", "runtime");
fLog.addParam("code", "i32");
buildWasmFf(module, "Fr", builder.header.P);
builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr);
builder.pOutput=module.alloc(builder.header.NVars*(builder.sizeFr-8));
builder.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4);
builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4);
buildHash2ComponentEntry();
buildTriggerComponent();
buildInit();
buildGetFromComponentEntry("getSubComponentOffset", 0 /* offset */, builder.TYPE_COMPONENT);
buildGetFromComponentEntry("getSubComponentSizes", 4 /* offset */, builder.TYPE_COMPONENT);
buildGetFromComponentEntry("getSignalOffset", 0 /* offset */, builder.TYPE_SIGNAL);
buildGetFromComponentEntry("getSignalSizes", 4 /* offset */, builder.TYPE_SIGNAL);
buildGetSignal();
buildSetSignal();
buildComponentStarted();
buildComponentFinished();
buildCheckConstraint();
buildGetNVars();
buildGetFrLen();
buildGetPWitness();
buildGetPRawPrime();
buildGetWitnessBuffer();
// buildFrToInt();
module.exportFunction("init");
module.exportFunction("getNVars");
module.exportFunction("getFrLen");
module.exportFunction("getSignalOffset32");
module.exportFunction("setSignal");
module.exportFunction("getPWitness");
module.exportFunction("Fr_toInt");
module.exportFunction("getPRawPrime");
module.exportFunction("getWitnessBuffer");
};

1030
ports/wasm/builder.js Normal file

File diff suppressed because it is too large Load Diff

10
ports/wasm/errs.js Normal file
View File

@@ -0,0 +1,10 @@
module.exports = {
STACK_OUT_OF_MEM: {code: 1, str: "Stack out of memory"},
STACK_TOO_SMALL: {code: 2, str: "Stack too small"},
HASH_NOT_FOUND: {code: 3, str: "Hash not found"},
INVALID_TYPE: {code: 4, str: "Invalid type"},
ACCESSING_NOT_ASSIGNED_SIGNAL: {code: 5, str: "Accessing a not assigned signal"},
SIGNAL_ASSIGNED_TWICE: {code: 6, str: "Signal assigned twice"},
CONSTRAIN_DOES_NOT_MATCH: {code: 7, str: "Constraint doesn't match"},
MAPISINPUT_DONT_MATCH: {code: 8, str: "MapIsInput don't match"},
};

163
ports/wasm/tester.js Normal file
View File

@@ -0,0 +1,163 @@
const chai = require("chai");
const assert = chai.assert;
const fs = require("fs");
var tmp = require("tmp-promise");
const path = require("path");
const compiler = require("../../src/compiler");
const utils = require("../../src/utils");
const loadR1cs = require("r1csfile").load;
const ZqField = require("ffjavascript").ZqField;
const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder;
module.exports = wasm_tester;
async function wasm_tester(circomFile, _options) {
tmp.setGracefulCleanup();
const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
// console.log(dir.path);
const baseName = path.basename(circomFile, ".circom");
const options = Object.assign({}, _options);
options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm"));
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
const promisesArr = [];
promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill)));
await compiler(circomFile, options);
await Promise.all(promisesArr);
const wasm = await fs.promises.readFile(path.join(dir.path, baseName + ".wasm"));
const wc = await WitnessCalculatorBuilder(wasm);
return new WasmTester(dir, baseName, wc);
}
class WasmTester {
constructor(dir, baseName, witnessCalculator) {
this.dir=dir;
this.baseName = baseName;
this.witnessCalculator = witnessCalculator;
}
async release() {
await this.dir.cleanup();
}
async calculateWitness(input, sanityCheck) {
return await this.witnessCalculator.calculateWitness(input, sanityCheck);
}
async loadSymbols() {
if (this.symbols) return;
this.symbols = {};
const symsStr = await fs.promises.readFile(
path.join(this.dir.path, this.baseName + ".sym"),
"utf8"
);
const lines = symsStr.split("\n");
for (let i=0; i<lines.length; i++) {
const arr = lines[i].split(",");
if (arr.length!=4) continue;
this.symbols[arr[3]] = {
labelIdx: Number(arr[0]),
varIdx: Number(arr[1]),
componentIdx: Number(arr[2]),
};
}
}
async loadConstraints() {
const self = this;
if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.F = new ZqField(r1cs.prime);
self.nVars = r1cs.nVars;
self.constraints = r1cs.constraints;
}
async assertOut(actualOut, expectedOut) {
const self = this;
if (!self.symbols) await self.loadSymbols();
checkObject("main", expectedOut);
function checkObject(prefix, eOut) {
if (Array.isArray(eOut)) {
for (let i=0; i<eOut.length; i++) {
checkObject(prefix + "["+i+"]", eOut[i]);
}
} else if ((typeof eOut == "object")&&(eOut.constructor.name == "Object")) {
for (let k in eOut) {
checkObject(prefix + "."+k, eOut[k]);
}
} else {
if (typeof self.symbols[prefix] == "undefined") {
assert(false, "Output variable not defined: "+ prefix);
}
const ba = actualOut[self.symbols[prefix].varIdx].toString();
const be = eOut.toString();
assert.strictEqual(ba, be, prefix);
}
}
}
async getDecoratedOutput(witness) {
const self = this;
const lines = [];
if (!self.symbols) await self.loadSymbols();
for (let n in self.symbols) {
let v;
if (utils.isDefined(witness[self.symbols[n].varIdx])) {
v = witness[self.symbols[n].varIdx].toString();
} else {
v = "undefined";
}
lines.push(`${n} --> ${v}`);
}
return lines.join("\n");
}
async checkConstraints(witness) {
const self = this;
if (!self.constraints) await self.loadConstraints();
for (let i=0; i<self.constraints.length; i++) {
checkConstraint(self.constraints[i]);
}
function checkConstraint(constraint) {
const F = self.F;
const a = evalLC(constraint[0]);
const b = evalLC(constraint[1]);
const c = evalLC(constraint[2]);
assert (F.isZero(F.sub(F.mul(a,b), c)), "Constraint doesn't match");
}
function evalLC(lc) {
const F = self.F;
let v = F.zero;
for (let w in lc) {
v = F.add(
v,
F.mul( lc[w], witness[w] )
);
}
return v;
}
}
}

View File

@@ -18,7 +18,6 @@
*/ */
const assert = require("assert"); const assert = require("assert");
const bigInt = require("big-integer");
const utils = require("./utils"); const utils = require("./utils");
const gen = require("./gencode").gen; const gen = require("./gencode").gen;
const createRefs = require("./gencode").createRefs; const createRefs = require("./gencode").createRefs;
@@ -34,10 +33,9 @@ function build(ctx) {
ctx.codes_sizes = []; ctx.codes_sizes = [];
ctx.definedSizes = {}; ctx.definedSizes = {};
ctx.addSizes = addSizes; ctx.addSizes = addSizes;
ctx.constantsMap = {};
ctx.addConstant = addConstant; ctx.addConstant = addConstant;
ctx.addConstant(bigInt.zero); ctx.addConstant(ctx.F.zero);
ctx.addConstant(bigInt.one); ctx.addConstant(ctx.F.one);
buildHeader(ctx); buildHeader(ctx);
buildEntryTables(ctx); buildEntryTables(ctx);
@@ -210,7 +208,7 @@ function buildHeader(ctx) {
NInputs: ctx.components[ ctx.getComponentIdx("main") ].nInSignals, NInputs: ctx.components[ ctx.getComponentIdx("main") ].nInSignals,
NOutputs: ctx.totals[ ctx.stOUTPUT ], NOutputs: ctx.totals[ ctx.stOUTPUT ],
NVars: ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL], NVars: ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL],
P: ctx.field.p P: ctx.F.p
}); });
} }
@@ -287,12 +285,7 @@ function addSizes(_sizes) {
} }
function addConstant(c) { function addConstant(c) {
c = bigInt(c); return this.builder.addConstant(c);
const s = c.toString();
if (typeof (this.constantsMap[s]) !== "undefined") return this.constantsMap[s];
const cIdx = this.builder.addConstant(c);
this.constantsMap[s] = cIdx;
return cIdx;
} }
function buildFunction(name, paramValues) { function buildFunction(name, paramValues) {
@@ -320,7 +313,7 @@ function buildFunction(name, paramValues) {
ctx.scopes = [{}]; ctx.scopes = [{}];
ctx.refs = []; ctx.refs = [];
ctx.conditionalCode = false; ctx.conditionalCode = false;
ctx.fnBuilder = ctx.builder.newFunctionBuilder(`${name}_${h}`, instanceDef); ctx.fnBuilder = ctx.builder.newFunctionBuilder(`${name}_${h}`, instanceDef, ctx.functions[name].params);
ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder(); ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
ctx.uniqueNames = Object.assign({},ctx.globalNames); ctx.uniqueNames = Object.assign({},ctx.globalNames);
ctx.returnValue = null; ctx.returnValue = null;
@@ -397,7 +390,7 @@ function hashComponentCall(ctx, cIdx) {
// TODO: At the moment generate a diferent function for each instance of the component // TODO: At the moment generate a diferent function for each instance of the component
const constParams = []; const constParams = [];
for (let p in ctx.components[cIdx].params) { for (let p in ctx.components[cIdx].params) {
constParams.push(p + "=" + value2str(ctx.components[cIdx].params[p])); constParams.push(p + "=" + value2str(ctx.F, ctx.components[cIdx].params[p]));
} }
for (let n in ctx.components[cIdx].names.o) { for (let n in ctx.components[cIdx].names.o) {
@@ -405,7 +398,7 @@ function hashComponentCall(ctx, cIdx) {
if ((entry.type == "S")&&(ctx.signals[entry.offset].o & ctx.IN)) { if ((entry.type == "S")&&(ctx.signals[entry.offset].o & ctx.IN)) {
travelSizes(n, entry.offset, entry.sizes, (prefix, offset) => { travelSizes(n, entry.offset, entry.sizes, (prefix, offset) => {
if (utils.isDefined(ctx.signals[offset].v)) { if (utils.isDefined(ctx.signals[offset].v)) {
constParams.push(prefix + "=" + bigInt(ctx.signals[offset].value)); constParams.push(prefix + "=" + ctx.F.e(ctx.signals[offset].v));
} }
}); });
} }
@@ -439,7 +432,7 @@ function hashFunctionCall(ctx, name, paramValues) {
const constParams = []; const constParams = [];
for (let i=0; i<ctx.functions[name].params.length; i++) { for (let i=0; i<ctx.functions[name].params.length; i++) {
if (!paramValues[i].used) { if (!paramValues[i].used) {
constParams.push(ctx.functions[name].params[i] + utils.accSizes2Str(paramValues[i].sizes) + "=" + value2str(paramValues[i].value)); constParams.push(ctx.functions[name].params[i] + utils.accSizes2Str(paramValues[i].sizes) + "=" + value2str(ctx.F, paramValues[i].value));
} }
} }
let instanceDef = name; let instanceDef = name;
@@ -453,16 +446,16 @@ function hashFunctionCall(ctx, name, paramValues) {
return {h, instanceDef}; return {h, instanceDef};
} }
function value2str(v) { function value2str(F, v) {
if (Array.isArray(v)) { if (Array.isArray(v)) {
let S="["; let S="[";
for (let i=0; i<v.length; i++) { for (let i=0; i<v.length; i++) {
if (i>0) S+=","; if (i>0) S+=",";
S+=value2str(v[i]); S+=value2str(F, v[i]);
} }
S+="]"; S+="]";
return S; return S;
} else { } else {
return bigInt(v).toString(); return F.toString(F.e(v));
} }
} }

View File

@@ -1,28 +0,0 @@
class BuilderWasm {
constructor() {
}
setHeader(header) {
this.header=header;
}
// ht is an array of 256 element that can be undefined or [Hash, Idx, KeyName] elements.
addHashMap(name, ht) {
this.hashTables[name] = ht;
}
addComponentEntriesTable(name, cet) {
this.componentEntriesTables[name] = cet;
}
addSizes(name, accSizes) {
this.sizes[name] = accSizes;
}
build() {
}
}
module.exports = BuilderWasm;

158
src/buildsyms.js Normal file
View File

@@ -0,0 +1,158 @@
const Readable = require("stream").Readable;
module.exports = function buildSyms(ctx) {
const rs = Readable();
let it = new ComponentIt(ctx, 0, "main");
let counter = 0;
rs._read = function() {
const actual = it.current();
if (actual == null ) {
rs.push(null);
return;
}
let s=actual.offset;
while (ctx.signals[s].e >= 0) s = ctx.signals[s].e;
let wId = ctx.signals[s].id;
if (typeof(wId) == "undefined") wId=-1;
rs.push(`${actual.offset},${wId},${actual.cIdx},${actual.name}\n`);
it.next();
counter ++;
if ((ctx.verbose)&&(counter%10000 == 0)) console.log("Symbols saved: "+counter);
};
return rs;
};
class SignalIt {
constructor (ctx, offset, prefix, cIdx) {
this.ctx = ctx;
this.offset = offset;
this.prefix = prefix;
this.cur = 0;
this.cIdx = cIdx;
}
next() {
this.cur = 1;
return this.current();
}
current() {
if (this.cur == 0) {
return {offset: this.offset, name: this.prefix, cIdx: this.cIdx};
}
}
}
class ArrayIt {
constructor (ctx, type, sizes, offset, prefix, cIdx) {
if (sizes.length == 0) {
if (type == "S") {
return new SignalIt(ctx, offset, prefix, cIdx);
} else {
return new ComponentIt(ctx, offset, prefix);
}
}
this.ctx = ctx;
this.type = type;
this.sizes = sizes;
this.offset = offset;
this.prefix = prefix;
this.cIdx = cIdx;
this.subIt = null;
this.cur = 0;
this.subArrSize = 1;
for (let i=1; i<sizes.length; i++) {
this.subArrSize *= sizes[i];
}
this._loadSubIt();
}
_loadSubIt() {
if (this.cur < this.sizes[0]) {
this.subIt = new ArrayIt(this.ctx, this.type, this.sizes.slice(1), this.offset + this.cur*this.subArrSize, this.prefix + "[" + this.cur + "]", this.cIdx);
}
}
next() {
if (this.subIt) {
const res = this.subIt.next();
if (res == null) {
this.subIt = null;
this.cur++;
this._loadSubIt();
}
}
return this.current();
}
current() {
if (this.subIt) {
return this.subIt.current();
} else {
return null;
}
}
}
class ComponentIt {
constructor (ctx, idxComponent, prefix) {
this.ctx = ctx;
this.idxComponent = idxComponent;
this.prefix = prefix;
this.names = Object.keys(ctx.components[idxComponent].names.o);
this.subIt = null;
this.cur = 0;
this._loadSubIt();
}
_loadSubIt() {
if (this.cur < this.names.length) {
const entrie = this.ctx.components[this.idxComponent].names.o[this.names[this.cur]];
this.subIt = new ArrayIt(this.ctx, entrie.type, entrie.sizes, entrie.offset, this.prefix + "." + this.names[this.cur], this.idxComponent);
}
}
next() {
if (this.subIt) {
const res = this.subIt.next();
if (res == null) {
this.subIt = null;
this.cur++;
this._loadSubIt();
}
}
return this.current();
}
current() {
if (this.subIt) {
return this.subIt.current();
} else {
return null;
}
}
}

View File

@@ -1,52 +0,0 @@
const ModuleBuilder = require("wasmbuilder").ModuleBuilder;
const gen = require("./gencode");
module.exports = function buildWasm(ctx) {
const fDefined = {};
ctx.module = new ModuleBuilder();
for (let f in ctx.functions) {
ctx.f = ctx.module.addFunction(f);
ctx.c = ctx.f.getCodeBuilder();
ctx.scope = {};
for (let p in ctx.functions[f].params) {
const param = ctx.functions[f].params[p];
ctx.f.addParam(param.name, "i32");
ctx.scope[param.name] = {
type: "PARAM",
sels: param.sels,
getter: () => { return ctx.c.getLocal(param.name); },
setter: (v) => { return ctx.c.setLocal(param.name, v); }
};
}
gen(ctx, ctx.functions[f].block);
}
for (let i=0; i<ctx.components.length; i++) {
const h = hashComponentCall(ctx, i);
const fName = ctx.components[i].temlate+"_"+h;
if (!fDefined[fName]) {
ctx.f = ctx.module.addFunction(fName);
ctx.c = ctx.f.getCodeBuilder();
ctx.scope = {};
for (let p in ctx.components[i].params) {
ctx.scope[p] = createConstant(ctx, ctx.components[i].params[p]);
}
gen(ctx, ctx.templates[ctx.components[i].temlate].block);
}
ctx.components[i].f = fName;
}
};
function buildSetSignal(ctx) {
}

View File

@@ -17,38 +17,36 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
const bigInt = require("big-integer"); const Scalar = require("ffjavascript").Scalar;
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const sONE = 0; const sONE = 0;
const build = require("./build"); const build = require("./build");
const BuilderC = require("./builder_c"); const BuilderC = require("../ports/c/builder.js");
const BuilderWasm = require("./builder_wasm"); const BuilderWasm = require("../ports/wasm/builder.js");
const constructionPhase = require("./construction_phase"); const constructionPhase = require("./construction_phase");
const Ctx = require("./ctx"); const Ctx = require("./ctx");
const ZqField = require("fflib").ZqField;
const utils = require("./utils"); const utils = require("./utils");
const buildR1cs = require("./r1csfile").buildR1cs; const buildR1cs = require("./r1csfile").buildR1cs;
const BigArray = require("./bigarray"); const BigArray = require("./bigarray");
const buildSyms = require("./buildsyms");
module.exports = compile; module.exports = compile;
async function compile(srcFile, options) { async function compile(srcFile, options) {
options.p = options.p || __P__; options.prime = options.prime || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
if (!options) { if (!options) {
options = {}; options = {};
} }
if (typeof options.reduceConstraints === "undefined") { if (typeof options.reduceConstraints === "undefined") {
options.reduceConstraints = true; options.reduceConstraints = true;
} }
const ctx = new Ctx(); const ctx = new Ctx(options.prime);
ctx.field = new ZqField(options.p);
ctx.verbose= options.verbose || false; ctx.verbose= options.verbose || false;
ctx.mainComponent = options.mainComponent || "main"; ctx.mainComponent = options.mainComponent || "main";
ctx.newThreadTemplates = options.newThreadTemplates; ctx.newThreadTemplates = options.newThreadTemplates;
constructionPhase(ctx, srcFile); constructionPhase(ctx, srcFile);
console.log("NConstraints Before: "+ctx.constraints.length); if (ctx.verbose) console.log("NConstraints Before: "+ctx.constraints.length);
if (ctx.error) { if (ctx.error) {
throw(ctx.error); throw(ctx.error);
@@ -69,13 +67,13 @@ async function compile(srcFile, options) {
// Repeat while reductions are performed // Repeat while reductions are performed
let oldNConstrains = -1; let oldNConstrains = -1;
while (ctx.constraints.length != oldNConstrains) { while (ctx.constraints.length != oldNConstrains) {
console.log("Reducing constraints: "+ctx.constraints.length); if (ctx.verbose) console.log("Reducing constraints: "+ctx.constraints.length);
oldNConstrains = ctx.constraints.length; oldNConstrains = ctx.constraints.length;
reduceConstrains(ctx); reduceConstrains(ctx);
} }
} }
console.log("NConstraints After: "+ctx.constraints.length); if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length);
generateWitnessNames(ctx); generateWitnessNames(ctx);
@@ -84,7 +82,8 @@ async function compile(srcFile, options) {
} }
if (options.cSourceWriteStream) { if (options.cSourceWriteStream) {
ctx.builder = new BuilderC(); if (ctx.verbose) console.log("Generating c...");
ctx.builder = new BuilderC(options.prime);
build(ctx); build(ctx);
const rdStream = ctx.builder.build(); const rdStream = ctx.builder.build();
rdStream.pipe(options.cSourceWriteStream); rdStream.pipe(options.cSourceWriteStream);
@@ -92,11 +91,18 @@ async function compile(srcFile, options) {
// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill)); // await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
} }
if (options.wasmWriteStream) { if ((options.wasmWriteStream)||(options.watWriteStream)) {
ctx.builder = new BuilderWasm(); if (ctx.verbose) console.log("Generating wasm...");
ctx.builder = new BuilderWasm(options.prime);
build(ctx); build(ctx);
const rdStream = ctx.builder.build(); if (options.wasmWriteStream) {
rdStream.pipe(options.wasmWriteStream); const rdStream = ctx.builder.build("wasm");
rdStream.pipe(options.wasmWriteStream);
}
if (options.watWriteStream) {
const rdStream = ctx.builder.build("wat");
rdStream.pipe(options.watWriteStream);
}
// await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill)); // await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
} }
@@ -109,7 +115,10 @@ async function compile(srcFile, options) {
} }
if (options.symWriteStream) { if (options.symWriteStream) {
buildSyms(ctx, options.symWriteStream); const rdStream = buildSyms(ctx);
rdStream.pipe(options.symWriteStream);
// await new Promise(fulfill => options.symWriteStream.on("finish", fulfill));
} }
// const def = buildCircuitDef(ctx, mainCode); // const def = buildCircuitDef(ctx, mainCode);
@@ -289,11 +298,11 @@ function reduceConstrains(ctx) {
t: "LC", t: "LC",
coefs: {} coefs: {}
}; };
const invCoef = c.c.coefs[isolatedSignal].modInv(__P__); const invCoef = ctx.F.inv(c.c.coefs[isolatedSignal]);
for (const s in c.c.coefs) { for (const s in c.c.coefs) {
if (s != isolatedSignal) { if (s != isolatedSignal) {
const v = __P__.minus(c.c.coefs[s]).times(invCoef).mod(__P__); const v = ctx.F.mul( ctx.F.neg(c.c.coefs[s]), invCoef);
if (!v.isZero()) { if (!ctx.F.isZero(v)) {
isolatedSignalEquivalence.coefs[s] = v; isolatedSignalEquivalence.coefs[s] = v;
} }
} }
@@ -385,9 +394,9 @@ function reduceConstrains(ctx) {
function isConstant(l) { function isConstant(l) {
for (let k in l.coefs) { for (let k in l.coefs) {
if ((k != sONE) && (!l.coefs[k].isZero())) return false; if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
} }
if (!l.coefs[sONE] || l.coefs[sONE].isZero()) return false; if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
return true; return true;
} }
@@ -504,6 +513,8 @@ function buildConstraints(ctx) {
return res; return res;
} }
*/ */
/*
function buildSyms(ctx, strm) { function buildSyms(ctx, strm) {
let nSyms; let nSyms;
@@ -543,5 +554,5 @@ function buildSyms(ctx, strm) {
} }
*/

View File

@@ -49,10 +49,11 @@ const assert = require("assert");
const iterateAST = require("./iterateast"); const iterateAST = require("./iterateast");
const utils = require("./utils"); const utils = require("./utils");
const bigInt = require("big-integer");
const LCAlgebra = require("./lcalgebra"); const LCAlgebra = require("./lcalgebra");
const parser = require("../parser/jaz.js").parser; const parser = require("../parser/jaz.js").parser;
const Scalar = require("ffjavascript").Scalar;
const {stringifyBigInts} = require("ffjavascript").utils;
/* TODO: Add lines information /* TODO: Add lines information
@@ -79,7 +80,7 @@ function constructionPhase(ctx, srcFile) {
assert(ctx.ast.type == "BLOCK"); assert(ctx.ast.type == "BLOCK");
ctx.lc = new LCAlgebra(ctx.field); ctx.lc = new LCAlgebra(ctx.F);
ctx.filePath= fullFilePath; ctx.filePath= fullFilePath;
ctx.fileName= fullFileName; ctx.fileName= fullFileName;
ctx.includedFiles = {}; ctx.includedFiles = {};
@@ -218,7 +219,7 @@ function execNumber(ctx, ast) {
s:[1,0], s:[1,0],
v: [{ v: [{
t: "N", t: "N",
v: bigInt(ast.value) v: ctx.F.e(ast.value)
}] }]
}; };
} }
@@ -253,7 +254,7 @@ function execDeclareComponent(ctx, ast) {
const size = val(ctx, sizeRef); const size = val(ctx, sizeRef);
if (size.t != "N") return ctx.throwError( ast.name.selectors[i], "expected a number"); if (size.t != "N") return ctx.throwError( ast.name.selectors[i], "expected a number");
sizes.push( size.v.toJSNumber() ); sizes.push( Scalar.toNumber(size.v) );
} }
let cIdx = ctx.addComponent(ast.name.name, sizes); let cIdx = ctx.addComponent(ast.name.name, sizes);
@@ -277,7 +278,7 @@ function execDeclareSignal(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array"); if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array");
if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time"); if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time");
sizes.push( size.v[0].v.toJSNumber() ); sizes.push( Scalar.toNumber(size.v[0].v) );
} }
let sIdx = ctx.addSignal(ast.name.name, sizes); let sIdx = ctx.addSignal(ast.name.name, sizes);
@@ -322,7 +323,7 @@ function execDeclareVariable(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array"); if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array");
if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time"); if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time");
sizes.push( size.v[0].v.toJSNumber() ); sizes.push( Scalar.toNumber(size.v[0].v) );
} }
const v = ctx.refs[ast.refId]; const v = ctx.refs[ast.refId];
@@ -353,13 +354,13 @@ function execAssignement(ctx, ast) {
if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array");
if (sel.v[0].t != "N") return {t: "NQ"}; if (sel.v[0].t != "N") return {t: "NQ"};
leftSels.push( sel.v[0].v.toJSNumber() ); leftSels.push( Scalar.toNumber(sel.v[0].v) );
} }
} }
} }
if (!left.s) return ctx.throwError(ast, "variable. not defined yet"); if ((!left)||(!left.s)) return ctx.throwError(ast, "variable. not defined yet");
if (left.t == "C") return execInstantiateComponet(ctx, left, ast.values[1], leftSels); if (left.t == "C") return execInstantiateComponet(ctx, left, ast.values[1], leftSels);
if ((left.t == "S")&&( ["<--", "<==", "-->", "==>"].indexOf(ast.op) < 0)) return ctx.throwError(ast, "Cannot assign to a signal with `=` use <-- or <== ops"); if ((left.t == "S")&&( ["<--", "<==", "-->", "==>"].indexOf(ast.op) < 0)) return ctx.throwError(ast, "Cannot assign to a signal with `=` use <-- or <== ops");
@@ -380,7 +381,7 @@ function execAssignement(ctx, ast) {
} else if (right.t == "S") { } else if (right.t == "S") {
for (let i=0; i<right.s[0]; i++) { for (let i=0; i<right.s[0]; i++) {
left.v[o+i]={t: "LC", coefs: {}}; left.v[o+i]={t: "LC", coefs: {}};
left.v[o+i].coefs[right.sIdx+i] = ctx.field.one; left.v[o+i].coefs[right.sIdx+i] = ctx.F.one;
} }
} }
} else if ( left.t == "S") { } else if ( left.t == "S") {
@@ -444,14 +445,14 @@ function execInstantiateComponet(ctx, vr, fn, sels) {
const templateName = fn.name; const templateName = fn.name;
const template = ctx.templates[templateName]; const template = ctx.templates[templateName];
if (!template) return ctx.throwError("Invalid Template"); if (!template) return ctx.throwError(fn, "Invalid Template");
const paramValues = []; const paramValues = [];
for (let i=0; i< fn.params.length; i++) { for (let i=0; i< fn.params.length; i++) {
const v = exec(ctx, fn.params[i]); const v = exec(ctx, fn.params[i]);
if (ctx.error) return; if (ctx.error) return;
for (let j=0; j<v.s[0]; j++) { for (let j=0; j<v.s[0]; j++) {
if (v.v[j].t != "N") ctx.throwError("Parameters of a template must be constant"); if (v.v[j].t != "N") ctx.throwError(fn, "Parameters of a template must be constant");
} }
paramValues.push(v); paramValues.push(v);
} }
@@ -558,13 +559,17 @@ function execFunctionCall(ctx, ast) {
if (ast.name == "log") { if (ast.name == "log") {
const v = exec(ctx, ast.params[0]); const v = exec(ctx, ast.params[0]);
const ev = val(ctx, v, ast); const ev = val(ctx, v, ast);
console.log(ev.v.toString()); if (ev.v) {
console.log(ev.v.toString());
} else {
console.log(JSON.stringify(stringifyBigInts(ev)));
}
return; return;
} }
if (ast.name == "assert") { if (ast.name == "assert") {
const v = exec(ctx, ast.params[0]); const v = exec(ctx, ast.params[0]);
const ev = val(ctx, v, ast); const ev = val(ctx, v, ast);
if (ev.isZero()) return ctx.throwError(ast, "Assertion failed"); if (ctx.F.isZero(ev)) return ctx.throwError(ast, "Assertion failed");
} }
const fnc = ctx.functions[ast.name]; const fnc = ctx.functions[ast.name];
@@ -620,6 +625,9 @@ function execReturn(ctx, ast) {
function execVariable(ctx, ast) { function execVariable(ctx, ast) {
const v = ctx.refs[ast.refId]; const v = ctx.refs[ast.refId];
if (!v) {
return ctx.throwError(ast, "Variable not defined: "+ast.name);
}
const sels = []; const sels = [];
for (let i=0; i< ast.selectors.length; i++) { for (let i=0; i< ast.selectors.length; i++) {
@@ -627,7 +635,7 @@ function execVariable(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (sel.s[0] != 1) return ctx.throwError(ast, "Variable selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Variable selector cannot be an array");
if (sel.v[0].t != "N") return NQVAL; if (sel.v[0].t != "N") return NQVAL;
sels.push(sel.v[0].v.toJSNumber()); sels.push(Scalar.toNumber(sel.v[0].v));
} }
let o = 0; let o = 0;
@@ -675,7 +683,7 @@ function execPin(ctx, ast) {
if (sel.s[0] != 1) return ctx.throwError(ast, "Component selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Component selector cannot be an array");
if (sel.v[0].t != "N") return NQVAL; if (sel.v[0].t != "N") return NQVAL;
selsC.push(sel.v[0].v.toJSNumber()); selsC.push(Scalar.toNumber(sel.v[0].v));
} }
const cIdx = ctx.getComponentIdx(ast.component.name, selsC); const cIdx = ctx.getComponentIdx(ast.component.name, selsC);
@@ -687,7 +695,7 @@ function execPin(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (sel.s[0] != 1) return ctx.throwError(ast, "Signal selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Signal selector cannot be an array");
if (sel.v[0].t != "N") return NQVAL; if (sel.v[0].t != "N") return NQVAL;
selsP.push(sel.v[0].v.toJSNumber()); selsP.push(Scalar.toNumber(sel.v[0].v));
} }
const sIdx = ctx.components[cIdx].names.getSignalIdx(ast.pin.name, selsP); const sIdx = ctx.components[cIdx].names.getSignalIdx(ast.pin.name, selsP);
@@ -734,7 +742,7 @@ function execLoop(ctx, ast) {
return; return;
} }
while ((!v.v[0].v.isZero())&&(!ctx.returnValue)) { while ((! ctx.F.isZero(v.v[0].v))&&(!ctx.returnValue)) {
exec(ctx, ast.body); exec(ctx, ast.body);
if (ctx.error) return; if (ctx.error) return;
@@ -777,7 +785,7 @@ function execIf(ctx, ast) {
return; return;
} }
if (!v.v[0].v.isZero()) { if (!ctx.F.isZero(v.v[0].v)) {
exec(ctx, ast.then); exec(ctx, ast.then);
} else { } else {
if (ast.else) { if (ast.else) {
@@ -804,7 +812,7 @@ function execTerCon(ctx, ast) {
return NQVAL; return NQVAL;
} }
if (!v.v[0].v.isZero()) { if (!ctx.F.isZero(v.v[0].v)) {
return exec(ctx, ast.values[1]); return exec(ctx, ast.values[1]);
} else { } else {
return exec(ctx, ast.values[2]); return exec(ctx, ast.values[2]);
@@ -843,7 +851,7 @@ function execOpOp(ctx, ast, op, lr) {
if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array");
if (sel.v[0].t != "N") return {t: "NQ"}; if (sel.v[0].t != "N") return {t: "NQ"};
leftSels.push( sel.v[0].v.toJSNumber() ); leftSels.push( Scalar.toNumber(sel.v[0].v) );
} }
} }
if (!left.s) return ctx.throwError(ast, "variable. not defined yet"); if (!left.s) return ctx.throwError(ast, "variable. not defined yet");
@@ -863,9 +871,11 @@ function execOpOp(ctx, ast, op, lr) {
if (ctx.error) return; if (ctx.error) return;
right = val(ctx, rightRef); right = val(ctx, rightRef);
} else { } else {
right = {t:"N", v: ctx.field.one}; right = {t:"N", v: ctx.F.one};
} }
if (!right) return ctx.throwError(ast, "adding a no number");
const resAfter = ctx.lc[op](resBefore, right); const resAfter = ctx.lc[op](resBefore, right);
left.v[o] = resAfter; left.v[o] = resAfter;
@@ -898,7 +908,7 @@ function val(ctx, a, ast) {
}; };
let sIdx = a.sIdx; let sIdx = a.sIdx;
while (ctx.signals[sIdx].e >= 0) sIdx = ctx.signals[sIdx].e; while (ctx.signals[sIdx].e >= 0) sIdx = ctx.signals[sIdx].e;
res.coefs[sIdx] = ctx.field.one; res.coefs[sIdx] = ctx.F.one;
return res; return res;
} else { } else {
ctx.throwError(ast, "Invalid type: " + a.t); ctx.throwError(ast, "Invalid type: " + a.t);
@@ -920,7 +930,9 @@ function execConstrain(ctx, ast) {
if (!ctx.lc.isZero(res)) { if (!ctx.lc.isZero(res)) {
ctx.constraints.push(ctx.lc.toQEX(res)); ctx.constraints.push(ctx.lc.toQEX(res));
if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length); if (ctx.verbose) {
if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length);
}
} }
return a; return a;
@@ -968,7 +980,7 @@ function execArray(ctx, ast) {
} else if (e.t == "S") { } else if (e.t == "S") {
for (let j=0; j<e.v.length;j++) { for (let j=0; j<e.v.length;j++) {
const sv = {t: "LC", coefs: {}}; const sv = {t: "LC", coefs: {}};
sv.coefs[e.sIdx+j] = ctx.field.one; sv.coefs[e.sIdx+j] = ctx.F.one;
res.v.push(sv); res.v.push(sv);
} }
} else { } else {

View File

@@ -1,6 +1,5 @@
const bigInt = require("big-integer");
const BigArray = require("./bigarray.js"); const BigArray = require("./bigarray.js");
const F1Field = require("ffjavascript").F1Field;
class TableName { class TableName {
constructor (ctx) { constructor (ctx) {
@@ -86,7 +85,9 @@ class TableName {
module.exports = class Ctx { module.exports = class Ctx {
constructor() { constructor(p) {
this.F = new F1Field(p);
this.stONE = 1; this.stONE = 1;
this.stOUTPUT = 2; this.stOUTPUT = 2;
@@ -121,7 +122,7 @@ module.exports = class Ctx {
const oneIdx = this.addSignal("one"); const oneIdx = this.addSignal("one");
this.signals[oneIdx] = { this.signals[oneIdx] = {
v: bigInt(1), v: this.F.one,
o: this.ONE, o: this.ONE,
e: -1, e: -1,
}; };

View File

@@ -1,7 +1,7 @@
const bigInt = require("big-integer");
const utils = require("./utils"); const utils = require("./utils");
const assert = require("assert"); const assert = require("assert");
const iterateAST = require("./iterateast"); const iterateAST = require("./iterateast");
const Scalar = require("ffjavascript").Scalar;
module.exports.gen = gen; module.exports.gen = gen;
module.exports.newRef = newRef; module.exports.newRef = newRef;
@@ -175,17 +175,17 @@ function gen(ctx, ast) {
} else if (ast.op == ">>") { } else if (ast.op == ">>") {
return genOp(ctx, ast, "shr", 2); return genOp(ctx, ast, "shr", 2);
} else if (ast.op == "<") { } else if (ast.op == "<") {
return genOp(ctx, ast, "lt", 2); return genOp(ctx, ast, "lt", 2, true);
} else if (ast.op == ">") { } else if (ast.op == ">") {
return genOp(ctx, ast, "gt", 2); return genOp(ctx, ast, "gt", 2, true);
} else if (ast.op == "<=") { } else if (ast.op == "<=") {
return genOp(ctx, ast, "leq", 2); return genOp(ctx, ast, "leq", 2, true);
} else if (ast.op == ">=") { } else if (ast.op == ">=") {
return genOp(ctx, ast, "geq", 2); return genOp(ctx, ast, "geq", 2, true);
} else if (ast.op == "==") { } else if (ast.op == "==") {
return genOp(ctx, ast, "eq", 2); return genOp(ctx, ast, "eq", 2, true);
} else if (ast.op == "!=") { } else if (ast.op == "!=") {
return genOp(ctx, ast, "neq", 2); return genOp(ctx, ast, "neq", 2, true);
} else if (ast.op == "?") { } else if (ast.op == "?") {
return genTerCon(ctx, ast); return genTerCon(ctx, ast);
} else { } else {
@@ -300,7 +300,7 @@ function genDeclareVariable(ctx, ast) {
const size = ctx.refs[sizeRef]; const size = ctx.refs[sizeRef];
if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array"); if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
if (size.used) return ctx.throwError(ast, "Variable size variables not allowed"); if (size.used) return ctx.throwError(ast, "Variable size variables not allowed");
sizes.push(size.value[0]); sizes.push(Scalar.toNumber(size.value[0]));
} }
sizes = utils.accSizes(sizes); sizes = utils.accSizes(sizes);
} else { } else {
@@ -320,7 +320,7 @@ function genDeclareVariable(ctx, ast) {
} }
function genNumber(ctx, ast) { function genNumber(ctx, ast) {
return newRef(ctx, "BIGINT", "_num", bigInt(ast.value)); return newRef(ctx, "BIGINT", "_num", ctx.F.e(ast.value));
} }
@@ -423,13 +423,21 @@ function genVariable(ctx, ast) {
} else if (v.type == "BIGINT") { } else if (v.type == "BIGINT") {
const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors ); const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
const offset = ctx.refs[refOffset]; const offset = ctx.refs[refOffset];
let ot;
if (offset.type == "BIGINT") {
ot = "R";
} else if (offset.type == "INT") {
ot= "RI";
} else {
assert(false);
}
if (v.used) { if (v.used) {
if (offset.used) { if (offset.used) {
const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
const res = ctx.refs[refRes]; const res = ctx.refs[refRes];
res.used = true; res.used = true;
ctx.fnBuilder.definePFrElement(res.label); ctx.fnBuilder.definePFrElement(res.label);
ctx.codeBuilder.assign(res.label, ["R", v.label], ["R", offset.label]); ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
return refRes; return refRes;
} else if ((offset.value[0]>0)||(l>0)) { } else if ((offset.value[0]>0)||(l>0)) {
const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
@@ -448,7 +456,7 @@ function genVariable(ctx, ast) {
const res = ctx.refs[resRef]; const res = ctx.refs[resRef];
res.used = true; res.used = true;
ctx.fnBuilder.definePFrElement(res.label); ctx.fnBuilder.definePFrElement(res.label);
ctx.codeBuilder.assign(res.label, ["R", v.label], ["R", offset.label]); ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
return resRef; return resRef;
} else { } else {
// return newSubRef(ctx, ast.name, ast.selectors); // return newSubRef(ctx, ast.name, ast.selectors);
@@ -499,7 +507,13 @@ function genGetSubComponentOffset(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label]; if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@@ -520,7 +534,13 @@ function genGetSubComponentSizes(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label]; if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@@ -553,7 +573,13 @@ function genGetSignalOffset(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label]; if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@@ -590,7 +616,13 @@ function genGetSignalSizes(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label]; if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@@ -743,7 +775,11 @@ function toRefA_Fr1(ctx, ast, aRef) {
const a = ctx.refs[aRef]; const a = ctx.refs[aRef];
if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element"); if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
if (a.used) { if (a.used) {
return ["R", a.label]; if (a.type == "BIGINT") {
return ["R", a.label];
} else {
assert(false);
}
} else { } else {
return ["C", ctx.addConstant(a.value[0])]; return ["C", ctx.addConstant(a.value[0])];
} }
@@ -754,7 +790,13 @@ function toRefA_Int1(ctx, ast, aRef) {
const a = ctx.refs[aRef]; const a = ctx.refs[aRef];
if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element"); if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
if (a.used) { if (a.used) {
return ["R", a.label]; if (a.type == "INT") {
return ["RI", a.label];
} else if (a.type == "BIGINT") {
return ["R", a.label];
} else {
assert(false);
}
} else { } else {
return ["V", a.value[0]]; return ["V", a.value[0]];
} }
@@ -818,9 +860,7 @@ function genArray(ctx, ast) {
function genFunctionCall(ctx, ast) { function genFunctionCall(ctx, ast) {
if (ast.name == "log") { if (ast.name == "log") {
const vRef = gen(ctx, ast.params[0]); const vRef = gen(ctx, ast.params[0]);
const val = ctx.refs[vRef]; ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef));
instantiateRef(ctx, vRef, val.value);
ctx.code+=`ctx->log(${val.label});`;
return vRef; return vRef;
} }
const params = []; const params = [];
@@ -910,7 +950,7 @@ function genLoop(ctx, ast) {
ctx.codeBuilder.assign(loopCond.label, ["R", cond.label], ["V", 0]); ctx.codeBuilder.assign(loopCond.label, ["R", cond.label], ["V", 0]);
} else { } else {
if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned"); if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
if (cond.value[0].isZero()) end=true; if (ctx.F.isZero(cond.value[0])) end=true;
} }
@@ -953,7 +993,7 @@ function genLoop(ctx, ast) {
} else { } else {
oldCodeBuilder.concat(ctx.codeBuilder); oldCodeBuilder.concat(ctx.codeBuilder);
ctx.codeBuilder = oldCodeBuilder; ctx.codeBuilder = oldCodeBuilder;
if (cond2.value[0].isZero()) end=true; if (ctx.F.isZero(cond2.value[0])) end=true;
} }
} else { } else {
ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]); ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]);
@@ -1002,7 +1042,7 @@ function genIf(ctx, ast) {
} else { } else {
if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned"); if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
if (!cond.value[0].isZero()) { if (!ctx.F.isZero(cond.value[0])) {
gen(ctx, ast.then); gen(ctx, ast.then);
} else { } else {
if (ast.else) { if (ast.else) {
@@ -1069,9 +1109,9 @@ function genOpOp(ctx, ast, op, lr) {
const res = ctx.refs[resRef]; const res = ctx.refs[resRef];
if (veval.used) { if (veval.used) {
instantiateRef(ctx, resRef); instantiateRef(ctx, resRef);
ctx.codeBuilder.fieldOp(res.label, op, [["R", veval.label], ["C", ctx.addConstant(bigInt.one)]]); ctx.codeBuilder.fieldOp(res.label, op, [["R", veval.label], ["C", ctx.addConstant(ctx.F.one)]]);
} else { } else {
res.value = [ctx.field[op](veval.value[0], bigInt(1))]; res.value = [ctx.F[op](veval.value[0], ctx.F.one)];
} }
genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef); genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef);
if (lr == "RIGHT") { if (lr == "RIGHT") {
@@ -1081,7 +1121,7 @@ function genOpOp(ctx, ast, op, lr) {
} }
} }
function genOp(ctx, ast, op, nOps) { function genOp(ctx, ast, op, nOps, adjustBool) {
const vals = []; const vals = [];
const valRefs = []; const valRefs = [];
@@ -1117,9 +1157,10 @@ function genOp(ctx, ast, op, nOps) {
} else { } else {
const params = []; const params = [];
for (let i=0; i<nOps; i++) { for (let i=0; i<nOps; i++) {
params.push(vals[i].value[0]); params.push(ctx.F.e(vals[i].value[0]));
} }
rRef = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](...params));
rRef = newRef(ctx, "BIGINT", "_tmp", adjustBool ? (ctx.F[op](...params)?ctx.F.one:ctx.F.zero) : ctx.F[op](...params));
} }
return rRef; return rRef;
} }
@@ -1201,7 +1242,7 @@ function genTerCon(ctx, ast) {
} else { } else {
if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned"); if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
if (!cond.value[0].isZero()) { if (!ctx.F.isZero(cond.value[0])) {
return gen(ctx, ast.values[1]); return gen(ctx, ast.values[1]);
} else { } else {
return gen(ctx, ast.values[2]); return gen(ctx, ast.values[2]);

View File

@@ -76,21 +76,14 @@ QEX QEX NQ NQ NQ
NQ NQ NQ NQ NQ NQ NQ NQ NQ NQ
*/ */
const bigInt = require("big-integer");
const utils = require("./utils"); const utils = require("./utils");
const sONE = 0; const sONE = 0;
class LCAlgebra { class LCAlgebra {
constructor (aField) { constructor (aField) {
const self = this; const self = this;
this.field= aField; this.F= aField;
[ [
["lt",2],
["leq",2],
["eq",2],
["neq",2],
["geq",2],
["gt",2],
["idiv",2], ["idiv",2],
["mod",2], ["mod",2],
["band",2], ["band",2],
@@ -102,12 +95,18 @@ class LCAlgebra {
["lnot",2], ["lnot",2],
["shl",2], ["shl",2],
["shr",2], ["shr",2],
["lt",2, true],
["leq",2, true],
["eq",2, true],
["neq",2, true],
["geq",2, true],
["gt",2, true]
].forEach( (op) => { ].forEach( (op) => {
self._genNQOp(op[0], op[1]); self._genNQOp(op[0], op[1], op[2]);
}); });
} }
_genNQOp(op, nOps) { _genNQOp(op, nOps, adjustBool) {
const self=this; const self=this;
self[op] = function() { self[op] = function() {
const operands = []; const operands = [];
@@ -118,7 +117,7 @@ class LCAlgebra {
} }
return { return {
t: "N", t: "N",
v: self.field[op](...operands) v: adjustBool ? ( self.F[op](...operands) ? self.F.one: self.F.zero) : self.F[op](...operands)
}; };
}; };
} }
@@ -129,7 +128,7 @@ class LCAlgebra {
t: "LC", t: "LC",
coefs: {} coefs: {}
}; };
lc.coefs[a.sIdx] = bigInt(1); lc.coefs[a.sIdx] = self.F.one;
return lc; return lc;
} else { } else {
return a; return a;
@@ -200,17 +199,17 @@ class LCAlgebra {
function add_N_N(a,b) { function add_N_N(a,b) {
return { return {
t: "N", t: "N",
v: self.field.add(a.v, b.v) v: self.F.add(a.v, b.v)
}; };
} }
function add_LC_N(a,b) { function add_LC_N(a,b) {
let res = self._clone(a); let res = self._clone(a);
if (b.v.isZero()) return res; if (self.F.isZero(b.v)) return res;
if (!utils.isDefined(res.coefs[sONE])) { if (!utils.isDefined(res.coefs[sONE])) {
res.coefs[sONE]= b.v; res.coefs[sONE]= b.v;
} else { } else {
res.coefs[sONE]= self.field.add(res.coefs[sONE], b.v); res.coefs[sONE]= self.F.add(res.coefs[sONE], b.v);
} }
return res; return res;
} }
@@ -221,7 +220,7 @@ class LCAlgebra {
if (!utils.isDefined(res.coefs[k])) { if (!utils.isDefined(res.coefs[k])) {
res.coefs[k]=b.coefs[k]; res.coefs[k]=b.coefs[k];
} else { } else {
res.coefs[k]= self.field.add(res.coefs[k], b.coefs[k]); res.coefs[k]= self.F.add(res.coefs[k], b.coefs[k]);
} }
} }
return res; return res;
@@ -283,14 +282,14 @@ class LCAlgebra {
function mul_N_N(a,b) { function mul_N_N(a,b) {
return { return {
t: "N", t: "N",
v: self.field.mul(a.v, b.v) v: self.F.mul(a.v, b.v)
}; };
} }
function mul_LC_N(a,b) { function mul_LC_N(a,b) {
let res = self._clone(a); let res = self._clone(a);
for (let k in res.coefs) { for (let k in res.coefs) {
res.coefs[k] = self.field.mul(res.coefs[k], b.v); res.coefs[k] = self.F.mul(res.coefs[k], b.v);
} }
return res; return res;
} }
@@ -318,10 +317,10 @@ class LCAlgebra {
const a = this._signal2lc(_a); const a = this._signal2lc(_a);
let res = this._clone(a); let res = this._clone(a);
if (res.t == "N") { if (res.t == "N") {
res.v = this.field.neg(a.v); res.v = this.F.neg(a.v);
} else if (res.t == "LC") { } else if (res.t == "LC") {
for (let k in res.coefs) { for (let k in res.coefs) {
res.coefs[k] = this.field.neg(res.coefs[k]); res.coefs[k] = this.F.neg(res.coefs[k]);
} }
} else if (res.t == "QEX") { } else if (res.t == "QEX") {
res.a = this.neg(res.a); res.a = this.neg(res.a);
@@ -338,10 +337,10 @@ class LCAlgebra {
div(a, b) { div(a, b) {
if (b.t == "N") { if (b.t == "N") {
if (b.v.isZero()) throw new Error("Division by zero"); if (this.F.isZero(b.v)) throw new Error("Division by zero");
const inv = { const inv = {
t: "N", t: "N",
v: this.field.inv(b.v) v: this.F.inv(b.v)
}; };
return this.mul(a, inv); return this.mul(a, inv);
} else { } else {
@@ -351,23 +350,23 @@ class LCAlgebra {
pow(a, b) { pow(a, b) {
if (b.t == "N") { if (b.t == "N") {
if (b.v.isZero()) { if (this.F.isZero(b.v)) {
if (this.isZero(a)) { if (this.isZero(a)) {
throw new Error("Zero to the Zero"); throw new Error("Zero to the Zero");
} }
return { return {
t: "N", t: "N",
v: this.field.one v: this.F.one
}; };
} else if (b.v.eq(this.field.one)) { } else if (this.F.eq(b.v, this.F.one)) {
return a; return a;
} else if (b.v.eq(bigInt(2))) { } else if (this.F.eq(b.v, this.F.two)) {
return this.mul(a,a); return this.mul(a,a);
} else { } else {
if (a.t=="N") { if (a.t=="N") {
return { return {
t: "N", t: "N",
v: this.field.pow(a.v, b.v) v: this.F.pow(a.v, b.v)
}; };
} else { } else {
return {t: "NQ"}; return {t: "NQ"};
@@ -381,18 +380,18 @@ class LCAlgebra {
substitute(where, signal, equivalence) { substitute(where, signal, equivalence) {
if (equivalence.t != "LC") throw new Error("Equivalence must be a Linear Combination"); if (equivalence.t != "LC") throw new Error("Equivalence must be a Linear Combination");
if (where.t == "LC") { if (where.t == "LC") {
if (!utils.isDefined(where.coefs[signal]) || where.coefs[signal].isZero()) return where; if (!utils.isDefined(where.coefs[signal]) || this.F.isZero(where.coefs[signal])) return where;
const res=this._clone(where); const res=this._clone(where);
const coef = res.coefs[signal]; const coef = res.coefs[signal];
for (let k in equivalence.coefs) { for (let k in equivalence.coefs) {
if (k != signal) { if (k != signal) {
const v = this.field.mul( coef, equivalence.coefs[k] ); const v = this.F.mul( coef, equivalence.coefs[k] );
if (!utils.isDefined(res.coefs[k])) { if (!utils.isDefined(res.coefs[k])) {
res.coefs[k]=v; res.coefs[k]=v;
} else { } else {
res.coefs[k]= this.field.add(res.coefs[k],v); res.coefs[k]= this.F.add(res.coefs[k],v);
} }
if (res.coefs[k].isZero()) delete res.coefs[k]; if (this.F.isZero(res.coefs[k])) delete res.coefs[k];
} }
} }
delete res.coefs[signal]; delete res.coefs[signal];
@@ -436,10 +435,10 @@ class LCAlgebra {
isZero(a) { isZero(a) {
if (a.t == "N") { if (a.t == "N") {
return a.v.isZero(); return this.F.isZero(a.v);
} else if (a.t == "LC") { } else if (a.t == "LC") {
for (let k in a.coefs) { for (let k in a.coefs) {
if (!a.coefs[k].isZero()) return false; if (!this.F.isZero(a.coefs[k])) return false;
} }
return true; return true;
} else if (a.t == "QEX") { } else if (a.t == "QEX") {
@@ -455,16 +454,16 @@ class LCAlgebra {
} else if (a.t == "LC") { } else if (a.t == "LC") {
let S=""; let S="";
for (let k in a.coefs) { for (let k in a.coefs) {
if (!a.coefs[k].isZero()) { if (!this.F.isZero(a.coefs[k])) {
let c; let c;
if (a.coefs[k].greater(this.field.p.divide(2))) { if (a.coefs[k].greater(this.F.p.divide(2))) {
S = S + "-"; S = S + "-";
c = this.field.p.minus(a.coefs[k]); c = this.F.p.minus(a.coefs[k]);
} else { } else {
if (S!="") S=S+" + "; if (S!="") S=S+" + ";
c = a.coefs[k]; c = a.coefs[k];
} }
if (!c.equals(bigInt.one)) { if (!c.equals(this.F.one)) {
S = S + c.toString() + "*"; S = S + c.toString() + "*";
} }
let sIdx = k; let sIdx = k;
@@ -491,11 +490,11 @@ class LCAlgebra {
} else if (n.t == "SIGNAL") { } else if (n.t == "SIGNAL") {
return getSignalValue(ctx, n.sIdx); return getSignalValue(ctx, n.sIdx);
} else if (n.t == "LC") { } else if (n.t == "LC") {
let v= this.field.zero; let v= this.F.zero;
for (let k in n.coefs) { for (let k in n.coefs) {
const s = getSignalValue(ctx, k); const s = getSignalValue(ctx, k);
if (s === null) return null; if (s === null) return null;
v = this.field.add(v, this.field.mul( n.coefs[k], s)); v = this.F.add(v, this.F.mul( n.coefs[k], s));
} }
return v; return v;
} else if (n.type == "QEX") { } else if (n.type == "QEX") {
@@ -506,7 +505,7 @@ class LCAlgebra {
const c = this.evaluate(ctx, n.c); const c = this.evaluate(ctx, n.c);
if (c === null) return null; if (c === null) return null;
return this.field.add(this.field.mul(a,b), c); return this.F.add(this.F.mul(a,b), c);
} else { } else {
return null; return null;
} }
@@ -529,24 +528,24 @@ class LCAlgebra {
let s = k; let s = k;
while (ctx.signals[s].e>=0) s= ctx.signals[s].e; while (ctx.signals[s].e>=0) s= ctx.signals[s].e;
if (utils.isDefined(ctx.signals[s].v)&&(k != sONE)) { if (utils.isDefined(ctx.signals[s].v)&&(k != sONE)) {
const v = this.field.mul(res.coefs[k], ctx.signals[s].v); const v = this.F.mul(res.coefs[k], ctx.signals[s].v);
if (!utils.isDefined(res.coefs[sONE])) { if (!utils.isDefined(res.coefs[sONE])) {
res.coefs[sONE]=v; res.coefs[sONE]=v;
} else { } else {
res.coefs[sONE]= this.field.add(res.coefs[sONE], v); res.coefs[sONE]= this.F.add(res.coefs[sONE], v);
} }
delete res.coefs[k]; delete res.coefs[k];
} else if (s != k) { } else if (s != k) {
if (!utils.isDefined(res.coefs[s])) { if (!utils.isDefined(res.coefs[s])) {
res.coefs[s]=res.coefs[k]; res.coefs[s]=res.coefs[k];
} else { } else {
res.coefs[s]= this.field.add(res.coefs[s], res.coefs[k]); res.coefs[s]= this.F.add(res.coefs[s], res.coefs[k]);
} }
delete res.coefs[k]; delete res.coefs[k];
} }
} }
for (let k in res.coefs) { for (let k in res.coefs) {
if (res.coefs[k].isZero()) delete res.coefs[k]; if (this.F.isZero(res.coefs[k])) delete res.coefs[k];
} }
return res; return res;
} else if (a.t == "QEX") { } else if (a.t == "QEX") {

View File

@@ -1,167 +1,15 @@
const fs = require("fs"); const fastFile = require("fastfile");
const assert = require("assert"); const assert = require("assert");
const bigInt = require("big-integer");
module.exports.buildR1cs = buildR1cs; module.exports.buildR1cs = buildR1cs;
module.exports.loadR1cs = loadR1cs;
async function loadR1cs(fileName, loadConstraints, loadMap) {
const res = {};
const fd = await fs.promises.open(fileName, "r");
const b = Buffer.allocUnsafe(4);
await fd.read(b, 0, 4, 0);
if (b.toString() != "r1cs") assert(false, "Invalid File format");
let p=4;
let v = await readU32();
if (v>1) assert(false, "Version not supported");
const nSections = await readU32();
let pHeader;
let pConstraints;
let headerSize;
let constraintsSize;
let pMap;
let mapSize;
for (let i=0; i<nSections; i++) {
let ht = await readU32();
let hl = await readU32();
if (ht == 1) {
if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
pHeader = p;
headerSize = hl;
} else if (ht==2) {
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
pConstraints = p;
constraintsSize = hl;
} else if (ht==3) {
pMap = p;
mapSize = hl;
}
p += hl;
}
if (typeof pHeader == "undefined") assert(false, "File has two header");
// Read Header
p = pHeader;
const fieldDefSize = await readU32();
const pFieldDef = p;
const defType = await readU32();
if (defType != 1) if (typeof pConstraints != "undefined") assert(false, "Field type not supported");
res.prime = await readBigInt();
if ( p != pFieldDef + fieldDefSize) assert("Invalid fieldDef size");
const bigIntFormat = await readU32();
if (bigIntFormat != 0) assert(false, "BigInt format not supported");
const idSize = await readU32();
if (idSize != 4) assert(false, "idSize not supported. Mus be 4");
res.nWires = await readU32();
res.nPubOuts = await readU32();
res.nPubIns = await readU32();
res.nPrvIns = await readU32();
res.nLabels = await readU32();
res.nConstraints = await readU32();
if (p != pHeader + headerSize) assert(false, "Invalid header section size");
if (loadConstraints) {
// Read Constraints
p = pConstraints;
res.constraints = [];
for (let i=0; i<res.nConstraints; i++) {
const c = await readConstraint();
res.constraints.push(c);
}
if (p != pConstraints + constraintsSize) assert(false, "Invalid constraints size");
}
// Read Labels
if (loadMap) {
p = pMap;
res.map = [];
for (let i=0; i<res.nLabels; i++) {
const idx = await readU32();
res.map.push(idx);
}
if (p != pMap + mapSize) assert(false, "Invalid Map size");
}
await fd.close();
return res;
async function readU32() {
const b = Buffer.allocUnsafe(4);
await fd.read(b, 0, 4, p);
p+=4;
return b.readInt32LE(0);
}
async function readBigInt() {
const bl = Buffer.allocUnsafe(1);
await fd.read(bl, 0, 1, p);
p++;
const l = bl[0];
const b = Buffer.allocUnsafe(l);
await fd.read(b, 0, l, p);
p += l;
const arr = Uint8Array.from(b);
const arrr = new Array(arr.length);
for (let i=0; i<arr.length; i++) {
arrr[i] = arr[arr.length-1-i];
}
const n = bigInt.fromArray(arrr, 256);
return n;
}
async function readConstraint() {
const c = {};
c.a = await readLC();
c.b = await readLC();
c.c = await readLC();
return c;
}
async function readLC() {
const lc= {};
const nIdx = await readU32();
for (let i=0; i<nIdx; i++) {
const idx = await readU32();
const val = await readBigInt();
lc[idx] = val;
}
return lc;
}
}
async function buildR1cs(ctx, fileName) { async function buildR1cs(ctx, fileName) {
const fd = await fs.promises.open(fileName, "w"); const fd = await fastFile.createOverride(fileName);
await fd.write("r1cs"); // Magic "r1cs" await fd.write(Buffer.from("r1cs"), 0); // Magic "r1cs"
let p = 4; let p = 4;
await writeU32(1); // Version await writeU32(1); // Version
@@ -171,18 +19,13 @@ async function buildR1cs(ctx, fileName) {
/////////// ///////////
await writeU32(1); // Header type await writeU32(1); // Header type
const pHeaderSize = p; const pHeaderSize = p;
await writeU32(0); // Temporally set to 0 length await writeU64(0); // Temporally set to 0 length
const n8 = (Math.floor( (ctx.F.bitLength - 1) / 64) +1)*8;
// Field Def // Field Def
const pFieldDefSize = p; await writeU32(n8); // Temporally set to 0 length
await writeU32(0); // Temporally set to 0 length await writeBigInt(ctx.F.p);
await writeU32(1);
await writeBigInt(ctx.field.p);
const fieldDefSize = p - pFieldDefSize - 4;
await writeU32(0); // Variable bigInt format
await writeU32(4); // Id Size
const NWires = const NWires =
ctx.totals[ctx.stONE] + ctx.totals[ctx.stONE] +
@@ -195,32 +38,31 @@ async function buildR1cs(ctx, fileName) {
await writeU32(ctx.totals[ctx.stOUTPUT]); await writeU32(ctx.totals[ctx.stOUTPUT]);
await writeU32(ctx.totals[ctx.stPUBINPUT]); await writeU32(ctx.totals[ctx.stPUBINPUT]);
await writeU32(ctx.totals[ctx.stPRVINPUT]); await writeU32(ctx.totals[ctx.stPRVINPUT]);
await writeU32(ctx.signals.length); await writeU64(ctx.signals.length);
await writeU32(ctx.constraints.length); await writeU32(ctx.constraints.length);
const headerSize = p - pHeaderSize - 4; const headerSize = p - pHeaderSize - 8;
// Write constraints // Write constraints
/////////// ///////////
await writeU32(2); // Constraints type await writeU32(2); // Constraints type
const pConstraintsSize = p; const pConstraintsSize = p;
await writeU32(0); // Temporally set to 0 length await writeU64(0); // Temporally set to 0 length
for (let i=0; i<ctx.constraints.length; i++) { for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%10000 == 0)) { if ((ctx.verbose)&&(i%10000 == 0)) {
if (ctx.verbose) console.log("writing constraint: ", i); if (ctx.verbose) console.log("writing constraint: ", i);
await fd.datasync();
} }
await writeConstraint(ctx.constraints[i]); await writeConstraint(ctx.constraints[i]);
} }
const constraintsSize = p - pConstraintsSize - 4; const constraintsSize = p - pConstraintsSize - 8;
// Write map // Write map
/////////// ///////////
await writeU32(3); // wires2label type await writeU32(3); // wires2label type
const pMapSize = p; const pMapSize = p;
await writeU32(0); // Temporally set to 0 length await writeU64(0); // Temporally set to 0 length
const arr = new Array(NWires); const arr = new Array(NWires);
@@ -234,30 +76,45 @@ async function buildR1cs(ctx, fileName) {
} }
} }
for (let i=0; i<arr.length; i++) { for (let i=0; i<arr.length; i++) {
await writeU32(arr[i]); await writeU64(arr[i]);
if ((ctx.verbose)&&(i%100000)) console.log("writing label2wire map: ", i); if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i);
} }
const mapSize = p - pMapSize -4; const mapSize = p - pMapSize - 8;
// Write sizes // Write sizes
await writeU32(headerSize, pHeaderSize); await writeU32(headerSize, pHeaderSize);
await writeU32(fieldDefSize, pFieldDefSize);
await writeU32(constraintsSize, pConstraintsSize); await writeU32(constraintsSize, pConstraintsSize);
await writeU32(mapSize, pMapSize); await writeU32(mapSize, pMapSize);
await fd.sync();
await fd.close(); await fd.close();
async function writeU32(v, pos) { async function writeU32(v, pos) {
let o = (typeof pos == "undefined") ? p : pos;
const b = Buffer.allocUnsafe(4); const b = Buffer.allocUnsafe(4);
b.writeInt32LE(v); b.writeInt32LE(v);
await fd.write(b, 0, 4, pos); await fd.write(b, o);
if (typeof(pos) == "undefined") p += 4; if (typeof(pos) == "undefined") p += 4;
} }
async function writeU64(v, pos) {
let o = (typeof pos == "undefined") ? p : pos;
const b = Buffer.allocUnsafe(8);
const LSB = v & 0xFFFFFFFF;
const MSB = Math.floor(v / 0x100000000);
b.writeInt32LE(LSB, 0);
b.writeInt32LE(MSB, 4);
await fd.write(b, o);
if (typeof(pos) == "undefined") p += 8;
}
async function writeConstraint(c) { async function writeConstraint(c) {
await writeLC(c.a); await writeLC(c.a);
await writeLC(c.b); await writeLC(c.b);
@@ -277,12 +134,17 @@ async function buildR1cs(ctx, fileName) {
} }
} }
async function writeBigInt(n) { async function writeBigInt(n, pos) {
const bytes = bigInt(n).toArray(256).value.reverse(); let o = (typeof pos == "undefined") ? p : pos;
await fd.write(Buffer.from([bytes.length, ...bytes ])); const s = n.toString(16);
const b = Buffer.from(s.padStart(n8*2, "0"), "hex");
const buff = Buffer.allocUnsafe(b.length);
for (let i=0; i<b.length; i++) buff[i] = b[b.length-1-i];
p += bytes.length+1; await fd.write(buff, o);
if (typeof(pos) == "undefined") p += n8;
} }
} }

View File

@@ -0,0 +1,21 @@
const Readable = require("stream").Readable;
module.exports = function streamFromArrayBin(a) {
const rs = Readable();
let curIndex = 0;
rs._read = function(size) {
if (curIndex >= a.length) {
rs.push(null);
return;
}
const start = curIndex;
const end = Math.min(a.length, curIndex+size);
curIndex = end;
rs.push(a.slice(start, end));
};
return rs;
};

View File

@@ -1,7 +1,7 @@
const Readable = require("stream").Readable; const Readable = require("stream").Readable;
module.exports = function streamFromMultiarray(ma) { module.exports = function streamFromArrayTxt(ma) {
const rs = Readable(); const rs = Readable();
let curIndex = getFirstIdx(ma); let curIndex = getFirstIdx(ma);
@@ -10,7 +10,7 @@ module.exports = function streamFromMultiarray(ma) {
let res; let res;
res = objFromIdx(ma, curIndex); res = objFromIdx(ma, curIndex);
curIndex = nextIdx(curIndex); curIndex = nextIdx(curIndex);
if (res!=null) { if (res!==null) {
rs.push(res + "\n"); rs.push(res + "\n");
} else { } else {
rs.push(null); rs.push(null);

View File

@@ -1,5 +1,4 @@
const fnv = require("fnv-plus"); const fnv = require("fnv-plus");
const bigInt = require("big-integer");
module.exports.ident =ident; module.exports.ident =ident;
@@ -8,8 +7,6 @@ module.exports.flatArray = flatArray;
module.exports.csArr = csArr; module.exports.csArr = csArr;
module.exports.accSizes = accSizes; module.exports.accSizes = accSizes;
module.exports.fnvHash = fnvHash; module.exports.fnvHash = fnvHash;
module.exports.stringifyBigInts = stringifyBigInts;
module.exports.unstringifyBigInts = unstringifyBigInts;
module.exports.sameSizes = sameSizes; module.exports.sameSizes = sameSizes;
module.exports.isDefined = isDefined; module.exports.isDefined = isDefined;
module.exports.accSizes2Str = accSizes2Str; module.exports.accSizes2Str = accSizes2Str;
@@ -45,7 +42,7 @@ function flatArray(a) {
fillArray(res, a[i]); fillArray(res, a[i]);
} }
} else { } else {
res.push(bigInt(a)); res.push(a);
} }
} }
} }
@@ -74,42 +71,6 @@ function fnvHash(str) {
return fnv.hash(str, 64).hex(); return fnv.hash(str, 64).hex();
} }
function stringifyBigInts(o) {
if ((typeof(o) == "bigint") || o.isZero !== undefined) {
return o.toString(10);
} else if (Array.isArray(o)) {
return o.map(stringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = stringifyBigInts(o[k]);
}
return res;
} else {
return o;
}
}
function unstringifyBigInts(o) {
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
return bigInt(o);
} else if (Array.isArray(o)) {
return o.map(unstringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = unstringifyBigInts(o[k]);
}
return res;
} else {
return bigInt(o);
}
}
function sameSizes(s1, s2) { function sameSizes(s1, s2) {
if (!Array.isArray(s1)) return false; if (!Array.isArray(s1)) return false;
if (!Array.isArray(s2)) return false; if (!Array.isArray(s2)) return false;

View File

@@ -1,15 +1,19 @@
const path = require("path"); const path = require("path");
const bigInt = require("big-integer"); const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field;
const c_tester = require("../index.js").c_tester; const c_tester = require("../index.js").c_tester;
const wasm_tester = require("../index.js").wasm_tester;
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const __P__ = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const Fr = new F1Field(__P__);
const basicCases = require("./basiccases.json");
function normalize(o) { function normalize(o) {
if ((typeof(o) == "bigint") || o.isZero !== undefined) { if ((typeof(o) == "bigint") || o.isZero !== undefined) {
const res = bigInt(o); return Fr.e(o);
return norm(res);
} else if (Array.isArray(o)) { } else if (Array.isArray(o)) {
return o.map(normalize); return o.map(normalize);
} else if (typeof o == "object") { } else if (typeof o == "object") {
@@ -19,23 +23,20 @@ function normalize(o) {
} }
return res; return res;
} else { } else {
const res = bigInt(o); return Fr.e(o);
return norm(res);
} }
function norm(n) {
let res = n.mod(__P__);
if (res.isNegative()) res = __P__.add(res);
return res;
}
} }
async function doTest(circuit, testVectors) { async function doTest(tester, circuit, testVectors) {
const cir = await c_tester(path.join(__dirname, "circuits", circuit)); const cir = await tester(path.join(__dirname, "circuits", circuit));
for (let i=0; i<testVectors.length; i++) { for (let i=0; i<testVectors.length; i++) {
const w = await cir.calculateWitness(normalize(testVectors[i][0])); const w = await cir.calculateWitness(normalize(testVectors[i][0]));
// console.log(testVectors[i][0]);
// console.log(w);
// console.log(testVectors[i][1]);
await cir.assertOut(w, normalize(testVectors[i][1]) ); await cir.assertOut(w, normalize(testVectors[i][1]) );
} }
@@ -45,299 +46,16 @@ async function doTest(circuit, testVectors) {
describe("basic cases", function () { describe("basic cases", function () {
this.timeout(100000); this.timeout(100000);
it("inout", async () => { for (let i=0; i<basicCases.length; i++) {
await doTest( it("c/c++ " + basicCases[i].name, async () => {
"inout.circom", await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv);
[ });
[{in1: 1, in2: [2,3], in3:[[4,5], [6,7], [8,9]]}, {out1: 1, out2: [2,3], out3: [[4,5], [6,7],[8,9]]}], }
]
);
});
it("add", async () => {
await doTest(
"add.circom",
[
[{in: [0,0]}, {out: 0}],
[{in: [0,1]}, {out: 1}],
[{in: [1,2]}, {out: 3}],
[{in: [__P__.minus(1),1]}, {out: 0}],
]
);
});
it("add constant", async () => {
await doTest(
"addconst1.circom",
[
[{in: 0}, {out: 15}],
[{in: 10}, {out: 25}],
[{in: __P__.minus(2)}, {out: 13}],
]
);
});
it("for unrolled", async () => {
await doTest(
"forunrolled.circom",
[
[{in: 0}, {out: [0,1,2]}],
[{in: 10}, {out: [10, 11, 12]}],
[{in: __P__.minus(2)}, {out: [__P__.minus(2), __P__.minus(1), 0]}],
]
);
});
it("for rolled", async () => {
await doTest(
"forrolled.circom",
[
[{in: 0}, {out: 0}],
[{in: 10}, {out: 10}],
]
);
});
it("while unrolled", async () => {
await doTest(
"whileunrolled.circom",
[
[{in: 0}, {out: [0,1,2]}],
[{in: 10}, {out: [10, 11, 12]}],
[{in: __P__.minus(2)}, {out: [__P__.minus(2), __P__.minus(1), 0]}],
]
);
});
it("while rolled", async () => {
await doTest(
"whilerolled.circom",
[
[{in: 0}, {out: 0}],
[{in: 10}, {out: 10}],
]
);
});
it("function1", async () => {
await doTest(
"function1.circom",
[
[{in: 0}, {out: 3}],
[{in: 10}, {out: 13}],
[{in: __P__.minus(2)}, {out: 1}],
]
);
});
it("function2", async () => {
await doTest(
"function2.circom",
[
[{in: 0}, {out: 3}],
[{in: 10}, {out: 13}],
[{in: __P__.minus(2)}, {out: 1}],
]
);
});
it("constants1", async () => {
await doTest(
"constants1.circom",
[
[{in: 0}, {out: 42}],
[{in: 10}, {out: 52}],
[{in: __P__.minus(2)}, {out: 40}],
]
);
});
it("arrays", async () => {
await doTest(
"arrays.circom",
[
[{in: 0}, {out: [1, 8, 51]}],
[{in: 10}, {out: [11, 28, 111]}],
[{in: __P__.minus(2)}, {out: [__P__.minus(1), 4, 39]}],
]
);
});
it("if unrolled", async () => {
await doTest(
"ifunrolled.circom",
[
[{in: 0}, {out: [1, 3, 6]}],
[{in: 10}, {out: [11, 13, 16]}],
[{in: __P__.minus(2)}, {out: [__P__.minus(1), 1, 4]}],
]
);
});
it("if rolled", async () => {
await doTest(
"ifrolled.circom",
[
[{in: 0}, {out: [1, 0, 0]}],
[{in: 1}, {out: [0, 1, 0]}],
[{in: 2}, {out: [0, 0, 1]}],
[{in: 3}, {out: [0, 0, 0]}],
[{in: __P__.minus(2)}, {out: [0,0,0]}],
]
);
});
it("inc", async () => {
await doTest(
"inc.circom",
[
[{in: 0}, {out: [5, 2]}],
[{in: 1}, {out: [6, 4]}],
[{in: 2}, {out: [7, 6]}],
[{in: 3}, {out: [8, 8]}],
[{in: __P__.minus(2)}, {out: [3,__P__.minus(2)]}],
]
);
});
it("dec", async () => {
await doTest(
"dec.circom",
[
[{in: 0}, {out: [1, __P__.minus(2)]}],
[{in: 1}, {out: [2, 0]}],
[{in: 2}, {out: [3, 2]}],
[{in: 3}, {out: [4, 4]}],
[{in: __P__.minus(2)}, {out: [__P__.minus(1),__P__.minus(6)]}],
]
);
});
it("ops", async () => {
await doTest(
"ops.circom",
[
[{in: [-2, 2]}, {add: 0, sub: -4, mul: -4}],
[{in: [-1, 1]}, {add: 0, sub: -2, mul: -1}],
[{in: [ 0, 0]}, {add: 0, sub: 0, mul: 0}],
[{in: [ 1,-1]}, {add: 0, sub: 2, mul: -1}],
[{in: [ 2,-2]}, {add: 0, sub: 4, mul: -4}],
[{in: [-2,-3]}, {add: -5, sub: 1, mul: 6}],
[{in: [ 2, 3]}, {add: 5, sub: -1, mul: 6}],
]
);
});
it("ops2", async () => {
await doTest(
"ops2.circom",
[
[{in: [-2, 2]}, {div: -1, idiv: bigInt("10944121435919637611123202872628637544274182200208017171849102093287904247807"), mod: 1}],
[{in: [-1, 1]}, {div: -1, idiv: -1, mod: 0}],
[{in: [ 1,-1]}, {div: -1, idiv: 0, mod: 1}],
]
);
});
it("ops3", async () => {
await doTest(
"ops3.circom",
[
[{in: [-2, 2]}, {neg1: 2,neg2: -2, pow: 4}],
[{in: [0, 1]}, {neg1: 0, neg2: -1, pow: 0}],
[{in: [ 1,-1]}, {neg1: -1, neg2: 1, pow: 1}],
]
);
});
it("Comparation ops", async () => {
await doTest(
"opscmp.circom",
[
[{in: [ 8, 9]}, {lt: 1, leq: 1, eq:0, neq:1, geq: 0, gt:0}],
[{in: [-2,-2]}, {lt: 0, leq: 1, eq:1, neq:0, geq: 1, gt:0}],
[{in: [-1,-2]}, {lt: 0, leq: 0, eq:0, neq:1, geq: 1, gt:1}],
[{in: [ 1,-1]}, {lt: 0, leq: 0, eq:0, neq:1, geq: 1, gt:1}], // In mod, negative values are higher than positive.
]
);
});
it("Bit ops", async () => {
const mask = bigInt("14474011154664524427946373126085988481658748083205070504932198000989141204991");
const m1m = bigInt("7414231717174750794300032619171286606889616317210963838766006185586667290624");
await doTest(
"opsbit.circom",
[
[{in: [ 5, 3]}, {and: 1, or: 7, xor:6, not1:mask.minus(5), shl: 40, shr:0}],
[{in: [ 0, 0]}, {and: 0, or: 0, xor:0, not1:mask, shl: 0, shr:0}],
[{in: [-1, 1]}, {and: 0, or: m1m.add(bigInt.one), xor:m1m.add(bigInt.one), not1:mask.minus(m1m), shl: m1m.shiftLeft(1).and(mask), shr:__P__.shiftRight(1).and(mask)}],
]
);
});
it("Logical ops", async () => {
await doTest(
"opslog.circom",
[
[{in: [ 5, 0]}, {and: 0, or: 1, not1:0}],
[{in: [ 0, 1]}, {and: 0, or: 1, not1:1}],
[{in: [-1, 9]}, {and: 1, or: 1, not1:0}],
[{in: [ 0, 0]}, {and: 0, or: 0, not1:1}],
]
);
});
it("Conditional Ternary operator", async () => { for (let i=0; i<basicCases.length; i++) {
await doTest( it("wasm " + basicCases[i].name, async () => {
"condternary.circom", await doTest(wasm_tester, basicCases[i].circuit, basicCases[i].tv);
[ });
[{in: 0}, {out: 21}], }
[{in: 1}, {out: 1}],
[{in: 2}, {out: 23}],
[{in:-1}, {out: 20}],
]
);
});
it("Compute block", async () => {
await doTest(
"compute.circom",
[
[{x: 1}, {y: 7}],
[{x: 2}, {y: 7}],
[{x: 3}, {y: 11}],
[{x:-1}, {y: -5}],
]
);
});
it("Component array ", async () => {
await doTest(
"componentarray.circom",
[
[{in: 1}, {out: 1}],
[{in: 2}, {out: 256}],
[{in: 3}, {out: 6561}],
[{in:-1}, {out: 1}],
]
);
});
it("Component array 2d", async () => {
await doTest(
"componentarray2.circom",
[
[{in: [1,2]}, {out: [1, 256]}],
[{in: [0,3]}, {out: [0, 6561]}],
]
);
});
it("Constant circuit", async () => {
await doTest(
"constantcircuit.circom",
[
// 0xbb67ae85
[{}, {out: [1,0,1,0, 0,0,0,1, 0,1,1,1, 0,1,0,1, 1,1,1,0, 0,1,1,0, 1,1,0,1, 1,1,0,1]}],
]
);
});
it("Constant internal circuit", async () => {
await doTest(
"constantinternalcircuit.circom",
[
[{in: 1}, {out: 5}],
[{in: 0}, {out: 4}],
[{in: -2}, {out: 2}],
[{in: 10}, {out: 14}]
]
);
});
it("include", async () => {
await doTest(
"include.circom",
[
[{in: 3}, {out: 6}],
[{in: 6}, {out: 15}],
]
);
});
}); });

307
test/basiccases.json Normal file
View File

@@ -0,0 +1,307 @@
[
{
"name": "inout",
"circuit": "inout.circom",
"tv": [
[{
"in1": 1,
"in2": [2,3],
"in3" : [[4,5], [6,7], [8,9]]
}, {
"out1": 1,
"out2": [2,3],
"out3": [[4,5], [6,7],[8,9]]
}]
]
},
{
"name": "add",
"circuit": "add.circom",
"tv": [
[{"in": [0,0]}, {"out": 0}],
[{"in": [0 ,1]}, {"out": 1}],
[{"in": [1 ,2]}, {"out": 3}],
[{"in": [-1,1]}, {"out": 0}]
]
},
{
"name": "add constant",
"circuit": "addconst1.circom",
"tv": [
[{"in": 0}, {"out": 15}],
[{"in": 10}, {"out": 25}],
[{"in": -2}, {"out": 13}]
]
},
{
"name": "for unrolled",
"circuit": "forunrolled.circom",
"tv": [
[{"in": 0}, {"out": [ 0, 1, 2]}],
[{"in": 10}, {"out": [10, 11, 12]}],
[{"in": -2}, {"out": [-2, -1, 0]}]
]
},
{
"name": "for rolled",
"circuit": "forrolled.circom",
"tv": [
[{"in": 0}, {"out": 0}],
[{"in": 10}, {"out": 10}]
]
},
{
"name": "while unrolled",
"circuit": "whileunrolled.circom",
"tv": [
[{"in": 0}, {"out": [ 0, 1, 2]}],
[{"in": 10}, {"out": [10, 11, 12]}],
[{"in": -2}, {"out": [-2, -1, 0]}]
]
},
{
"name": "while rolled",
"circuit": "whilerolled.circom",
"tv": [
[{"in": 0}, {"out": 0}],
[{"in": 10}, {"out": 10}]
]
},
{
"name": "function1",
"circuit": "function1.circom",
"tv": [
[{"in": 0}, {"out": 3}],
[{"in": 10}, {"out": 13}],
[{"in": -2}, {"out": 1}]
]
},
{
"name": "function2",
"circuit": "function2.circom",
"tv": [
[{"in": 0 }, {"out": 3}],
[{"in": 10}, {"out": 13}],
[{"in": -2}, {"out": 1}]
]
},
{
"name": "constants1",
"circuit": "constants1.circom",
"tv": [
[{"in": 0}, {"out": 42}],
[{"in": 10}, {"out": 52}],
[{"in": -2}, {"out": 40}]
]
},
{
"name": "arrays",
"circuit": "arrays.circom",
"tv": [
[{"in": 0}, {"out": [ 1, 8, 51]}],
[{"in": 10}, {"out": [11, 28, 111]}],
[{"in": -2}, {"out": [-1, 4, 39]}]
]
},
{
"name": "if unrolled",
"circuit": "ifunrolled.circom",
"tv": [
[{"in": 0}, {"out": [ 1, 3, 6]}],
[{"in": 10}, {"out": [11, 13, 16]}],
[{"in": -2}, {"out": [-1, 1, 4]}]
]
},
{
"name": "if rolled",
"circuit": "ifrolled.circom",
"tv": [
[{"in": 0}, {"out": [1, 0, 0]}],
[{"in": 1}, {"out": [0, 1, 0]}],
[{"in": 2}, {"out": [0, 0, 1]}],
[{"in": 3}, {"out": [0, 0, 0]}],
[{"in": -2}, {"out": [0, 0, 0]}]
]
},
{
"name": "inc",
"circuit": "inc.circom",
"tv": [
[{"in": 0}, {"out": [5, 2]}],
[{"in": 1}, {"out": [6, 4]}],
[{"in": 2}, {"out": [7, 6]}],
[{"in": 3}, {"out": [8, 8]}],
[{"in": -2}, {"out": [3,-2]}]
]
},
{
"name": "dec",
"circuit": "dec.circom",
"tv": [
[{"in": 0}, {"out": [ 1, -2]}],
[{"in": 1}, {"out": [ 2, 0]}],
[{"in": 2}, {"out": [ 3, 2]}],
[{"in": 3}, {"out": [ 4, 4]}],
[{"in": -2}, {"out": [-1, -6]}]
]
},
{
"name": "ops",
"circuit": "ops.circom",
"tv": [
[{"in": [-2, 2]}, {"add": 0, "sub": -4, "mul": -4}],
[{"in": [-1, 1]}, {"add": 0, "sub": -2, "mul": -1}],
[{"in": [ 0, 0]}, {"add": 0, "sub": 0, "mul": 0}],
[{"in": [ 1,-1]}, {"add": 0, "sub": 2, "mul": -1}],
[{"in": [ 2,-2]}, {"add": 0, "sub": 4, "mul": -4}],
[{"in": [-2,-3]}, {"add": -5, "sub": 1, "mul": 6}],
[{"in": [ 2, 3]}, {"add": 5, "sub": -1, "mul": 6}]
]
},
{
"name": "ops2",
"circuit": "ops2.circom",
"tv": [
[{"in": [-2, 2]}, {"div": -1, "idiv": "10944121435919637611123202872628637544274182200208017171849102093287904247807", "mod": 1}],
[{"in": [-1, 1]}, {"div": -1, "idiv": -1, "mod": 0}],
[{"in": [ 1,-1]}, {"div": -1, "idiv": 0, "mod": 1}]
]
},
{
"name": "ops3",
"circuit": "ops3.circom",
"tv": [
[{"in": [-2, 2]}, {"neg1": 2, "neg2": -2, "pow": 4}],
[{"in": [ 0, 1]}, {"neg1": 0, "neg2": -1, "pow": 0}],
[{"in": [ 1,-1]}, {"neg1": -1, "neg2": 1, "pow": 1}]
]
},
{
"name": "Comparation ops",
"circuit": "opscmp.circom",
"tv": [
[{"in": [ 8, 9]}, {"lt": 1, "leq": 1, "eq":0, "neq":1, "geq": 0, "gt":0}],
[{"in": [-2,-2]}, {"lt": 0, "leq": 1, "eq":1, "neq":0, "geq": 1, "gt":0}],
[{"in": [-1,-2]}, {"lt": 0, "leq": 0, "eq":0, "neq":1, "geq": 1, "gt":1}],
[{"in": [ 1,-1]}, {"lt": 0, "leq": 0, "eq":0, "neq":1, "geq": 1, "gt":1}]
]
},
{
"name": "Bit ops",
"circuit": "opsbit.circom",
"tv": [
[
{
"in": [ 5, 3]
},
{
"and": 1,
"or": 7,
"xor":6,
"not1": "7059779437489773633646340506914701874769131765994106666166191815402473914361",
"shl": 40,
"shr":0
}
],
[
{
"in": [ 0, 0]
},
{
"and": 0,
"or": 0,
"xor":0,
"not1":"7059779437489773633646340506914701874769131765994106666166191815402473914366",
"shl": 0,
"shr":0
}
],
[
{
"in": [-1, 1]
},
{
"and": 0,
"or": 0,
"xor": 0,
"not1": "7059779437489773633646340506914701874769131765994106666166191815402473914367",
"shl": "14828463434349501588600065238342573213779232634421927677532012371173334581248",
"shr": "10944121435919637611123202872628637544274182200208017171849102093287904247808"
}
]
]
},
{
"name": "Logical ops",
"circuit": "opslog.circom",
"tv": [
[{"in": [ 5, 0]}, {"and": 0, "or": 1, "not1":0}],
[{"in": [ 0, 1]}, {"and": 0, "or": 1, "not1":1}],
[{"in": [-1, 9]}, {"and": 1, "or": 1, "not1":0}],
[{"in": [ 0, 0]}, {"and": 0, "or": 0, "not1":1}]
]
},
{
"name": "Conditional Ternary operator",
"circuit": "condternary.circom",
"tv": [
[{"in": 0}, {"out": 21}],
[{"in": 1}, {"out": 1}],
[{"in": 2}, {"out": 23}],
[{"in":-1}, {"out": 20}]
]
},
{
"name": "Compute block",
"circuit": "compute.circom",
"tv": [
[{"x": 1}, {"y": 7}],
[{"x": 2}, {"y": 7}],
[{"x": 3}, {"y": 11}],
[{"x":-1}, {"y": -5}]
]
},
{
"name": "Component array",
"circuit": "componentarray.circom",
"tv": [
[{"in": 1}, {"out": 1}],
[{"in": 2}, {"out": 256}],
[{"in": 3}, {"out": 6561}],
[{"in":-1}, {"out": 1}]
]
},
{
"name": "Component array 2d",
"circuit": "componentarray2.circom",
"tv": [
[{"in": [1,2]}, {"out": [1, 256]}],
[{"in": [0,3]}, {"out": [0, 6561]}]
]
},
{
"name": "Constant circuit",
"circuit": "constantcircuit.circom",
"tv": [
[{}, {"out": [1,0,1,0, 0,0,0,1, 0,1,1,1, 0,1,0,1, 1,1,1,0, 0,1,1,0, 1,1,0,1, 1,1,0,1]}]
]
},
{
"name": "Constant internal circuit",
"circuit": "constantinternalcircuit.circom",
"tv": [
[{"in": 1}, {"out": 5}],
[{"in": 0}, {"out": 4}],
[{"in": -2}, {"out": 2}],
[{"in": 10}, {"out": 14}]
]
},
{
"name": "include",
"circuit": "include.circom",
"tv": [
[{"in": 3}, {"out": 6}],
[{"in": 6}, {"out": 15}]
]
}
]

View File

@@ -1,67 +0,0 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const bigInt = snarkjs.bigInt;
const compiler = require("../index.js");
const assert = chai.assert;
async function assertThrowsAsync(fn, regExp) {
let f = () => {};
try {
await fn();
} catch(e) {
f = () => { throw e; };
} finally {
assert.throws(f, regExp);
}
}
describe("Sum test", () => {
it("Should compile a code with an undefined if", async () => {
await compiler(path.join(__dirname, "circuits", "undefinedif.circom"));
});
it("Should compile a code with vars inside a for", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "forvariables.circom"));
const circuit = new snarkjs.Circuit(cirDef);
const witness = circuit.calculateWitness({ "in": 111});
assert(witness[0].equals(bigInt(1)));
assert(witness[1].equals(bigInt(114)));
assert(witness[2].equals(bigInt(111)));
});
it("Should compile a code with an undefined if", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "mixvarsignal.circom"));
const circuit = new snarkjs.Circuit(cirDef);
const witness = circuit.calculateWitness({ "i": 111});
assert(witness[0].equals(bigInt(1)));
assert(witness[1].equals(bigInt(111*111)));
assert(witness[2].equals(bigInt(111)));
});
// it("Should assign signal ERROR", async () => {
// await assertThrowsAsync(async () => {
// await compiler(path.join(__dirname, "circuits", "assignsignal.circom"));
// }, /Cannot assign to a signal .*/);
// });
it("Should compile a code with compute", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "compute.circom"));
const circuit = new snarkjs.Circuit(cirDef);
const witness = circuit.calculateWitness({ "x": 6});
assert(witness[0].equals(bigInt(1)));
assert(witness[1].equals(bigInt(37)));
assert(witness[2].equals(bigInt(6)));
});
it("Should compile a code with compute", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "inout.circom"));
assert.equal(cirDef.constraints.length, 1);
});
});

View File

@@ -31,9 +31,11 @@ template Main() {
out[0] === in+c[0]; out[0] === in+c[0];
out[1] <-- d[1]+c[1]; out[1] <-- d[1]+c[1];
// out[1] === (in+in)+3+c[1];
out[1] === 2*in+3+c[1]; out[1] === 2*in+3+c[1];
out[2] <-- d[2]+c[2]; out[2] <-- d[2]+c[2];
// out[2] === (in+in+in+in+in+in)+12+c[2];
out[2] === 6*in+12+c[2]; out[2] === 6*in+12+c[2];
} }

View File

@@ -1 +0,0 @@
{"x": "3"}

View File

@@ -1,407 +0,0 @@
const tester = require("../c/buildasm/buildzqfieldtester.js");
const ZqField = require("fflib").ZqField;
const bigInt = require("big-integer");
const bn128q = new bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
const bn128r = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const secp256k1q = new bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
const secp256k1r = new bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);
const mnt6753q = new bigInt("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001");
const mnt6753r = new bigInt("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601");
describe("field asm test", function () {
this.timeout(1000000000);
it("bn128r add", async () => {
const tv = buildTestVector2(bn128r, "add");
await tester(bn128r, tv);
});
it("secp256k1q add", async () => {
const tv = buildTestVector2(secp256k1q, "add");
await tester(secp256k1q, tv);
});
it("mnt6753q add", async () => {
const tv = buildTestVector2(mnt6753q, "add");
await tester(mnt6753q, tv);
});
it("bn128r sub", async () => {
const tv = buildTestVector2(bn128r, "sub");
await tester(bn128r, tv);
});
it("secp256k1q sub", async () => {
const tv = buildTestVector2(secp256k1q, "sub");
await tester(secp256k1q, tv);
});
it("mnt6753q sub", async () => {
const tv = buildTestVector2(mnt6753q, "sub");
await tester(mnt6753q, tv);
});
it("bn128r neg", async () => {
const tv = buildTestVector1(bn128r, "neg");
await tester(bn128r, tv);
});
it("secp256k1q neg", async () => {
const tv = buildTestVector1(secp256k1q, "neg");
await tester(secp256k1q, tv);
});
it("mnt6753q neg", async () => {
const tv = buildTestVector1(mnt6753q, "neg");
await tester(mnt6753q, tv);
});
it("bn128r mul", async () => {
const tv = buildTestVector2(bn128r, "mul");
await tester(bn128r, tv);
});
it("secp256k1q mul", async () => {
const tv = buildTestVector2(secp256k1q, "mul");
await tester(secp256k1q, tv);
});
it("mnt6753q mul", async () => {
const tv = buildTestVector2(mnt6753q, "mul");
await tester(mnt6753q, tv);
});
it("bn128r binary and", async () => {
const tv = buildTestVector2(bn128r, "band");
await tester(bn128r, tv);
});
it("secp256k1q binary and", async () => {
const tv = buildTestVector2(secp256k1q, "band");
await tester(secp256k1q, tv);
});
it("mnt6753q binary and", async () => {
const tv = buildTestVector2(mnt6753q, "band");
await tester(mnt6753q, tv);
});
it("bn128r binary or", async () => {
const tv = buildTestVector2(bn128r, "bor");
await tester(bn128r, tv);
});
it("secp256k1q binary or", async () => {
const tv = buildTestVector2(secp256k1q, "bor");
await tester(secp256k1q, tv);
});
it("mnt6753q binary or", async () => {
const tv = buildTestVector2(mnt6753q, "bor");
await tester(mnt6753q, tv);
});
it("bn128r binary xor", async () => {
const tv = buildTestVector2(bn128r, "bxor");
await tester(bn128r, tv);
});
it("secp256k1q binary xor", async () => {
const tv = buildTestVector2(secp256k1q, "bxor");
await tester(secp256k1q, tv);
});
it("mnt6753q binary xor", async () => {
const tv = buildTestVector2(mnt6753q, "bxor");
await tester(mnt6753q, tv);
});
it("bn128r binary not", async () => {
const tv = buildTestVector1(bn128r, "bnot");
await tester(bn128r, tv);
});
it("secp256k1q binary not", async () => {
const tv = buildTestVector1(secp256k1q, "bnot");
await tester(secp256k1q, tv);
});
it("mnt6753q binary not", async () => {
const tv = buildTestVector1(mnt6753q, "bnot");
await tester(mnt6753q, tv);
});
it("bn128r eq", async () => {
const tv = buildTestVector2(bn128r, "eq");
await tester(bn128r, tv);
});
it("secp256k1q eq", async () => {
const tv = buildTestVector2(secp256k1q, "eq");
await tester(secp256k1q, tv);
});
it("mnt6753q eq", async () => {
const tv = buildTestVector2(mnt6753q, "eq");
await tester(mnt6753q, tv);
});
it("bn128r neq", async () => {
const tv = buildTestVector2(bn128r, "neq");
await tester(bn128r, tv);
});
it("secp256k1q neq", async () => {
const tv = buildTestVector2(secp256k1q, "neq");
await tester(secp256k1q, tv);
});
it("mnt6753q neq", async () => {
const tv = buildTestVector2(mnt6753q, "neq");
await tester(mnt6753q, tv);
});
it("bn128r lt", async () => {
const tv = buildTestVector2(bn128r, "lt");
await tester(bn128r, tv);
});
it("secp256k1q lt", async () => {
const tv = buildTestVector2(secp256k1q, "lt");
await tester(secp256k1q, tv);
});
it("mnt6753q lt", async () => {
const tv = buildTestVector2(mnt6753q, "lt");
await tester(mnt6753q, tv);
});
it("bn128r gt", async () => {
const tv = buildTestVector2(bn128r, "gt");
await tester(bn128r, tv);
});
it("secp256k1q gt", async () => {
const tv = buildTestVector2(secp256k1q, "gt");
await tester(secp256k1q, tv);
});
it("mnt6753q gt", async () => {
const tv = buildTestVector2(mnt6753q, "gt");
await tester(mnt6753q, tv);
});
it("bn128r leq", async () => {
const tv = buildTestVector2(bn128r, "leq");
await tester(bn128r, tv);
});
it("secp256k1q leq", async () => {
const tv = buildTestVector2(secp256k1q, "leq");
await tester(secp256k1q, tv);
});
it("mnt6753q leq", async () => {
const tv = buildTestVector2(mnt6753q, "leq");
await tester(mnt6753q, tv);
});
it("bn128r geq", async () => {
const tv = buildTestVector2(bn128r, "geq");
await tester(bn128r, tv);
});
it("secp256k1q geq", async () => {
const tv = buildTestVector2(secp256k1q, "geq");
await tester(secp256k1q, tv);
});
it("mnt6753q geq", async () => {
const tv = buildTestVector2(mnt6753q, "geq");
await tester(mnt6753q, tv);
});
it("bn128r logical and", async () => {
const tv = buildTestVector2(bn128r, "land");
await tester(bn128r, tv);
});
it("secp256k1q logical and", async () => {
const tv = buildTestVector2(secp256k1q, "land");
await tester(secp256k1q, tv);
});
it("mnt6753q logical and", async () => {
const tv = buildTestVector2(mnt6753q, "land");
await tester(mnt6753q, tv);
});
it("bn128r logical or", async () => {
const tv = buildTestVector2(bn128r, "lor");
await tester(bn128r, tv);
});
it("secp256k1q logical or", async () => {
const tv = buildTestVector2(secp256k1q, "lor");
await tester(secp256k1q, tv);
});
it("mnt6753q logical or", async () => {
const tv = buildTestVector2(mnt6753q, "lor");
await tester(mnt6753q, tv);
});
it("bn128r logical not", async () => {
const tv = buildTestVector1(bn128r, "lnot");
await tester(bn128r, tv);
});
it("secp256k1q logical not", async () => {
const tv = buildTestVector1(secp256k1q, "lnot");
await tester(secp256k1q, tv);
});
it("mnt6753q logical not", async () => {
const tv = buildTestVector1(mnt6753q, "lnot");
await tester(mnt6753q, tv);
});
it("bn128r idiv", async () => {
const tv = buildTestVector2(bn128r, "idiv");
await tester(bn128r, tv);
});
it("secp256k1q idiv", async () => {
const tv = buildTestVector2(secp256k1q, "idiv");
await tester(secp256k1q, tv);
});
it("mnt6753q idiv", async () => {
const tv = buildTestVector2(mnt6753q, "idiv");
await tester(mnt6753q, tv);
});
it("bn128r inv", async () => {
const tv = buildTestVector1(bn128r, "inv");
await tester(bn128r, tv);
});
it("secp256k1q inv", async () => {
const tv = buildTestVector1(secp256k1q, "inv");
await tester(secp256k1q, tv);
});
it("mnt6753q inv", async () => {
const tv = buildTestVector1(mnt6753q, "inv");
await tester(mnt6753q, tv);
});
it("bn128r div", async () => {
const tv = buildTestVector2(bn128r, "div");
await tester(bn128r, tv);
});
it("secp256k1q div", async () => {
const tv = buildTestVector2(secp256k1q, "div");
await tester(secp256k1q, tv);
});
it("mnt6753q div", async () => {
const tv = buildTestVector2(mnt6753q, "div");
await tester(mnt6753q, tv);
});
it("bn128r square", async () => {
const tv = buildTestVector1(bn128r, "square");
await tester(bn128r, tv);
});
it("secp256k1q square", async () => {
const tv = buildTestVector1(secp256k1q, "square");
await tester(secp256k1q, tv);
});
it("mnt6753q square", async () => {
const tv = buildTestVector1(mnt6753q, "square");
await tester(mnt6753q, tv);
});
});
function buildTestVector2(p, op) {
const F = new ZqField(p);
const tv = [];
const nums = getCriticalNumbers(p, 2);
const excludeZero = ["div", "mod", "idiv"].indexOf(op) >= 0;
for (let i=0; i<nums.length; i++) {
for (let j=0; j<nums.length; j++) {
if ((excludeZero)&&(nums[j][0].isZero())) continue;
tv.push([
[nums[i][1], nums[j][1], op],
F[op](nums[i][0], nums[j][0])
]);
}
}
return tv;
}
function buildTestVector1(p, op) {
const F = new ZqField(p);
const tv = [];
const nums = getCriticalNumbers(p, 2);
const excludeZero = ["inv"].indexOf(op) >= 0;
for (let i=0; i<nums.length; i++) {
if ((excludeZero)&&(nums[i][0].isZero())) continue;
tv.push([
[nums[i][1], op],
F[op](nums[i][0])
]);
}
return tv;
}
function getCriticalNumbers(p, lim) {
const numbers = [];
addFrontier(0);
addFrontier(bigInt.one.shiftLeft(31));
addFrontier(p.minus(bigInt.one.shiftLeft(31)));
addFrontier(bigInt.one.shiftLeft(32));
addFrontier(p.minus(bigInt.one.shiftLeft(32)));
addFrontier(bigInt.one.shiftLeft(63));
addFrontier(p.minus(bigInt.one.shiftLeft(63)));
addFrontier(bigInt.one.shiftLeft(64));
addFrontier(p.minus(bigInt.one.shiftLeft(64)));
addFrontier(bigInt.one.shiftLeft(p.bitLength()-1));
addFrontier(p.shiftRight(1));
function addFrontier(f) {
for (let i=-lim; i<=lim; i++) {
let n = bigInt(f).add(bigInt(i));
n = n.mod(p);
if (n.isNegative()) n = p.add(n);
addNumber(n);
}
}
return numbers;
function addNumber(n) {
if (n.lt(bigInt("80000000", 16)) ) {
addShortPositive(n);
addShortMontgomeryPositive(n);
}
if (n.geq(p.minus(bigInt("80000000", 16))) ) {
addShortNegative(n);
addShortMontgomeryNegative(n);
}
addLongNormal(n);
addLongMontgomery(n);
function addShortPositive(a) {
numbers.push([a, "0x"+a.toString(16)]);
}
function addShortMontgomeryPositive(a) {
let S = "0x" + bigInt("40", 16).shiftLeft(56).add(a).toString(16);
S = S + "," + getLongString(toMontgomery(a));
numbers.push([a, S]);
}
function addShortNegative(a) {
const b = bigInt("80000000", 16 ).add(a.minus( p.minus(bigInt("80000000", 16 ))));
numbers.push([a, "0x"+b.toString(16)]);
}
function addShortMontgomeryNegative(a) {
const b = bigInt("80000000", 16 ).add(a.minus( p.minus(bigInt("80000000", 16 ))));
let S = "0x" + bigInt("40", 16).shiftLeft(56).add(b).toString(16);
S = S + "," + getLongString(toMontgomery(a));
numbers.push([a, S]);
}
function addLongNormal(a) {
let S = "0x" + bigInt("80", 16).shiftLeft(56).toString(16);
S = S + "," + getLongString(a);
numbers.push([a, S]);
}
function addLongMontgomery(a) {
let S = "0x" + bigInt("C0", 16).shiftLeft(56).toString(16);
S = S + "," + getLongString(toMontgomery(a));
numbers.push([a, S]);
}
function getLongString(a) {
if (a.isZero()) {
return "0x0";
}
let r = a;
let S = "";
while (!r.isZero()) {
if (S!= "") S = S+",";
S += "0x" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16);
r = r.shiftRight(64);
}
return S;
}
function toMontgomery(a) {
const n64 = Math.floor((p.bitLength() - 1) / 64)+1;
const R = bigInt.one.shiftLeft(n64*64);
return a.times(R).mod(p);
}
}
}