mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-07 11:16:42 +01:00
Compare commits
10 Commits
feature/se
...
v0.5.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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.
|
||||
|
||||
|
||||
43
TUTORIAL.md
43
TUTORIAL.md
@@ -6,7 +6,7 @@ This tutorial will guide you in creating your first Zero Knowledge zkSnark circu
|
||||
|
||||
### 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 (!).
|
||||
|
||||
@@ -16,6 +16,7 @@ Run:
|
||||
|
||||
```sh
|
||||
npm install -g circom
|
||||
npm install -g circom_runtime
|
||||
npm install -g snarkjs
|
||||
```
|
||||
|
||||
@@ -42,7 +43,7 @@ template Multiplier() {
|
||||
signal private input a;
|
||||
signal private input b;
|
||||
signal output c;
|
||||
|
||||
|
||||
c <== a*b;
|
||||
}
|
||||
|
||||
@@ -62,10 +63,12 @@ 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 -r optin will generate `circuit.r1cs` ( The r1cs constraint system of the circuit in binary format)
|
||||
The -w will generate `circuit.wasm` (The wasm code to generate the witness)
|
||||
The -s will generate `circuit.sym` (This is the 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 +77,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 +85,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,10 +101,10 @@ 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`
|
||||
|
||||
@@ -109,13 +112,13 @@ The output of the setup will in the form of 2 files: `proving_key.json` and `ver
|
||||
|
||||
Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constrains of the circuit.
|
||||
|
||||
`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.
|
||||
|
||||
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 33. It means that you know two numbers `a` and `b` and when you multiply them, it results in 33.
|
||||
|
||||
> Of course you can always use one and the same number as `a` and `b`. We will deal with this problem later.
|
||||
> Of course you can always use one and the same number as `a` or `b`. We will deal with this problem later.
|
||||
|
||||
So you want to prove that you know 3 and 11.
|
||||
|
||||
@@ -128,9 +131,13 @@ Let's create a file named `input.json`
|
||||
Now let's calculate the witness:
|
||||
|
||||
```sh
|
||||
snarkjs calculatewitness
|
||||
snarkjs --wasm circuit.wasm --input input.json --witness witness.json
|
||||
```
|
||||
|
||||
`calcwit` is part of the circom_runtime package and it's just a wrapper in JS to call the wasm module.
|
||||
|
||||
You can use `circom_runtime` from your own project to calulate the witness.
|
||||
|
||||
You may want to take a look at `witness.json` file with all the signals.
|
||||
|
||||
### Create the proof
|
||||
@@ -214,20 +221,20 @@ 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.
|
||||
|
||||
|
||||
@@ -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
|
||||
23
cli.js
23
cli.js
@@ -23,6 +23,7 @@
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const compiler = require("./src/compiler");
|
||||
|
||||
@@ -30,12 +31,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")
|
||||
@@ -71,18 +74,25 @@ 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;
|
||||
options.sanityCheck = argv.sanitycheck;
|
||||
options.prime = argv.prime || bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
|
||||
if (argv.csource) {
|
||||
options.cSourceWriteStream = fs.createWriteStream(cSourceName);
|
||||
}
|
||||
if (argv.wasm) {
|
||||
options.wasmWriteStream = fs.createWriteStream(wasmName);
|
||||
}
|
||||
if (argv.wat) {
|
||||
options.watWriteStream = fs.createWriteStream(watName);
|
||||
}
|
||||
if (argv.r1cs) {
|
||||
options.r1csFileName = r1csName;
|
||||
}
|
||||
@@ -97,6 +107,7 @@ compiler(fullFileName, options).then( () => {
|
||||
let cSourceDone = false;
|
||||
let wasmDone = false;
|
||||
let symDone = false;
|
||||
let watDone = false;
|
||||
if (options.cSourceWriteStream) {
|
||||
options.cSourceWriteStream.on("finish", () => {
|
||||
cSourceDone = true;
|
||||
@@ -113,6 +124,14 @@ compiler(fullFileName, options).then( () => {
|
||||
} else {
|
||||
wasmDone = true;
|
||||
}
|
||||
if (options.watWriteStream) {
|
||||
options.watWriteStream.on("finish", () => {
|
||||
watDone = true;
|
||||
finishIfDone();
|
||||
});
|
||||
} else {
|
||||
watDone = true;
|
||||
}
|
||||
if (options.symWriteStream) {
|
||||
options.symWriteStream.on("finish", () => {
|
||||
symDone = true;
|
||||
@@ -122,7 +141,7 @@ compiler(fullFileName, options).then( () => {
|
||||
symDone = true;
|
||||
}
|
||||
function finishIfDone() {
|
||||
if ((cSourceDone)&&(symDone)&&(wasmDone)) {
|
||||
if ((cSourceDone)&&(symDone)&&(wasmDone)&&(watDone)) {
|
||||
setTimeout(() => {
|
||||
process.exit(0);
|
||||
}, 300);
|
||||
|
||||
@@ -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 00 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 00 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 00 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 00 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 00 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
|
||||
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;
|
||||
|
||||
1121
package-lock.json
generated
1121
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "circom",
|
||||
"version": "0.0.35",
|
||||
"version": "0.5.3",
|
||||
"description": "Language to generate logic circuits",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
@@ -30,19 +30,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.32",
|
||||
"ejs": "^3.0.1",
|
||||
"fflib": "0.0.2",
|
||||
"chai": "^4.2.0",
|
||||
"circom_runtime": "0.0.3",
|
||||
"ffiasm": "0.0.2",
|
||||
"ffjavascript": "0.0.3",
|
||||
"ffwasm": "0.0.6",
|
||||
"fnv-plus": "^1.3.1",
|
||||
"optimist": "^0.6.1",
|
||||
"rimraf-promise": "^2.0.0",
|
||||
"r1csfile": "0.0.3",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const streamFromMultiArray = require("./stream_from_multiarray");
|
||||
const streamFromMultiArray = require("../../src/streamfromarray_txt.js");
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils");
|
||||
const utils = require("../../src/utils");
|
||||
const assert = require("assert");
|
||||
|
||||
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();
|
||||
@@ -94,6 +94,9 @@ class CodeBuilderC {
|
||||
this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
|
||||
}
|
||||
|
||||
log(val) {
|
||||
this.ops.push({op: "LOG", val});
|
||||
}
|
||||
|
||||
concat(cb) {
|
||||
this.ops.push(...cb.ops);
|
||||
@@ -211,6 +214,8 @@ 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 == "LOG") {
|
||||
code.push(`ctx->log(${ref2src(o.val)});`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -342,6 +347,8 @@ class BuilderC {
|
||||
this.constants = [];
|
||||
this.functions = [];
|
||||
this.components = [];
|
||||
this.usedConstants = {};
|
||||
|
||||
}
|
||||
|
||||
setHeader(header) {
|
||||
@@ -362,7 +369,11 @@ class BuilderC {
|
||||
}
|
||||
|
||||
addConstant(c) {
|
||||
c = bigInt(c);
|
||||
const cS = c.toString();
|
||||
if (this.usedConstants[cS]) return this.usedConstants[cS];
|
||||
this.constants.push(c);
|
||||
this.usedConstants[cS] = this.constants.length - 1;
|
||||
return this.constants.length - 1;
|
||||
}
|
||||
|
||||
@@ -4,16 +4,15 @@ 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 utils = require("../../src/utils");
|
||||
const loadR1cs = require("r1csfile").load;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
const buildZqField = require("ffiasm").buildZqField;
|
||||
|
||||
module.exports = c_tester;
|
||||
|
||||
@@ -31,23 +30,40 @@ async function c_tester(circomFile, _options) {
|
||||
options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp"));
|
||||
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
|
||||
options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
|
||||
|
||||
options.p = options.p || bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
await compiler(circomFile, options);
|
||||
|
||||
const cdir = path.join(__dirname, "..", "c");
|
||||
await exec("cp" +
|
||||
` ${path.join(dir.path, baseName + ".cpp")}` +
|
||||
" /tmp/circuit.cpp"
|
||||
);
|
||||
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.h"), source.h, "utf8");
|
||||
await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8");
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
await exec("nasm -fmacho64 --prefix _ " +
|
||||
` ${path.join(dir.path, "fr.asm")}`
|
||||
);
|
||||
} else if (process.platform === "linux") {
|
||||
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++" +
|
||||
` ${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.c")}` +
|
||||
` ${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);
|
||||
@@ -68,17 +84,20 @@ class CTester {
|
||||
async calculateWitness(input) {
|
||||
await fs.promises.writeFile(
|
||||
path.join(this.dir.path, "in.json"),
|
||||
JSON.stringify(stringifyBigInts(input), null, 1)
|
||||
JSON.stringify(utils.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")
|
||||
);
|
||||
|
||||
const res = unstringifyBigInts(JSON.parse(resStr));
|
||||
const res = utils.unstringifyBigInts(JSON.parse(resStr));
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -92,10 +111,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]),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -105,7 +125,7 @@ class CTester {
|
||||
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.nVars = r1cs.nVars;
|
||||
self.constraints = r1cs.constraints;
|
||||
}
|
||||
|
||||
@@ -129,7 +149,7 @@ 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 ba = bigInt(actualOut[self.symbols[prefix].varIdx]).toString();
|
||||
const be = bigInt(eOut).toString();
|
||||
assert.strictEqual(ba, be, prefix);
|
||||
}
|
||||
@@ -142,8 +162,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";
|
||||
}
|
||||
@@ -161,9 +181,9 @@ 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 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");
|
||||
}
|
||||
847
ports/wasm/build_runtime.js
Normal file
847
ports/wasm/build_runtime.js
Normal file
@@ -0,0 +1,847 @@
|
||||
const errs = require("./errs");
|
||||
|
||||
|
||||
const buildWasmFf = require("ffwasm").buildWasmFf;
|
||||
|
||||
|
||||
module.exports = function buildRuntime(module, builder) {
|
||||
|
||||
const pSanityCheck = module.alloc(4);
|
||||
|
||||
function buildInit() {
|
||||
const f = module.addFunction("init");
|
||||
f.addParam("sanityCheck", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
// Set the stack to current memory
|
||||
f.addCode(
|
||||
c.i32_store(
|
||||
c.i32_const(4),
|
||||
c.i32_shl(
|
||||
c.i32_and(
|
||||
c.current_memory(),
|
||||
c.i32_const(0xFFFFFFF8)
|
||||
),
|
||||
c.i32_const(16)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Save Sanity check flag
|
||||
f.addCode(
|
||||
c.i32_store(
|
||||
c.i32_const(pSanityCheck),
|
||||
c.getLocal("sanityCheck")
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(
|
||||
// i=0
|
||||
c.setLocal("i", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
// if (i==NComponents) break
|
||||
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
|
||||
|
||||
// inputSignalsToTrigger[i] = components[i].nInputSignals
|
||||
c.i32_store(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pInputSignalsToTrigger),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
c.i32_load(
|
||||
c.i32_add(
|
||||
c.i32_load(c.i32_const(builder.ppComponents)),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(builder.sizeofComponent) // Sizeof component
|
||||
)
|
||||
),
|
||||
builder.offsetComponentNInputSignals
|
||||
)
|
||||
),
|
||||
|
||||
// i=i+1
|
||||
c.setLocal(
|
||||
"i",
|
||||
c.i32_add(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
// i=0
|
||||
c.setLocal("i", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
// if (i==NSignals) break
|
||||
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NSignals))),
|
||||
|
||||
// signalsAssigned[i] = false
|
||||
c.i32_store(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignalsAssigned),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
c.i32_const(0)
|
||||
),
|
||||
|
||||
// i=i+1
|
||||
c.setLocal(
|
||||
"i",
|
||||
c.i32_add(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
c.br(0)
|
||||
))
|
||||
));
|
||||
|
||||
f.addCode(
|
||||
c.call(
|
||||
"Fr_copy",
|
||||
c.i32_const(builder.pSignals),
|
||||
c.i32_add(
|
||||
c.i32_load(c.i32_const(builder.ppConstants)),
|
||||
c.i32_const(builder.addConstant(1) * builder.sizeFr)
|
||||
)
|
||||
)
|
||||
);
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.i32_store(
|
||||
c.i32_const(builder.pSignalsAssigned),
|
||||
c.i32_const(1)
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(
|
||||
// i=0
|
||||
c.setLocal("i", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
// if (i==NComponents) break
|
||||
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
|
||||
|
||||
// if (inputSignalsToTrigger[i] == 0) triggerComponent(i)
|
||||
c.if(
|
||||
c.i32_eqz(
|
||||
c.i32_load(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pInputSignalsToTrigger),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.call(
|
||||
"triggerComponent",
|
||||
c.getLocal("i")
|
||||
)
|
||||
),
|
||||
|
||||
// i=i+1
|
||||
c.setLocal(
|
||||
"i",
|
||||
c.i32_add(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function ifSanityCheck(c, ...args) {
|
||||
return c.if(
|
||||
c.i32_load(c.i32_const(pSanityCheck)),
|
||||
[].concat(...[...args])
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function buildTriggerComponent() {
|
||||
const f = module.addFunction("triggerComponent");
|
||||
f.addParam("component", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.call_indirect(
|
||||
c.getLocal("component"), // Idx in table
|
||||
c.getLocal("component") // Parameter
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function buildHash2ComponentEntry() {
|
||||
const f = module.addFunction("hash2ComponentEntry");
|
||||
f.addParam("component", "i32");
|
||||
f.addParam("hash", "i64");
|
||||
f.setReturnType("i32");
|
||||
|
||||
f.addLocal("pComponent", "i32");
|
||||
f.addLocal("pHashTable", "i32");
|
||||
f.addLocal("hIdx", "i32");
|
||||
f.addLocal("h", "i64");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"pComponent",
|
||||
c.i32_add(
|
||||
c.i32_load(c.i32_const(builder.ppComponents)), // pComponents
|
||||
c.i32_mul(
|
||||
c.getLocal("component"),
|
||||
c.i32_const(20) // sizeof(Component)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.setLocal(
|
||||
"pHashTable",
|
||||
c.i32_load(c.getLocal("pComponent"))
|
||||
),
|
||||
c.setLocal(
|
||||
"hIdx",
|
||||
c.i32_and(
|
||||
c.i32_wrap_i64(c.getLocal("hash")),
|
||||
c.i32_const(0xFF)
|
||||
)
|
||||
),
|
||||
c.block(c.loop(
|
||||
c.setLocal(
|
||||
"h",
|
||||
c.i64_load(
|
||||
c.i32_add(
|
||||
c.getLocal("pHashTable"),
|
||||
c.i32_mul(
|
||||
c.getLocal("hIdx"),
|
||||
c.i32_const(12)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.br_if(1, c.i64_eq(c.getLocal("h"), c.getLocal("hash"))),
|
||||
c.if(
|
||||
c.i64_eqz(c.getLocal("h")),
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.HASH_NOT_FOUND.code),
|
||||
c.i32_const(errs.HASH_NOT_FOUND.pointer),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0)
|
||||
)
|
||||
),
|
||||
c.setLocal(
|
||||
"hIdx",
|
||||
c.i32_and(
|
||||
c.i32_add(
|
||||
c.getLocal("hIdx"),
|
||||
c.i32_const(1)
|
||||
),
|
||||
c.i32_const(0xFF)
|
||||
)
|
||||
),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.i32_add( // pComponentEntry
|
||||
c.i32_load( // pComponentEntryTable
|
||||
c.i32_add(
|
||||
c.getLocal("pComponent"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
c.i32_mul(
|
||||
c.i32_load( // idx to the componentEntry
|
||||
c.i32_add(
|
||||
c.getLocal("pHashTable"),
|
||||
c.i32_mul(
|
||||
c.getLocal("hIdx"),
|
||||
c.i32_const(12)
|
||||
)
|
||||
),
|
||||
8
|
||||
),
|
||||
c.i32_const(12)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildGetFromComponentEntry(fnName, offset, type) {
|
||||
const f = module.addFunction(fnName);
|
||||
f.addParam("pR", "i32");
|
||||
f.addParam("component", "i32");
|
||||
f.addParam("hash", "i64");
|
||||
f.addLocal("pComponentEntry", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"pComponentEntry",
|
||||
c.call(
|
||||
"hash2ComponentEntry",
|
||||
c.getLocal("component"),
|
||||
c.getLocal("hash")
|
||||
)
|
||||
),
|
||||
c.if( // If type is not signal
|
||||
c.i32_ne(
|
||||
c.i32_load(
|
||||
c.getLocal("pComponentEntry"),
|
||||
8 // type offset
|
||||
),
|
||||
c.i32_const(type)
|
||||
),
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.INVALID_TYPE.code),
|
||||
c.i32_const(errs.INVALID_TYPE.pointer),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0)
|
||||
)
|
||||
),
|
||||
c.i32_store(
|
||||
c.getLocal("pR"),
|
||||
c.i32_load(
|
||||
c.getLocal("pComponentEntry"),
|
||||
offset
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const f2 = module.addFunction(fnName + "32");
|
||||
f2.addParam("pR", "i32");
|
||||
f2.addParam("component", "i32");
|
||||
f2.addParam("hashMSB", "i32");
|
||||
f2.addParam("hashLSB", "i32");
|
||||
|
||||
const c2 = f2.getCodeBuilder();
|
||||
|
||||
f2.addCode(
|
||||
c2.call(
|
||||
fnName,
|
||||
c2.getLocal("pR"),
|
||||
c2.getLocal("component"),
|
||||
c2.i64_or(
|
||||
c2.i64_shl(
|
||||
c2.i64_extend_i32_u(c2.getLocal("hashMSB")),
|
||||
c2.i64_const(32)
|
||||
),
|
||||
c2.i64_extend_i32_u(c2.getLocal("hashLSB"))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function buildGetSignal() {
|
||||
const f = module.addFunction("getSignal");
|
||||
f.addParam("cIdx", "i32");
|
||||
f.addParam("pR", "i32");
|
||||
f.addParam("component", "i32");
|
||||
f.addParam("signal", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.if(
|
||||
c.i32_eqz(
|
||||
c.i32_load(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignalsAssigned),
|
||||
c.i32_mul(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
)
|
||||
),
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
|
||||
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(
|
||||
c.call(
|
||||
"Fr_copy",
|
||||
c.getLocal("pR"),
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignals),
|
||||
c.i32_mul(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(builder.sizeFr)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.call("logGetSignal", c.getLocal("signal"), c.getLocal("pR") )
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
|
||||
function buildSetSignal() {
|
||||
const f = module.addFunction("setSignal");
|
||||
f.addParam("cIdx", "i32");
|
||||
f.addParam("component", "i32");
|
||||
f.addParam("signal", "i32");
|
||||
f.addParam("pVal", "i32");
|
||||
f.addLocal("signalsToTrigger", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.call("logSetSignal", c.getLocal("signal"), c.getLocal("pVal") ),
|
||||
c.if(
|
||||
c.i32_load(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignalsAssigned),
|
||||
c.i32_mul(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
),
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code),
|
||||
c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0)
|
||||
)
|
||||
),
|
||||
c.i32_store(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignalsAssigned),
|
||||
c.i32_mul(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
c.i32_const(1)
|
||||
),
|
||||
));
|
||||
|
||||
f.addCode(
|
||||
c.call(
|
||||
"Fr_copy",
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignals),
|
||||
c.i32_mul(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(builder.sizeFr)
|
||||
)
|
||||
),
|
||||
c.getLocal("pVal"),
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(
|
||||
c.if( // If ( mapIsInput[s >> 5] & 1 << (s & 0x1f) )
|
||||
c.i32_and(
|
||||
c.i32_load(
|
||||
c.i32_add(
|
||||
c.i32_load(c.i32_const(builder.ppMapIsInput)),
|
||||
c.i32_shl(
|
||||
c.i32_shr_u(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(5)
|
||||
),
|
||||
c.i32_const(2)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.i32_shl(
|
||||
c.i32_const(1),
|
||||
c.i32_and(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(0x1F)
|
||||
)
|
||||
)
|
||||
),
|
||||
[
|
||||
|
||||
...c.setLocal(
|
||||
"signalsToTrigger",
|
||||
c.i32_load(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pInputSignalsToTrigger),
|
||||
c.i32_mul(
|
||||
c.getLocal("component"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
...c.if( // if (signalsToTrigger > 0)
|
||||
c.i32_gt_u(
|
||||
c.getLocal("signalsToTrigger"),
|
||||
c.i32_const(0)
|
||||
),
|
||||
[
|
||||
...c.setLocal( // signalsToTrigger--
|
||||
"signalsToTrigger",
|
||||
c.i32_sub(
|
||||
c.getLocal("signalsToTrigger"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
...c.i32_store(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pInputSignalsToTrigger),
|
||||
c.i32_mul(
|
||||
c.getLocal("component"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
c.getLocal("signalsToTrigger"),
|
||||
),
|
||||
...c.if( // if (signalsToTrigger==0) triggerCompomnent(component)
|
||||
c.i32_eqz(c.getLocal("signalsToTrigger")),
|
||||
c.call(
|
||||
"triggerComponent",
|
||||
c.getLocal("component")
|
||||
)
|
||||
)
|
||||
],
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.MAPISINPUT_DONT_MATCH.code),
|
||||
c.i32_const(errs.MAPISINPUT_DONT_MATCH.pointer),
|
||||
c.getLocal("component"),
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildComponentFinished() {
|
||||
const f = module.addFunction("componentFinished");
|
||||
f.addParam("cIdx", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.call("logFinishComponent", c.getLocal("cIdx"))
|
||||
));
|
||||
|
||||
f.addCode(c.ret([]));
|
||||
}
|
||||
|
||||
function buildComponentStarted() {
|
||||
const f = module.addFunction("componentStarted");
|
||||
f.addParam("cIdx", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.call("logStartComponent", c.getLocal("cIdx"))
|
||||
));
|
||||
|
||||
f.addCode(c.ret([]));
|
||||
}
|
||||
|
||||
function buildCheckConstraint() {
|
||||
const pTmp = module.alloc(builder.sizeFr);
|
||||
const f = module.addFunction("checkConstraint");
|
||||
f.addParam("cIdx", "i32");
|
||||
f.addParam("pA", "i32");
|
||||
f.addParam("pB", "i32");
|
||||
f.addParam("pStr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(ifSanityCheck(c,
|
||||
c.call(
|
||||
"Fr_eq",
|
||||
c.i32_const(pTmp),
|
||||
c.getLocal("pA"),
|
||||
c.getLocal("pB")
|
||||
),
|
||||
c.if (
|
||||
c.i32_eqz(
|
||||
c.call(
|
||||
"Fr_isTrue",
|
||||
c.i32_const(pTmp),
|
||||
)
|
||||
),
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.code),
|
||||
c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.pointer),
|
||||
c.getLocal("cIdx"),
|
||||
c.getLocal("pA"),
|
||||
c.getLocal("pB"),
|
||||
c.getLocal("pStr"),
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
function buildGetNVars() {
|
||||
const f = module.addFunction("getNVars");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.i32_const(builder.header.NVars));
|
||||
}
|
||||
|
||||
function buildGetFrLen() {
|
||||
const f = module.addFunction("getFrLen");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.i32_const(builder.sizeFr));
|
||||
}
|
||||
|
||||
function buildGetPRawPrime() {
|
||||
const f = module.addFunction("getPRawPrime");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.i32_const(module.modules["Fr_F1m"].pq));
|
||||
}
|
||||
|
||||
function buildGetPWitness() {
|
||||
const f = module.addFunction("getPWitness");
|
||||
f.addParam("w", "i32");
|
||||
f.addLocal("signal", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"signal",
|
||||
c.i32_load( // wit2sig[w]
|
||||
c.i32_add(
|
||||
c.i32_load( c.i32_const(builder.ppWit2sig)),
|
||||
c.i32_mul(
|
||||
c.getLocal("w"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (builder.sanityCheck) {
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.i32_eqz(
|
||||
c.i32_load(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignalsAssigned),
|
||||
c.i32_mul(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
)
|
||||
),
|
||||
c.call(
|
||||
"error",
|
||||
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
|
||||
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0),
|
||||
c.i32_const(0)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
f.addCode(
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignals),
|
||||
|
||||
c.i32_mul(
|
||||
c.getLocal("signal"),
|
||||
c.i32_const(builder.sizeFr)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildGetWitnessBuffer() {
|
||||
const f = module.addFunction("getWitnessBuffer");
|
||||
f.setReturnType("i32");
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("pSrc", "i32");
|
||||
f.addLocal("pDst", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("i", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
// if (i==NComponents) break
|
||||
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NVars))),
|
||||
|
||||
c.setLocal(
|
||||
"pSrc",
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignals),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(builder.sizeFr)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.call(
|
||||
"Fr_toLongNormal",
|
||||
c.getLocal("pSrc")
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"pDst",
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignals),
|
||||
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.pSignals)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
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.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4);
|
||||
builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4);
|
||||
|
||||
buildHash2ComponentEntry();
|
||||
|
||||
buildTriggerComponent();
|
||||
buildInit();
|
||||
|
||||
buildGetFromComponentEntry("getSubComponentOffset", 0 /* offset */, builder.TYPE_COMPONENT);
|
||||
buildGetFromComponentEntry("getSubComponentSizes", 4 /* offset */, builder.TYPE_COMPONENT);
|
||||
|
||||
buildGetFromComponentEntry("getSignalOffset", 0 /* offset */, builder.TYPE_SIGNAL);
|
||||
buildGetFromComponentEntry("getSignalSizes", 4 /* offset */, builder.TYPE_SIGNAL);
|
||||
|
||||
buildGetSignal();
|
||||
buildSetSignal();
|
||||
|
||||
buildComponentStarted();
|
||||
buildComponentFinished();
|
||||
|
||||
buildCheckConstraint();
|
||||
|
||||
buildGetNVars();
|
||||
buildGetFrLen();
|
||||
buildGetPWitness();
|
||||
buildGetPRawPrime();
|
||||
buildGetWitnessBuffer();
|
||||
|
||||
// buildFrToInt();
|
||||
|
||||
module.exportFunction("init");
|
||||
module.exportFunction("getNVars");
|
||||
module.exportFunction("getFrLen");
|
||||
module.exportFunction("getSignalOffset32");
|
||||
module.exportFunction("setSignal");
|
||||
module.exportFunction("getPWitness");
|
||||
module.exportFunction("Fr_toInt");
|
||||
module.exportFunction("getPRawPrime");
|
||||
module.exportFunction("getWitnessBuffer");
|
||||
|
||||
};
|
||||
1023
ports/wasm/builder.js
Normal file
1023
ports/wasm/builder.js
Normal file
File diff suppressed because it is too large
Load Diff
10
ports/wasm/errs.js
Normal file
10
ports/wasm/errs.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
STACK_OUT_OF_MEM: {code: 1, str: "Stack out of memory"},
|
||||
STACK_TOO_SMALL: {code: 2, str: "Stack too small"},
|
||||
HASH_NOT_FOUND: {code: 3, str: "Hash not found"},
|
||||
INVALID_TYPE: {code: 4, str: "Invalid type"},
|
||||
ACCESSING_NOT_ASSIGNED_SIGNAL: {code: 5, str: "Accessing a not assigned signal"},
|
||||
SIGNAL_ASSIGNED_TWICE: {code: 6, str: "Signal assigned twice"},
|
||||
CONSTRAIN_DOES_NOT_MATCH: {code: 7, str: "Constraint doesn't match"},
|
||||
MAPISINPUT_DONT_MATCH: {code: 8, str: "MapIsInput don't match"},
|
||||
};
|
||||
164
ports/wasm/tester.js
Normal file
164
ports/wasm/tester.js
Normal file
@@ -0,0 +1,164 @@
|
||||
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 bigInt = require("big-integer");
|
||||
const utils = require("../../src/utils");
|
||||
const loadR1cs = require("r1csfile").load;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
|
||||
const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder;
|
||||
|
||||
module.exports = wasm_tester;
|
||||
|
||||
async function wasm_tester(circomFile, _options) {
|
||||
tmp.setGracefulCleanup();
|
||||
|
||||
const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
|
||||
|
||||
// console.log(dir.path);
|
||||
|
||||
const baseName = path.basename(circomFile, ".circom");
|
||||
const options = Object.assign({}, _options);
|
||||
|
||||
options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm"));
|
||||
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
|
||||
options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
|
||||
|
||||
const promisesArr = [];
|
||||
promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill)));
|
||||
|
||||
await compiler(circomFile, options);
|
||||
|
||||
await Promise.all(promisesArr);
|
||||
|
||||
const wasm = await fs.promises.readFile(path.join(dir.path, baseName + ".wasm"));
|
||||
|
||||
const wc = await WitnessCalculatorBuilder(wasm);
|
||||
|
||||
return new WasmTester(dir, baseName, wc);
|
||||
}
|
||||
|
||||
class WasmTester {
|
||||
|
||||
constructor(dir, baseName, witnessCalculator) {
|
||||
this.dir=dir;
|
||||
this.baseName = baseName;
|
||||
this.witnessCalculator = witnessCalculator;
|
||||
}
|
||||
|
||||
async release() {
|
||||
await this.dir.cleanup();
|
||||
}
|
||||
|
||||
async calculateWitness(input, sanityCheck) {
|
||||
return await this.witnessCalculator.calculateWitness(input, sanityCheck);
|
||||
}
|
||||
|
||||
async loadSymbols() {
|
||||
if (this.symbols) return;
|
||||
this.symbols = {};
|
||||
const symsStr = await fs.promises.readFile(
|
||||
path.join(this.dir.path, this.baseName + ".sym"),
|
||||
"utf8"
|
||||
);
|
||||
const lines = symsStr.split("\n");
|
||||
for (let i=0; i<lines.length; i++) {
|
||||
const arr = lines[i].split(",");
|
||||
if (arr.length!=4) continue;
|
||||
this.symbols[arr[3]] = {
|
||||
labelIdx: Number(arr[0]),
|
||||
varIdx: Number(arr[1]),
|
||||
componentIdx: Number(arr[2]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async loadConstraints() {
|
||||
const self = this;
|
||||
if (this.constraints) return;
|
||||
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
|
||||
self.field = 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 = bigInt(actualOut[self.symbols[prefix].varIdx]).toString();
|
||||
const be = bigInt(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.field;
|
||||
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;
|
||||
let v = F.zero;
|
||||
for (let w in lc) {
|
||||
v = F.add(
|
||||
v,
|
||||
F.mul( lc[w], witness[w] )
|
||||
);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
10
src/build.js
10
src/build.js
@@ -34,7 +34,6 @@ function build(ctx) {
|
||||
ctx.codes_sizes = [];
|
||||
ctx.definedSizes = {};
|
||||
ctx.addSizes = addSizes;
|
||||
ctx.constantsMap = {};
|
||||
ctx.addConstant = addConstant;
|
||||
ctx.addConstant(bigInt.zero);
|
||||
ctx.addConstant(bigInt.one);
|
||||
@@ -287,12 +286,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 +314,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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
}
|
||||
@@ -18,17 +18,18 @@
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const __P__ = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
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 ZqField = require("ffjavascript").ZqField;
|
||||
const utils = require("./utils");
|
||||
const buildR1cs = require("./r1csfile").buildR1cs;
|
||||
const BigArray = require("./bigarray");
|
||||
const buildSyms = require("./buildsyms");
|
||||
|
||||
module.exports = compile;
|
||||
|
||||
@@ -48,7 +49,7 @@ async function compile(srcFile, options) {
|
||||
|
||||
constructionPhase(ctx, srcFile);
|
||||
|
||||
console.log("NConstraints Before: "+ctx.constraints.length);
|
||||
if (ctx.verbose) console.log("NConstraints Before: "+ctx.constraints.length);
|
||||
|
||||
if (ctx.error) {
|
||||
throw(ctx.error);
|
||||
@@ -69,13 +70,13 @@ async function compile(srcFile, options) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("NConstraints After: "+ctx.constraints.length);
|
||||
if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length);
|
||||
|
||||
generateWitnessNames(ctx);
|
||||
|
||||
@@ -92,11 +93,17 @@ async function compile(srcFile, options) {
|
||||
// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
|
||||
}
|
||||
|
||||
if (options.wasmWriteStream) {
|
||||
if ((options.wasmWriteStream)||(options.watWriteStream)) {
|
||||
ctx.builder = new BuilderWasm();
|
||||
build(ctx);
|
||||
const rdStream = ctx.builder.build();
|
||||
rdStream.pipe(options.wasmWriteStream);
|
||||
if (options.wasmWriteStream) {
|
||||
const rdStream = ctx.builder.build("wasm");
|
||||
rdStream.pipe(options.wasmWriteStream);
|
||||
}
|
||||
if (options.watWriteStream) {
|
||||
const rdStream = ctx.builder.build("wat");
|
||||
rdStream.pipe(options.watWriteStream);
|
||||
}
|
||||
|
||||
// await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
|
||||
}
|
||||
@@ -109,7 +116,10 @@ async function compile(srcFile, options) {
|
||||
}
|
||||
|
||||
if (options.symWriteStream) {
|
||||
buildSyms(ctx, options.symWriteStream);
|
||||
const rdStream = buildSyms(ctx);
|
||||
rdStream.pipe(options.symWriteStream);
|
||||
|
||||
// await new Promise(fulfill => options.symWriteStream.on("finish", fulfill));
|
||||
}
|
||||
|
||||
// const def = buildCircuitDef(ctx, mainCode);
|
||||
@@ -504,6 +514,8 @@ function buildConstraints(ctx) {
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
function buildSyms(ctx, strm) {
|
||||
|
||||
let nSyms;
|
||||
@@ -543,5 +555,5 @@ function buildSyms(ctx, strm) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -558,7 +558,11 @@ 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(ev));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ast.name == "assert") {
|
||||
@@ -920,7 +924,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;
|
||||
|
||||
@@ -423,13 +423,21 @@ function genVariable(ctx, ast) {
|
||||
} 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 +456,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);
|
||||
@@ -499,7 +507,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 +534,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 +573,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 +616,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]];
|
||||
}
|
||||
@@ -743,7 +775,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 +790,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 +860,7 @@ 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;
|
||||
}
|
||||
const params = [];
|
||||
|
||||
210
src/r1csfile.js
210
src/r1csfile.js
@@ -4,166 +4,6 @@ const assert = require("assert");
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
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 readDouble64();
|
||||
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 readDouble64() {
|
||||
const b = Buffer.allocUnsafe(8);
|
||||
await fd.read(b, 0, 8, p);
|
||||
|
||||
p+=8;
|
||||
|
||||
return b.readDoubleLE(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) {
|
||||
|
||||
@@ -180,18 +20,13 @@ async function buildR1cs(ctx, fileName) {
|
||||
///////////
|
||||
await writeU32(1); // Header type
|
||||
const pHeaderSize = p;
|
||||
await writeDouble64(0); // Temporally set to 0 length
|
||||
await writeU64(0); // Temporally set to 0 length
|
||||
|
||||
|
||||
const n8 = (Math.floor( (ctx.field.p.bitLength() - 1) / 64) +1)*8;
|
||||
// Field Def
|
||||
const pFieldDefSize = p;
|
||||
await writeU32(0); // Temporally set to 0 length
|
||||
await writeU32(1);
|
||||
await writeU32(n8); // Temporally set to 0 length
|
||||
await writeBigInt(ctx.field.p);
|
||||
const fieldDefSize = p - pFieldDefSize - 4;
|
||||
|
||||
await writeU32(0); // Variable bigInt format
|
||||
await writeU32(4); // Id Size
|
||||
|
||||
const NWires =
|
||||
ctx.totals[ctx.stONE] +
|
||||
@@ -204,7 +39,7 @@ async function buildR1cs(ctx, fileName) {
|
||||
await writeU32(ctx.totals[ctx.stOUTPUT]);
|
||||
await writeU32(ctx.totals[ctx.stPUBINPUT]);
|
||||
await writeU32(ctx.totals[ctx.stPRVINPUT]);
|
||||
await writeU32(ctx.signals.length);
|
||||
await writeU64(ctx.signals.length);
|
||||
await writeU32(ctx.constraints.length);
|
||||
|
||||
const headerSize = p - pHeaderSize - 8;
|
||||
@@ -213,7 +48,7 @@ async function buildR1cs(ctx, fileName) {
|
||||
///////////
|
||||
await writeU32(2); // Constraints type
|
||||
const pConstraintsSize = p;
|
||||
await writeDouble64(0); // Temporally set to 0 length
|
||||
await writeU64(0); // Temporally set to 0 length
|
||||
|
||||
for (let i=0; i<ctx.constraints.length; i++) {
|
||||
if ((ctx.verbose)&&(i%10000 == 0)) {
|
||||
@@ -229,7 +64,7 @@ async function buildR1cs(ctx, fileName) {
|
||||
///////////
|
||||
await writeU32(3); // wires2label type
|
||||
const pMapSize = p;
|
||||
await writeDouble64(0); // Temporally set to 0 length
|
||||
await writeU64(0); // Temporally set to 0 length
|
||||
|
||||
|
||||
const arr = new Array(NWires);
|
||||
@@ -243,17 +78,16 @@ 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 writeU64(arr[i]);
|
||||
if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i);
|
||||
}
|
||||
|
||||
const mapSize = p - pMapSize - 8;
|
||||
|
||||
// Write sizes
|
||||
await writeDouble64(headerSize, pHeaderSize);
|
||||
await writeU32(fieldDefSize, pFieldDefSize);
|
||||
await writeDouble64(constraintsSize, pConstraintsSize);
|
||||
await writeDouble64(mapSize, pMapSize);
|
||||
await writeU32(headerSize, pHeaderSize);
|
||||
await writeU32(constraintsSize, pConstraintsSize);
|
||||
await writeU32(mapSize, pMapSize);
|
||||
|
||||
await fd.sync();
|
||||
await fd.close();
|
||||
@@ -267,9 +101,13 @@ async function buildR1cs(ctx, fileName) {
|
||||
if (typeof(pos) == "undefined") p += 4;
|
||||
}
|
||||
|
||||
async function writeDouble64(v, pos) {
|
||||
async function writeU64(v, pos) {
|
||||
const b = Buffer.allocUnsafe(8);
|
||||
b.writeDoubleLE(v);
|
||||
|
||||
const LSB = v & 0xFFFFFFFF;
|
||||
const MSB = Math.floor(v / 0x100000000);
|
||||
b.writeInt32LE(LSB, 0);
|
||||
b.writeInt32LE(MSB, 4);
|
||||
|
||||
await fd.write(b, 0, 8, pos);
|
||||
|
||||
@@ -295,12 +133,18 @@ async function buildR1cs(ctx, fileName) {
|
||||
}
|
||||
}
|
||||
|
||||
async function writeBigInt(n) {
|
||||
async function writeBigInt(n, pos) {
|
||||
const b = Buffer.allocUnsafe(n8);
|
||||
|
||||
const bytes = bigInt(n).toArray(256).value.reverse();
|
||||
const dwords = bigInt(n).toArray(0x100000000).value;
|
||||
|
||||
await fd.write(Buffer.from([bytes.length, ...bytes ]));
|
||||
for (let i=0; i<dwords.length; i++) {
|
||||
b.writeUInt32LE(dwords[dwords.length-1-i], i*4, 4 );
|
||||
}
|
||||
b.fill(0, dwords.length*4);
|
||||
|
||||
p += bytes.length+1;
|
||||
await fd.write(b, 0, fs, pos);
|
||||
|
||||
if (typeof(pos) == "undefined") p += n8;
|
||||
}
|
||||
}
|
||||
|
||||
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,7 @@
|
||||
|
||||
const Readable = require("stream").Readable;
|
||||
|
||||
module.exports = function streamFromMultiarray(ma) {
|
||||
module.exports = function streamFromArrayTxt(ma) {
|
||||
const rs = Readable();
|
||||
|
||||
let curIndex = getFirstIdx(ma);
|
||||
@@ -10,7 +10,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);
|
||||
@@ -2,9 +2,11 @@ const path = require("path");
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const c_tester = require("../index.js").c_tester;
|
||||
const wasm_tester = require("../index.js").wasm_tester;
|
||||
|
||||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
|
||||
const basicCases = require("./basiccases.json");
|
||||
|
||||
function normalize(o) {
|
||||
if ((typeof(o) == "bigint") || o.isZero !== undefined) {
|
||||
@@ -31,11 +33,14 @@ function normalize(o) {
|
||||
}
|
||||
|
||||
|
||||
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 +50,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);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
307
test/basiccases.json
Normal file
307
test/basiccases.json
Normal file
@@ -0,0 +1,307 @@
|
||||
[
|
||||
{
|
||||
"name": "inout",
|
||||
"circuit": "inout.circom",
|
||||
"tv": [
|
||||
[{
|
||||
"in1": 1,
|
||||
"in2": [2,3],
|
||||
"in3" : [[4,5], [6,7], [8,9]]
|
||||
}, {
|
||||
"out1": 1,
|
||||
"out2": [2,3],
|
||||
"out3": [[4,5], [6,7],[8,9]]
|
||||
}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "add",
|
||||
"circuit": "add.circom",
|
||||
"tv": [
|
||||
[{"in": [0,0]}, {"out": 0}],
|
||||
[{"in": [0 ,1]}, {"out": 1}],
|
||||
[{"in": [1 ,2]}, {"out": 3}],
|
||||
[{"in": [-1,1]}, {"out": 0}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "add constant",
|
||||
"circuit": "addconst1.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": 15}],
|
||||
[{"in": 10}, {"out": 25}],
|
||||
[{"in": -2}, {"out": 13}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "for unrolled",
|
||||
"circuit": "forunrolled.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": [ 0, 1, 2]}],
|
||||
[{"in": 10}, {"out": [10, 11, 12]}],
|
||||
[{"in": -2}, {"out": [-2, -1, 0]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "for rolled",
|
||||
"circuit": "forrolled.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": 0}],
|
||||
[{"in": 10}, {"out": 10}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "while unrolled",
|
||||
"circuit": "whileunrolled.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": [ 0, 1, 2]}],
|
||||
[{"in": 10}, {"out": [10, 11, 12]}],
|
||||
[{"in": -2}, {"out": [-2, -1, 0]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "while rolled",
|
||||
"circuit": "whilerolled.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": 0}],
|
||||
[{"in": 10}, {"out": 10}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "function1",
|
||||
"circuit": "function1.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": 3}],
|
||||
[{"in": 10}, {"out": 13}],
|
||||
[{"in": -2}, {"out": 1}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "function2",
|
||||
"circuit": "function2.circom",
|
||||
"tv": [
|
||||
[{"in": 0 }, {"out": 3}],
|
||||
[{"in": 10}, {"out": 13}],
|
||||
[{"in": -2}, {"out": 1}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "constants1",
|
||||
"circuit": "constants1.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": 42}],
|
||||
[{"in": 10}, {"out": 52}],
|
||||
[{"in": -2}, {"out": 40}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arrays",
|
||||
"circuit": "arrays.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": [ 1, 8, 51]}],
|
||||
[{"in": 10}, {"out": [11, 28, 111]}],
|
||||
[{"in": -2}, {"out": [-1, 4, 39]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "if unrolled",
|
||||
"circuit": "ifunrolled.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": [ 1, 3, 6]}],
|
||||
[{"in": 10}, {"out": [11, 13, 16]}],
|
||||
[{"in": -2}, {"out": [-1, 1, 4]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "if rolled",
|
||||
"circuit": "ifrolled.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": [1, 0, 0]}],
|
||||
[{"in": 1}, {"out": [0, 1, 0]}],
|
||||
[{"in": 2}, {"out": [0, 0, 1]}],
|
||||
[{"in": 3}, {"out": [0, 0, 0]}],
|
||||
[{"in": -2}, {"out": [0, 0, 0]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "inc",
|
||||
"circuit": "inc.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": [5, 2]}],
|
||||
[{"in": 1}, {"out": [6, 4]}],
|
||||
[{"in": 2}, {"out": [7, 6]}],
|
||||
[{"in": 3}, {"out": [8, 8]}],
|
||||
[{"in": -2}, {"out": [3,-2]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "dec",
|
||||
"circuit": "dec.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": [ 1, -2]}],
|
||||
[{"in": 1}, {"out": [ 2, 0]}],
|
||||
[{"in": 2}, {"out": [ 3, 2]}],
|
||||
[{"in": 3}, {"out": [ 4, 4]}],
|
||||
[{"in": -2}, {"out": [-1, -6]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ops",
|
||||
"circuit": "ops.circom",
|
||||
"tv": [
|
||||
[{"in": [-2, 2]}, {"add": 0, "sub": -4, "mul": -4}],
|
||||
[{"in": [-1, 1]}, {"add": 0, "sub": -2, "mul": -1}],
|
||||
[{"in": [ 0, 0]}, {"add": 0, "sub": 0, "mul": 0}],
|
||||
[{"in": [ 1,-1]}, {"add": 0, "sub": 2, "mul": -1}],
|
||||
[{"in": [ 2,-2]}, {"add": 0, "sub": 4, "mul": -4}],
|
||||
[{"in": [-2,-3]}, {"add": -5, "sub": 1, "mul": 6}],
|
||||
[{"in": [ 2, 3]}, {"add": 5, "sub": -1, "mul": 6}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ops2",
|
||||
"circuit": "ops2.circom",
|
||||
"tv": [
|
||||
[{"in": [-2, 2]}, {"div": -1, "idiv": "10944121435919637611123202872628637544274182200208017171849102093287904247807", "mod": 1}],
|
||||
[{"in": [-1, 1]}, {"div": -1, "idiv": -1, "mod": 0}],
|
||||
[{"in": [ 1,-1]}, {"div": -1, "idiv": 0, "mod": 1}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ops3",
|
||||
"circuit": "ops3.circom",
|
||||
"tv": [
|
||||
[{"in": [-2, 2]}, {"neg1": 2, "neg2": -2, "pow": 4}],
|
||||
[{"in": [ 0, 1]}, {"neg1": 0, "neg2": -1, "pow": 0}],
|
||||
[{"in": [ 1,-1]}, {"neg1": -1, "neg2": 1, "pow": 1}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Comparation ops",
|
||||
"circuit": "opscmp.circom",
|
||||
"tv": [
|
||||
[{"in": [ 8, 9]}, {"lt": 1, "leq": 1, "eq":0, "neq":1, "geq": 0, "gt":0}],
|
||||
[{"in": [-2,-2]}, {"lt": 0, "leq": 1, "eq":1, "neq":0, "geq": 1, "gt":0}],
|
||||
[{"in": [-1,-2]}, {"lt": 0, "leq": 0, "eq":0, "neq":1, "geq": 1, "gt":1}],
|
||||
[{"in": [ 1,-1]}, {"lt": 0, "leq": 0, "eq":0, "neq":1, "geq": 1, "gt":1}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Bit ops",
|
||||
"circuit": "opsbit.circom",
|
||||
"tv": [
|
||||
[
|
||||
{
|
||||
"in": [ 5, 3]
|
||||
},
|
||||
{
|
||||
"and": 1,
|
||||
"or": 7,
|
||||
"xor":6,
|
||||
"not1": "7059779437489773633646340506914701874769131765994106666166191815402473914361",
|
||||
"shl": 40,
|
||||
"shr":0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"in": [ 0, 0]
|
||||
},
|
||||
{
|
||||
"and": 0,
|
||||
"or": 0,
|
||||
"xor":0,
|
||||
"not1":"7059779437489773633646340506914701874769131765994106666166191815402473914366",
|
||||
"shl": 0,
|
||||
"shr":0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"in": [-1, 1]
|
||||
},
|
||||
{
|
||||
"and": 0,
|
||||
"or": 0,
|
||||
"xor": 0,
|
||||
"not1": "7059779437489773633646340506914701874769131765994106666166191815402473914367",
|
||||
"shl": "14828463434349501588600065238342573213779232634421927677532012371173334581248",
|
||||
"shr": "10944121435919637611123202872628637544274182200208017171849102093287904247808"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Logical ops",
|
||||
"circuit": "opslog.circom",
|
||||
"tv": [
|
||||
[{"in": [ 5, 0]}, {"and": 0, "or": 1, "not1":0}],
|
||||
[{"in": [ 0, 1]}, {"and": 0, "or": 1, "not1":1}],
|
||||
[{"in": [-1, 9]}, {"and": 1, "or": 1, "not1":0}],
|
||||
[{"in": [ 0, 0]}, {"and": 0, "or": 0, "not1":1}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Conditional Ternary operator",
|
||||
"circuit": "condternary.circom",
|
||||
"tv": [
|
||||
[{"in": 0}, {"out": 21}],
|
||||
[{"in": 1}, {"out": 1}],
|
||||
[{"in": 2}, {"out": 23}],
|
||||
[{"in":-1}, {"out": 20}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Compute block",
|
||||
"circuit": "compute.circom",
|
||||
"tv": [
|
||||
[{"x": 1}, {"y": 7}],
|
||||
[{"x": 2}, {"y": 7}],
|
||||
[{"x": 3}, {"y": 11}],
|
||||
[{"x":-1}, {"y": -5}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Component array",
|
||||
"circuit": "componentarray.circom",
|
||||
"tv": [
|
||||
[{"in": 1}, {"out": 1}],
|
||||
[{"in": 2}, {"out": 256}],
|
||||
[{"in": 3}, {"out": 6561}],
|
||||
[{"in":-1}, {"out": 1}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Component array 2d",
|
||||
"circuit": "componentarray2.circom",
|
||||
"tv": [
|
||||
[{"in": [1,2]}, {"out": [1, 256]}],
|
||||
[{"in": [0,3]}, {"out": [0, 6561]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Constant circuit",
|
||||
"circuit": "constantcircuit.circom",
|
||||
"tv": [
|
||||
[{}, {"out": [1,0,1,0, 0,0,0,1, 0,1,1,1, 0,1,0,1, 1,1,1,0, 0,1,1,0, 1,1,0,1, 1,1,0,1]}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Constant internal circuit",
|
||||
"circuit": "constantinternalcircuit.circom",
|
||||
"tv": [
|
||||
[{"in": 1}, {"out": 5}],
|
||||
[{"in": 0}, {"out": 4}],
|
||||
[{"in": -2}, {"out": 2}],
|
||||
[{"in": 10}, {"out": 14}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "include",
|
||||
"circuit": "include.circom",
|
||||
"tv": [
|
||||
[{"in": 3}, {"out": 6}],
|
||||
[{"in": 6}, {"out": 15}]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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