mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-06 18:56:40 +01:00
Compare commits
99 Commits
feature/wi
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d5077106a | ||
|
|
b68c9fa5d2 | ||
|
|
94cb37bd9e | ||
|
|
9f15dd2e29 | ||
|
|
334697dd0c | ||
|
|
6c48e9ba01 | ||
|
|
42162b10c1 | ||
|
|
a84873161f | ||
|
|
9bf1354bf1 | ||
|
|
ed4c4b4de0 | ||
|
|
a1f3f714ea | ||
|
|
dafc9db614 | ||
|
|
6e4a192c6a | ||
|
|
e1286c29c7 | ||
|
|
a002bcbc25 | ||
|
|
f9f1d0c13e | ||
|
|
fc01aad8b6 | ||
|
|
3d5aa14cdc | ||
|
|
5dc54bb7d2 | ||
|
|
349a39dc95 | ||
|
|
0a2aee9932 | ||
|
|
bad8fad3d0 | ||
|
|
0a707648fc | ||
|
|
263dc73906 | ||
|
|
8e730d93a4 | ||
|
|
bbe10438e0 | ||
|
|
c2cef8d80c | ||
|
|
2200408986 | ||
|
|
5f13d37fdc | ||
|
|
3b46b74d4a | ||
|
|
aa2d768465 | ||
|
|
f02ceb2508 | ||
|
|
d014d67032 | ||
|
|
2e1b35a94d | ||
|
|
7cef1be2c3 | ||
|
|
4b631994ca | ||
|
|
7239abcef1 | ||
|
|
633f755e34 | ||
|
|
923b19c414 | ||
|
|
90cc7d5072 | ||
|
|
145d5a21ad | ||
|
|
cbb0b229bc | ||
|
|
1d14e8c603 | ||
|
|
1e2fb12631 | ||
|
|
0e1a1bcc23 | ||
|
|
989987bfc2 | ||
|
|
5f3ef322a7 | ||
|
|
3c8e61b9a4 | ||
|
|
c39423e411 | ||
|
|
06b6c1a49e | ||
|
|
6b712f3587 | ||
|
|
26cad30222 | ||
|
|
f48de61ca9 | ||
|
|
89cea4755c | ||
|
|
9bf6ecc4f3 | ||
|
|
59d591c988 | ||
|
|
9fe8be9828 | ||
|
|
7e24d6f57d | ||
|
|
8655573b34 | ||
|
|
8fc6e3f1c6 | ||
|
|
c32d303d27 | ||
|
|
744d3b241c | ||
|
|
1a5f7d1a2b | ||
|
|
434e7ac498 | ||
|
|
99afb4312e | ||
|
|
67ec7c5d5b | ||
|
|
a76f3b5988 | ||
|
|
bc9d395e70 | ||
|
|
7fc457ac90 | ||
|
|
8c4980c3f9 | ||
|
|
767ca60008 | ||
|
|
f25842f67c | ||
|
|
92399017df | ||
|
|
1463685b11 | ||
|
|
a1ae6e4a44 | ||
|
|
c7c6b799ad | ||
|
|
b107a11432 | ||
|
|
96776d2374 | ||
|
|
ca7379995e | ||
|
|
f604c31e0d | ||
|
|
a9c0593ec0 | ||
|
|
80cce0ccbb | ||
|
|
fcef4f5f32 | ||
|
|
3ef303593b | ||
|
|
16cf75c94b | ||
|
|
d79d59416d | ||
|
|
eae13a94fa | ||
|
|
7e41508860 | ||
|
|
5d374237e1 | ||
|
|
a18b603b22 | ||
|
|
f261992689 | ||
|
|
45e359aa35 | ||
|
|
da6cff2335 | ||
|
|
38b4a7a8b3 | ||
|
|
825f31b420 | ||
|
|
b9b384681b | ||
|
|
eb8cb0af74 | ||
|
|
ef899e618b | ||
|
|
8f63d18ff4 |
@@ -1,7 +1,4 @@
|
||||
module.exports = {
|
||||
"plugins": [
|
||||
"mocha"
|
||||
],
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true,
|
||||
@@ -27,7 +24,6 @@ module.exports = {
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"mocha/no-exclusive-tests": "error"
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
2
COPYING
2
COPYING
@@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
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
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
# Circom
|
||||
|
||||
Circom is a language designed to write arithmetic circuits that can be used in zero knowledge proofs.
|
||||
Circom is a language designed to write arithmetic circuits that can be used in zero-knowledge proofs.
|
||||
|
||||
In particular, it is designed to work in [zksnarks JavaScript library](https://github.com/iden3/zksnark).
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### Circom Docs
|
||||
|
||||
You can read the details of circom in [the documentation webpage](https://docs.circom.io/).
|
||||
|
||||
### Tutorial
|
||||
|
||||
A good starting point [is this tutorial](https://github.com/iden3/circom/blob/master/TUTORIAL.md)
|
||||
|
||||
80
TUTORIAL.md
80
TUTORIAL.md
@@ -1,14 +1,14 @@
|
||||
# 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.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**
|
||||
|
||||
@@ -22,7 +22,7 @@ npm install -g snarkjs
|
||||
|
||||
## 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
|
||||
|
||||
@@ -42,7 +42,7 @@ template Multiplier() {
|
||||
signal private input a;
|
||||
signal private input b;
|
||||
signal output c;
|
||||
|
||||
|
||||
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:
|
||||
|
||||
```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*
|
||||
@@ -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:
|
||||
|
||||
```sh
|
||||
snarkjs --help
|
||||
snarkjs --help
|
||||
```
|
||||
|
||||
### 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:
|
||||
|
||||
```sh
|
||||
snarkjs info -c circuit.json
|
||||
snarkjs info -r circuit.r1cs
|
||||
```
|
||||
|
||||
You can also print the constraints of the circuit by running:
|
||||
|
||||
```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:
|
||||
|
||||
```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
|
||||
|
||||
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.
|
||||
|
||||
@@ -128,7 +132,7 @@ Let's create a file named `input.json`
|
||||
Now let's calculate the witness:
|
||||
|
||||
```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.
|
||||
@@ -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`
|
||||
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
> 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
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
snarkjs generatecall
|
||||
@@ -197,15 +201,15 @@ If you change any bit in the parameters, the result will be verifiably false.
|
||||
|
||||
## 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.
|
||||
|
||||
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() {
|
||||
@@ -214,35 +218,35 @@ template Multiplier() {
|
||||
signal output c;
|
||||
signal inva;
|
||||
signal invb;
|
||||
|
||||
|
||||
inva <-- 1/(a-1);
|
||||
(a-1)*inva === 1;
|
||||
|
||||
|
||||
invb <-- 1/(b-1);
|
||||
(b-1)*invb === 1;
|
||||
|
||||
(b-1)*invb === 1;
|
||||
|
||||
c <== a*b;
|
||||
}
|
||||
|
||||
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).
|
||||
|
||||
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
Enjoy zero knowledge proving!
|
||||
Enjoy zero-knowledge proving!
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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") %>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
5841
c/buildasm/fr.asm
5841
c/buildasm/fr.asm
File diff suppressed because it is too large
Load Diff
@@ -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) %>
|
||||
|
||||
185
c/buildasm/fr.c
185
c/buildasm/fr.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
BIN
c/buildasm/fr.o
BIN
c/buildasm/fr.o
Binary file not shown.
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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"],
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)) %>
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -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`);
|
||||
} %>
|
||||
|
||||
|
||||
229
c/calcwit.cpp
229
c/calcwit.cpp
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
73
c/calcwit.h
73
c/calcwit.h
@@ -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
|
||||
58
c/circom.h
58
c/circom.h
@@ -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
|
||||
202
c/main.cpp
202
c/main.cpp
@@ -1,202 +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");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
BIN
c/mainjson
BIN
c/mainjson
Binary file not shown.
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
25
c/utils.cpp
25
c/utils.cpp
@@ -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;
|
||||
}
|
||||
10
c/utils.h
10
c/utils.h
@@ -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
|
||||
199
c/zqfield.cpp
199
c/zqfield.cpp
@@ -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);
|
||||
}
|
||||
|
||||
49
c/zqfield.h
49
c/zqfield.h
@@ -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
|
||||
128
cli.js
128
cli.js
@@ -23,6 +23,9 @@
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const Scalar = require("ffjavascript").Scalar;
|
||||
const stringifyBigInts = require("ffjavascript").utils.stringifyBigInts;
|
||||
const fastFile = require("fastfile");
|
||||
|
||||
const compiler = require("./src/compiler");
|
||||
|
||||
@@ -30,12 +33,14 @@ const version = require("./package").version;
|
||||
|
||||
const argv = require("yargs")
|
||||
.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("c", "csource")
|
||||
.alias("w", "wasm")
|
||||
.alias("t", "wat")
|
||||
.alias("s", "sym")
|
||||
.alias("r", "r1cs")
|
||||
.alias("p", "prime")
|
||||
.alias("n", "newThreadTemplates")
|
||||
.help("h")
|
||||
.alias("h", "help")
|
||||
@@ -57,62 +62,68 @@ const argv = require("yargs")
|
||||
.argv;
|
||||
|
||||
|
||||
let inputFile;
|
||||
if (argv._.length == 0) {
|
||||
inputFile = "circuit.circom";
|
||||
} else if (argv._.length == 1) {
|
||||
inputFile = argv._[0];
|
||||
} else {
|
||||
console.log("Only one circuit at a time is permited");
|
||||
process.exit(1);
|
||||
}
|
||||
async function run() {
|
||||
let inputFile;
|
||||
if (argv._.length == 0) {
|
||||
inputFile = "circuit.circom";
|
||||
} else if (argv._.length == 1) {
|
||||
inputFile = argv._[0];
|
||||
} else {
|
||||
console.log("Only one circuit at a time is permited");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fullFileName = path.resolve(process.cwd(), inputFile);
|
||||
const fileName = path.basename(fullFileName, ".circom");
|
||||
const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp";
|
||||
const wasmName = typeof(argv.wasm) === "string" ? argv.wasm : fileName + ".wasm";
|
||||
const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs";
|
||||
const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym";
|
||||
const fullFileName = path.resolve(process.cwd(), inputFile);
|
||||
const fileName = path.basename(fullFileName, ".circom");
|
||||
const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp";
|
||||
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 symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym";
|
||||
|
||||
const options = {};
|
||||
options.reduceConstraints = !argv.fast;
|
||||
options.verbose = argv.verbose || false;
|
||||
if (argv.csource) {
|
||||
options.cSourceWriteStream = fs.createWriteStream(cSourceName);
|
||||
}
|
||||
if (argv.wasm) {
|
||||
options.wasmWriteStream = fs.createWriteStream(wasmName);
|
||||
}
|
||||
if (argv.r1cs) {
|
||||
options.r1csFileName = r1csName;
|
||||
}
|
||||
if (argv.sym) {
|
||||
options.symWriteStream = fs.createWriteStream(symName);
|
||||
}
|
||||
if (argv.newThreadTemplates) {
|
||||
options.newThreadTemplates = new RegExp(argv.newThreadTemplates);
|
||||
}
|
||||
const options = {};
|
||||
options.reduceConstraints = !argv.fast;
|
||||
options.verbose = argv.verbose || false;
|
||||
options.sanityCheck = argv.sanitycheck;
|
||||
|
||||
compiler(fullFileName, options).then( () => {
|
||||
let cSourceDone = false;
|
||||
let wasmDone = false;
|
||||
if (argv.csource) {
|
||||
options.cSourceFile = await fastFile.createOverride(cSourceName);
|
||||
const noExt = cSourceName.substr(0, cSourceName.lastIndexOf(".")) || cSourceName;
|
||||
options.dataFile = await fastFile.createOverride(noExt+".dat");
|
||||
}
|
||||
if (argv.wasm) {
|
||||
options.wasmFile = await fastFile.createOverride(wasmName);
|
||||
}
|
||||
if (argv.wat) {
|
||||
options.watFile = await fastFile.createOverride(watName);
|
||||
}
|
||||
if (argv.r1cs) {
|
||||
options.r1csFileName = r1csName;
|
||||
}
|
||||
if (argv.sym) {
|
||||
options.symWriteStream = fs.createWriteStream(symName);
|
||||
}
|
||||
if (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);
|
||||
}
|
||||
|
||||
|
||||
await compiler(fullFileName, options);
|
||||
|
||||
if (options.cSourceFile) await options.cSourceFile.close();
|
||||
if (options.dataFile) await options.dataFile.close();
|
||||
if (options.wasmFile) await options.wasmFile.close();
|
||||
if (options.watFile) await options.watFile.close();
|
||||
let symDone = false;
|
||||
if (options.cSourceWriteStream) {
|
||||
options.cSourceWriteStream.on("finish", () => {
|
||||
cSourceDone = true;
|
||||
finishIfDone();
|
||||
});
|
||||
} else {
|
||||
cSourceDone = true;
|
||||
}
|
||||
if (options.wasmWriteStream) {
|
||||
options.wasmWriteStream.on("finish", () => {
|
||||
wasmDone = true;
|
||||
finishIfDone();
|
||||
});
|
||||
} else {
|
||||
wasmDone = true;
|
||||
}
|
||||
if (options.symWriteStream) {
|
||||
options.symWriteStream.on("finish", () => {
|
||||
symDone = true;
|
||||
@@ -122,12 +133,17 @@ compiler(fullFileName, options).then( () => {
|
||||
symDone = true;
|
||||
}
|
||||
function finishIfDone() {
|
||||
if ((cSourceDone)&&(symDone)&&(wasmDone)) {
|
||||
if (symDone) {
|
||||
setTimeout(() => {
|
||||
process.exit(0);
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
run().then(()=> {
|
||||
process.exit(0);
|
||||
}, (err) => {
|
||||
// console.log(err);
|
||||
console.log(err.stack);
|
||||
@@ -138,11 +154,9 @@ compiler(fullFileName, options).then( () => {
|
||||
if (argv.verbose) console.log(err.stack);
|
||||
}
|
||||
if (err.ast) {
|
||||
console.error(JSON.stringify(err.ast, null, 1));
|
||||
console.error(JSON.stringify(stringifyBigInts(err.ast), null, 1));
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -152,114 +152,93 @@ Size in bytes of the section
|
||||
|
||||
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))
|
||||
┃ 32 │ 01 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
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ is │ 01 00 00 00 ┃ nPrvIn
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ is │ 01 00 00 00 ┃ nLabels
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ is │ 01 00 00 00 ┃ mConstraints
|
||||
┃ 32 │ 01 00 00 00 ┃ mConstraints
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
|
||||
````
|
||||
|
||||
#### fieldDefSize
|
||||
#### field Size (fs)
|
||||
|
||||
Size: 4 bytes
|
||||
Format: Little-Endian
|
||||
|
||||
Size of the field Definition
|
||||
Size in bytes of a field element. Mast be a multiple of 8.
|
||||
|
||||
Example:
|
||||
```
|
||||
0x00 0x0 0x00 0x00
|
||||
```
|
||||
|
||||
#### fieldDef
|
||||
#### Prime
|
||||
|
||||
Field dfinition the first 4 bytes are the type in LE. 0x0000001 Ar prime fields.
|
||||
|
||||
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.
|
||||
Prime Number of the field
|
||||
|
||||
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
|
||||
|
||||
Size: `is` bytes
|
||||
Size: 4 bytes
|
||||
Format: Little-Endian
|
||||
|
||||
Total Number of wires including ONE signal (Index 0).
|
||||
|
||||
#### Number of public outputs
|
||||
|
||||
Size: `is` bytes
|
||||
Size: 4 bytes
|
||||
Format: Little-Endian
|
||||
|
||||
Total Number of wires public output wires. They should be starting at idx 1
|
||||
|
||||
#### Number of public inputs
|
||||
|
||||
Size: `is` bytes
|
||||
Size: 4 bytes
|
||||
Format: Little-Endian
|
||||
|
||||
Total Number of wires public input wires. They should be starting just after the public output
|
||||
|
||||
#### 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
|
||||
|
||||
Total Number of wires private input wires. They should be starting just after the public inputs
|
||||
|
||||
#### Number of constraints (m)
|
||||
|
||||
Size: `ìs` bytes
|
||||
Size: 4 bytes
|
||||
Format: Little-Endian
|
||||
|
||||
Total Number of constraints
|
||||
@@ -269,115 +248,115 @@ Total Number of constraints
|
||||
Section Type: 0x02
|
||||
|
||||
````
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ is │ nA ┃ ╲
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ is │ wireId_1 ┃ V │ a_{0,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ is │ wireId_2 ┃ V │ a_{0,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nA ┃ V │ a_{0,wireId_nA} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ nB ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_1 ┃ V │ b_{0,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
|
||||
┃ is │ wireId_2 ┃ V │ b_{0,wireId_2} ┃ ╲
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_0
|
||||
... ... ╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nB ┃ V │ b_{0,wireId_nB} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ nC ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_1 ┃ V │ c_{0,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ is │ wireId_2 ┃ V │ c_{0,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nC ┃ V │ c_{0,wireId_nC} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 32 │ nA ┃ ╲
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 32 │ wireId_1 ┃ fs │ a_{0,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ 32 │ wireId_2 ┃ fs │ a_{0,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nA ┃ fs │ a_{0,wireId_nA} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ nB ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_1 ┃ fs │ b_{0,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
|
||||
┃ 32 │ wireId_2 ┃ fs │ b_{0,wireId_2} ┃ ╲
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_0
|
||||
... ... ╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nB ┃ fs │ b_{0,wireId_nB} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ nC ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_1 ┃ fs │ c_{0,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ 32 │ wireId_2 ┃ fs │ c_{0,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nC ┃ fs │ c_{0,wireId_nC} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱
|
||||
|
||||
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ is │ nA ┃ ╲
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ is │ wireId_1 ┃ V │ a_{1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ is │ wireId_2 ┃ V │ a_{1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nA ┃ V │ a_{1,wireId_nA} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ nB ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_1 ┃ V │ b_{1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
|
||||
┃ is │ wireId_2 ┃ V │ b_{1,wireId_2} ┃ ╲
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_1
|
||||
... ... ╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nB ┃ V │ b_{1,wireId_nB} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ nC ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_1 ┃ V │ c_{1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ is │ wireId_2 ┃ V │ c_{1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nC ┃ V │ c_{1,wireId_nC} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 32 │ nA ┃ ╲
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 32 │ wireId_1 ┃ fs │ a_{1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ 32 │ wireId_2 ┃ fs │ a_{1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nA ┃ fs │ a_{1,wireId_nA} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ nB ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_1 ┃ fs │ b_{1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
|
||||
┃ 32 │ wireId_2 ┃ fs │ b_{1,wireId_2} ┃ ╲
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_1
|
||||
... ... ╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nB ┃ fs │ b_{1,wireId_nB} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ nC ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_1 ┃ fs │ c_{1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ 32 │ wireId_2 ┃ fs │ c_{1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nC ┃ fs │ c_{1,wireId_nC} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱
|
||||
|
||||
...
|
||||
...
|
||||
...
|
||||
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ is │ nA ┃ ╲
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ is │ wireId_1 ┃ V │ a_{m-1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ is │ wireId_2 ┃ V │ a_{m-1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nA ┃ V │ a_{m-1,wireId_nA} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ nB ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_1 ┃ V │ b_{m-1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
|
||||
┃ is │ wireId_2 ┃ V │ b_{m-1,wireId_2} ┃ ╲
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_{m-1}
|
||||
... ... ╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nB ┃ V │ b_{m-1,wireId_nB} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ nC ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_1 ┃ V │ c_{m-1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ is │ wireId_2 ┃ V │ c_{m-1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ is │ wireId_nC ┃ V │ c_{m-1,wireId_nC} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱ ╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 32 │ nA ┃ ╲
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 32 │ wireId_1 ┃ fs │ a_{m-1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ 32 │ wireId_2 ┃ fs │ a_{m-1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nA ┃ fs │ a_{m-1,wireId_nA} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ nB ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_1 ┃ fs │ b_{m-1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
|
||||
┃ 32 │ wireId_2 ┃ fs │ b_{m-1,wireId_2} ┃ ╲
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_{m-1}
|
||||
... ... ╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nB ┃ fs │ b_{m-1,wireId_nB} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ nC ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_1 ┃ fs │ c_{m-1,wireId_1} ┃ │
|
||||
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
|
||||
┃ 32 │ wireId_2 ┃ fs │ c_{m-1,wireId_2} ┃ │
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
|
||||
... ... │
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
|
||||
┃ 32 │ wireId_nC ┃ fs │ c_{m-1,wireId_nC} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱
|
||||
````
|
||||
|
||||
|
||||
@@ -401,7 +380,7 @@ $$
|
||||
|
||||
#### Number of nonZero Factors
|
||||
|
||||
Size: `ìs` bytes
|
||||
Size: 4 bytes
|
||||
Format: Little-Endian
|
||||
|
||||
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
|
||||
|
||||
Size: `is` bytes
|
||||
Size: 4 bytes
|
||||
Format: Little-Endian
|
||||
|
||||
WireId of the nonZero Factor
|
||||
|
||||
#### Value of the factor
|
||||
|
||||
The first byte indicate the length N in bytes of the number in the upcoming bytes.
|
||||
|
||||
The next N bytes represent the value in Little Endian format.
|
||||
This is the factor that multiplies the associated wire in the linear convination.
|
||||
|
||||
For example, to represent the linear combination:
|
||||
|
||||
@@ -436,13 +413,13 @@ The linear combination would be represented as:
|
||||
````
|
||||
┏━━━━━━━━━━━━━━━━━┓
|
||||
┃ 03 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┓
|
||||
┃ 04 00 00 00 ┃ 01 05 ┃
|
||||
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
|
||||
┃ 05 00 00 00 ┃ 01 08 ┃
|
||||
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
|
||||
┃ 76 03 00 00 ┃ 02 04 01 ┃
|
||||
┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 04 00 00 00 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 05 00 00 00 ┃ 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 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:
|
||||
|
||||
````
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 72 31 63 77 ┃ Magic
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 01 00 00 00 ┃ Version
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 03 00 00 00 ┃ nSections
|
||||
┗━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||
┃ 01 00 00 00 ┃ 49 00 00 00 ┃ SectionType: Header
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||
┃ 25 00 00 00 ┃ 10 00 00 00 ┃ FieldDefSize FieldDef
|
||||
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430┃
|
||||
┣━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┃ 00 00 00 00 ┃ Big Int format
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 04 00 00 00 ┃ Id Size
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 07 00 00 00 ┃ # of wires
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 01 00 00 00 ┃ # Public Outs
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 02 00 00 00 ┃ # Public Ins
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 03 00 00 00 ┃ # Private Ins
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ e8 03 00 00 ┃ # Labels
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 03 00 00 00 ┃ # Constraints
|
||||
┗━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||
┃ 02 00 00 00 ┃ 8b 00 00 00 ┃ SectionType: Constraints
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0
|
||||
┃ 02 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
|
||||
┃ 05 00 00 00 ┃ 01 03 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||
┃ 06 00 00 00 ┃ 01 08 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 03 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
|
||||
┃ 00 00 00 00 ┃ 01 02 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||
┃ 02 00 00 00 ┃ 01 14 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||
┃ 03 00 00 00 ┃ 01 0C ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 02 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
|
||||
┃ 00 00 00 00 ┃ 01 05 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||
┃ 02 00 00 00 ┃ 01 07 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 72316377 ┃ Magic
|
||||
┣━━━━━━━━━━┫
|
||||
┃ 01000000 ┃ Version
|
||||
┣━━━━━━━━━━┫
|
||||
┃ 03000000 ┃ nSections
|
||||
┗━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 01000000 ┃ 40000000 00000000 ┃ SectionType: Header
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 20000000 ┃ Field Size
|
||||
┣━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 ┃
|
||||
┣━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┃ 07000000 ┃ # of wires
|
||||
┣━━━━━━━━━━┫
|
||||
┃ 01000000 ┃ # Public Outs
|
||||
┣━━━━━━━━━━┫
|
||||
┃ 02000000 ┃ # Public Ins
|
||||
┣━━━━━━━━━━┫
|
||||
┃ 03000000 ┃ # Private Ins
|
||||
┣━━━━━━━━━━┻━━━━━━━━┓
|
||||
┃ e8030000 00000000 ┃ # Labels
|
||||
┣━━━━━━━━━━┳━━━━━━━━┛
|
||||
┃ 03000000 ┃ # Constraints
|
||||
┗━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 02000000 ┃ 88200000 00000000 ┃ SectionType: Constraints
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0
|
||||
┃ 02000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 05000000 ┃ 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 06000000 ┃ 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 03000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 00000000 ┃ 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 02000000 ┃ 01140000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 03000000 ┃ 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 02000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 00000000 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 02000000 ┃ 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
┏━━━━━━━━━━━━━━┓ Constraint 1: (4w_1 + 8w_4 + 3w_5) * (6w_6 + 44w_3) = 0
|
||||
┃ 03 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┓
|
||||
┃ 01 00 00 00 ┃ 01 04 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
|
||||
┃ 04 00 00 00 ┃ 01 08 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
|
||||
┃ 05 00 00 00 ┃ 01 03 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 02 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┓
|
||||
┃ 03 00 00 00 ┃ 01 2C ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
|
||||
┃ 06 00 00 00 ┃ 01 06 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 00 00 00 00 ┃
|
||||
┗━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓ Constraint 1: (4w_1 + 8w_4 + 3w_5) * (6w_6 + 44w_3) = 0
|
||||
┃ 03000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 01000000 ┃ 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 04000000 ┃ 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 05000000 ┃ 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 02000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 03000000 ┃ 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 06000000 ┃ 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 00000000 ┃
|
||||
┗━━━━━━━━━━┛
|
||||
|
||||
┏━━━━━━━━━━━━━━┓ Constraint 2: (4w_6) * (6w_0 + 5w_3 + 11w_2) - (600w_6) = 0
|
||||
┃ 01 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┓
|
||||
┃ 06 00 00 00 ┃ 01 04 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 03 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┓
|
||||
┃ 00 00 00 00 ┃ 01 06 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
|
||||
┃ 02 00 00 00 ┃ 01 0B ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
|
||||
┃ 03 00 00 00 ┃ 01 05 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 01 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━╋━━━━━━━━━━━━━┓
|
||||
┃ 06 00 00 00 ┃ 02 58 02 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓ Constraint 2: (4w_6) * (6w_0 + 5w_3 + 11w_2) - (600w_6) = 0
|
||||
┃ 01000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 06000000 ┃ 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 03000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 00000000 ┃ 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 02000000 ┃ 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 03000000 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 01000000 ┃
|
||||
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 06000000 ┃ 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||
┃ 03 00 00 00 ┃ 1c 00 00 00 ┃ Wire to Label Map
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃ 00 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 03 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 0a 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 0b 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 0c 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 0f 00 00 00 ┃
|
||||
┣━━━━━━━━━━━━━━┫
|
||||
┃ 44 01 00 00 ┃
|
||||
┗━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 03000000 ┃ 38000000 00000000 ┃ Wire to Label Map
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 00000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 03000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 0a000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 0b000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 0c000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 0f000000 00000000 ┃
|
||||
┣━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ 44010000 00000000 ┃
|
||||
┗━━━━━━━━━━━━━━━━━━━┛
|
||||
````
|
||||
|
||||
And the binary representation in Hex:
|
||||
|
||||
````
|
||||
72 31 63 77
|
||||
01 00 00 00
|
||||
03 00 00 00
|
||||
01 00 00 00 49 00 00 00
|
||||
25 00 00 00 10 00 00 00
|
||||
20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
|
||||
00 00 00 00
|
||||
04 00 00 00
|
||||
07 00 00 00
|
||||
01 00 00 00
|
||||
02 00 00 00
|
||||
03 00 00 00
|
||||
e8 03 00 00
|
||||
03 00 00 00
|
||||
02 00 00 00 8b 00 00 00
|
||||
02 00 00 00
|
||||
05 00 00 00 01 03
|
||||
06 00 00 00 01 08
|
||||
03 00 00 00
|
||||
00 00 00 00 01 02
|
||||
02 00 00 00 01 14
|
||||
03 00 00 00 01 0C
|
||||
02 00 00 00
|
||||
00 00 00 00 01 05
|
||||
02 00 00 00 01 07
|
||||
03 00 00 00
|
||||
01 00 00 00 01 04
|
||||
04 00 00 00 01 08
|
||||
05 00 00 00 01 03
|
||||
02 00 00 00
|
||||
03 00 00 00 01 2C
|
||||
06 00 00 00 01 06
|
||||
00 00 00 00
|
||||
01 00 00 00
|
||||
06 00 00 00 01 04
|
||||
03 00 00 00
|
||||
00 00 00 00 01 06
|
||||
02 00 00 00 01 0B
|
||||
03 00 00 00 01 05
|
||||
01 00 00 00
|
||||
06 00 00 00 02 58 02
|
||||
03 00 00 00 1c 00 00 00
|
||||
00 00 00 00
|
||||
03 00 00 00
|
||||
0a 00 00 00
|
||||
0b 00 00 00
|
||||
0c 00 00 00
|
||||
0f 00 00 00
|
||||
44 01 00 00
|
||||
72316377
|
||||
01000000
|
||||
03000000
|
||||
01000000 40000000 00000000
|
||||
20000000
|
||||
010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
|
||||
07000000
|
||||
01000000
|
||||
02000000
|
||||
03000000
|
||||
e8030000 00000000
|
||||
03000000
|
||||
02000000 88200000 00000000
|
||||
02000000
|
||||
05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
06000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
03000000
|
||||
00000000 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
02000000 01140000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
03000000 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
02000000
|
||||
00000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
02000000 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
03000000
|
||||
01000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
04000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
02000000
|
||||
03000000 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
06000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000
|
||||
01000000
|
||||
06000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
03000000
|
||||
00000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
02000000 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
03000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
01000000
|
||||
06000000 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
03000000 38000000 00000000
|
||||
00000000 00000000
|
||||
03000000 00000000
|
||||
0a000000 00000000
|
||||
0b000000 00000000
|
||||
0c000000 00000000
|
||||
0f000000 00000000
|
||||
44010000 00000000
|
||||
|
||||
````
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
5
index.js
5
index.js
@@ -1,3 +1,4 @@
|
||||
module.exports.compiler = require("./src/compiler.js");
|
||||
module.exports.c_tester = require("./src/c_tester.js");
|
||||
module.exports.tester = require("./src/c_tester.js");
|
||||
module.exports.c_tester = require("./ports/c/tester.js");
|
||||
module.exports.wasm_tester = require("./ports/wasm/tester.js");
|
||||
module.exports.tester = module.exports.wasm_tester;
|
||||
|
||||
1203
package-lock.json
generated
1203
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "circom",
|
||||
"version": "0.0.35",
|
||||
"version": "0.5.34",
|
||||
"description": "Language to generate logic circuits",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
@@ -29,20 +29,20 @@
|
||||
"url": "https://github.com/iden3/circom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.32",
|
||||
"ejs": "^3.0.1",
|
||||
"fflib": "0.0.2",
|
||||
"chai": "^4.2.0",
|
||||
"circom_runtime": "0.1.9",
|
||||
"fastfile": "0.0.18",
|
||||
"ffiasm": "0.1.1",
|
||||
"ffjavascript": "0.2.22",
|
||||
"ffwasm": "0.0.7",
|
||||
"fnv-plus": "^1.3.1",
|
||||
"optimist": "^0.6.1",
|
||||
"rimraf-promise": "^2.0.0",
|
||||
"r1csfile": "0.0.16",
|
||||
"tmp-promise": "^2.0.2",
|
||||
"yargs": "^12.0.2"
|
||||
"wasmbuilder": "0.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-mocha": "^5.3.0",
|
||||
"eslint": "^6.8.0",
|
||||
"jison": "^0.4.18",
|
||||
"snarkjs": "0.1.14"
|
||||
"yargs": "^15.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
166
parser/jaz.jison
166
parser/jaz.jison
@@ -132,10 +132,8 @@ include { return 'include'; }
|
||||
|
||||
|
||||
%{
|
||||
const bigInt = require('big-integer');
|
||||
const Scalar = require('ffjavascript').Scalar;
|
||||
const util = require('util');
|
||||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const __MASK__ = new bigInt(2).pow(253).minus(1);
|
||||
|
||||
function setLines(dst, first, last) {
|
||||
last = last || first;
|
||||
@@ -266,20 +264,12 @@ identifierList
|
||||
ifStatment
|
||||
: 'if' '(' expression ')' statment 'else' statment
|
||||
{
|
||||
if ($3.type == "NUMBER") {
|
||||
$$ = !$3.value.eq(0) ? $5 : $7;
|
||||
} else {
|
||||
$$ = { type: "IF", condition: $3, then: $5, else: $7 };
|
||||
}
|
||||
$$ = { type: "IF", condition: $3, then: $5, else: $7 };
|
||||
setLines($$, @1, @7);
|
||||
}
|
||||
| 'if' '(' expression ')' statment
|
||||
{
|
||||
if ($3.type == "NUMBER") {
|
||||
$$ = !$3.value.eq(0) ? $5 : { type: "NUMBER", value: bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "IF", condition: $3, then: $5 };
|
||||
}
|
||||
$$ = { type: "IF", condition: $3, then: $5 };
|
||||
setLines($$, @1, @5);
|
||||
}
|
||||
;
|
||||
@@ -451,11 +441,7 @@ e17
|
||||
}
|
||||
| e17 '?' e17 ':' e17 %prec TERCOND
|
||||
{
|
||||
if ($1.type == "NUMBER") {
|
||||
$$ = !$1.value.eq(0) ? $3 : $5;
|
||||
} else {
|
||||
$$ = { type: "OP", op: "?", values: [$1, $3, $5] };
|
||||
}
|
||||
$$ = { type: "OP", op: "?", values: [$1, $3, $5] };
|
||||
setLines($$, @1, @5);
|
||||
}
|
||||
| e16 %prec EMPTY
|
||||
@@ -478,11 +464,7 @@ e16
|
||||
e15
|
||||
: e15 '||' e14
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: !$1.value.eq(0) || !$3.value.eq(0) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "||", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "||", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e14 %prec EMPTY
|
||||
@@ -494,11 +476,7 @@ e15
|
||||
e14
|
||||
: e14 '&&' e13
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: !$1.value.eq(0) && !$3.value.eq(0) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "&&", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "&&", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e13 %prec EMPTY
|
||||
@@ -510,11 +488,7 @@ e14
|
||||
e13
|
||||
: e13 '|' e12
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.or($3.value).and(__MASK__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "|", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "|", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e12 %prec EMPTY
|
||||
@@ -527,11 +501,7 @@ e13
|
||||
e12
|
||||
: e12 '^' e11
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.xor($3.value).and(__MASK__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "^", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "^", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e11 %prec EMPTY
|
||||
@@ -543,11 +513,7 @@ e12
|
||||
e11
|
||||
: e11 '&' e10
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.and($3.value).and(__MASK__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "&", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "&", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e10 %prec EMPTY
|
||||
@@ -562,20 +528,12 @@ e11
|
||||
e10
|
||||
: e10 '==' e9
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.equals($3.value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "==", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "==", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e10 '!=' e9
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.eq($3.value) ? bigInt(0) : bigInt(1) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "!=", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "!=", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e9 %prec EMPTY
|
||||
@@ -587,38 +545,22 @@ e10
|
||||
e9
|
||||
: e9 '<=' e7
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.lesserOrEquals($3.value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "<=", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "<=", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e9 '>=' e7
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.greaterOrEquals($3.value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: ">=", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: ">=", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e9 '<' e7
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.lesser($3.value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "<", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "<", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e9 '>' e7
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.greater($3.value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: ">", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: ">", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e7 %prec EMPTY
|
||||
@@ -630,22 +572,12 @@ e9
|
||||
e7
|
||||
: e7 '<<' e6
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
let v = $3.value.greater(256) ? 256 : $3.value.value;
|
||||
$$ = { type: "NUMBER", value: $1.value.shiftLeft(v).and(__MASK__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "<<", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "<<", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e7 '>>' e6
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
let v = $3.value.greater(256) ? 256 : $3.value.value;
|
||||
$$ = {type: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: ">>", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: ">>", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e6 %prec EMPTY
|
||||
@@ -657,20 +589,12 @@ e7
|
||||
e6
|
||||
: e6 '+' e5
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: ($1.value.plus($3.value)).mod(__P__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "+", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "+", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e6 '-' e5
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: ($1.value.plus(__P__).minus($3.value)).mod(__P__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "-", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "-", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e5 %prec EMPTY
|
||||
@@ -683,38 +607,22 @@ e6
|
||||
e5
|
||||
: e5 '*' e4
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: ($1.value.times($3.value)).mod(__P__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "*", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "*", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e5 '/' e4
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: ($1.value.times($3.value.modInv(__P__))).mod(__P__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "/", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "/", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e5 '\\' e4
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: ($1.value.divide($3.value)) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "\\", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "\\", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e5 '%' e4
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.mod($3.value) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "%", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "%", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e4 %prec EMPTY
|
||||
@@ -726,11 +634,7 @@ e5
|
||||
e4
|
||||
: e4 '**' e3
|
||||
{
|
||||
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
|
||||
$$ = { type: "NUMBER", value: $1.value.modPow($3.value, __P__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "**", values: [$1, $3] };
|
||||
}
|
||||
$$ = { type: "OP", op: "**", values: [$1, $3] };
|
||||
setLines($$, @1, @3);
|
||||
}
|
||||
| e3 %prec EMPTY
|
||||
@@ -758,29 +662,17 @@ e3
|
||||
}
|
||||
| '-' e3 %prec UMINUS
|
||||
{
|
||||
if ($2.type == "NUMBER") {
|
||||
$$ = { type: "NUMBER", value: __P__.minus($2.value).mod(__P__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "UMINUS", values: [$2] };
|
||||
}
|
||||
$$ = { type: "OP", op: "UMINUS", values: [$2] };
|
||||
setLines($$, @1, @2);
|
||||
}
|
||||
| '!' e3
|
||||
{
|
||||
if ($2.type == "NUMBER") {
|
||||
$$ = { type: "NUMBER", value: $2.value.eq(0) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "!", values: [$2] };
|
||||
}
|
||||
$$ = { type: "OP", op: "!", values: [$2] };
|
||||
setLines($$, @1, @2);
|
||||
}
|
||||
| '~' e3
|
||||
{
|
||||
if ($2.type == "NUMBER") {
|
||||
$$ = { type: "NUMBER", value: $2.value.xor(__MASK__) };
|
||||
} else {
|
||||
$$ = { type: "OP", op: "~", values: [$2] };
|
||||
}
|
||||
$$ = { type: "OP", op: "~", values: [$2] };
|
||||
setLines($$, @1, @2);
|
||||
}
|
||||
| e2 %prec EMPTY
|
||||
@@ -817,12 +709,12 @@ e0
|
||||
}
|
||||
| DECNUMBER
|
||||
{
|
||||
$$ = {type: "NUMBER", value: bigInt($1).mod(__P__) }
|
||||
$$ = {type: "NUMBER", value: Scalar.fromString($1) }
|
||||
setLines($$, @1);
|
||||
}
|
||||
| HEXNUMBER
|
||||
{
|
||||
$$ = {type: "NUMBER", value: bigInt($1.substr(2).toUpperCase(), 16).mod(__P__) }
|
||||
$$ = {type: "NUMBER", value: Scalar.fromString($1.substr(2).toUpperCase(), 16) }
|
||||
setLines($$, @1);
|
||||
}
|
||||
| '(' expression ')' %prec EMPTY
|
||||
|
||||
168
parser/jaz.js
168
parser/jaz.js
@@ -146,21 +146,13 @@ case 20:
|
||||
break;
|
||||
case 21:
|
||||
|
||||
if ($$[$0-4].type == "NUMBER") {
|
||||
this.$ = !$$[$0-4].value.eq(0) ? $$[$0-2] : $$[$0];
|
||||
} else {
|
||||
this.$ = { type: "IF", condition: $$[$0-4], then: $$[$0-2], else: $$[$0] };
|
||||
}
|
||||
this.$ = { type: "IF", condition: $$[$0-4], then: $$[$0-2], else: $$[$0] };
|
||||
setLines(this.$, _$[$0-6], _$[$0]);
|
||||
|
||||
break;
|
||||
case 22:
|
||||
|
||||
if ($$[$0-2].type == "NUMBER") {
|
||||
this.$ = !$$[$0-2].value.eq(0) ? $$[$0] : { type: "NUMBER", value: bigInt(0) };
|
||||
} else {
|
||||
this.$ = { type: "IF", condition: $$[$0-2], then: $$[$0] };
|
||||
}
|
||||
this.$ = { type: "IF", condition: $$[$0-2], then: $$[$0] };
|
||||
setLines(this.$, _$[$0-4], _$[$0]);
|
||||
|
||||
break;
|
||||
@@ -321,11 +313,7 @@ case 50:
|
||||
break;
|
||||
case 51:
|
||||
|
||||
if ($$[$0-4].type == "NUMBER") {
|
||||
this.$ = !$$[$0-4].value.eq(0) ? $$[$0-2] : $$[$0];
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "?", values: [$$[$0-4], $$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "?", values: [$$[$0-4], $$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-4], _$[$0]);
|
||||
|
||||
break;
|
||||
@@ -336,71 +324,43 @@ case 52: case 53: case 54: case 56: case 58: case 60:
|
||||
break;
|
||||
case 55:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
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]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "||", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 57:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
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]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "&&", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 59:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.or($$[$0].value).and(__MASK__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "|", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "|", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 61:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.xor($$[$0].value).and(__MASK__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "^", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "^", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 63:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.and($$[$0].value).and(__MASK__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "&", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "&", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 65:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.equals($$[$0].value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "==", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "==", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 66:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.eq($$[$0].value) ? bigInt(0) : bigInt(1) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "!=", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "!=", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
@@ -411,63 +371,37 @@ case 67: case 72:
|
||||
break;
|
||||
case 68:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.lesserOrEquals($$[$0].value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "<=", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "<=", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 69:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.greaterOrEquals($$[$0].value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: ">=", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: ">=", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 70:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.lesser($$[$0].value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "<", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "<", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 71:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.greater($$[$0].value) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: ">", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: ">", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 73:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
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]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "<<", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 74:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
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]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: ">>", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
@@ -478,71 +412,43 @@ case 75:
|
||||
break;
|
||||
case 76:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: ($$[$0-2].value.plus($$[$0].value)).mod(__P__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "+", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "+", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 77:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: ($$[$0-2].value.plus(__P__).minus($$[$0].value)).mod(__P__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "-", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "-", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 79:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: ($$[$0-2].value.times($$[$0].value)).mod(__P__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "*", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "*", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 80:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: ($$[$0-2].value.times($$[$0].value.modInv(__P__))).mod(__P__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "/", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "/", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 81:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: ($$[$0-2].value.divide($$[$0].value)) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "\\", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "\\", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 82:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.mod($$[$0].value) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "%", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "%", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
case 84:
|
||||
|
||||
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
|
||||
this.$ = { type: "NUMBER", value: $$[$0-2].value.modPow($$[$0].value, __P__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "**", values: [$$[$0-2], $$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "**", values: [$$[$0-2], $$[$0]] };
|
||||
setLines(this.$, _$[$0-2], _$[$0]);
|
||||
|
||||
break;
|
||||
@@ -566,31 +472,19 @@ case 88:
|
||||
break;
|
||||
case 89:
|
||||
|
||||
if ($$[$0].type == "NUMBER") {
|
||||
this.$ = { type: "NUMBER", value: __P__.minus($$[$0].value).mod(__P__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "UMINUS", values: [$$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "UMINUS", values: [$$[$0]] };
|
||||
setLines(this.$, _$[$0-1], _$[$0]);
|
||||
|
||||
break;
|
||||
case 90:
|
||||
|
||||
if ($$[$0].type == "NUMBER") {
|
||||
this.$ = { type: "NUMBER", value: $$[$0].value.eq(0) ? bigInt(1) : bigInt(0) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "!", values: [$$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "!", values: [$$[$0]] };
|
||||
setLines(this.$, _$[$0-1], _$[$0]);
|
||||
|
||||
break;
|
||||
case 91:
|
||||
|
||||
if ($$[$0].type == "NUMBER") {
|
||||
this.$ = { type: "NUMBER", value: $$[$0].value.xor(__MASK__) };
|
||||
} else {
|
||||
this.$ = { type: "OP", op: "~", values: [$$[$0]] };
|
||||
}
|
||||
this.$ = { type: "OP", op: "~", values: [$$[$0]] };
|
||||
setLines(this.$, _$[$0-1], _$[$0]);
|
||||
|
||||
break;
|
||||
@@ -613,13 +507,13 @@ case 97: case 102: case 103:
|
||||
break;
|
||||
case 98:
|
||||
|
||||
this.$ = {type: "NUMBER", value: bigInt($$[$0]).mod(__P__) }
|
||||
this.$ = {type: "NUMBER", value: Scalar.fromString($$[$0]) }
|
||||
setLines(this.$, _$[$0]);
|
||||
|
||||
break;
|
||||
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]);
|
||||
|
||||
break;
|
||||
@@ -866,10 +760,8 @@ parse: function parse(input) {
|
||||
return true;
|
||||
}};
|
||||
|
||||
const bigInt = require('big-integer');
|
||||
const Scalar = require('ffjavascript').Scalar;
|
||||
const util = require('util');
|
||||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const __MASK__ = new bigInt(2).pow(253).minus(1);
|
||||
|
||||
function setLines(dst, first, last) {
|
||||
last = last || first;
|
||||
@@ -1365,7 +1257,7 @@ case 77: console.log("INVALID: " + yy_.yytext); return 'INVALID'
|
||||
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}}
|
||||
});
|
||||
return lexer;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
const streamFromMultiArray = require("./stream_from_multiarray");
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils");
|
||||
const utils = require("../../src/utils");
|
||||
const assert = require("assert");
|
||||
const Scalar = require("ffjavascript").Scalar;
|
||||
const F1Field = require("ffjavascript").F1Field;
|
||||
const BigArray = require("../../src/bigarray");
|
||||
|
||||
function ref2src(c) {
|
||||
if (c[0] == "R") {
|
||||
if ((c[0] == "R")||(c[0] == "RI")) {
|
||||
return c[1];
|
||||
} else if (c[0] == "V") {
|
||||
return c[1].toString();
|
||||
@@ -58,8 +59,9 @@ class CodeBuilderC {
|
||||
this.ops.push({op: "SETSIGNAL", component, signal, value});
|
||||
}
|
||||
|
||||
getSignal(dLabel, component, signal) {
|
||||
this.ops.push({op: "GETSIGNAL", dLabel, component, signal});
|
||||
getSignal(dLabel, component, signal, n) {
|
||||
if (typeof(n) == "undefined") n=1;
|
||||
this.ops.push({op: "GETSIGNAL", dLabel, component, signal, n});
|
||||
}
|
||||
|
||||
copyN(dLabel, offset, src, n) {
|
||||
@@ -94,6 +96,13 @@ class CodeBuilderC {
|
||||
this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
|
||||
}
|
||||
|
||||
checkAssert(a, strErr) {
|
||||
this.ops.push({op: "CHECKASSERT", a, strErr});
|
||||
}
|
||||
|
||||
log(val) {
|
||||
this.ops.push({op: "LOG", val});
|
||||
}
|
||||
|
||||
concat(cb) {
|
||||
this.ops.push(...cb.ops);
|
||||
@@ -173,7 +182,7 @@ class CodeBuilderC {
|
||||
} else if (o.op == "SETSIGNAL") {
|
||||
code.push(`ctx->setSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${ref2src(o.value)});`);
|
||||
} else if (o.op == "GETSIGNAL") {
|
||||
code.push(`ctx->getSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${o.dLabel});`);
|
||||
code.push(`ctx->multiGetSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${o.dLabel}, ${o.n});`);
|
||||
} else if (o.op == "COPYN") {
|
||||
const oS = ref2src(o.offset);
|
||||
const dLabel = (oS != "0") ? (o.dLabel + "+" + oS) : o.dLabel;
|
||||
@@ -211,6 +220,10 @@ class CodeBuilderC {
|
||||
code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`);
|
||||
} else if (o.op == "CHECKCONSTRAINT") {
|
||||
code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`);
|
||||
} else if (o.op == "CHECKASSERT") {
|
||||
code.push(`ctx->checkAssert(__cIdx, ${ref2src(o.a)}, "${o.strErr}");`);
|
||||
} else if (o.op == "LOG") {
|
||||
code.push(`ctx->log(${ref2src(o.val)});`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -335,13 +348,23 @@ class FunctionBuilderC {
|
||||
}
|
||||
|
||||
class BuilderC {
|
||||
constructor() {
|
||||
constructor(p, verbose) {
|
||||
this.F = new F1Field(p);
|
||||
|
||||
this.hashMaps={};
|
||||
this.componentEntriesTables={};
|
||||
this.componentEntriesTables=new BigArray();
|
||||
this.sizes ={};
|
||||
this.constants = [];
|
||||
this.functions = [];
|
||||
this.components = [];
|
||||
this.components = new BigArray();
|
||||
this.usedConstants = {};
|
||||
this.verbose = verbose;
|
||||
|
||||
|
||||
this.sizePointers = {};
|
||||
this.hashMapPointers = {};
|
||||
this.functionIdx = {};
|
||||
this.nCets = 0;
|
||||
}
|
||||
|
||||
setHeader(header) {
|
||||
@@ -353,8 +376,11 @@ class BuilderC {
|
||||
this.hashMaps[name] = hm;
|
||||
}
|
||||
|
||||
addComponentEntriesTable(name, cet) {
|
||||
this.componentEntriesTables[name] = cet;
|
||||
addComponentEntriesTable(name, cet, idComponent) {
|
||||
this.componentEntriesTables[idComponent] = {
|
||||
name: name,
|
||||
cet: cet
|
||||
};
|
||||
}
|
||||
|
||||
addSizes(name, accSizes) {
|
||||
@@ -362,7 +388,11 @@ class BuilderC {
|
||||
}
|
||||
|
||||
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.usedConstants[cS] = this.constants.length - 1;
|
||||
return this.constants.length - 1;
|
||||
}
|
||||
|
||||
@@ -396,219 +426,305 @@ class BuilderC {
|
||||
|
||||
_buildHeader(code) {
|
||||
code.push(
|
||||
"#include \"circom.h\"",
|
||||
"#include \"calcwit.h\"",
|
||||
"#include \"circom.hpp\"",
|
||||
"#include \"calcwit.hpp\"",
|
||||
`#define NSignals ${this.header.NSignals}`,
|
||||
`#define NComponents ${this.header.NComponents}`,
|
||||
`#define NOutputs ${this.header.NOutputs}`,
|
||||
`#define NInputs ${this.header.NInputs}`,
|
||||
`#define NVars ${this.header.NVars}`,
|
||||
`#define NPublic ${this.header.NPublic}`,
|
||||
`#define __P__ "${this.header.P.toString()}"`,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
_buildHashMaps(code) {
|
||||
async _buildHashMaps(fdData) {
|
||||
|
||||
code.push("// Hash Maps ");
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.pHashMaps = fdData.pos;
|
||||
|
||||
const buff = new Uint8Array(256*12);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
for (let hmName in this.hashMaps ) {
|
||||
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.hashMapPointers[hmName] = fdData.pos;
|
||||
const hm = this.hashMaps[hmName];
|
||||
|
||||
let c = `Circom_HashEntry ${hmName}[256] = {`;
|
||||
for (let i=0; i<256; i++) {
|
||||
c += i>0 ? "," : "";
|
||||
if (hm[i]) {
|
||||
c += `{0x${hm[i][0]}LL, ${hm[i][1]}} /* ${hm[i][2]} */`;
|
||||
} else {
|
||||
c += "{0,0}";
|
||||
}
|
||||
buffV.setUint32(i*12, hm[i] ? parseInt( hm[i][0].slice(8), 16 ) : 0, true);
|
||||
buffV.setUint32(i*12+4, hm[i] ? parseInt( hm[i][0].slice(0,8), 16 ) : 0, true);
|
||||
buffV.setUint32(i*12+8, hm[i] ? hm[i][1] : 0, true);
|
||||
}
|
||||
c += "};";
|
||||
code.push(c);
|
||||
|
||||
await fdData.write(buff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_buildComponentEntriesTables(code) {
|
||||
code.push("// Component Entry tables");
|
||||
for (let cetName in this.componentEntriesTables) {
|
||||
const cet = this.componentEntriesTables[cetName];
|
||||
async _buildComponentEntriesTables(fdData) {
|
||||
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.pCets = fdData.pos;
|
||||
for (let i=0; i< this.componentEntriesTables.length; i++) {
|
||||
if ((this.verbose)&&(i%100000 ==0)) console.log(`_buildComponentEntriesTables ${i}/${this.componentEntriesTables.length}`);
|
||||
const cet = this.componentEntriesTables[i].cet;
|
||||
|
||||
this.components[i].entryTablePointer = fdData.pos;
|
||||
const buff = new Uint8Array(16*cet.length);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
|
||||
code.push(`Circom_ComponentEntry ${cetName}[${cet.length}] = {`);
|
||||
for (let j=0; j<cet.length; j++) {
|
||||
const ty = cet[j].type == "S" ? "_typeSignal" : "_typeComponent";
|
||||
code.push(` ${j>0?",":" "}{${cet[j].offset},${cet[j].sizeName}, ${ty}}`);
|
||||
utils.setUint64(buffV, 16*j+0, this.sizePointers[ cet[j].sizeName]);
|
||||
buffV.setUint32(16*j+8, cet[j].offset, true);
|
||||
buffV.setUint32(16*j+12, cet[j].type == "S" ? 0 : 1, true); // Size type 0-> Signal, 1->Component
|
||||
this.nCets ++;
|
||||
}
|
||||
code.push("};");
|
||||
|
||||
await fdData.write(buff);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_buildSizes(code) {
|
||||
code.push("// Sizes");
|
||||
async _buildSizes(fdData) {
|
||||
for (let sName in this.sizes) {
|
||||
const accSizes = this.sizes[sName];
|
||||
|
||||
let c = `Circom_Size ${sName}[${accSizes.length}] = {`;
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.sizePointers[sName] = fdData.pos;
|
||||
|
||||
const buff = new Uint8Array(4*accSizes.length);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
for (let i=0; i<accSizes.length; i++) {
|
||||
if (i>0) c += ",";
|
||||
c += accSizes[i];
|
||||
buffV.setUint32(i*4, accSizes[i], true);
|
||||
}
|
||||
c += "};";
|
||||
code.push(c);
|
||||
await fdData.write(buff);
|
||||
}
|
||||
}
|
||||
|
||||
_buildConstants(code) {
|
||||
|
||||
async _buildConstants(fdData) {
|
||||
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(`FrElement _constants[${self.constants.length}] = {`);
|
||||
const frSize = (8 + self.F.n64*8);
|
||||
const buff = new Uint8Array(self.constants.length* frSize);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
|
||||
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.pConstants = fdData.pos;
|
||||
|
||||
let o = 0;
|
||||
for (let i=0; i<self.constants.length; i++) {
|
||||
code.push((i>0 ? "," : " ") + "{" + number2Code(self.constants[i]) + "}");
|
||||
Fr2Bytes(buffV, o, self.constants[i]);
|
||||
o += frSize;
|
||||
}
|
||||
code.push("};");
|
||||
|
||||
function number2Code(n) {
|
||||
if (n.lt(bigInt("80000000", 16)) ) {
|
||||
return addShortMontgomeryPositive(n);
|
||||
}
|
||||
if (n.geq(self.header.P.minus(bigInt("80000000", 16))) ) {
|
||||
return addShortMontgomeryNegative(n);
|
||||
}
|
||||
return addLongMontgomery(n);
|
||||
await fdData.write(buff);
|
||||
|
||||
|
||||
function addShortMontgomeryPositive(a) {
|
||||
return `${a.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`;
|
||||
}
|
||||
function Fr2Bytes(buffV, offset, n) {
|
||||
const minShort = self.F.neg(self.F.e("80000000"));
|
||||
const maxShort = self.F.e("7FFFFFFF", 16);
|
||||
|
||||
|
||||
function addShortMontgomeryNegative(a) {
|
||||
const b = a.minus(self.header.P);
|
||||
return `${b.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`;
|
||||
}
|
||||
|
||||
function addLongMontgomery(a) {
|
||||
return `0, 0xC0000000, { ${getLongString(toMontgomery(a))} }`;
|
||||
}
|
||||
|
||||
function getLongString(a) {
|
||||
let r = bigInt(a);
|
||||
let S = "";
|
||||
let i = 0;
|
||||
while (!r.isZero()) {
|
||||
if (S!= "") S = S+",";
|
||||
S += "0x" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16) + "LL";
|
||||
i++;
|
||||
r = r.shiftRight(64);
|
||||
if ( (self.F.geq(n, minShort))
|
||||
&&(self.F.leq(n, maxShort)))
|
||||
{
|
||||
if (self.F.geq(n, self.F.zero)) {
|
||||
return shortMontgomeryPositive(n);
|
||||
} else {
|
||||
return shortMontgomeryNegative(n);
|
||||
}
|
||||
while (i<n64) {
|
||||
if (S!= "") S = S+",";
|
||||
S += "0LL";
|
||||
i++;
|
||||
}
|
||||
|
||||
return longMontgomery(n);
|
||||
|
||||
|
||||
function shortMontgomeryPositive(a) {
|
||||
buffV.setUint32(offset, Scalar.toNumber(a) , true );
|
||||
buffV.setUint32(offset + 4, 0x40000000 , true );
|
||||
long(buffV, offset + 8, toMontgomery(a));
|
||||
}
|
||||
|
||||
|
||||
function shortMontgomeryNegative(a) {
|
||||
const b = -Scalar.toNumber(self.F.neg(a));
|
||||
buffV.setUint32(offset, b , true );
|
||||
buffV.setUint32(offset + 4, 0x40000000 , true );
|
||||
long(buffV, offset + 8, toMontgomery(a));
|
||||
}
|
||||
|
||||
function longMontgomery(a) {
|
||||
buffV.setUint32(offset, 0 , true );
|
||||
buffV.setUint32(offset + 4, 0xC0000000 , true );
|
||||
long(buffV, offset + 8, toMontgomery(a));
|
||||
}
|
||||
|
||||
function long(buffV, offset, a) {
|
||||
|
||||
let p = offset;
|
||||
const arr = Scalar.toArray(a, 0x100000000);
|
||||
for (let i=0; i<self.F.n64*2; i++) {
|
||||
const idx = arr.length-1-i;
|
||||
|
||||
if ( idx >=0) {
|
||||
buffV.setUint32(p, arr[idx], true);
|
||||
} else {
|
||||
buffV.setUint32(p, 0, true);
|
||||
}
|
||||
p+= 4;
|
||||
}
|
||||
return S;
|
||||
}
|
||||
|
||||
function toMontgomery(a) {
|
||||
return a.times(R).mod(self.header.P);
|
||||
return self.F.mul(a, self.F.R);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_buildFunctions(code) {
|
||||
const listedFunctions = [];
|
||||
for (let i=0; i<this.functions.length; i++) {
|
||||
const cfb = this.functions[i];
|
||||
cfb.build(code);
|
||||
if (this.functions[i].type == "COMPONENT") {
|
||||
this.functionIdx[this.functions[i].name] = listedFunctions.length;
|
||||
listedFunctions.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_buildComponents(code) {
|
||||
code.push("// Components");
|
||||
code.push(`Circom_Component _components[${this.components.length}] = {`);
|
||||
for (let i=0; i<this.components.length; i++) {
|
||||
const c = this.components[i];
|
||||
code.push("// Function Table");
|
||||
code.push(`Circom_ComponentFunction _functionTable[${listedFunctions.length}] = {`);
|
||||
for (let i=0; i<listedFunctions.length; i++) {
|
||||
const sep = i>0 ? " ," : " ";
|
||||
code.push(`${sep}{${c.hashMapName}, ${c.entryTableName}, ${c.functionName}, ${c.nInSignals}, ${c.newThread}}`);
|
||||
code.push(`${sep}${this.functions[listedFunctions[i]].name}`);
|
||||
}
|
||||
code.push("};");
|
||||
}
|
||||
|
||||
_buildMapIsInput(code) {
|
||||
code.push("// mapIsInput");
|
||||
code.push(`u32 _mapIsInput[${this.mapIsInput.length}] = {`);
|
||||
let line = "";
|
||||
|
||||
async _buildComponents(fdData) {
|
||||
|
||||
const buff = new Uint8Array(32);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.pComponents = fdData.pos;
|
||||
|
||||
for (let i=0; i<this.components.length; i++) {
|
||||
if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildComponents ${i}/${this.components.length}`);
|
||||
const c = this.components[i];
|
||||
|
||||
utils.setUint64(buffV, 0, this.hashMapPointers[c.hashMapName], true);
|
||||
utils.setUint64(buffV, 8, c.entryTablePointer, true);
|
||||
utils.setUint64(buffV, 16, this.functionIdx[c.functionName], true);
|
||||
buffV.setUint32(24, c.nInSignals, true);
|
||||
buffV.setUint32(28, c.newThread ? 1 : 0, true);
|
||||
|
||||
await fdData.write(buff);
|
||||
}
|
||||
}
|
||||
|
||||
async _buildMapIsInput(fdData) {
|
||||
|
||||
const buff = new Uint8Array(this.mapIsInput.length * 4);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.pMapIsInput = fdData.pos;
|
||||
|
||||
for (let i=0; i<this.mapIsInput.length; i++) {
|
||||
line += i>0 ? ", " : " ";
|
||||
line += toHex(this.mapIsInput[i]);
|
||||
if (((i+1) % 64)==0) {
|
||||
code.push(" "+line);
|
||||
line = "";
|
||||
}
|
||||
}
|
||||
if (line != "") code.push(" "+line);
|
||||
code.push("};");
|
||||
if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildMapIsInput ${i}/${this.mapIsInput.length}`);
|
||||
|
||||
function toHex(number) {
|
||||
if (number < 0) number = 0xFFFFFFFF + number + 1;
|
||||
let S=number.toString(16).toUpperCase();
|
||||
while (S.length<8) S = "0" + S;
|
||||
return "0x"+S;
|
||||
buffV.setUint32(4*i, this.mapIsInput[i], true);
|
||||
}
|
||||
|
||||
await fdData.write(buff);
|
||||
}
|
||||
|
||||
_buildWit2Sig(code) {
|
||||
code.push("// Witness to Signal Table");
|
||||
code.push(`int _wit2sig[${this.wit2sig.length}] = {`);
|
||||
let line = "";
|
||||
async _buildWit2Sig(fdData) {
|
||||
|
||||
const buff = new Uint8Array(this.wit2sig.length * 4);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
this.pWit2Sig = fdData.pos;
|
||||
|
||||
for (let i=0; i<this.wit2sig.length; i++) {
|
||||
line += i>0 ? "," : " ";
|
||||
line += this.wit2sig[i];
|
||||
if (((i+1) % 64) == 0) {
|
||||
code.push(" "+line);
|
||||
line = "";
|
||||
if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildWit2Sig ${i}/${this.wit2sig.length}`);
|
||||
|
||||
buffV.setUint32(4*i, this.wit2sig[i], true);
|
||||
}
|
||||
|
||||
await fdData.write(buff);
|
||||
}
|
||||
|
||||
async _buildCircuitVar(fdData) {
|
||||
|
||||
const buff = new Uint8Array(76);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
|
||||
utils.setUint64(buffV, 0, this.pWit2Sig, true);
|
||||
utils.setUint64(buffV, 8, this.pComponents, true);
|
||||
utils.setUint64(buffV, 16, this.pMapIsInput, true);
|
||||
utils.setUint64(buffV, 24, this.pConstants, true);
|
||||
utils.setUint64(buffV, 32, this.pPriemStr, true);
|
||||
utils.setUint64(buffV, 40, this.pCets, true);
|
||||
|
||||
buffV.setUint32(48, this.header.NSignals, true);
|
||||
buffV.setUint32(52, this.header.NComponents, true);
|
||||
buffV.setUint32(56, this.header.NOutputs, true);
|
||||
buffV.setUint32(60, this.header.NInputs, true);
|
||||
buffV.setUint32(64, this.header.NVars, true);
|
||||
buffV.setUint32(68, this.nCets, true);
|
||||
buffV.setUint32(72, this.header.NPublic, true);
|
||||
|
||||
fdData.pos = 0;
|
||||
|
||||
await fdData.write(buff);
|
||||
}
|
||||
|
||||
async _buildPrimeStr(fdData) {
|
||||
this.pPriemStr = fdData.pos;
|
||||
const strBuff = new TextEncoder("utf-8").encode(this.header.P.toString());
|
||||
await fdData.write(strBuff);
|
||||
|
||||
const zB = new Uint8Array(1);
|
||||
zB[0] =0;
|
||||
await fdData.write(zB);
|
||||
}
|
||||
|
||||
|
||||
async build(fdCode, fdData) {
|
||||
const encoder = new TextEncoder("utf-8");
|
||||
fdData.pos = 76;
|
||||
while (fdData.pos % 8) fdData.pos++;
|
||||
|
||||
const code=new BigArray();
|
||||
this._buildHeader(code);
|
||||
await this._buildPrimeStr(fdData);
|
||||
await this._buildSizes(fdData);
|
||||
await this._buildConstants(fdData);
|
||||
await this._buildHashMaps(fdData);
|
||||
await this._buildComponentEntriesTables(fdData);
|
||||
this._buildFunctions(code);
|
||||
await this._buildComponents(fdData);
|
||||
await this._buildMapIsInput(fdData);
|
||||
await this._buildWit2Sig(fdData);
|
||||
await this._buildCircuitVar(fdData);
|
||||
await writeCode(code);
|
||||
|
||||
async function writeCode(c) {
|
||||
if (c.push) {
|
||||
for (let i=0; i<c.length; i++) {
|
||||
await writeCode(c[i]);
|
||||
}
|
||||
} else if (typeof c === "string") {
|
||||
await fdCode.write(encoder.encode(c + "\n"));
|
||||
}
|
||||
}
|
||||
if (line != "") code.push(" "+line);
|
||||
code.push("};");
|
||||
}
|
||||
|
||||
_buildCircuitVar(code) {
|
||||
|
||||
code.push(
|
||||
"// Circuit Variable",
|
||||
"Circom_Circuit _circuit = {" ,
|
||||
" NSignals,",
|
||||
" NComponents,",
|
||||
" NInputs,",
|
||||
" NOutputs,",
|
||||
" NVars,",
|
||||
" _wit2sig,",
|
||||
" _components,",
|
||||
" _mapIsInput,",
|
||||
" _constants,",
|
||||
" __P__",
|
||||
"};"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
build() {
|
||||
const code=[];
|
||||
this._buildHeader(code);
|
||||
this._buildSizes(code);
|
||||
this._buildConstants(code);
|
||||
this._buildHashMaps(code);
|
||||
this._buildComponentEntriesTables(code);
|
||||
this._buildFunctions(code);
|
||||
this._buildComponents(code);
|
||||
this._buildMapIsInput(code);
|
||||
this._buildWit2Sig(code);
|
||||
this._buildCircuitVar(code);
|
||||
return streamFromMultiArray(code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,18 @@ const assert = chai.assert;
|
||||
const fs = require("fs");
|
||||
var tmp = require("tmp-promise");
|
||||
const path = require("path");
|
||||
const compiler = require("./compiler");
|
||||
const compiler = require("../../src/compiler");
|
||||
const util = require("util");
|
||||
const exec = util.promisify(require("child_process").exec);
|
||||
|
||||
const stringifyBigInts = require("./utils").stringifyBigInts;
|
||||
const unstringifyBigInts = require("./utils").unstringifyBigInts;
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils");
|
||||
const loadR1cs = require("./r1csfile").loadR1cs;
|
||||
const ZqField = require("fflib").ZqField;
|
||||
const Scalar = require("ffjavascript").Scalar;
|
||||
const utils = require("../../src/utils");
|
||||
const loadR1cs = require("r1csfile").load;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
const buildZqField = require("ffiasm").buildZqField;
|
||||
const fastFile = require("fastfile");
|
||||
|
||||
const {stringifyBigInts, unstringifyBigInts } = require("ffjavascript").utils;
|
||||
|
||||
module.exports = c_tester;
|
||||
|
||||
@@ -28,26 +30,50 @@ async function c_tester(circomFile, _options) {
|
||||
const baseName = path.basename(circomFile, ".circom");
|
||||
const options = Object.assign({}, _options);
|
||||
|
||||
options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp"));
|
||||
options.cSourceFile = await fastFile.createOverride(path.join(dir.path, baseName + ".cpp"));
|
||||
options.dataFile = await fastFile.createOverride(path.join(dir.path, baseName + ".dat"));
|
||||
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
|
||||
options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
|
||||
|
||||
options.p = options.p || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
await compiler(circomFile, options);
|
||||
|
||||
const cdir = path.join(__dirname, "..", "c");
|
||||
await exec("cp" +
|
||||
` ${path.join(dir.path, baseName + ".cpp")}` +
|
||||
" /tmp/circuit.cpp"
|
||||
);
|
||||
await exec("g++" +
|
||||
await options.cSourceFile.close();
|
||||
await options.dataFile.close();
|
||||
|
||||
const source = await buildZqField(options.p, "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.hpp"), source.hpp, "utf8");
|
||||
await fs.promises.writeFile(path.join(dir.path, "fr.cpp"), source.cpp, "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, "calcwit.cpp")}` +
|
||||
` ${path.join(cdir, "utils.cpp")}` +
|
||||
` ${path.join(cdir, "fr.c")}` +
|
||||
` ${path.join(cdir, "fr.o")}` +
|
||||
` ${path.join(dir.path, "fr.cpp")}` +
|
||||
` ${path.join(dir.path, "fr.o")}` +
|
||||
` ${path.join(dir.path, baseName + ".cpp")} ` +
|
||||
` -o ${path.join(dir.path, baseName)}` +
|
||||
` -I ${cdir}` +
|
||||
" -lgmp -std=c++11 -DSANITY_CHECK"
|
||||
` -I ${dir.path} -I${cdir}` +
|
||||
" -lgmp -std=c++11 -DSANITY_CHECK -g"
|
||||
);
|
||||
|
||||
// console.log(dir.path);
|
||||
@@ -70,10 +96,13 @@ class CTester {
|
||||
path.join(this.dir.path, "in.json"),
|
||||
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, "out.json")}`
|
||||
);
|
||||
if (r.stdout) {
|
||||
console.log(r.stdout);
|
||||
}
|
||||
const resStr = await fs.promises.readFile(
|
||||
path.join(this.dir.path, "out.json")
|
||||
);
|
||||
@@ -92,10 +121,11 @@ class CTester {
|
||||
const lines = symsStr.split("\n");
|
||||
for (let i=0; i<lines.length; i++) {
|
||||
const arr = lines[i].split(",");
|
||||
if (arr.length!=3) continue;
|
||||
this.symbols[arr[2]] = {
|
||||
idx: Number(arr[0]),
|
||||
idxWit: Number(arr[1])
|
||||
if (arr.length!=4) continue;
|
||||
this.symbols[arr[3]] = {
|
||||
labelIdx: Number(arr[0]),
|
||||
varIdx: Number(arr[1]),
|
||||
componentIdx: Number(arr[2]),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -104,8 +134,8 @@ class CTester {
|
||||
const self = this;
|
||||
if (this.constraints) return;
|
||||
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
|
||||
self.field = new ZqField(r1cs.prime);
|
||||
self.nWires = r1cs.nWires;
|
||||
self.F = new ZqField(r1cs.prime);
|
||||
self.nVars = r1cs.nVars;
|
||||
self.constraints = r1cs.constraints;
|
||||
}
|
||||
|
||||
@@ -129,8 +159,8 @@ class CTester {
|
||||
if (typeof self.symbols[prefix] == "undefined") {
|
||||
assert(false, "Output variable not defined: "+ prefix);
|
||||
}
|
||||
const ba = bigInt(actualOut[self.symbols[prefix].idxWit]).toString();
|
||||
const be = bigInt(eOut).toString();
|
||||
const ba = actualOut[self.symbols[prefix].varIdx].toString();
|
||||
const be = eOut.toString();
|
||||
assert.strictEqual(ba, be, prefix);
|
||||
}
|
||||
}
|
||||
@@ -142,8 +172,8 @@ class CTester {
|
||||
if (!self.symbols) await self.loadSymbols();
|
||||
for (let n in self.symbols) {
|
||||
let v;
|
||||
if (utils.isDefined(witness[self.symbols[n].idxWit])) {
|
||||
v = witness[self.symbols[n].idxWit].toString();
|
||||
if (utils.isDefined(witness[self.symbols[n].varIdx])) {
|
||||
v = witness[self.symbols[n].varIdx].toString();
|
||||
} else {
|
||||
v = "undefined";
|
||||
}
|
||||
@@ -160,16 +190,16 @@ class CTester {
|
||||
}
|
||||
|
||||
function checkConstraint(constraint) {
|
||||
const F = self.field;
|
||||
const a = evalLC(constraint.a);
|
||||
const b = evalLC(constraint.b);
|
||||
const c = evalLC(constraint.c);
|
||||
const F = self.F;
|
||||
const a = evalLC(constraint[0]);
|
||||
const b = evalLC(constraint[1]);
|
||||
const c = evalLC(constraint[2]);
|
||||
|
||||
assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match");
|
||||
}
|
||||
|
||||
function evalLC(lc) {
|
||||
const F = self.field;
|
||||
const F = self.F;
|
||||
let v = F.zero;
|
||||
for (let w in lc) {
|
||||
v = F.add(
|
||||
924
ports/wasm/build_runtime.js
Normal file
924
ports/wasm/build_runtime.js
Normal file
@@ -0,0 +1,924 @@
|
||||
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.getLocal("cIdx"),
|
||||
c.getLocal("component"),
|
||||
c.getLocal("signal"),
|
||||
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 buildMultiGetSignal() {
|
||||
const f = module.addFunction("multiGetSignal");
|
||||
f.addParam("cIdx", "i32");
|
||||
f.addParam("pR", "i32");
|
||||
f.addParam("component", "i32");
|
||||
f.addParam("signal", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("i", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
c.br_if(1, c.i32_eq(c.getLocal("i"), c.getLocal("n"))),
|
||||
c.call(
|
||||
"getSignal",
|
||||
c.getLocal("cIdx"),
|
||||
c.i32_add(
|
||||
c.getLocal("pR"),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(builder.sizeFr)
|
||||
)
|
||||
),
|
||||
c.getLocal("component"),
|
||||
c.i32_add(
|
||||
c.getLocal("signal"),
|
||||
c.getLocal("i")
|
||||
)
|
||||
),
|
||||
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
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 buildCheckAssert() {
|
||||
const f = module.addFunction("checkAssert");
|
||||
f.addParam("cIdx", "i32");
|
||||
f.addParam("pA", "i32");
|
||||
f.addParam("pStr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.if (
|
||||
c.i32_eqz(
|
||||
c.call(
|
||||
"Fr_isTrue",
|
||||
c.getLocal("pA"),
|
||||
)
|
||||
),
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.ASSERT_DOES_NOT_MATCH.code),
|
||||
c.i32_const(errs.ASSERT_DOES_NOT_MATCH.pointer),
|
||||
c.getLocal("cIdx"),
|
||||
c.getLocal("pA"),
|
||||
c.getLocal("pStr"),
|
||||
c.i32_const(0)
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
function buildGetNVars() {
|
||||
const f = module.addFunction("getNVars");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.i32_const(builder.header.NVars));
|
||||
}
|
||||
|
||||
function buildGetNPublic() {
|
||||
const f = module.addFunction("getNPublic");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.i32_const(builder.header.NPublic));
|
||||
}
|
||||
|
||||
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();
|
||||
buildMultiGetSignal();
|
||||
|
||||
buildComponentStarted();
|
||||
buildComponentFinished();
|
||||
|
||||
buildCheckConstraint();
|
||||
buildCheckAssert();
|
||||
|
||||
buildGetNVars();
|
||||
buildGetNPublic();
|
||||
buildGetFrLen();
|
||||
buildGetPWitness();
|
||||
buildGetPRawPrime();
|
||||
buildGetWitnessBuffer();
|
||||
|
||||
// buildFrToInt();
|
||||
|
||||
module.exportFunction("init");
|
||||
module.exportFunction("getNVars");
|
||||
module.exportFunction("getNPublic");
|
||||
module.exportFunction("getFrLen");
|
||||
module.exportFunction("getSignalOffset32");
|
||||
module.exportFunction("setSignal");
|
||||
module.exportFunction("multiGetSignal");
|
||||
module.exportFunction("getPWitness");
|
||||
module.exportFunction("Fr_toInt");
|
||||
module.exportFunction("getPRawPrime");
|
||||
module.exportFunction("getWitnessBuffer");
|
||||
|
||||
};
|
||||
1058
ports/wasm/builder.js
Normal file
1058
ports/wasm/builder.js
Normal file
File diff suppressed because it is too large
Load Diff
11
ports/wasm/errs.js
Normal file
11
ports/wasm/errs.js
Normal file
@@ -0,0 +1,11 @@
|
||||
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"},
|
||||
ASSERT_DOES_NOT_MATCH: {code: 9, str: "Assert not satisfied"},
|
||||
};
|
||||
162
ports/wasm/tester.js
Normal file
162
ports/wasm/tester.js
Normal file
@@ -0,0 +1,162 @@
|
||||
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 fastFile = require("fastfile");
|
||||
|
||||
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.wasmFile = await fastFile.createOverride(path.join(dir.path, baseName + ".wasm"));
|
||||
|
||||
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
|
||||
options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
|
||||
|
||||
await compiler(circomFile, options);
|
||||
|
||||
await options.wasmFile.close();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const SUBARRAY_SIZE = 0x10000;
|
||||
const SUBARRAY_SIZE = 0x40000;
|
||||
|
||||
const BigArrayHandler = {
|
||||
get: function(obj, prop) {
|
||||
@@ -19,15 +19,17 @@ const BigArrayHandler = {
|
||||
class _BigArray {
|
||||
constructor (initSize) {
|
||||
this.length = initSize || 0;
|
||||
this.arr = [];
|
||||
this.arr = new Array(SUBARRAY_SIZE);
|
||||
|
||||
for (let i=0; i<initSize; i+=SUBARRAY_SIZE) {
|
||||
this.arr[i/SUBARRAY_SIZE] = new Array(Math.min(SUBARRAY_SIZE, initSize - i));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
push (element) {
|
||||
this.setElement (this.length, element);
|
||||
push () {
|
||||
for (let i=0; i<arguments.length; i++) {
|
||||
this.setElement (this.length, arguments[i]);
|
||||
}
|
||||
}
|
||||
getElement(idx) {
|
||||
idx = parseInt(idx);
|
||||
@@ -39,13 +41,26 @@ class _BigArray {
|
||||
idx = parseInt(idx);
|
||||
const idx1 = Math.floor(idx / SUBARRAY_SIZE);
|
||||
if (!this.arr[idx1]) {
|
||||
this.arr[idx1] = [];
|
||||
this.arr[idx1] = new Array(SUBARRAY_SIZE);
|
||||
}
|
||||
const idx2 = idx % SUBARRAY_SIZE;
|
||||
this.arr[idx1][idx2] = value;
|
||||
if (idx >= this.length) this.length = idx+1;
|
||||
return true;
|
||||
}
|
||||
getKeys() {
|
||||
const newA = new BigArray();
|
||||
for (let i=0; i<this.arr.length; i++) {
|
||||
if (this.arr[i]) {
|
||||
for (let j=0; j<this.arr[i].length; j++) {
|
||||
if (typeof this.arr[i][j] !== "undefined") {
|
||||
newA.push(i*SUBARRAY_SIZE+j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return newA;
|
||||
}
|
||||
}
|
||||
|
||||
class BigArray {
|
||||
|
||||
72
src/build.js
72
src/build.js
@@ -18,10 +18,10 @@
|
||||
*/
|
||||
|
||||
const assert = require("assert");
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils");
|
||||
const gen = require("./gencode").gen;
|
||||
const createRefs = require("./gencode").createRefs;
|
||||
const BigArray = require("./bigarray");
|
||||
|
||||
module.exports = build;
|
||||
|
||||
@@ -34,33 +34,37 @@ function build(ctx) {
|
||||
ctx.codes_sizes = [];
|
||||
ctx.definedSizes = {};
|
||||
ctx.addSizes = addSizes;
|
||||
ctx.constantsMap = {};
|
||||
ctx.addConstant = addConstant;
|
||||
ctx.addConstant(bigInt.zero);
|
||||
ctx.addConstant(bigInt.one);
|
||||
ctx.addConstant(ctx.F.zero);
|
||||
ctx.addConstant(ctx.F.one);
|
||||
|
||||
if (ctx.verbose) console.log("buildHeader...");
|
||||
buildHeader(ctx);
|
||||
if (ctx.verbose) console.log("buildEntryTables...");
|
||||
buildEntryTables(ctx);
|
||||
ctx.globalNames = ctx.uniqueNames;
|
||||
|
||||
if (ctx.verbose) console.log("buildCode...");
|
||||
buildCode(ctx);
|
||||
|
||||
if (ctx.verbose) console.log("buildComponentsArray...");
|
||||
buildComponentsArray(ctx);
|
||||
|
||||
if (ctx.verbose) console.log("buildMapIsInput...");
|
||||
buildMapIsInput(ctx);
|
||||
|
||||
if (ctx.verbose) console.log("buildWit2Sig...");
|
||||
buildWit2Sig(ctx);
|
||||
|
||||
}
|
||||
|
||||
function buildEntryTables(ctx) {
|
||||
|
||||
const codes_hashMaps = [];
|
||||
const codes_componentEntries = [];
|
||||
const definedHashMaps = {};
|
||||
for (let i=0; i<ctx.components.length; i++) {
|
||||
if (ctx.verbose && (i%100000 ==0)) console.log(`buildEntryTables component: ${i}/${ctx.components.length}`);
|
||||
const {htName, htMap} = addHashTable(i);
|
||||
|
||||
let code = "";
|
||||
const componentEntriesTableName = ctx.getUniqueName("_entryTable" + ctx.components[i].template);
|
||||
|
||||
const componentEntriesTable = [];
|
||||
@@ -74,34 +78,14 @@ function buildEntryTables(ctx) {
|
||||
});
|
||||
}
|
||||
|
||||
ctx.builder.addComponentEntriesTable(componentEntriesTableName, componentEntriesTable);
|
||||
|
||||
|
||||
code += `Circom_ComponentEntry ${componentEntriesTableName}[${htMap.length}] = {\n`;
|
||||
for (let j=0; j<htMap.length; j++) {
|
||||
const entry = ctx.components[i].names.o[htMap[j]];
|
||||
code += j>0 ? " ," : " ";
|
||||
const sizeName = ctx.addSizes(entry.sizes);
|
||||
|
||||
const ty = entry.type == "S" ? "_typeSignal" : "_typeComponent";
|
||||
code += `{${entry.offset},${sizeName}, ${ty}}\n`;
|
||||
}
|
||||
code += "};\n";
|
||||
codes_componentEntries.push(code);
|
||||
ctx.builder.addComponentEntriesTable(componentEntriesTableName, componentEntriesTable, i);
|
||||
|
||||
ctx.components[i].htName = htName;
|
||||
ctx.components[i].etName = componentEntriesTableName;
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
"// HashMaps\n" ,
|
||||
codes_hashMaps , "\n" ,
|
||||
"\n" ,
|
||||
"// Component Entries\n" ,
|
||||
codes_componentEntries , "\n" ,
|
||||
"\n"
|
||||
];
|
||||
return;
|
||||
|
||||
function addHashTable(cIdx) {
|
||||
const keys = Object.keys(ctx.components[cIdx].names.o);
|
||||
@@ -133,6 +117,7 @@ function buildCode(ctx) {
|
||||
|
||||
const fnComponents = [];
|
||||
for (let i=0; i<ctx.components.length; i++) {
|
||||
if (ctx.verbose && (i%100000 ==0)) console.log(`buildCode component: ${i}/${ctx.components.length}`);
|
||||
const {h, instanceDef} = hashComponentCall(ctx, i);
|
||||
const fName = ctx.components[i].template+"_"+h;
|
||||
if (!fDefined[fName]) {
|
||||
@@ -182,6 +167,7 @@ function buildCode(ctx) {
|
||||
|
||||
function buildComponentsArray(ctx) {
|
||||
for (let i=0; i< ctx.components.length; i++) {
|
||||
if (ctx.verbose && (i%1000000 ==0)) console.log(`buildComponentsArray component: ${i}/${ctx.components.length}`);
|
||||
let newThread;
|
||||
if (ctx.newThreadTemplates) {
|
||||
if (ctx.newThreadTemplates.test(ctx.components[i].template)) {
|
||||
@@ -210,7 +196,8 @@ function buildHeader(ctx) {
|
||||
NInputs: ctx.components[ ctx.getComponentIdx("main") ].nInSignals,
|
||||
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],
|
||||
P: ctx.field.p
|
||||
NPublic: ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT],
|
||||
P: ctx.F.p
|
||||
});
|
||||
}
|
||||
|
||||
@@ -219,6 +206,7 @@ function buildMapIsInput(ctx) {
|
||||
let map = [];
|
||||
let acc = 0;
|
||||
for (i=0; i<ctx.signals.length; i++) {
|
||||
if (ctx.verbose && (i%1000000 ==0)) console.log(`buildMapIsInput signal: ${i}/${ctx.signals.length}`);
|
||||
if (ctx.signals[i].o & ctx.IN) {
|
||||
acc = acc | (1 << (i%32) );
|
||||
}
|
||||
@@ -243,8 +231,9 @@ function buildWit2Sig(ctx) {
|
||||
ctx.totals[ctx.stPUBINPUT] +
|
||||
ctx.totals[ctx.stPRVINPUT] +
|
||||
ctx.totals[ctx.stINTERNAL];
|
||||
const arr = Array(NVars);
|
||||
const arr = new BigArray(NVars);
|
||||
for (let i=0; i<ctx.signals.length; i++) {
|
||||
if (ctx.verbose && (i%1000000 ==0)) console.log(`buildWit2Sig signal: ${i}/${ctx.signals.length}`);
|
||||
const outIdx = ctx.signals[i].id;
|
||||
if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
|
||||
assert(typeof outIdx != "undefined", `Signal ${i} does not have index`);
|
||||
@@ -287,12 +276,7 @@ function addSizes(_sizes) {
|
||||
}
|
||||
|
||||
function addConstant(c) {
|
||||
c = bigInt(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;
|
||||
return this.builder.addConstant(c);
|
||||
}
|
||||
|
||||
function buildFunction(name, paramValues) {
|
||||
@@ -320,7 +304,7 @@ function buildFunction(name, paramValues) {
|
||||
ctx.scopes = [{}];
|
||||
ctx.refs = [];
|
||||
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.uniqueNames = Object.assign({},ctx.globalNames);
|
||||
ctx.returnValue = null;
|
||||
@@ -397,7 +381,7 @@ function hashComponentCall(ctx, cIdx) {
|
||||
// TODO: At the moment generate a diferent function for each instance of the component
|
||||
const constParams = [];
|
||||
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) {
|
||||
@@ -405,7 +389,7 @@ function hashComponentCall(ctx, cIdx) {
|
||||
if ((entry.type == "S")&&(ctx.signals[entry.offset].o & ctx.IN)) {
|
||||
travelSizes(n, entry.offset, entry.sizes, (prefix, offset) => {
|
||||
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 +423,7 @@ function hashFunctionCall(ctx, name, paramValues) {
|
||||
const constParams = [];
|
||||
for (let i=0; i<ctx.functions[name].params.length; i++) {
|
||||
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;
|
||||
@@ -453,16 +437,16 @@ function hashFunctionCall(ctx, name, paramValues) {
|
||||
return {h, instanceDef};
|
||||
}
|
||||
|
||||
function value2str(v) {
|
||||
function value2str(F, v) {
|
||||
if (Array.isArray(v)) {
|
||||
let S="[";
|
||||
for (let i=0; i<v.length; i++) {
|
||||
if (i>0) S+=",";
|
||||
S+=value2str(v[i]);
|
||||
S+=value2str(F, v[i]);
|
||||
}
|
||||
S+="]";
|
||||
return S;
|
||||
} else {
|
||||
return bigInt(v).toString();
|
||||
return F.toString(F.e(v));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
158
src/buildsyms.js
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
|
||||
}
|
||||
586
src/compiler.js
586
src/compiler.js
@@ -17,38 +17,61 @@
|
||||
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const Scalar = require("ffjavascript").Scalar;
|
||||
const sONE = 0;
|
||||
const build = require("./build");
|
||||
const BuilderC = require("./builder_c");
|
||||
const BuilderWasm = require("./builder_wasm");
|
||||
const BuilderC = require("../ports/c/builder.js");
|
||||
const BuilderWasm = require("../ports/wasm/builder.js");
|
||||
const constructionPhase = require("./construction_phase");
|
||||
const Ctx = require("./ctx");
|
||||
const ZqField = require("fflib").ZqField;
|
||||
const utils = require("./utils");
|
||||
const buildR1cs = require("./r1csfile").buildR1cs;
|
||||
const BigArray = require("./bigarray");
|
||||
const buildSyms = require("./buildsyms");
|
||||
const {performance} = require("perf_hooks");
|
||||
|
||||
module.exports = compile;
|
||||
const measures = {};
|
||||
|
||||
function ms2String(v) {
|
||||
v = Math.floor(v);
|
||||
const ms = v % 1000;
|
||||
v = Math.floor(v/1000);
|
||||
const secs = v % 60;
|
||||
v = Math.floor(v/60);
|
||||
const mins = v % 60;
|
||||
v = Math.floor(v/60);
|
||||
const hours = v % 24;
|
||||
const days = Math.floor(v/24);
|
||||
let S = "";
|
||||
if (days) S = S + days + "D ";
|
||||
if ((S!="")||(hours)) S = S + hours.toString().padStart(2, "0") + ":";
|
||||
if ((S!="")||(mins)) S = S + mins.toString().padStart(2, "0") + ":";
|
||||
if ((S!="")||(secs)) S = S + secs.toString().padStart(2, "0");
|
||||
S+=".";
|
||||
S = S + ms.toString().padStart(3, "0");
|
||||
return S;
|
||||
}
|
||||
|
||||
async function compile(srcFile, options) {
|
||||
options.p = options.p || __P__;
|
||||
options.prime = options.prime || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (typeof options.reduceConstraints === "undefined") {
|
||||
options.reduceConstraints = true;
|
||||
}
|
||||
const ctx = new Ctx();
|
||||
ctx.field = new ZqField(options.p);
|
||||
const ctx = new Ctx(options.prime);
|
||||
ctx.verbose= options.verbose || false;
|
||||
ctx.mainComponent = options.mainComponent || "main";
|
||||
ctx.newThreadTemplates = options.newThreadTemplates;
|
||||
|
||||
measures.constructionPhase = -performance.now();
|
||||
constructionPhase(ctx, srcFile);
|
||||
measures.constructionPhase += performance.now();
|
||||
|
||||
console.log("NConstraints Before: "+ctx.constraints.length);
|
||||
if (ctx.verbose) console.log("NConstraints Before: "+ctx.constraints.length);
|
||||
if (ctx.verbose) console.log("NSignals Before: "+ctx.signals.length);
|
||||
|
||||
if (ctx.error) {
|
||||
throw(ctx.error);
|
||||
@@ -58,62 +81,98 @@ async function compile(srcFile, options) {
|
||||
throw new Error("A main component must be defined");
|
||||
}
|
||||
|
||||
if (ctx.verbose) console.log("Classify Signals");
|
||||
classifySignals(ctx);
|
||||
|
||||
if (ctx.verbose) console.log("Reduce Constants");
|
||||
measures.reduceConstants = -performance.now();
|
||||
reduceConstants(ctx);
|
||||
measures.reduceConstants += performance.now();
|
||||
|
||||
if (options.reduceConstraints) {
|
||||
|
||||
if (ctx.verbose) console.log("Reduce Constraints");
|
||||
// Repeat while reductions are performed
|
||||
/*
|
||||
let oldNConstrains = -1;
|
||||
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;
|
||||
reduceConstrains(ctx);
|
||||
}
|
||||
*/
|
||||
measures.reduceConstraints = -performance.now();
|
||||
await reduceConstrains(ctx);
|
||||
measures.reduceConstraints += performance.now();
|
||||
|
||||
}
|
||||
if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length);
|
||||
|
||||
console.log("NConstraints After: "+ctx.constraints.length);
|
||||
if (ctx.verbose) console.log("Classify Signals");
|
||||
measures.classifySignals = -performance.now();
|
||||
classifySignals(ctx);
|
||||
measures.classifySignals += performance.now();
|
||||
|
||||
measures.generateWitnessNames = -performance.now();
|
||||
generateWitnessNames(ctx);
|
||||
measures.generateWitnessNames += performance.now();
|
||||
|
||||
if (ctx.error) {
|
||||
throw(ctx.error);
|
||||
}
|
||||
|
||||
if (options.cSourceWriteStream) {
|
||||
ctx.builder = new BuilderC();
|
||||
build(ctx);
|
||||
const rdStream = ctx.builder.build();
|
||||
rdStream.pipe(options.cSourceWriteStream);
|
||||
|
||||
// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
|
||||
if (options.r1csFileName) {
|
||||
measures.generateR1cs = -performance.now();
|
||||
await buildR1cs(ctx, options.r1csFileName);
|
||||
measures.generateR1cs += performance.now();
|
||||
}
|
||||
|
||||
if (options.wasmWriteStream) {
|
||||
ctx.builder = new BuilderWasm();
|
||||
build(ctx);
|
||||
const rdStream = ctx.builder.build();
|
||||
rdStream.pipe(options.wasmWriteStream);
|
||||
if (ctx.error) throw(ctx.error);
|
||||
|
||||
// await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
|
||||
delete ctx.constraints; // Liberate memory.
|
||||
|
||||
if (options.cSourceFile) {
|
||||
if (ctx.verbose) console.log("Generating c...");
|
||||
measures.generateC = -performance.now();
|
||||
ctx.builder = new BuilderC(options.prime, ctx.verbose);
|
||||
build(ctx);
|
||||
await ctx.builder.build(options.cSourceFile, options.dataFile);
|
||||
measures.generateC += performance.now();
|
||||
}
|
||||
|
||||
if (ctx.error) throw(ctx.error);
|
||||
|
||||
if ((options.wasmFile)||(options.watFile)) {
|
||||
if (ctx.verbose) console.log("Generating wasm...");
|
||||
measures.generateWasm = -performance.now();
|
||||
ctx.builder = new BuilderWasm(options.prime);
|
||||
build(ctx);
|
||||
if (options.wasmFile) {
|
||||
await ctx.builder.build(options.wasmFile, "wasm");
|
||||
}
|
||||
if (options.watFile) {
|
||||
await ctx.builder.build(options.watFile, "wat");
|
||||
}
|
||||
measures.generateWasm += performance.now();
|
||||
}
|
||||
|
||||
// const mainCode = gen(ctx,ast);
|
||||
if (ctx.error) throw(ctx.error);
|
||||
|
||||
if (options.r1csFileName) {
|
||||
await buildR1cs(ctx, options.r1csFileName);
|
||||
}
|
||||
|
||||
if (options.symWriteStream) {
|
||||
buildSyms(ctx, options.symWriteStream);
|
||||
measures.generateSyms = -performance.now();
|
||||
const rdStream = buildSyms(ctx);
|
||||
rdStream.pipe(options.symWriteStream);
|
||||
measures.generateSyms += performance.now();
|
||||
|
||||
await new Promise(fulfill => options.symWriteStream.on("finish", fulfill));
|
||||
}
|
||||
|
||||
// const def = buildCircuitDef(ctx, mainCode);
|
||||
|
||||
if (ctx.verbose) {
|
||||
for (let [mStr, mValue] of Object.entries(measures)) {
|
||||
console.log(mStr + ": " + ms2String(mValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,27 +183,36 @@ function classifySignals(ctx) {
|
||||
|
||||
function priorize(t1, t2) {
|
||||
if ((t1 == ERROR) || (t2==ERROR)) return ERROR;
|
||||
if (t1 == ctx.stINTERNAL) {
|
||||
return t2;
|
||||
} else if (t2==ctx.stINTERNAL) {
|
||||
return t1;
|
||||
}
|
||||
if ((t1 == ctx.stONE) || (t2 == ctx.stONE)) return ctx.stONE;
|
||||
if ((t1 == ctx.stOUTPUT) || (t2 == ctx.stOUTPUT)) return ctx.stOUTPUT;
|
||||
if ((t1 == ctx.stPUBINPUT) || (t2 == ctx.stPUBINPUT)) return ctx.stPUBINPUT;
|
||||
if ((t1 == ctx.stPRVINPUT) || (t2 == ctx.stPRVINPUT)) return ctx.stPRVINPUT;
|
||||
if ((t1 == ctx.stINTERNAL) || (t2 == ctx.stINTERNAL)) return ctx.stINTERNAL;
|
||||
if ((t1 == ctx.stCONSTANT) || (t2 == ctx.stCONSTANT)) return ctx.stCONSTANT;
|
||||
if ((t1 == ctx.stDISCARDED) || (t2 == ctx.stDISCARDED)) return ctx.stDISCARDED;
|
||||
if (t1!=t2) return ERROR;
|
||||
return t1;
|
||||
}
|
||||
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`marking as internal: ${i}/${ctx.constraints.length}`);
|
||||
|
||||
const c = ctx.constraints[i];
|
||||
for (let s in c.a.coefs) ctx.signals[s].c = ctx.stINTERNAL;
|
||||
for (let s in c.b.coefs) ctx.signals[s].c = ctx.stINTERNAL;
|
||||
for (let s in c.c.coefs) ctx.signals[s].c = ctx.stINTERNAL;
|
||||
}
|
||||
|
||||
|
||||
// First classify the signals
|
||||
for (let s=0; s<ctx.signals.length; s++) {
|
||||
if ((ctx.verbose)&&(s%100000 == 0)) console.log(`classify signals: ${s}/${ctx.signals.length}`);
|
||||
const signal = ctx.signals[s];
|
||||
let tAll = ctx.stINTERNAL;
|
||||
let tAll = ctx.stDISCARDED;
|
||||
let lSignal = signal;
|
||||
let end = false;
|
||||
while (!end) {
|
||||
let t = lSignal.c || ctx.stINTERNAL;
|
||||
let t = lSignal.c || ctx.stDISCARDED;
|
||||
if (s == 0) {
|
||||
t = ctx.stONE;
|
||||
} else if (lSignal.o & ctx.MAIN) {
|
||||
@@ -242,17 +310,68 @@ function reduceConstants(ctx) {
|
||||
ctx.constraints = newConstraints;
|
||||
}
|
||||
|
||||
function reduceConstrains(ctx) {
|
||||
indexVariables();
|
||||
let possibleConstraints = ctx.constraints;
|
||||
let ii=0;
|
||||
while (possibleConstraints.length>0) {
|
||||
let nextPossibleConstraints = new BigArray();
|
||||
for (let i=0; i<possibleConstraints.length; i++) {
|
||||
ii++;
|
||||
if ((ctx.verbose)&&(ii%10000 == 0)) console.log("reducing constraints: ", i);
|
||||
if (!ctx.constraints[i]) continue;
|
||||
const c = ctx.constraints[i];
|
||||
async function reduceConstrains(ctx) {
|
||||
const sig2constraint = new BigArray();
|
||||
let removedSignals = new BigArray();
|
||||
let nRemoved;
|
||||
let lIdx;
|
||||
|
||||
|
||||
let possibleConstraints = new BigArray(ctx.constraints.length);
|
||||
let nextPossibleConstraints;
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`indexing constraints: ${i}/${ctx.constraints.length}`);
|
||||
|
||||
const insertedSig = { 0: true}; // Do not insert one.
|
||||
const c = ctx.constraints[i];
|
||||
for (let s in c.a.coefs) {
|
||||
if (!insertedSig[s]) {
|
||||
if (!sig2constraint[s]) sig2constraint[s] = {};
|
||||
sig2constraint[s][i] = true;
|
||||
insertedSig[s] = true;
|
||||
}
|
||||
}
|
||||
for (let s in c.b.coefs) {
|
||||
if (!insertedSig[s]) {
|
||||
if (!sig2constraint[s]) sig2constraint[s] = {};
|
||||
sig2constraint[s][i] = true;
|
||||
insertedSig[s] = true;
|
||||
}
|
||||
}
|
||||
for (let s in c.c.coefs) {
|
||||
if (!insertedSig[s]) {
|
||||
if (!sig2constraint[s]) sig2constraint[s] = {};
|
||||
sig2constraint[s][i] = true;
|
||||
insertedSig[s] = true;
|
||||
}
|
||||
}
|
||||
possibleConstraints[i] = ctx.constraints.length - i -1;
|
||||
}
|
||||
|
||||
let totalRemoved = 0;
|
||||
while (possibleConstraints.length >0) {
|
||||
if (possibleConstraints.length>1<<20) {
|
||||
nextPossibleConstraints = new BigArray();
|
||||
} else {
|
||||
nextPossibleConstraints = {};
|
||||
}
|
||||
removedSignals = {};
|
||||
nRemoved = 0;
|
||||
lIdx = {};
|
||||
for (let i=0;i<possibleConstraints.length;i++) {
|
||||
if ((ctx.verbose)&&(i%10000 == 0)) {
|
||||
await Promise.resolve();
|
||||
console.log(`reducing constraints: ${i}/${possibleConstraints.length} reduced: ${nRemoved}`);
|
||||
}
|
||||
|
||||
const c = ctx.constraints[possibleConstraints[i]];
|
||||
if (!c) continue;
|
||||
|
||||
// Limit of number of lelements removed per step
|
||||
if (nRemoved>5000000) {
|
||||
nextPossibleConstraints[possibleConstraints[i]] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Swap a and b if b has more variables.
|
||||
if (Object.keys(c.b).length > Object.keys(c.a).length) {
|
||||
@@ -276,272 +395,195 @@ function reduceConstrains(ctx) {
|
||||
}
|
||||
|
||||
if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
|
||||
const isolatedSignal = getFirstInternalSignal(ctx, c.c);
|
||||
const freeC = substituteRemoved(c.c);
|
||||
const isolatedSignal = getFirstInternalSignal(ctx, freeC);
|
||||
if (isolatedSignal) {
|
||||
removedSignals[isolatedSignal] = isolateSignal(freeC, isolatedSignal);
|
||||
if (lIdx[isolatedSignal]) {
|
||||
const sigs = Object.keys(lIdx[isolatedSignal]);
|
||||
|
||||
let lSignal = ctx.signals[isolatedSignal];
|
||||
while (lSignal.e>=0) {
|
||||
lSignal = ctx.signals[lSignal.e];
|
||||
}
|
||||
|
||||
|
||||
const isolatedSignalEquivalence = {
|
||||
t: "LC",
|
||||
coefs: {}
|
||||
};
|
||||
const invCoef = c.c.coefs[isolatedSignal].modInv(__P__);
|
||||
for (const s in c.c.coefs) {
|
||||
if (s != isolatedSignal) {
|
||||
const v = __P__.minus(c.c.coefs[s]).times(invCoef).mod(__P__);
|
||||
if (!v.isZero()) {
|
||||
isolatedSignalEquivalence.coefs[s] = v;
|
||||
}
|
||||
for (let k=0; k<sigs.length; k++) {
|
||||
const s = sigs[k];
|
||||
const oldLC = removedSignals[s];
|
||||
removedSignals[s] = substitute(removedSignals[s], isolatedSignal, removedSignals[isolatedSignal]);
|
||||
if (oldLC !== removedSignals[s]) addTolIdx(removedSignals[s], s);
|
||||
}
|
||||
}
|
||||
|
||||
for (let j in lSignal.inConstraints) {
|
||||
if ((j!=i)&&(ctx.constraints[j])) {
|
||||
ctx.constraints[j] = ctx.lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
|
||||
linkSignalsConstraint(j);
|
||||
if (j<i) {
|
||||
nextPossibleConstraints.push(j);
|
||||
}
|
||||
}
|
||||
addTolIdx(removedSignals[isolatedSignal], isolatedSignal);
|
||||
ctx.constraints[possibleConstraints[i]] = null;
|
||||
nRemoved ++;
|
||||
|
||||
delete lIdx[isolatedSignal];
|
||||
|
||||
const cts = Object.keys(sig2constraint[isolatedSignal]);
|
||||
for (let k=0; k<cts.length; k++) {
|
||||
if (ctx.constraints[cts[k]]) nextPossibleConstraints[cts[k]] = true;
|
||||
}
|
||||
|
||||
ctx.constraints[i] = null;
|
||||
|
||||
lSignal.c = ctx.stDISCARDED;
|
||||
} else {
|
||||
if (ctx.lc.isZero(c.c)) ctx.constraints[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
possibleConstraints = nextPossibleConstraints;
|
||||
}
|
||||
unindexVariables();
|
||||
|
||||
// Pack the constraints
|
||||
let o = 0;
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
if (ctx.constraints[i]) {
|
||||
if (o != i) {
|
||||
ctx.constraints[o] = ctx.constraints[i];
|
||||
}
|
||||
o++;
|
||||
if (nextPossibleConstraints.getKeys) {
|
||||
nextPossibleConstraints = nextPossibleConstraints.getKeys();
|
||||
} else {
|
||||
nextPossibleConstraints = Object.keys(nextPossibleConstraints);
|
||||
}
|
||||
}
|
||||
ctx.constraints.length = o;
|
||||
|
||||
function indexVariables() {
|
||||
for (let i=0; i<ctx.constraints.length; i++) linkSignalsConstraint(i);
|
||||
}
|
||||
for (let i=0; i<nextPossibleConstraints.length;i++) {
|
||||
if ((ctx.verbose)&&(i%10000 == 0)) {
|
||||
await Promise.resolve();
|
||||
console.log(`substituting constraints: ${i}/${nextPossibleConstraints.length}`);
|
||||
}
|
||||
const c = ctx.constraints[nextPossibleConstraints[i]];
|
||||
if (c) {
|
||||
const nc = {
|
||||
a: substituteRemoved(c.a, nextPossibleConstraints[i]),
|
||||
b: substituteRemoved(c.b, nextPossibleConstraints[i]),
|
||||
c: substituteRemoved(c.c, nextPossibleConstraints[i])
|
||||
};
|
||||
if (ctx.lc.isZero(nc)) {
|
||||
delete ctx.constraints[nextPossibleConstraints[i]];
|
||||
} else {
|
||||
ctx.constraints[nextPossibleConstraints[i]] = nc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function linkSignalsConstraint(cidx) {
|
||||
const ct = ctx.constraints[cidx];
|
||||
for (let k in ct.a.coefs) linkSignal(k, cidx);
|
||||
for (let k in ct.b.coefs) linkSignal(k, cidx);
|
||||
for (let k in ct.c.coefs) linkSignal(k, cidx);
|
||||
}
|
||||
const removedSignalsList = Object.keys(removedSignals);
|
||||
|
||||
for (let i=0; i<removedSignalsList.length; i++) {
|
||||
if ((ctx.verbose )&&(i%100000 == 0)) console.log(`removing signals: ${i}/${removedSignalsList.length}`);
|
||||
const s = removedSignalsList[i];
|
||||
|
||||
function unindexVariables() {
|
||||
for (let s=0; s<ctx.signals.length; s++) {
|
||||
let lSignal = ctx.signals[s];
|
||||
while (lSignal.e>=0) {
|
||||
lSignal = ctx.signals[lSignal.e];
|
||||
}
|
||||
if (lSignal.inConstraints) delete lSignal.inConstraints;
|
||||
|
||||
sig2constraint[s] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function unlinkSignal(signalName, cidx) {
|
||||
let lSignal = ctx.signals[signalName];
|
||||
while (lSignal.e>=0) {
|
||||
lSignal = ctx.signals[lSignal.e];
|
||||
possibleConstraints = new BigArray();
|
||||
// Reverse
|
||||
for (let i=0; i<nextPossibleConstraints.length; i++) {
|
||||
possibleConstraints[i] = nextPossibleConstraints[nextPossibleConstraints.length -1 -i];
|
||||
}
|
||||
if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) {
|
||||
delete lSignal.inConstraints[cidx];
|
||||
}
|
||||
}
|
||||
*/
|
||||
possibleConstraints = nextPossibleConstraints;
|
||||
|
||||
function linkSignal(signalName, cidx) {
|
||||
let lSignal = ctx.signals[signalName];
|
||||
while (lSignal.e>=0) {
|
||||
lSignal = ctx.signals[lSignal.e];
|
||||
}
|
||||
if (!lSignal.inConstraints) lSignal.inConstraints = {};
|
||||
lSignal.inConstraints[cidx] = true;
|
||||
totalRemoved += nRemoved;
|
||||
if (ctx.verbose) console.log(`Removed: ${totalRemoved} TotalConstraints: ${ctx.constraints.length}` );
|
||||
}
|
||||
|
||||
|
||||
let o=0;
|
||||
for (let i=0; i<ctx.constraints.length;i++) {
|
||||
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`reordering constraints: ${i}/${ctx.constraints.length}`);
|
||||
if (ctx.constraints[i]) {
|
||||
if (!ctx.lc.isZero(ctx.constraints[i])) {
|
||||
ctx.constraints[o] = ctx.constraints[i];
|
||||
o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.constraints.length = o;
|
||||
|
||||
function getFirstInternalSignal(ctx, l) {
|
||||
for (let k in l.coefs) {
|
||||
k = Number(k);
|
||||
const signal = ctx.signals[k];
|
||||
if (signal.c == ctx.stINTERNAL) return k;
|
||||
if ( ( ((signal.o & ctx.MAIN) == 0)
|
||||
||( ((signal.o & ctx.IN) == 0)
|
||||
&&((signal.o & ctx.OUT) == 0)))
|
||||
&&((signal.o & ctx.ONE) ==0)
|
||||
&&(!ctx.F.isZero(l.coefs[k]))
|
||||
&&(!removedSignals[k])) return k;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isolateSignal(lc, s) {
|
||||
const eq = {
|
||||
t: "LC",
|
||||
coefs: {}
|
||||
};
|
||||
const invCoef = ctx.F.inv(lc.coefs[s]);
|
||||
for (const k in lc.coefs) {
|
||||
if (k != s) {
|
||||
const v = ctx.F.mul( ctx.F.neg(lc.coefs[k]), invCoef);
|
||||
if (!ctx.F.isZero(v)) {
|
||||
eq.coefs[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
function substituteRemoved(lc, idxConstraint) {
|
||||
const newLc = ctx.lc._clone(lc);
|
||||
for (let k in lc.coefs) {
|
||||
if (removedSignals[k]) {
|
||||
delete newLc.coefs[k];
|
||||
for (let k2 in removedSignals[k].coefs) {
|
||||
const newP = ctx.F.mul(removedSignals[k].coefs[k2], lc.coefs[k]);
|
||||
if (!ctx.F.isZero(newP)) {
|
||||
if (newLc.coefs[k2]) {
|
||||
newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
|
||||
if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
|
||||
} else {
|
||||
newLc.coefs[k2] = newP;
|
||||
}
|
||||
}
|
||||
if ((typeof idxConstraint != "undefined")&&(k2!=0)) {
|
||||
if (!sig2constraint[k2]) sig2constraint[k2] = {};
|
||||
sig2constraint[k2][idxConstraint] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return newLc;
|
||||
}
|
||||
|
||||
function substitute(lc, s, eq) {
|
||||
if (!lc.coefs[s]) return lc;
|
||||
const newLc = ctx.lc._clone(lc);
|
||||
delete newLc.coefs[s];
|
||||
for (let k2 in eq.coefs) {
|
||||
const newP = ctx.F.mul(eq.coefs[k2], lc.coefs[s]);
|
||||
if (!ctx.F.isZero(newP)) {
|
||||
if (newLc.coefs[k2]) {
|
||||
newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
|
||||
if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
|
||||
} else {
|
||||
newLc.coefs[k2] = newP;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newLc;
|
||||
}
|
||||
|
||||
function isConstant(l) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
function buildCircuitDef(ctx, mainCode) {
|
||||
const res = {
|
||||
mainCode: mainCode
|
||||
};
|
||||
res.signalName2Idx = ctx.signalName2Idx;
|
||||
|
||||
res.components = [];
|
||||
res.componentName2Idx = {};
|
||||
for (let c in ctx.components) {
|
||||
const idCoponent = res.components.length;
|
||||
res.components.push({
|
||||
name: c,
|
||||
params: ctx.components[c].params,
|
||||
template: ctx.components[c].template,
|
||||
inputSignals: 0
|
||||
});
|
||||
res.componentName2Idx[c] = idCoponent;
|
||||
}
|
||||
|
||||
res.signals = new Array(ctx.signalNames.length);
|
||||
for (let i=0; i<ctx.signalNames.length; i++) {
|
||||
res.signals[i] = {
|
||||
names: ctx.signalNames[i],
|
||||
triggerComponents: []
|
||||
};
|
||||
ctx.signalNames[i].map( (fullName) => {
|
||||
const idComponet = res.componentName2Idx[ctx.signals[fullName].component];
|
||||
if (ctx.signals[fullName].direction == "IN") {
|
||||
res.signals[i].triggerComponents.push(idComponet);
|
||||
res.components[idComponet].inputSignals++;
|
||||
function addTolIdx(lc, newS) {
|
||||
const sigs = Object.keys(lc.coefs);
|
||||
for (let k=0; k<sigs.length; k++) {
|
||||
const s = sigs[k];
|
||||
if (s) {
|
||||
if (!lIdx[s]) lIdx[s] = {};
|
||||
lIdx[s][newS] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
res.constraints = buildConstraints(ctx);
|
||||
|
||||
res.templates = ctx.templates;
|
||||
|
||||
res.functions = {};
|
||||
for (let f in ctx.functions) {
|
||||
res.functions[f] = {
|
||||
params: ctx.functionParams[f],
|
||||
func: ctx.functions[f]
|
||||
};
|
||||
}
|
||||
|
||||
res.nPrvInputs = ctx.totals.prvInput;
|
||||
res.nPubInputs = ctx.totals.pubInput;
|
||||
res.nInputs = res.nPrvInputs + res.nPubInputs;
|
||||
res.nOutputs = ctx.totals.output;
|
||||
res.nVars = res.nInputs + res.nOutputs + ctx.totals.one + ctx.totals.internal;
|
||||
res.nConstants = ctx.totals.constant;
|
||||
res.nSignals = res.nVars + res.nConstants;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Build constraints
|
||||
|
||||
A constraint like this
|
||||
|
||||
[s1 + 2*s2 + 3*s3] * [ s2 + 5*s4] - [s0 ] = 0
|
||||
[ 5*s2 + 6*s3] * [ s2 + ] - [s0 + 2* s2] = 0
|
||||
[s1 + s3] * [ s2 + 5*s3] - [s4 ] = 0
|
||||
|
||||
is converted to
|
||||
|
||||
[
|
||||
[{"1":"1","2":"2","3":"3"} , {"2":"1","4":"5"} , {"0":"1" }],
|
||||
[{ "2":"5","3":"6"} , {"2":"1" } , {"0":"1", "2":"2"}],
|
||||
[{"1":"1", "3":"1"} , {"2":"1","3":"5"} , {"4":"1" }]
|
||||
]
|
||||
^ ^ ^
|
||||
| | |
|
||||
A B C
|
||||
|
||||
*/
|
||||
/*
|
||||
function buildConstraints(ctx) {
|
||||
const res = [];
|
||||
|
||||
function fillLC(dst, src) {
|
||||
if (src.t != "LC") throw new Error("Constraint is not a LINEARCOMBINATION");
|
||||
for (let s in src.coefs) {
|
||||
const v = src.coefs[s].toString();
|
||||
const id = ctx.signalName2Idx[s];
|
||||
dst[id] = v;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
const A = {};
|
||||
const B = {};
|
||||
const C = {};
|
||||
|
||||
fillLC(A, ctx.constraints[i].a);
|
||||
fillLC(B, ctx.constraints[i].b);
|
||||
fillLC(C, ctx.lc.negate(ctx.constraints[i].c));
|
||||
|
||||
res.push([A,B,C]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
function buildSyms(ctx, strm) {
|
||||
|
||||
let nSyms;
|
||||
|
||||
addSymbolsComponent(ctx.mainComponent + ".", ctx.getComponentIdx(ctx.mainComponent));
|
||||
|
||||
|
||||
function addSymbolsComponent(prefix, idComponet) {
|
||||
for (let n in ctx.components[idComponet].names.o) {
|
||||
const entrie = ctx.components[idComponet].names.o[n];
|
||||
addSymbolArray(prefix+n, entrie.type, entrie.sizes, entrie.offset);
|
||||
}
|
||||
}
|
||||
|
||||
function addSymbolArray(prefix, type, sizes, offset) {
|
||||
if (sizes.length==0) {
|
||||
if (type == "S") {
|
||||
let s=offset;
|
||||
while (ctx.signals[s].e >= 0) s = ctx.signals[s].e;
|
||||
let wId = ctx.signals[s].id;
|
||||
if (typeof(wId) == "undefined") wId=-1;
|
||||
strm.write(`${offset},${wId},${prefix}\n`);
|
||||
nSyms ++;
|
||||
if ((ctx.verbose)&&(nSyms%10000 == 0)) console.log("Symbols saved: "+nSyms);
|
||||
} else {
|
||||
addSymbolsComponent(prefix+".", offset);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
let acc = 0;
|
||||
for (let i=0; i<sizes[0]; i++) {
|
||||
acc += addSymbolArray(`${prefix}[${i}]`, type, sizes.slice(1), offset + acc );
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -49,10 +49,11 @@ const assert = require("assert");
|
||||
const iterateAST = require("./iterateast");
|
||||
const utils = require("./utils");
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const LCAlgebra = require("./lcalgebra");
|
||||
const parser = require("../parser/jaz.js").parser;
|
||||
const Scalar = require("ffjavascript").Scalar;
|
||||
|
||||
const {stringifyBigInts} = require("ffjavascript").utils;
|
||||
|
||||
/* TODO: Add lines information
|
||||
|
||||
@@ -79,7 +80,7 @@ function constructionPhase(ctx, srcFile) {
|
||||
|
||||
assert(ctx.ast.type == "BLOCK");
|
||||
|
||||
ctx.lc = new LCAlgebra(ctx.field);
|
||||
ctx.lc = new LCAlgebra(ctx.F);
|
||||
ctx.filePath= fullFilePath;
|
||||
ctx.fileName= fullFileName;
|
||||
ctx.includedFiles = {};
|
||||
@@ -218,7 +219,7 @@ function execNumber(ctx, ast) {
|
||||
s:[1,0],
|
||||
v: [{
|
||||
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);
|
||||
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);
|
||||
@@ -277,7 +278,7 @@ function execDeclareSignal(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
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");
|
||||
sizes.push( size.v[0].v.toJSNumber() );
|
||||
sizes.push( Scalar.toNumber(size.v[0].v) );
|
||||
}
|
||||
|
||||
let sIdx = ctx.addSignal(ast.name.name, sizes);
|
||||
@@ -322,7 +323,7 @@ function execDeclareVariable(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
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");
|
||||
sizes.push( size.v[0].v.toJSNumber() );
|
||||
sizes.push( Scalar.toNumber(size.v[0].v) );
|
||||
}
|
||||
|
||||
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.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 == "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") {
|
||||
for (let i=0; i<right.s[0]; i++) {
|
||||
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") {
|
||||
@@ -427,10 +428,17 @@ function execAssignement(ctx, ast) {
|
||||
}
|
||||
|
||||
// Skip if an out is assigned directly to an input.
|
||||
if ((!isIn)||(!isOut)) {
|
||||
sDest.e = sIdx;
|
||||
} else {
|
||||
if (utils.isDefined(sSrc.v)) sDest.v = sSrc.v;
|
||||
if (!(isIn&&isOut)) {
|
||||
if (isIn) {
|
||||
sDest.e = sIdx;
|
||||
} else if (isOut) {
|
||||
sSrc.e = dIdx;
|
||||
} else {
|
||||
sDest.e = sIdx;
|
||||
}
|
||||
if (!isOut) {
|
||||
if (utils.isDefined(sSrc.v)) sDest.v = sSrc.v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,14 +452,14 @@ function execInstantiateComponet(ctx, vr, fn, sels) {
|
||||
const templateName = fn.name;
|
||||
|
||||
const template = ctx.templates[templateName];
|
||||
if (!template) return ctx.throwError("Invalid Template");
|
||||
if (!template) return ctx.throwError(fn, "Invalid Template");
|
||||
|
||||
const paramValues = [];
|
||||
for (let i=0; i< fn.params.length; i++) {
|
||||
const v = exec(ctx, fn.params[i]);
|
||||
if (ctx.error) return;
|
||||
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);
|
||||
}
|
||||
@@ -558,18 +566,26 @@ function execFunctionCall(ctx, ast) {
|
||||
if (ast.name == "log") {
|
||||
const v = exec(ctx, ast.params[0]);
|
||||
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;
|
||||
}
|
||||
if (ast.name == "assert") {
|
||||
ast.fileName = ctx.fileName;
|
||||
ast.filePath = ctx.filePath;
|
||||
|
||||
const v = exec(ctx, ast.params[0]);
|
||||
const ev = val(ctx, v, ast);
|
||||
if (ev.isZero()) return ctx.throwError(ast, "Assertion failed");
|
||||
if ((typeof ev.v !== "undefined")&&(ctx.F.isZero(ev.v))) return ctx.throwError(ast, "Assertion failed");
|
||||
return;
|
||||
}
|
||||
|
||||
const fnc = ctx.functions[ast.name];
|
||||
|
||||
if (!fnc) return ctx.throwError("Function not defined");
|
||||
if (!fnc) return ctx.throwError(ast, "Function not defined");
|
||||
|
||||
const paramValues = [];
|
||||
for (let i=0; i< ast.params.length; i++) {
|
||||
@@ -620,6 +636,9 @@ function execReturn(ctx, ast) {
|
||||
function execVariable(ctx, ast) {
|
||||
|
||||
const v = ctx.refs[ast.refId];
|
||||
if (!v) {
|
||||
return ctx.throwError(ast, "Variable not defined: "+ast.name);
|
||||
}
|
||||
|
||||
const sels = [];
|
||||
for (let i=0; i< ast.selectors.length; i++) {
|
||||
@@ -627,7 +646,7 @@ function execVariable(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
if (sel.s[0] != 1) return ctx.throwError(ast, "Variable selector cannot be an array");
|
||||
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;
|
||||
@@ -675,7 +694,7 @@ function execPin(ctx, ast) {
|
||||
|
||||
if (sel.s[0] != 1) return ctx.throwError(ast, "Component selector cannot be an array");
|
||||
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);
|
||||
@@ -687,7 +706,10 @@ function execPin(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
if (sel.s[0] != 1) return ctx.throwError(ast, "Signal selector cannot be an array");
|
||||
if (sel.v[0].t != "N") return NQVAL;
|
||||
selsP.push(sel.v[0].v.toJSNumber());
|
||||
selsP.push(Scalar.toNumber(sel.v[0].v));
|
||||
}
|
||||
if (!ctx.components[cIdx]) {
|
||||
return ctx.throwError(ast, "Component not defined yet");
|
||||
}
|
||||
const sIdx = ctx.components[cIdx].names.getSignalIdx(ast.pin.name, selsP);
|
||||
|
||||
@@ -734,7 +756,7 @@ function execLoop(ctx, ast) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((!v.v[0].v.isZero())&&(!ctx.returnValue)) {
|
||||
while ((! ctx.F.isZero(v.v[0].v))&&(!ctx.returnValue)) {
|
||||
exec(ctx, ast.body);
|
||||
if (ctx.error) return;
|
||||
|
||||
@@ -777,7 +799,7 @@ function execIf(ctx, ast) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!v.v[0].v.isZero()) {
|
||||
if (!ctx.F.isZero(v.v[0].v)) {
|
||||
exec(ctx, ast.then);
|
||||
} else {
|
||||
if (ast.else) {
|
||||
@@ -804,7 +826,7 @@ function execTerCon(ctx, ast) {
|
||||
return NQVAL;
|
||||
}
|
||||
|
||||
if (!v.v[0].v.isZero()) {
|
||||
if (!ctx.F.isZero(v.v[0].v)) {
|
||||
return exec(ctx, ast.values[1]);
|
||||
} else {
|
||||
return exec(ctx, ast.values[2]);
|
||||
@@ -843,7 +865,7 @@ function execOpOp(ctx, ast, op, lr) {
|
||||
if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array");
|
||||
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");
|
||||
@@ -863,9 +885,12 @@ function execOpOp(ctx, ast, op, lr) {
|
||||
if (ctx.error) return;
|
||||
right = val(ctx, rightRef);
|
||||
} else {
|
||||
right = {t:"N", v: ctx.field.one};
|
||||
right = {t:"N", v: ctx.F.one};
|
||||
}
|
||||
|
||||
if (!right) return ctx.throwError(ast, "right operand is not initialized");
|
||||
if (!resBefore) return ctx.throwError(ast, "left operand is not initialized");
|
||||
|
||||
const resAfter = ctx.lc[op](resBefore, right);
|
||||
left.v[o] = resAfter;
|
||||
|
||||
@@ -898,7 +923,7 @@ function val(ctx, a, ast) {
|
||||
};
|
||||
let sIdx = a.sIdx;
|
||||
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;
|
||||
} else {
|
||||
ctx.throwError(ast, "Invalid type: " + a.t);
|
||||
@@ -920,7 +945,9 @@ function execConstrain(ctx, ast) {
|
||||
|
||||
if (!ctx.lc.isZero(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;
|
||||
@@ -968,7 +995,7 @@ function execArray(ctx, ast) {
|
||||
} else if (e.t == "S") {
|
||||
for (let j=0; j<e.v.length;j++) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const bigInt = require("big-integer");
|
||||
const BigArray = require("./bigarray.js");
|
||||
|
||||
const F1Field = require("ffjavascript").F1Field;
|
||||
|
||||
class TableName {
|
||||
constructor (ctx) {
|
||||
@@ -86,7 +85,9 @@ class TableName {
|
||||
|
||||
module.exports = class Ctx {
|
||||
|
||||
constructor() {
|
||||
constructor(p) {
|
||||
|
||||
this.F = new F1Field(p);
|
||||
|
||||
this.stONE = 1;
|
||||
this.stOUTPUT = 2;
|
||||
@@ -121,7 +122,7 @@ module.exports = class Ctx {
|
||||
|
||||
const oneIdx = this.addSignal("one");
|
||||
this.signals[oneIdx] = {
|
||||
v: bigInt(1),
|
||||
v: this.F.one,
|
||||
o: this.ONE,
|
||||
e: -1,
|
||||
};
|
||||
|
||||
170
src/gencode.js
170
src/gencode.js
@@ -1,7 +1,7 @@
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils");
|
||||
const assert = require("assert");
|
||||
const iterateAST = require("./iterateast");
|
||||
const Scalar = require("ffjavascript").Scalar;
|
||||
|
||||
module.exports.gen = gen;
|
||||
module.exports.newRef = newRef;
|
||||
@@ -175,17 +175,17 @@ function gen(ctx, ast) {
|
||||
} else if (ast.op == ">>") {
|
||||
return genOp(ctx, ast, "shr", 2);
|
||||
} else if (ast.op == "<") {
|
||||
return genOp(ctx, ast, "lt", 2);
|
||||
return genOp(ctx, ast, "lt", 2, true);
|
||||
} else if (ast.op == ">") {
|
||||
return genOp(ctx, ast, "gt", 2);
|
||||
return genOp(ctx, ast, "gt", 2, true);
|
||||
} else if (ast.op == "<=") {
|
||||
return genOp(ctx, ast, "leq", 2);
|
||||
return genOp(ctx, ast, "leq", 2, true);
|
||||
} else if (ast.op == ">=") {
|
||||
return genOp(ctx, ast, "geq", 2);
|
||||
return genOp(ctx, ast, "geq", 2, true);
|
||||
} else if (ast.op == "==") {
|
||||
return genOp(ctx, ast, "eq", 2);
|
||||
return genOp(ctx, ast, "eq", 2, true);
|
||||
} else if (ast.op == "!=") {
|
||||
return genOp(ctx, ast, "neq", 2);
|
||||
return genOp(ctx, ast, "neq", 2, true);
|
||||
} else if (ast.op == "?") {
|
||||
return genTerCon(ctx, ast);
|
||||
} else {
|
||||
@@ -284,6 +284,32 @@ function genDeclareComponent(ctx, ast) {
|
||||
}
|
||||
|
||||
function genDeclareSignal(ctx, ast) {
|
||||
|
||||
const v = ctx.refs[ast.refId];
|
||||
|
||||
let sizes;
|
||||
if (ast.name.selectors.length>0) {
|
||||
sizes=[];
|
||||
for (let i=0; i< ast.name.selectors.length; i++) {
|
||||
const sizeRef = gen(ctx, ast.name.selectors[i]);
|
||||
const size = ctx.refs[sizeRef];
|
||||
if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
|
||||
if (size.used) return ctx.throwError(ast, "Signal size variables not allowed");
|
||||
sizes.push(Scalar.toNumber(size.value[0]));
|
||||
}
|
||||
sizes = utils.accSizes(sizes);
|
||||
} else {
|
||||
sizes = [1,0];
|
||||
}
|
||||
|
||||
if ((!v.sizes)&&(sizes)) {
|
||||
v.sizes = sizes;
|
||||
}
|
||||
|
||||
if (v.sizes) {
|
||||
if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a signal with different sized");
|
||||
}
|
||||
|
||||
return ast.refId;
|
||||
}
|
||||
|
||||
@@ -300,7 +326,7 @@ function genDeclareVariable(ctx, ast) {
|
||||
const size = ctx.refs[sizeRef];
|
||||
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");
|
||||
sizes.push(size.value[0]);
|
||||
sizes.push(Scalar.toNumber(size.value[0]));
|
||||
}
|
||||
sizes = utils.accSizes(sizes);
|
||||
} else {
|
||||
@@ -320,7 +346,7 @@ function genDeclareVariable(ctx, ast) {
|
||||
}
|
||||
|
||||
function genNumber(ctx, ast) {
|
||||
return newRef(ctx, "BIGINT", "_num", bigInt(ast.value));
|
||||
return newRef(ctx, "BIGINT", "_num", ctx.F.e(ast.value));
|
||||
}
|
||||
|
||||
|
||||
@@ -414,22 +440,31 @@ function genVariable(ctx, ast) {
|
||||
vOffset = genGetSignalOffset(ctx, -1, ast.name);
|
||||
}
|
||||
|
||||
const resRef = newRef(ctx, "BIGINT", "_sigValue");
|
||||
const sizes = v.sizes.slice(l);
|
||||
|
||||
const resRef = newRef(ctx, "BIGINT", "_sigValue", null, sizes);
|
||||
const res = ctx.refs[resRef];
|
||||
instantiateRef(ctx, resRef);
|
||||
ctx.codeBuilder.getSignal(res.label, ["CC"], toRefA_Int1(ctx, ast, vOffset));
|
||||
ctx.codeBuilder.getSignal(res.label, ["CC"], toRefA_Int1(ctx, ast, vOffset), sizes[0]);
|
||||
return resRef;
|
||||
|
||||
} else if (v.type == "BIGINT") {
|
||||
const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
|
||||
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 (offset.used) {
|
||||
const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
|
||||
const res = ctx.refs[refRes];
|
||||
res.used = true;
|
||||
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;
|
||||
} else if ((offset.value[0]>0)||(l>0)) {
|
||||
const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
|
||||
@@ -448,7 +483,7 @@ function genVariable(ctx, ast) {
|
||||
const res = ctx.refs[resRef];
|
||||
res.used = true;
|
||||
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;
|
||||
} else {
|
||||
// return newSubRef(ctx, ast.name, ast.selectors);
|
||||
@@ -478,13 +513,18 @@ function genPin(ctx, ast) {
|
||||
vsIdx = genGetSignalOffset(ctx, vcIdx, ast.pin.name);
|
||||
}
|
||||
|
||||
const resRef = newRef(ctx, "BIGINT", "_sigValue");
|
||||
const l = ast.selectors ? ast.selectors.length : 0;
|
||||
|
||||
const sizes = [1,0]; // TODO, Treat array
|
||||
|
||||
const resRef = newRef(ctx, "BIGINT", "_sigValue", null, sizes);
|
||||
const res = ctx.refs[resRef];
|
||||
instantiateRef(ctx, resRef);
|
||||
ctx.codeBuilder.getSignal(
|
||||
res.label,
|
||||
toRefA_Int1(ctx, ast.component, vcIdx),
|
||||
toRefA_Int1(ctx, ast.pin, vsIdx)
|
||||
toRefA_Int1(ctx, ast.pin, vsIdx),
|
||||
sizes[0]
|
||||
);
|
||||
return resRef;
|
||||
}
|
||||
@@ -499,7 +539,13 @@ function genGetSubComponentOffset(ctx, cIdxRef, label) {
|
||||
if (cIdxRef>=0) {
|
||||
const cIdx = ctx.refs[cIdxRef];
|
||||
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 {
|
||||
c = ["V", cIdx.value[0]];
|
||||
}
|
||||
@@ -520,7 +566,13 @@ function genGetSubComponentSizes(ctx, cIdxRef, label) {
|
||||
if (cIdxRef>=0) {
|
||||
const cIdx = ctx.refs[cIdxRef];
|
||||
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 {
|
||||
c = ["V", cIdx.value[0]];
|
||||
}
|
||||
@@ -553,7 +605,13 @@ function genGetSignalOffset(ctx, cIdxRef, label) {
|
||||
if (cIdxRef>=0) {
|
||||
const cIdx = ctx.refs[cIdxRef];
|
||||
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 {
|
||||
c = ["V", cIdx.value[0]];
|
||||
}
|
||||
@@ -590,7 +648,13 @@ function genGetSignalSizes(ctx, cIdxRef, label) {
|
||||
if (cIdxRef>=0) {
|
||||
const cIdx = ctx.refs[cIdxRef];
|
||||
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 {
|
||||
c = ["V", cIdx.value[0]];
|
||||
}
|
||||
@@ -691,7 +755,15 @@ function genVarAssignment(ctx, ast, lRef, sels, rRef) {
|
||||
|
||||
if (instantiated) {
|
||||
if (offset.used) {
|
||||
ctx.codeBuilder.copyN(left.label, ["R", offset.label], ["R", right.label], right.sizes[0]);
|
||||
let ot;
|
||||
if (offset.type == "BIGINT") {
|
||||
ot = "R";
|
||||
} else if (offset.type == "INT") {
|
||||
ot= "RI";
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
ctx.codeBuilder.copyN(left.label, [ot, offset.label], ["R", right.label], right.sizes[0]);
|
||||
} else {
|
||||
ctx.codeBuilder.copyN(left.label, ["V", offset.value[0]], ["R", right.label], right.sizes[0]);
|
||||
}
|
||||
@@ -743,7 +815,11 @@ function toRefA_Fr1(ctx, ast, aRef) {
|
||||
const a = ctx.refs[aRef];
|
||||
if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
|
||||
if (a.used) {
|
||||
return ["R", a.label];
|
||||
if (a.type == "BIGINT") {
|
||||
return ["R", a.label];
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
return ["C", ctx.addConstant(a.value[0])];
|
||||
}
|
||||
@@ -754,7 +830,13 @@ function toRefA_Int1(ctx, ast, aRef) {
|
||||
const a = ctx.refs[aRef];
|
||||
if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
|
||||
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 {
|
||||
return ["V", a.value[0]];
|
||||
}
|
||||
@@ -818,9 +900,13 @@ function genArray(ctx, ast) {
|
||||
function genFunctionCall(ctx, ast) {
|
||||
if (ast.name == "log") {
|
||||
const vRef = gen(ctx, ast.params[0]);
|
||||
const val = ctx.refs[vRef];
|
||||
instantiateRef(ctx, vRef, val.value);
|
||||
ctx.code+=`ctx->log(${val.label});`;
|
||||
ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef));
|
||||
return vRef;
|
||||
}
|
||||
if (ast.name == "assert") {
|
||||
const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
|
||||
const vRef = gen(ctx, ast.params[0]);
|
||||
ctx.codeBuilder.checkAssert(toRefA_Fr1(ctx, ast.params[0], vRef), strErr);
|
||||
return vRef;
|
||||
}
|
||||
const params = [];
|
||||
@@ -897,7 +983,7 @@ function genLoop(ctx, ast) {
|
||||
if (ctx.error) return;
|
||||
|
||||
const cond = ctx.refs[condRef];
|
||||
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
|
||||
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genLoop: Operation cannot be done on an array");
|
||||
|
||||
if (cond.used) {
|
||||
inLoop = true;
|
||||
@@ -910,7 +996,7 @@ function genLoop(ctx, ast) {
|
||||
ctx.codeBuilder.assign(loopCond.label, ["R", cond.label], ["V", 0]);
|
||||
} else {
|
||||
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 +1039,7 @@ function genLoop(ctx, ast) {
|
||||
} else {
|
||||
oldCodeBuilder.concat(ctx.codeBuilder);
|
||||
ctx.codeBuilder = oldCodeBuilder;
|
||||
if (cond2.value[0].isZero()) end=true;
|
||||
if (ctx.F.isZero(cond2.value[0])) end=true;
|
||||
}
|
||||
} else {
|
||||
ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]);
|
||||
@@ -974,7 +1060,7 @@ function genIf(ctx, ast) {
|
||||
const condRef = gen(ctx, ast.condition);
|
||||
if (ctx.error) return;
|
||||
const cond = ctx.refs[condRef];
|
||||
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
|
||||
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genIf: Operation cannot be done on an array");
|
||||
|
||||
if (cond.used) {
|
||||
let thenCode, elseCode;
|
||||
@@ -1002,7 +1088,7 @@ function genIf(ctx, ast) {
|
||||
|
||||
} else {
|
||||
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);
|
||||
} else {
|
||||
if (ast.else) {
|
||||
@@ -1069,9 +1155,9 @@ function genOpOp(ctx, ast, op, lr) {
|
||||
const res = ctx.refs[resRef];
|
||||
if (veval.used) {
|
||||
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 {
|
||||
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);
|
||||
if (lr == "RIGHT") {
|
||||
@@ -1081,7 +1167,7 @@ function genOpOp(ctx, ast, op, lr) {
|
||||
}
|
||||
}
|
||||
|
||||
function genOp(ctx, ast, op, nOps) {
|
||||
function genOp(ctx, ast, op, nOps, adjustBool) {
|
||||
const vals = [];
|
||||
const valRefs = [];
|
||||
|
||||
@@ -1094,7 +1180,12 @@ function genOp(ctx, ast, op, nOps) {
|
||||
valRefs.push(ref);
|
||||
vals.push(v);
|
||||
|
||||
if (!utils.sameSizes(v.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array");
|
||||
if (!utils.sameSizes(v.sizes, [1,0])) {
|
||||
console.log("xx");
|
||||
console.log(i);
|
||||
console.log(v);
|
||||
return ctx.throwError(ast, "genOp2: Operation cannot be done on an array");
|
||||
}
|
||||
if ( (!v.used)
|
||||
&&( (!utils.isDefined(v.value))
|
||||
||(!utils.isDefined(v.value[0]))))
|
||||
@@ -1117,9 +1208,10 @@ function genOp(ctx, ast, op, nOps) {
|
||||
} else {
|
||||
const params = [];
|
||||
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;
|
||||
}
|
||||
@@ -1129,7 +1221,7 @@ function genTerCon(ctx, ast) {
|
||||
const condRef = gen(ctx, ast.values[0]);
|
||||
if (ctx.error) return;
|
||||
const cond = ctx.refs[condRef];
|
||||
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
|
||||
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genTer: Operation cannot be done on an array");
|
||||
|
||||
if (cond.used) {
|
||||
let thenCode, elseCode;
|
||||
@@ -1201,7 +1293,7 @@ function genTerCon(ctx, ast) {
|
||||
|
||||
} else {
|
||||
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]);
|
||||
} else {
|
||||
return gen(ctx, ast.values[2]);
|
||||
|
||||
@@ -76,21 +76,14 @@ QEX QEX NQ NQ NQ
|
||||
NQ NQ NQ NQ NQ
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils");
|
||||
const sONE = 0;
|
||||
|
||||
class LCAlgebra {
|
||||
constructor (aField) {
|
||||
const self = this;
|
||||
this.field= aField;
|
||||
this.F= aField;
|
||||
[
|
||||
["lt",2],
|
||||
["leq",2],
|
||||
["eq",2],
|
||||
["neq",2],
|
||||
["geq",2],
|
||||
["gt",2],
|
||||
["idiv",2],
|
||||
["mod",2],
|
||||
["band",2],
|
||||
@@ -102,12 +95,18 @@ class LCAlgebra {
|
||||
["lnot",2],
|
||||
["shl",2],
|
||||
["shr",2],
|
||||
["lt",2, true],
|
||||
["leq",2, true],
|
||||
["eq",2, true],
|
||||
["neq",2, true],
|
||||
["geq",2, true],
|
||||
["gt",2, true]
|
||||
].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;
|
||||
self[op] = function() {
|
||||
const operands = [];
|
||||
@@ -118,18 +117,19 @@ class LCAlgebra {
|
||||
}
|
||||
return {
|
||||
t: "N",
|
||||
v: self.field[op](...operands)
|
||||
v: adjustBool ? ( self.F[op](...operands) ? self.F.one: self.F.zero) : self.F[op](...operands)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
_signal2lc(a) {
|
||||
const self = this;
|
||||
if (a.t == "S") {
|
||||
const lc = {
|
||||
t: "LC",
|
||||
coefs: {}
|
||||
};
|
||||
lc.coefs[a.sIdx] = bigInt(1);
|
||||
lc.coefs[a.sIdx] = self.F.one;
|
||||
return lc;
|
||||
} else {
|
||||
return a;
|
||||
@@ -200,17 +200,17 @@ class LCAlgebra {
|
||||
function add_N_N(a,b) {
|
||||
return {
|
||||
t: "N",
|
||||
v: self.field.add(a.v, b.v)
|
||||
v: self.F.add(a.v, b.v)
|
||||
};
|
||||
}
|
||||
|
||||
function add_LC_N(a,b) {
|
||||
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])) {
|
||||
res.coefs[sONE]= b.v;
|
||||
} 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;
|
||||
}
|
||||
@@ -221,7 +221,7 @@ class LCAlgebra {
|
||||
if (!utils.isDefined(res.coefs[k])) {
|
||||
res.coefs[k]=b.coefs[k];
|
||||
} 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;
|
||||
@@ -283,14 +283,14 @@ class LCAlgebra {
|
||||
function mul_N_N(a,b) {
|
||||
return {
|
||||
t: "N",
|
||||
v: self.field.mul(a.v, b.v)
|
||||
v: self.F.mul(a.v, b.v)
|
||||
};
|
||||
}
|
||||
|
||||
function mul_LC_N(a,b) {
|
||||
let res = self._clone(a);
|
||||
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;
|
||||
}
|
||||
@@ -318,10 +318,10 @@ class LCAlgebra {
|
||||
const a = this._signal2lc(_a);
|
||||
let res = this._clone(a);
|
||||
if (res.t == "N") {
|
||||
res.v = this.field.neg(a.v);
|
||||
res.v = this.F.neg(a.v);
|
||||
} else if (res.t == "LC") {
|
||||
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") {
|
||||
res.a = this.neg(res.a);
|
||||
@@ -338,10 +338,10 @@ class LCAlgebra {
|
||||
|
||||
div(a, b) {
|
||||
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 = {
|
||||
t: "N",
|
||||
v: this.field.inv(b.v)
|
||||
v: this.F.inv(b.v)
|
||||
};
|
||||
return this.mul(a, inv);
|
||||
} else {
|
||||
@@ -351,23 +351,23 @@ class LCAlgebra {
|
||||
|
||||
pow(a, b) {
|
||||
if (b.t == "N") {
|
||||
if (b.v.isZero()) {
|
||||
if (this.F.isZero(b.v)) {
|
||||
if (this.isZero(a)) {
|
||||
throw new Error("Zero to the Zero");
|
||||
}
|
||||
return {
|
||||
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;
|
||||
} else if (b.v.eq(bigInt(2))) {
|
||||
} else if (this.F.eq(b.v, this.F.two)) {
|
||||
return this.mul(a,a);
|
||||
} else {
|
||||
if (a.t=="N") {
|
||||
return {
|
||||
t: "N",
|
||||
v: this.field.pow(a.v, b.v)
|
||||
v: this.F.pow(a.v, b.v)
|
||||
};
|
||||
} else {
|
||||
return {t: "NQ"};
|
||||
@@ -381,18 +381,18 @@ class LCAlgebra {
|
||||
substitute(where, signal, equivalence) {
|
||||
if (equivalence.t != "LC") throw new Error("Equivalence must be a Linear Combination");
|
||||
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 coef = res.coefs[signal];
|
||||
for (let k in equivalence.coefs) {
|
||||
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])) {
|
||||
res.coefs[k]=v;
|
||||
} 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];
|
||||
@@ -436,10 +436,10 @@ class LCAlgebra {
|
||||
|
||||
isZero(a) {
|
||||
if (a.t == "N") {
|
||||
return a.v.isZero();
|
||||
return this.F.isZero(a.v);
|
||||
} else if (a.t == "LC") {
|
||||
for (let k in a.coefs) {
|
||||
if (!a.coefs[k].isZero()) return false;
|
||||
if (!this.F.isZero(a.coefs[k])) return false;
|
||||
}
|
||||
return true;
|
||||
} else if (a.t == "QEX") {
|
||||
@@ -455,16 +455,16 @@ class LCAlgebra {
|
||||
} else if (a.t == "LC") {
|
||||
let S="";
|
||||
for (let k in a.coefs) {
|
||||
if (!a.coefs[k].isZero()) {
|
||||
if (!this.F.isZero(a.coefs[k])) {
|
||||
let c;
|
||||
if (a.coefs[k].greater(this.field.p.divide(2))) {
|
||||
if (a.coefs[k].greater(this.F.p.divide(2))) {
|
||||
S = S + "-";
|
||||
c = this.field.p.minus(a.coefs[k]);
|
||||
c = this.F.p.minus(a.coefs[k]);
|
||||
} else {
|
||||
if (S!="") S=S+" + ";
|
||||
c = a.coefs[k];
|
||||
}
|
||||
if (!c.equals(bigInt.one)) {
|
||||
if (!c.equals(this.F.one)) {
|
||||
S = S + c.toString() + "*";
|
||||
}
|
||||
let sIdx = k;
|
||||
@@ -491,11 +491,11 @@ class LCAlgebra {
|
||||
} else if (n.t == "SIGNAL") {
|
||||
return getSignalValue(ctx, n.sIdx);
|
||||
} else if (n.t == "LC") {
|
||||
let v= this.field.zero;
|
||||
let v= this.F.zero;
|
||||
for (let k in n.coefs) {
|
||||
const s = getSignalValue(ctx, k);
|
||||
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;
|
||||
} else if (n.type == "QEX") {
|
||||
@@ -506,7 +506,7 @@ class LCAlgebra {
|
||||
const c = this.evaluate(ctx, n.c);
|
||||
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 {
|
||||
return null;
|
||||
}
|
||||
@@ -529,24 +529,24 @@ class LCAlgebra {
|
||||
let s = k;
|
||||
while (ctx.signals[s].e>=0) s= ctx.signals[s].e;
|
||||
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])) {
|
||||
res.coefs[sONE]=v;
|
||||
} 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];
|
||||
} else if (s != k) {
|
||||
if (!utils.isDefined(res.coefs[s])) {
|
||||
res.coefs[s]=res.coefs[k];
|
||||
} 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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
} else if (a.t == "QEX") {
|
||||
|
||||
298
src/r1csfile.js
298
src/r1csfile.js
@@ -1,188 +1,36 @@
|
||||
|
||||
const fs = require("fs");
|
||||
const fastFile = require("fastfile");
|
||||
const assert = require("assert");
|
||||
const bigInt = require("big-integer");
|
||||
const BigArray = require("./bigarray");
|
||||
|
||||
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) {
|
||||
|
||||
const fd = await fs.promises.open(fileName, "w");
|
||||
const fd = await fastFile.createOverride(fileName, 1<<24, 1<<22);
|
||||
|
||||
const buffBigInt = new Uint8Array(ctx.F.n8);
|
||||
|
||||
await fd.write("r1cs"); // Magic "r1cs"
|
||||
const type = "r1cs";
|
||||
const buff = new Uint8Array(4);
|
||||
for (let i=0; i<4; i++) buff[i] = type.charCodeAt(i);
|
||||
await fd.write(buff, 0); // Magic "r1cs"
|
||||
|
||||
let p = 4;
|
||||
await writeU32(1); // Version
|
||||
await writeU32(3); // Number of Sections
|
||||
await fd.writeULE32(1); // Version
|
||||
await fd.writeULE32(3); // Number of Sections
|
||||
|
||||
// Write the header
|
||||
///////////
|
||||
await writeU32(1); // Header type
|
||||
const pHeaderSize = p;
|
||||
await writeU32(0); // Temporally set to 0 length
|
||||
await fd.writeULE32(1); // Header type
|
||||
const pHeaderSize = fd.pos;
|
||||
await fd.writeULE64(0); // Temporally set to 0 length
|
||||
|
||||
|
||||
const n8 = (Math.floor( (ctx.F.bitLength - 1) / 64) +1)*8;
|
||||
// Field Def
|
||||
const pFieldDefSize = p;
|
||||
await writeU32(0); // Temporally set to 0 length
|
||||
await writeU32(1);
|
||||
await writeBigInt(ctx.field.p);
|
||||
const fieldDefSize = p - pFieldDefSize - 4;
|
||||
|
||||
await writeU32(0); // Variable bigInt format
|
||||
await writeU32(4); // Id Size
|
||||
await fd.writeULE32(n8); // Temporally set to 0 length
|
||||
await writeBigInt(ctx.F.p);
|
||||
|
||||
const NWires =
|
||||
ctx.totals[ctx.stONE] +
|
||||
@@ -191,39 +39,38 @@ async function buildR1cs(ctx, fileName) {
|
||||
ctx.totals[ctx.stPRVINPUT] +
|
||||
ctx.totals[ctx.stINTERNAL];
|
||||
|
||||
await writeU32(NWires);
|
||||
await writeU32(ctx.totals[ctx.stOUTPUT]);
|
||||
await writeU32(ctx.totals[ctx.stPUBINPUT]);
|
||||
await writeU32(ctx.totals[ctx.stPRVINPUT]);
|
||||
await writeU32(ctx.signals.length);
|
||||
await writeU32(ctx.constraints.length);
|
||||
await fd.writeULE32(NWires);
|
||||
await fd.writeULE32(ctx.totals[ctx.stOUTPUT]);
|
||||
await fd.writeULE32(ctx.totals[ctx.stPUBINPUT]);
|
||||
await fd.writeULE32(ctx.totals[ctx.stPRVINPUT]);
|
||||
await fd.writeULE64(ctx.signals.length);
|
||||
await fd.writeULE32(ctx.constraints.length);
|
||||
|
||||
const headerSize = p - pHeaderSize - 4;
|
||||
const headerSize = fd.pos - pHeaderSize - 8;
|
||||
|
||||
// Write constraints
|
||||
///////////
|
||||
await writeU32(2); // Constraints type
|
||||
const pConstraintsSize = p;
|
||||
await writeU32(0); // Temporally set to 0 length
|
||||
await fd.writeULE32(2); // Constraints type
|
||||
const pConstraintsSize = fd.pos;
|
||||
await fd.writeULE64(0); // Temporally set to 0 length
|
||||
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
if ((ctx.verbose)&&(i%10000 == 0)) {
|
||||
if (ctx.verbose) console.log("writing constraint: ", i);
|
||||
await fd.datasync();
|
||||
}
|
||||
await writeConstraint(ctx.constraints[i]);
|
||||
await writeConstraint(ctx.constraints[i], i);
|
||||
}
|
||||
|
||||
const constraintsSize = p - pConstraintsSize - 4;
|
||||
const constraintsSize = fd.pos - pConstraintsSize - 8;
|
||||
|
||||
// Write map
|
||||
///////////
|
||||
await writeU32(3); // wires2label type
|
||||
const pMapSize = p;
|
||||
await writeU32(0); // Temporally set to 0 length
|
||||
await fd.writeULE32(3); // wires2label type
|
||||
const pMapSize = fd.pos;
|
||||
await fd.writeULE64(0); // Temporally set to 0 length
|
||||
|
||||
|
||||
const arr = new Array(NWires);
|
||||
const arr = new BigArray(NWires);
|
||||
for (let i=0; i<ctx.signals.length; i++) {
|
||||
const outIdx = ctx.signals[i].id;
|
||||
if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
|
||||
@@ -234,55 +81,66 @@ async function buildR1cs(ctx, fileName) {
|
||||
}
|
||||
}
|
||||
for (let i=0; i<arr.length; i++) {
|
||||
await writeU32(arr[i]);
|
||||
if ((ctx.verbose)&&(i%100000)) console.log("writing label2wire map: ", i);
|
||||
await fd.writeULE64(arr[i]);
|
||||
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`writing wire2label map: ${i}/${arr.length}`);
|
||||
}
|
||||
|
||||
const mapSize = p - pMapSize -4;
|
||||
const mapSize = fd.pos - pMapSize - 8;
|
||||
|
||||
// Write sizes
|
||||
await writeU32(headerSize, pHeaderSize);
|
||||
await writeU32(fieldDefSize, pFieldDefSize);
|
||||
await writeU32(constraintsSize, pConstraintsSize);
|
||||
await writeU32(mapSize, pMapSize);
|
||||
await fd.writeULE64(headerSize, pHeaderSize);
|
||||
await fd.writeULE64(constraintsSize, pConstraintsSize);
|
||||
await fd.writeULE64(mapSize, pMapSize);
|
||||
|
||||
await fd.sync();
|
||||
await fd.close();
|
||||
|
||||
async function writeU32(v, pos) {
|
||||
const b = Buffer.allocUnsafe(4);
|
||||
b.writeInt32LE(v);
|
||||
|
||||
await fd.write(b, 0, 4, pos);
|
||||
|
||||
if (typeof(pos) == "undefined") p += 4;
|
||||
}
|
||||
|
||||
async function writeConstraint(c) {
|
||||
await writeLC(c.a);
|
||||
await writeLC(c.b);
|
||||
await writeLC(ctx.lc.neg(c.c));
|
||||
}
|
||||
|
||||
async function writeLC(lc) {
|
||||
const idxs = Object.keys(lc.coefs);
|
||||
await writeU32(idxs.length);
|
||||
for (let s in lc.coefs) {
|
||||
let lSignal = ctx.signals[s];
|
||||
function writeConstraint(c, ctIdx) {
|
||||
const n8 = ctx.F.n8;
|
||||
const idxA = Object.keys(c.a.coefs);
|
||||
const idxB = Object.keys(c.b.coefs);
|
||||
const idxC = Object.keys(c.c.coefs);
|
||||
const buff = new Uint8Array((idxA.length+idxB.length+idxC.length)*(n8+4) + 12);
|
||||
const buffV = new DataView(buff.buffer);
|
||||
let o=0;
|
||||
|
||||
buffV.setUint32(o, idxA.length, true); o+=4;
|
||||
for (let i=0; i<idxA.length; i++) {
|
||||
const coef = idxA[i];
|
||||
let lSignal = ctx.signals[coef];
|
||||
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
|
||||
|
||||
await writeU32(lSignal.id);
|
||||
await writeBigInt(lc.coefs[s]);
|
||||
if (lSignal.id >= NWires) throw new Error("Signal Coef A: " + coef + " Constraint: " + ctIdx + " id: " + lSignal.id);
|
||||
buffV.setUint32(o, lSignal.id, true); o+=4;
|
||||
ctx.F.toRprLE(buff, o, c.a.coefs[coef]); o+=n8;
|
||||
}
|
||||
|
||||
buffV.setUint32(o, idxB.length, true); o+=4;
|
||||
for (let i=0; i<idxB.length; i++) {
|
||||
const coef = idxB[i];
|
||||
let lSignal = ctx.signals[coef];
|
||||
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
|
||||
if (lSignal.id >= NWires) throw new Error("Signal Coef B: " + coef + " Constraint: " + ctIdx + " id: " + lSignal.id);
|
||||
buffV.setUint32(o, lSignal.id, true); o+=4;
|
||||
ctx.F.toRprLE(buff, o, c.b.coefs[coef]); o+=n8;
|
||||
}
|
||||
|
||||
buffV.setUint32(o, idxC.length, true); o+=4;
|
||||
for (let i=0; i<idxC.length; i++) {
|
||||
const coef = idxC[i];
|
||||
let lSignal = ctx.signals[coef];
|
||||
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
|
||||
if (lSignal.id >= NWires) throw new Error("Signal Coef C: " + coef + " Constraint: " + ctIdx + " id: " + lSignal.id);
|
||||
buffV.setUint32(o, lSignal.id, true); o+=4;
|
||||
ctx.F.toRprLE(buff, o, ctx.F.neg(c.c.coefs[coef])); o+=n8;
|
||||
}
|
||||
|
||||
return fd.write(buff);
|
||||
}
|
||||
|
||||
async function writeBigInt(n) {
|
||||
async function writeBigInt(n, pos) {
|
||||
|
||||
const bytes = bigInt(n).toArray(256).value.reverse();
|
||||
ctx.F.toRprLE(buffBigInt, 0, n);
|
||||
|
||||
await fd.write(Buffer.from([bytes.length, ...bytes ]));
|
||||
await fd.write(buffBigInt, pos);
|
||||
|
||||
p += bytes.length+1;
|
||||
}
|
||||
}
|
||||
|
||||
21
src/streamfromarray_bin.js
Normal file
21
src/streamfromarray_bin.js
Normal 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;
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
const Readable = require("stream").Readable;
|
||||
|
||||
module.exports = function streamFromMultiarray(ma) {
|
||||
module.exports = function streamFromArrayTxt(ma) {
|
||||
const rs = Readable();
|
||||
|
||||
let curIndex = getFirstIdx(ma);
|
||||
@@ -10,7 +9,7 @@ module.exports = function streamFromMultiarray(ma) {
|
||||
let res;
|
||||
res = objFromIdx(ma, curIndex);
|
||||
curIndex = nextIdx(curIndex);
|
||||
if (res!=null) {
|
||||
if (res!==null) {
|
||||
rs.push(res + "\n");
|
||||
} else {
|
||||
rs.push(null);
|
||||
@@ -22,7 +21,7 @@ module.exports = function streamFromMultiarray(ma) {
|
||||
|
||||
|
||||
function getFirstIdx(ma) {
|
||||
if (!Array.isArray(ma)) return [];
|
||||
if (typeof ma.push !== "function" ) return [];
|
||||
return [0, ...getFirstIdx(ma[0])];
|
||||
}
|
||||
|
||||
50
src/utils.js
50
src/utils.js
@@ -1,5 +1,4 @@
|
||||
const fnv = require("fnv-plus");
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports.ident =ident;
|
||||
|
||||
@@ -8,11 +7,10 @@ module.exports.flatArray = flatArray;
|
||||
module.exports.csArr = csArr;
|
||||
module.exports.accSizes = accSizes;
|
||||
module.exports.fnvHash = fnvHash;
|
||||
module.exports.stringifyBigInts = stringifyBigInts;
|
||||
module.exports.unstringifyBigInts = unstringifyBigInts;
|
||||
module.exports.sameSizes = sameSizes;
|
||||
module.exports.isDefined = isDefined;
|
||||
module.exports.accSizes2Str = accSizes2Str;
|
||||
module.exports.setUint64 = setUint64;
|
||||
|
||||
function ident(text) {
|
||||
if (typeof text === "string") {
|
||||
@@ -45,7 +43,7 @@ function flatArray(a) {
|
||||
fillArray(res, a[i]);
|
||||
}
|
||||
} else {
|
||||
res.push(bigInt(a));
|
||||
res.push(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,42 +72,6 @@ function fnvHash(str) {
|
||||
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) {
|
||||
if (!Array.isArray(s1)) return false;
|
||||
if (!Array.isArray(s2)) return false;
|
||||
@@ -129,6 +91,14 @@ function accSizes2Str(sizes) {
|
||||
return `[${sizes[0]/sizes[1]}]`+accSizes2Str(sizes.slice(1));
|
||||
}
|
||||
|
||||
function setUint64(buffV, o, n) {
|
||||
const sLSB = n >>> 0;
|
||||
const sMSB = (n - sLSB) / 0x100000000;
|
||||
buffV.setUint32(o, sLSB , true);
|
||||
buffV.setUint32(o+4, sMSB , true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
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 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) {
|
||||
if ((typeof(o) == "bigint") || o.isZero !== undefined) {
|
||||
const res = bigInt(o);
|
||||
return norm(res);
|
||||
return Fr.e(o);
|
||||
} else if (Array.isArray(o)) {
|
||||
return o.map(normalize);
|
||||
} else if (typeof o == "object") {
|
||||
@@ -19,23 +23,20 @@ function normalize(o) {
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
const res = bigInt(o);
|
||||
return norm(res);
|
||||
return Fr.e(o);
|
||||
}
|
||||
|
||||
function norm(n) {
|
||||
let res = n.mod(__P__);
|
||||
if (res.isNegative()) res = __P__.add(res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function doTest(circuit, testVectors) {
|
||||
const cir = await c_tester(path.join(__dirname, "circuits", circuit));
|
||||
async function doTest(tester, circuit, testVectors) {
|
||||
const cir = await tester(path.join(__dirname, "circuits", circuit));
|
||||
|
||||
for (let i=0; i<testVectors.length; i++) {
|
||||
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]) );
|
||||
}
|
||||
|
||||
@@ -45,299 +46,16 @@ async function doTest(circuit, testVectors) {
|
||||
describe("basic cases", function () {
|
||||
this.timeout(100000);
|
||||
|
||||
it("inout", async () => {
|
||||
await doTest(
|
||||
"inout.circom",
|
||||
[
|
||||
[{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}],
|
||||
]
|
||||
);
|
||||
});
|
||||
for (let i=0; i< basicCases.length; i++) {
|
||||
it("c/c++ " + basicCases[i].name, async () => {
|
||||
await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv);
|
||||
});
|
||||
}
|
||||
|
||||
it("Conditional Ternary operator", async () => {
|
||||
await doTest(
|
||||
"condternary.circom",
|
||||
[
|
||||
[{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}],
|
||||
]
|
||||
);
|
||||
});
|
||||
for (let i=0; i<basicCases.length; i++) {
|
||||
it("wasm " + basicCases[i].name, async () => {
|
||||
await doTest(wasm_tester, basicCases[i].circuit, basicCases[i].tv);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
318
test/basiccases.json
Normal file
318
test/basiccases.json
Normal file
@@ -0,0 +1,318 @@
|
||||
[
|
||||
{
|
||||
"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": "fnarray",
|
||||
"circuit": "fnarray.circom",
|
||||
"tv": [
|
||||
[{
|
||||
"in": [1, 8, 25]
|
||||
}, {
|
||||
"out": [2, 16, 50]
|
||||
}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"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}]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -31,9 +31,11 @@ template Main() {
|
||||
out[0] === in+c[0];
|
||||
|
||||
out[1] <-- d[1]+c[1];
|
||||
// out[1] === (in+in)+3+c[1];
|
||||
out[1] === 2*in+3+c[1];
|
||||
|
||||
out[2] <-- d[2]+c[2];
|
||||
// out[2] === (in+in+in+in+in+in)+12+c[2];
|
||||
out[2] === 6*in+12+c[2];
|
||||
}
|
||||
|
||||
|
||||
21
test/circuits/fnarray.circom
Normal file
21
test/circuits/fnarray.circom
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
|
||||
|
||||
function calc(h) {
|
||||
var res[3];
|
||||
for (var i=0; i<3; i++) res[i] = h[i]*2;
|
||||
return res;
|
||||
}
|
||||
|
||||
template Test() {
|
||||
signal input in[3];
|
||||
signal output out[3];
|
||||
|
||||
var cout[3] = calc(in);
|
||||
for (var i=0; i<3; i++) out[i] <-- cout[i];
|
||||
|
||||
for (var i=0; i<3; i++) out[i] === in[i]*2;
|
||||
}
|
||||
|
||||
component main = Test();
|
||||
@@ -1 +0,0 @@
|
||||
{"x": "3"}
|
||||
407
test/fieldasm.js
407
test/fieldasm.js
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user