mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-07 03:06:42 +01:00
Compare commits
40 Commits
v0.0.32
...
feature/wi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
babe908d35 | ||
|
|
6c1a3e7687 | ||
|
|
111c91c70d | ||
|
|
a8d597d8c5 | ||
|
|
3a9766a008 | ||
|
|
20058a38d6 | ||
|
|
f6092e3944 | ||
|
|
e11e6768e4 | ||
|
|
63fd72cdc7 | ||
|
|
da969a5e16 | ||
|
|
b564201170 | ||
|
|
e62c1cdbc3 | ||
|
|
ec0e7f421b | ||
|
|
afa8201c2c | ||
|
|
1f94f7f3ec | ||
|
|
eaf4396cb3 | ||
|
|
2a45647274 | ||
|
|
305bc7456f | ||
|
|
ff1c12bcc3 | ||
|
|
fbcc753bc1 | ||
|
|
1e3d1235cb | ||
|
|
7b0b203c60 | ||
|
|
80846667ea | ||
|
|
7181c372d9 | ||
|
|
aecc28a79b | ||
|
|
0be08d67b0 | ||
|
|
6cdb006909 | ||
|
|
f4bbcfd90c | ||
|
|
93330f065b | ||
|
|
66291a0efe | ||
|
|
83c95b5188 | ||
|
|
13c4c81a0f | ||
|
|
51ff27b9c6 | ||
|
|
6985892f86 | ||
|
|
bacb7afde7 | ||
|
|
d04eff6c0d | ||
|
|
230894921e | ||
|
|
64029e1842 | ||
|
|
700412f23d | ||
|
|
832077fbe9 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -61,3 +61,9 @@ typings/
|
|||||||
.next
|
.next
|
||||||
|
|
||||||
tmp
|
tmp
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Workspace files are user-specific
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
|||||||
24
Project.sublime-project
Normal file
24
Project.sublime-project
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": ".",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"SublimeAnarchyDebug": {
|
||||||
|
"debug": {
|
||||||
|
"executable": "${project_path}/test/circuits/add",
|
||||||
|
"params": [
|
||||||
|
"addin.json",
|
||||||
|
"out.bin",
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
],
|
||||||
|
"environment": [
|
||||||
|
],
|
||||||
|
"working_dir": "${project_path}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ To waranty binary outputs:
|
|||||||
.
|
.
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
out[n+e-1] * (out[n+e-1] - 1) == 0
|
out[n+e-1] * (out[n+e-1] - 1) === 0
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
245
c/buildasm/add.asm.ejs
Normal file
245
c/buildasm/add.asm.ejs
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
<% 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
217
c/buildasm/binops.asm.ejs
Normal file
217
c/buildasm/binops.asm.ejs
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
<% 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
|
||||||
|
|
||||||
|
|
||||||
72
c/buildasm/buildzqfield.js
Normal file
72
c/buildasm/buildzqfield.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
75
c/buildasm/buildzqfieldtester.js
Normal file
75
c/buildasm/buildzqfieldtester.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
108
c/buildasm/cmpops.asm.ejs
Normal file
108
c/buildasm/cmpops.asm.ejs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
|
||||||
|
<% 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") %>
|
||||||
|
|
||||||
133
c/buildasm/copy.asm.ejs
Normal file
133
c/buildasm/copy.asm.ejs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
; 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
Normal file
5841
c/buildasm/fr.asm
Normal file
File diff suppressed because it is too large
Load Diff
53
c/buildasm/fr.asm.ejs
Normal file
53
c/buildasm/fr.asm.ejs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
|
||||||
|
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
Normal file
185
c/buildasm/fr.c
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
184
c/buildasm/fr.c.ejs
Normal file
184
c/buildasm/fr.c.ejs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
67
c/buildasm/fr.h
Normal file
67
c/buildasm/fr.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
67
c/buildasm/fr.h.ejs
Normal file
67
c/buildasm/fr.h.ejs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#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
Normal file
BIN
c/buildasm/fr.o
Normal file
Binary file not shown.
97
c/buildasm/logicalops.asm.ejs
Normal file
97
c/buildasm/logicalops.asm.ejs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<% 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
64
c/buildasm/main.c
Normal file
64
c/buildasm/main.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#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]);
|
||||||
|
}
|
||||||
342
c/buildasm/montgomery.asm.ejs
Normal file
342
c/buildasm/montgomery.asm.ejs
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<%
|
||||||
|
//////////////////////
|
||||||
|
// 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
|
||||||
|
|
||||||
275
c/buildasm/mul.asm.ejs
Normal file
275
c/buildasm/mul.asm.ejs
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
<% 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
|
||||||
|
|
||||||
|
|
||||||
78
c/buildasm/neg.asm.ejs
Normal file
78
c/buildasm/neg.asm.ejs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<% 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
|
||||||
33
c/buildasm/old/buildfieldasm.js
Normal file
33
c/buildasm/old/buildfieldasm.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
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"],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
209
c/buildasm/old/buildzqfield.js
Normal file
209
c/buildasm/old/buildzqfield.js
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
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();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
68
c/buildasm/old/buildzqfieldtester.js
Normal file
68
c/buildasm/old/buildzqfieldtester.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
302
c/buildasm/old/fr.asm.ejs.old
Normal file
302
c/buildasm/old/fr.asm.ejs.old
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
|
||||||
|
|
||||||
|
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)) %>
|
||||||
|
|
||||||
|
|
||||||
251
c/buildasm/old/mul.asm.ejs
Normal file
251
c/buildasm/old/mul.asm.ejs
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
; 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
|
||||||
317
c/buildasm/sub.asm.ejs
Normal file
317
c/buildasm/sub.asm.ejs
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
<% 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
|
||||||
|
|
||||||
|
|
||||||
218
c/buildasm/tester.cpp
Normal file
218
c/buildasm/tester.cpp
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
73
c/buildasm/utils.asm.ejs
Normal file
73
c/buildasm/utils.asm.ejs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<% 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
Normal file
229
c/calcwit.cpp
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
#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
Normal file
73
c/calcwit.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#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
Normal file
58
c/circom.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#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
|
||||||
214
c/main.cpp
Normal file
214
c/main.cpp
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
#include "calcwit.h"
|
||||||
|
#include "circom.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define handle_error(msg) \
|
||||||
|
do { perror(msg); exit(EXIT_FAILURE); } while (0)
|
||||||
|
|
||||||
|
void loadBin(Circom_CalcWit *ctx, std::string filename) {
|
||||||
|
int fd;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
// map input
|
||||||
|
fd = open(filename.c_str(), O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
handle_error("open");
|
||||||
|
|
||||||
|
if (fstat(fd, &sb) == -1) /* To obtain file size */
|
||||||
|
handle_error("fstat");
|
||||||
|
|
||||||
|
|
||||||
|
u8 *in;
|
||||||
|
|
||||||
|
in = (u8 *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
if (in == MAP_FAILED)
|
||||||
|
handle_error("mmap");
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
FrElement v;
|
||||||
|
u8 *p = in;
|
||||||
|
for (int i=0; i<_circuit.NInputs; i++) {
|
||||||
|
v.type = Fr_LONG;
|
||||||
|
for (int j=0; j<Fr_N64; j++) {
|
||||||
|
v.longVal[j] = *(u64 *)p;
|
||||||
|
}
|
||||||
|
p += 8;
|
||||||
|
ctx->setSignal(0, 0, _circuit.wit2sig[1 + _circuit.NOutputs + i], &v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*ItFunc)(Circom_CalcWit *ctx, int idx, json val);
|
||||||
|
|
||||||
|
void iterateArr(Circom_CalcWit *ctx, int o, Circom_Sizes sizes, json jarr, ItFunc f) {
|
||||||
|
if (!jarr.is_array()) {
|
||||||
|
assert((sizes[0] == 1)&&(sizes[1] == 0));
|
||||||
|
f(ctx, o, jarr);
|
||||||
|
} else {
|
||||||
|
int n = sizes[0] / sizes[1];
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
iterateArr(ctx, o + i*sizes[1], sizes+1, jarr[i], f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void itFunc(Circom_CalcWit *ctx, int o, json val) {
|
||||||
|
|
||||||
|
FrElement v;
|
||||||
|
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
if (val.is_string()) {
|
||||||
|
s = val.get<std::string>();
|
||||||
|
} else if (val.is_number()) {
|
||||||
|
|
||||||
|
double vd = val.get<double>();
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::fixed << std::setprecision(0) << vd;
|
||||||
|
s = stream.str();
|
||||||
|
} else {
|
||||||
|
handle_error("Invalid JSON type");
|
||||||
|
}
|
||||||
|
|
||||||
|
Fr_str2element (&v, s.c_str());
|
||||||
|
|
||||||
|
ctx->setSignal(0, 0, o, &v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loadJson(Circom_CalcWit *ctx, std::string filename) {
|
||||||
|
std::ifstream inStream(filename);
|
||||||
|
json j;
|
||||||
|
inStream >> j;
|
||||||
|
|
||||||
|
for (json::iterator it = j.begin(); it != j.end(); ++it) {
|
||||||
|
// std::cout << it.key() << " => " << it.value() << '\n';
|
||||||
|
u64 h = fnv1a(it.key());
|
||||||
|
int o;
|
||||||
|
try {
|
||||||
|
o = ctx->getSignalOffset(0, h);
|
||||||
|
} catch (std::runtime_error e) {
|
||||||
|
std::ostringstream errStrStream;
|
||||||
|
errStrStream << "Error loadin variable: " << it.key() << "\n" << e.what();
|
||||||
|
throw std::runtime_error(errStrStream.str() );
|
||||||
|
}
|
||||||
|
Circom_Sizes sizes = ctx->getSignalSizes(0, h);
|
||||||
|
iterateArr(ctx, o, sizes, it.value(), itFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeOutBin(Circom_CalcWit *ctx, std::string filename) {
|
||||||
|
FILE *write_ptr;
|
||||||
|
|
||||||
|
write_ptr = fopen(filename.c_str(),"wb");
|
||||||
|
|
||||||
|
// Add header
|
||||||
|
// 4 bytes --> total number of constraints
|
||||||
|
uint32_t witnessLength = _circuit.NVars;
|
||||||
|
// 4 bytes --> witness element size (measured in number of 32bit words)
|
||||||
|
uint32_t witnessSize = 8; // witness size = 8*32 = 256 bits
|
||||||
|
// 8bytes --> empty
|
||||||
|
uint64_t otherField = 0;
|
||||||
|
|
||||||
|
fwrite(&witnessLength, 4, 1, write_ptr);
|
||||||
|
fwrite(&witnessSize, 4, 1, write_ptr);
|
||||||
|
fwrite(&otherField, 8, 1, write_ptr);
|
||||||
|
|
||||||
|
FrElement v;
|
||||||
|
|
||||||
|
u8 buffOut[256];
|
||||||
|
for (int i=0;i<_circuit.NVars;i++) {
|
||||||
|
size_t size=256;
|
||||||
|
ctx->getWitness(i, &v);
|
||||||
|
Fr_toLongNormal(&v);
|
||||||
|
fwrite(v.longVal, Fr_N64*8, 1, write_ptr);
|
||||||
|
}
|
||||||
|
fclose(write_ptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeOutJson(Circom_CalcWit *ctx, std::string filename) {
|
||||||
|
|
||||||
|
std::ofstream outFile;
|
||||||
|
outFile.open (filename);
|
||||||
|
|
||||||
|
outFile << "[\n";
|
||||||
|
|
||||||
|
FrElement v;
|
||||||
|
|
||||||
|
for (int i=0;i<_circuit.NVars;i++) {
|
||||||
|
ctx->getWitness(i, &v);
|
||||||
|
char *pcV = Fr_element2str(&v);
|
||||||
|
std::string sV = std::string(pcV);
|
||||||
|
outFile << (i ? "," : " ") << "\"" << sV << "\"\n";
|
||||||
|
free(pcV);
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile << "]\n";
|
||||||
|
outFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasEnding (std::string const &fullString, std::string const &ending) {
|
||||||
|
if (fullString.length() >= ending.length()) {
|
||||||
|
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
Fr_init();
|
||||||
|
if (argc!=3) {
|
||||||
|
std::string cl = argv[0];
|
||||||
|
std::string base_filename = cl.substr(cl.find_last_of("/\\") + 1);
|
||||||
|
std::cout << "Usage: " << base_filename << " <input.<bin|json>> <output.<bin|json>>\n";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// open output
|
||||||
|
Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit);
|
||||||
|
|
||||||
|
std::string infilename = argv[1];
|
||||||
|
|
||||||
|
if (hasEnding(infilename, std::string(".bin"))) {
|
||||||
|
loadBin(ctx, infilename);
|
||||||
|
} else if (hasEnding(infilename, std::string(".json"))) {
|
||||||
|
loadJson(ctx, infilename);
|
||||||
|
} else {
|
||||||
|
handle_error("Invalid input extension (.bin / .json)");
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->join();
|
||||||
|
|
||||||
|
printf("Finished!\n");
|
||||||
|
|
||||||
|
std::string outfilename = argv[2];
|
||||||
|
|
||||||
|
if (hasEnding(outfilename, std::string(".bin"))) {
|
||||||
|
writeOutBin(ctx, outfilename);
|
||||||
|
} else if (hasEnding(outfilename, std::string(".json"))) {
|
||||||
|
writeOutJson(ctx, outfilename);
|
||||||
|
} else {
|
||||||
|
handle_error("Invalid output extension (.bin / .json)");
|
||||||
|
}
|
||||||
|
|
||||||
|
delete ctx;
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
c/mainjson
Normal file
BIN
c/mainjson
Normal file
Binary file not shown.
47
c/mainjson.cpp
Normal file
47
c/mainjson.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#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
Normal file
25
c/utils.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#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
Normal file
10
c/utils.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#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
Normal file
199
c/zqfield.cpp
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
#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
Normal file
49
c/zqfield.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#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
|
||||||
82
cli.js
82
cli.js
@@ -30,12 +30,25 @@ const version = require("./package").version;
|
|||||||
|
|
||||||
const argv = require("yargs")
|
const argv = require("yargs")
|
||||||
.version(version)
|
.version(version)
|
||||||
.usage("circom [input source circuit file] -o [output definition circuit file]")
|
.usage("circom [input source circuit file] -o [output definition circuit file] -c [output c file]")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
|
.alias("c", "csource")
|
||||||
|
.alias("w", "wasm")
|
||||||
|
.alias("s", "sym")
|
||||||
|
.alias("r", "r1cs")
|
||||||
|
.alias("n", "newThreadTemplates")
|
||||||
.help("h")
|
.help("h")
|
||||||
.alias("h", "help")
|
.alias("h", "help")
|
||||||
.alias("v", "verbose")
|
.option("verbose", {
|
||||||
.alias("f", "fast")
|
alias: "v",
|
||||||
|
type: "boolean",
|
||||||
|
description: "Run with verbose logging"
|
||||||
|
})
|
||||||
|
.option("fast", {
|
||||||
|
alias: "f",
|
||||||
|
type: "boolean",
|
||||||
|
description: "Do not optimize constraints"
|
||||||
|
})
|
||||||
.epilogue(`Copyright (C) 2018 0kims association
|
.epilogue(`Copyright (C) 2018 0kims association
|
||||||
This program comes with ABSOLUTELY NO WARRANTY;
|
This program comes with ABSOLUTELY NO WARRANTY;
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
@@ -55,11 +68,66 @@ if (argv._.length == 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fullFileName = path.resolve(process.cwd(), inputFile);
|
const fullFileName = path.resolve(process.cwd(), inputFile);
|
||||||
const outName = argv.output ? argv.output : "circuit.json";
|
const fileName = path.basename(fullFileName, ".circom");
|
||||||
|
const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp";
|
||||||
|
const wasmName = typeof(argv.wasm) === "string" ? argv.wasm : fileName + ".wasm";
|
||||||
|
const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs";
|
||||||
|
const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym";
|
||||||
|
|
||||||
compiler(fullFileName, {reduceConstraints: !argv.fast}).then( (cir) => {
|
const options = {};
|
||||||
fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8");
|
options.reduceConstraints = !argv.fast;
|
||||||
process.exit(0);
|
options.verbose = argv.verbose || false;
|
||||||
|
if (argv.csource) {
|
||||||
|
options.cSourceWriteStream = fs.createWriteStream(cSourceName);
|
||||||
|
}
|
||||||
|
if (argv.wasm) {
|
||||||
|
options.wasmWriteStream = fs.createWriteStream(wasmName);
|
||||||
|
}
|
||||||
|
if (argv.r1cs) {
|
||||||
|
options.r1csFileName = r1csName;
|
||||||
|
}
|
||||||
|
if (argv.sym) {
|
||||||
|
options.symWriteStream = fs.createWriteStream(symName);
|
||||||
|
}
|
||||||
|
if (argv.newThreadTemplates) {
|
||||||
|
options.newThreadTemplates = new RegExp(argv.newThreadTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler(fullFileName, options).then( () => {
|
||||||
|
let cSourceDone = false;
|
||||||
|
let wasmDone = false;
|
||||||
|
let symDone = false;
|
||||||
|
if (options.cSourceWriteStream) {
|
||||||
|
options.cSourceWriteStream.on("finish", () => {
|
||||||
|
cSourceDone = true;
|
||||||
|
finishIfDone();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cSourceDone = true;
|
||||||
|
}
|
||||||
|
if (options.wasmWriteStream) {
|
||||||
|
options.wasmWriteStream.on("finish", () => {
|
||||||
|
wasmDone = true;
|
||||||
|
finishIfDone();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
wasmDone = true;
|
||||||
|
}
|
||||||
|
if (options.symWriteStream) {
|
||||||
|
options.symWriteStream.on("finish", () => {
|
||||||
|
symDone = true;
|
||||||
|
finishIfDone();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
symDone = true;
|
||||||
|
}
|
||||||
|
function finishIfDone() {
|
||||||
|
if ((cSourceDone)&&(symDone)&&(wasmDone)) {
|
||||||
|
setTimeout(() => {
|
||||||
|
process.exit(0);
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
// console.log(err);
|
// console.log(err);
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
|
|||||||
BIN
doc/lc_example.monopic
Normal file
BIN
doc/lc_example.monopic
Normal file
Binary file not shown.
683
doc/r1cs_bin_format.md
Normal file
683
doc/r1cs_bin_format.md
Normal file
@@ -0,0 +1,683 @@
|
|||||||
|
# Binary format for R1CS
|
||||||
|
|
||||||
|
---
|
||||||
|
eip:
|
||||||
|
title: r1cs binary format
|
||||||
|
author: Jordi Baylina <jordi@baylina.cat>
|
||||||
|
discussions-to:
|
||||||
|
status: draft
|
||||||
|
type: Standards Track
|
||||||
|
category: ERC
|
||||||
|
created: 2019-09-24
|
||||||
|
requires:
|
||||||
|
---
|
||||||
|
|
||||||
|
## Simple Summary
|
||||||
|
|
||||||
|
This standard defines a standard format for a binery representation of a r1cs constraint system.
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
The zero knowledge primitives, requires the definition of a statment that wants to be proved. This statment can be expressed as a deterministric program or an algebraic circuit. Lots of primitives like zkSnarks, bulletProofs or aurora, requires to convert this statment to a rank-one constraint system.
|
||||||
|
|
||||||
|
This standard specifies a format for a r1cs and allows the to connect a set of tools that compiles a program or a circuit to r1cs that can be used for the zksnarks or bulletproofs primitives.
|
||||||
|
|
||||||
|
## Specification
|
||||||
|
|
||||||
|
### General considerations
|
||||||
|
|
||||||
|
The standard extension is `.r1cs`
|
||||||
|
|
||||||
|
|
||||||
|
A deterministic program (or circuit) is a program that generates a set of deterministic values given an input. All those values are labeled from l_{0} to l_{n_labels}
|
||||||
|
|
||||||
|
This file defines a map beween l_{i} -> w_{j} and defines a series a R1CS of the form
|
||||||
|
|
||||||
|
$$
|
||||||
|
\left\{ \begin{array}{rclclcl}
|
||||||
|
(a_{0,0}w_0 + a_{0,1}w_1 + ... + a_{0,n}w_{n}) &\cdot& (b_{0,0} w_0 + b_{0,1} w_1 + ... + b_{0,n} w_{n}) &-& (c_{0,0} w_0 + c_{0,1} w_1 + ... + c_{0,n}w_{n}) &=& 0 \\
|
||||||
|
(a_{1,0}w_0 + a_{1,1}w_1 + ... + a_{1,n}w_{n}) &\cdot& (b_{1,0} w_0 + b_{1,1} w_1 + ... + b_{1,n} w_{n}) &-& (c_{1,0} w_0 + c_{1,1}w_1 + ... + c_{1,n}w_{n}) &=& 0 \\
|
||||||
|
...\\
|
||||||
|
(a_{m-1,0}w_0 + a_{m-1,1}w_1 + ... + a_{m-1,n}w_{n}) &\cdot& (b_{m-1,0} w_0 + b_{m-1,1} w_1 + ... + b_{m-1,n} w_{n}) &-& (c_{m-1,0} w_0 + c_{m-1,1}w_1 + ... + c_{m-1,n}w_{n}) &=& 0
|
||||||
|
\end{array} \right.
|
||||||
|
$$
|
||||||
|
|
||||||
|
Wire 0 must be always mapped to label 0 and it's an input forced to value "1" implicitly
|
||||||
|
|
||||||
|
|
||||||
|
### Format of the file
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ 72 31 63 73 ┃ Magic "r1cs"
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ 01 00 00 00 ┃ Version 1
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ 03 00 00 00 ┃ Number of Sections
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ sectionType ┃ 8 │ SectionSize ┃
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ Section Content ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ sectionType ┃ 8 │ SectionSize ┃
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ Section Content ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
...
|
||||||
|
...
|
||||||
|
...
|
||||||
|
````
|
||||||
|
|
||||||
|
#### Magic Number
|
||||||
|
|
||||||
|
Size: 4 bytes
|
||||||
|
The file start with a constant 4 bytes (magic number) "r1cs"
|
||||||
|
|
||||||
|
```
|
||||||
|
0x72 0x31 0x63 0x73
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Version
|
||||||
|
|
||||||
|
Size: 4 bytes
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
For this standard it's fixed to
|
||||||
|
|
||||||
|
```
|
||||||
|
0x01 0x00 0x00 0x00
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Number of Sections
|
||||||
|
|
||||||
|
Size: 4 bytes
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
Number of sections contained in the file
|
||||||
|
|
||||||
|
#### SectionType
|
||||||
|
|
||||||
|
Size: 4 bytes
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
Type of the section.
|
||||||
|
|
||||||
|
Currently there are 3 types of sections defined:
|
||||||
|
|
||||||
|
* 0x00000001 : Header Section
|
||||||
|
* 0x00000002 : Constraint Section
|
||||||
|
* 0x00000003 : Wire2LabelId Map Section
|
||||||
|
|
||||||
|
If the file contain other types, the format is valid, but they MUST be ignored.
|
||||||
|
|
||||||
|
Any order of the section must be accepted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
0x01 0x00 0x00 0x00
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SectionSize
|
||||||
|
|
||||||
|
Size: `ws` bytes
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
Size in bytes of the section
|
||||||
|
|
||||||
|
### Header Section
|
||||||
|
|
||||||
|
Section Type: 0x01
|
||||||
|
````
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ FieldDefSize ┃ FieldDef ┃ field Id
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ 00 00 00 00 ┃ bigInt Format
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 4 │ is ┃ Id size ( Normally 4 (32bits))
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ is │ 01 00 00 00 ┃ nWires
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ is │ 01 00 00 00 ┃ nPubOut
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ is │ 01 00 00 00 ┃ nPubIn
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ is │ 01 00 00 00 ┃ nPrvIn
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ is │ 01 00 00 00 ┃ nLabels
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ is │ 01 00 00 00 ┃ mConstraints
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
#### fieldDefSize
|
||||||
|
|
||||||
|
Size: 4 bytes
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
Size of the field Definition
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
0x00 0x0 0x00 0x00
|
||||||
|
```
|
||||||
|
|
||||||
|
#### fieldDef
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
0x00 0x00 0x00 0x00
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
Total Number of wires including ONE signal (Index 0).
|
||||||
|
|
||||||
|
#### Number of public outputs
|
||||||
|
|
||||||
|
Size: `is` 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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
Total Number of constraints
|
||||||
|
|
||||||
|
### Constraints section
|
||||||
|
|
||||||
|
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} ┃ ╱
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||||
|
╱
|
||||||
|
|
||||||
|
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||||
|
┃ 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} ┃ ╱
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||||
|
╱
|
||||||
|
|
||||||
|
...
|
||||||
|
...
|
||||||
|
...
|
||||||
|
|
||||||
|
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||||
|
┃ 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} ┃ ╱
|
||||||
|
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||||
|
╱ ╱
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Constraints
|
||||||
|
|
||||||
|
Each constraint contains 3 linear combinations A, B, C.
|
||||||
|
|
||||||
|
The constraint is such that:
|
||||||
|
```
|
||||||
|
A*B-C = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Linear combination
|
||||||
|
|
||||||
|
Each linear combination is of the form:
|
||||||
|
|
||||||
|
$$
|
||||||
|
a_{j,0}w_0 + a_{j,1}w_1 + ... + a_{j,n}w_{n}
|
||||||
|
$$
|
||||||
|
|
||||||
|
#### Number of nonZero Factors
|
||||||
|
|
||||||
|
Size: `ìs` bytes
|
||||||
|
Format: Little-Endian
|
||||||
|
|
||||||
|
Total number of non Zero factors in the linear compination.
|
||||||
|
|
||||||
|
The factors MUST be sorted in ascending order.
|
||||||
|
|
||||||
|
#### Factor
|
||||||
|
|
||||||
|
For each factor we have the index of the factor and the value of the factor.
|
||||||
|
|
||||||
|
#### WireId of the factor
|
||||||
|
|
||||||
|
Size: `is` 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.
|
||||||
|
|
||||||
|
For example, to represent the linear combination:
|
||||||
|
|
||||||
|
$$
|
||||||
|
5w_4 +8w_5 + 260w_{886}
|
||||||
|
$$
|
||||||
|
|
||||||
|
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 ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
|
### WireId2LabelId Map Section
|
||||||
|
|
||||||
|
Section Type: 0x03
|
||||||
|
|
||||||
|
````
|
||||||
|
┏━━┳━━━━━━━━━━━━━━━━━━━┳━━┳━━━━━━━━━━━━━━━━━━━┓ ┏━━┳━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃is│ labelId of Wire_0 ┃is│ labelId of Wire_1 ┃ ... ┃is│ labelId of Wire_n ┃
|
||||||
|
┗━━┻━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━━━━━━━━━━━━━━━┛ ┗━━┻━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
````
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
|
||||||
|
Variable size for field elements allows to shrink the size of the file and allows to work with any field.
|
||||||
|
|
||||||
|
Version allows to update the format.
|
||||||
|
|
||||||
|
Have a very good comprasion ratio for sparse r1cs as it's the normal case.
|
||||||
|
|
||||||
|
The motivation of having a map between l and w is that this allows optimizers to calculate equivalent r1cs systems but keeping the original values geneated by the circuit.
|
||||||
|
|
||||||
|
|
||||||
|
## Backward Compatibility
|
||||||
|
|
||||||
|
N.A.
|
||||||
|
|
||||||
|
## Test Cases
|
||||||
|
### Example
|
||||||
|
|
||||||
|
Given this r1cs in a 256 bit Field:
|
||||||
|
|
||||||
|
|
||||||
|
$$
|
||||||
|
\left\{ \begin{array}{rclclcl}
|
||||||
|
(3w_5 + 8w_6) &\cdot& (2w_0 + 20w_2 + 12w_3) &-& (5w_0 + 7w_2) &=& 0 \\
|
||||||
|
(4w_1 + 8w_4 + 3w_5) &\cdot& (6w_6 + 44w_3) && &=& 0 \\
|
||||||
|
(4w_6) &\cdot& (6w_0 + 5w_3 + 11s_2) &-& (600w_6) &=& 0
|
||||||
|
\end{array} \right.
|
||||||
|
$$
|
||||||
|
|
||||||
|
And a Wire to label map.
|
||||||
|
|
||||||
|
$$
|
||||||
|
w_0 := l_0 \\
|
||||||
|
w_1 := l_3 \\
|
||||||
|
w_2 := l_{10} \\
|
||||||
|
w_3 := l_{11} \\
|
||||||
|
w_4 := l_{12} \\
|
||||||
|
w_5 := l_{15} \\
|
||||||
|
w_6 := l_{324} \\
|
||||||
|
$$
|
||||||
|
|
||||||
|
The format will be:
|
||||||
|
|
||||||
|
````
|
||||||
|
┏━━━━━━━━━━━━━━┓
|
||||||
|
┃ 72 31 63 77 ┃ Magic
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 01 00 00 00 ┃ Version
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 03 00 00 00 ┃ nSections
|
||||||
|
┗━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||||
|
┃ 01 00 00 00 ┃ 49 00 00 00 ┃ SectionType: Header
|
||||||
|
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||||
|
┃ 25 00 00 00 ┃ 10 00 00 00 ┃ FieldDefSize FieldDef
|
||||||
|
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ 20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430┃
|
||||||
|
┣━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
┃ 00 00 00 00 ┃ Big Int format
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 04 00 00 00 ┃ Id Size
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 07 00 00 00 ┃ # of wires
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 01 00 00 00 ┃ # Public Outs
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 02 00 00 00 ┃ # Public Ins
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 03 00 00 00 ┃ # Private Ins
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ e8 03 00 00 ┃ # Labels
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 03 00 00 00 ┃ # Constraints
|
||||||
|
┗━━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||||
|
┃ 02 00 00 00 ┃ 8b 00 00 00 ┃ SectionType: Constraints
|
||||||
|
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0
|
||||||
|
┃ 02 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
|
||||||
|
┃ 05 00 00 00 ┃ 01 03 ┃
|
||||||
|
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||||
|
┃ 06 00 00 00 ┃ 01 08 ┃
|
||||||
|
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━┓
|
||||||
|
┃ 03 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
|
||||||
|
┃ 00 00 00 00 ┃ 01 02 ┃
|
||||||
|
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||||
|
┃ 02 00 00 00 ┃ 01 14 ┃
|
||||||
|
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||||
|
┃ 03 00 00 00 ┃ 01 0C ┃
|
||||||
|
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━┓
|
||||||
|
┃ 02 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
|
||||||
|
┃ 00 00 00 00 ┃ 01 05 ┃
|
||||||
|
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||||
|
┃ 02 00 00 00 ┃ 01 07 ┃
|
||||||
|
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━┓ 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 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 ┃
|
||||||
|
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||||
|
┃ 03 00 00 00 ┃ 1c 00 00 00 ┃ Wire to Label Map
|
||||||
|
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||||
|
┏━━━━━━━━━━━━━━┓
|
||||||
|
┃ 00 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 03 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 0a 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 0b 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 0c 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 0f 00 00 00 ┃
|
||||||
|
┣━━━━━━━━━━━━━━┫
|
||||||
|
┃ 44 01 00 00 ┃
|
||||||
|
┗━━━━━━━━━━━━━━┛
|
||||||
|
````
|
||||||
|
|
||||||
|
And the binary representation in Hex:
|
||||||
|
|
||||||
|
````
|
||||||
|
72 31 63 77
|
||||||
|
01 00 00 00
|
||||||
|
03 00 00 00
|
||||||
|
01 00 00 00 49 00 00 00
|
||||||
|
25 00 00 00 10 00 00 00
|
||||||
|
20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
|
||||||
|
00 00 00 00
|
||||||
|
04 00 00 00
|
||||||
|
07 00 00 00
|
||||||
|
01 00 00 00
|
||||||
|
02 00 00 00
|
||||||
|
03 00 00 00
|
||||||
|
e8 03 00 00
|
||||||
|
03 00 00 00
|
||||||
|
02 00 00 00 8b 00 00 00
|
||||||
|
02 00 00 00
|
||||||
|
05 00 00 00 01 03
|
||||||
|
06 00 00 00 01 08
|
||||||
|
03 00 00 00
|
||||||
|
00 00 00 00 01 02
|
||||||
|
02 00 00 00 01 14
|
||||||
|
03 00 00 00 01 0C
|
||||||
|
02 00 00 00
|
||||||
|
00 00 00 00 01 05
|
||||||
|
02 00 00 00 01 07
|
||||||
|
03 00 00 00
|
||||||
|
01 00 00 00 01 04
|
||||||
|
04 00 00 00 01 08
|
||||||
|
05 00 00 00 01 03
|
||||||
|
02 00 00 00
|
||||||
|
03 00 00 00 01 2C
|
||||||
|
06 00 00 00 01 06
|
||||||
|
00 00 00 00
|
||||||
|
01 00 00 00
|
||||||
|
06 00 00 00 01 04
|
||||||
|
03 00 00 00
|
||||||
|
00 00 00 00 01 06
|
||||||
|
02 00 00 00 01 0B
|
||||||
|
03 00 00 00 01 05
|
||||||
|
01 00 00 00
|
||||||
|
06 00 00 00 02 58 02
|
||||||
|
03 00 00 00 1c 00 00 00
|
||||||
|
00 00 00 00
|
||||||
|
03 00 00 00
|
||||||
|
0a 00 00 00
|
||||||
|
0b 00 00 00
|
||||||
|
0c 00 00 00
|
||||||
|
0f 00 00 00
|
||||||
|
44 01 00 00
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
circom will output this format.
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||||
|
|
||||||
BIN
doc/r1cs_bin_format.monopic
Normal file
BIN
doc/r1cs_bin_format.monopic
Normal file
Binary file not shown.
BIN
doc/r1cs_example.monopic
Normal file
BIN
doc/r1cs_example.monopic
Normal file
Binary file not shown.
4
index.js
4
index.js
@@ -1 +1,3 @@
|
|||||||
module.exports = require("./src/compiler.js");
|
module.exports.compiler = require("./src/compiler.js");
|
||||||
|
module.exports.c_tester = require("./src/c_tester.js");
|
||||||
|
module.exports.tester = require("./src/c_tester.js");
|
||||||
|
|||||||
73
package-lock.json
generated
73
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "circom",
|
"name": "circom",
|
||||||
"version": "0.0.32",
|
"version": "0.0.35",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -111,8 +111,7 @@
|
|||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"big-integer": {
|
"big-integer": {
|
||||||
"version": "1.6.43",
|
"version": "1.6.43",
|
||||||
@@ -132,7 +131,6 @@
|
|||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -249,8 +247,7 @@
|
|||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"cross-spawn": {
|
"cross-spawn": {
|
||||||
"version": "6.0.5",
|
"version": "6.0.5",
|
||||||
@@ -308,6 +305,11 @@
|
|||||||
"integrity": "sha1-zR9rpHfFY4xAyX7ZtXLbW6tdgzE=",
|
"integrity": "sha1-zR9rpHfFY4xAyX7ZtXLbW6tdgzE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ejs": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-cuIMtJwxvzumSAkqaaoGY/L6Fc/t6YvoP9/VIaK0V/CyqKLEQ8sqODmYfy/cjXEdZ9+OOL8TecbJu+1RsofGDw=="
|
||||||
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||||
@@ -536,6 +538,21 @@
|
|||||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"fflib": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflib/-/fflib-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-TvQ3nQjJwdyrFBZAz+GTWz1mv9hHwRiQmZX3T2G0P+cBAlyw42lm4W62i+Ofj1ZOW1XNrEEhFhxHPnutTsJBwA==",
|
||||||
|
"requires": {
|
||||||
|
"big-integer": "^1.6.48"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"big-integer": {
|
||||||
|
"version": "1.6.48",
|
||||||
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
|
||||||
|
"integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"figures": {
|
"figures": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
|
||||||
@@ -585,11 +602,15 @@
|
|||||||
"integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==",
|
"integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"fnv-plus": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fnv-plus/-/fnv-plus-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw=="
|
||||||
|
},
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"functional-red-black-tree": {
|
"functional-red-black-tree": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@@ -620,7 +641,6 @@
|
|||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
||||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
@@ -677,7 +697,6 @@
|
|||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
@@ -686,8 +705,7 @@
|
|||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"inquirer": {
|
"inquirer": {
|
||||||
"version": "6.2.2",
|
"version": "6.2.2",
|
||||||
@@ -911,7 +929,6 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@@ -1107,8 +1124,7 @@
|
|||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"path-is-inside": {
|
"path-is-inside": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -1196,11 +1212,18 @@
|
|||||||
"version": "2.6.3",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
||||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rimraf-promise": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf-promise/-/rimraf-promise-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-PdvkN4wa3slmvDZt37yYUUPHaVI=",
|
||||||
|
"requires": {
|
||||||
|
"rimraf": "^2.4.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"run-async": {
|
"run-async": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
|
||||||
@@ -1405,6 +1428,24 @@
|
|||||||
"os-tmpdir": "~1.0.2"
|
"os-tmpdir": "~1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tmp-promise": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-zl71nFWjPKW2KXs+73gEk8RmqvtAeXPxhWDkTUoa3MSMkjq3I+9OeknjF178MQoMYsdqL730hfzvNfEkePxq9Q==",
|
||||||
|
"requires": {
|
||||||
|
"tmp": "0.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tmp": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==",
|
||||||
|
"requires": {
|
||||||
|
"rimraf": "^2.6.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "circom",
|
"name": "circom",
|
||||||
"version": "0.0.32",
|
"version": "0.0.35",
|
||||||
"description": "Language to generate logic circuits",
|
"description": "Language to generate logic circuits",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
@@ -30,7 +30,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"big-integer": "^1.6.32",
|
"big-integer": "^1.6.32",
|
||||||
|
"ejs": "^3.0.1",
|
||||||
|
"fflib": "0.0.2",
|
||||||
|
"fnv-plus": "^1.3.1",
|
||||||
"optimist": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
|
"rimraf-promise": "^2.0.0",
|
||||||
|
"tmp-promise": "^2.0.2",
|
||||||
"yargs": "^12.0.2"
|
"yargs": "^12.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ include { return 'include'; }
|
|||||||
\& { return '&'; }
|
\& { return '&'; }
|
||||||
\| { return '|'; }
|
\| { return '|'; }
|
||||||
\! { return '!'; }
|
\! { return '!'; }
|
||||||
|
\~ { return '~'; }
|
||||||
\< { return '<'; }
|
\< { return '<'; }
|
||||||
\> { return '>'; }
|
\> { return '>'; }
|
||||||
\! { return '!'; }
|
\! { return '!'; }
|
||||||
|
|||||||
@@ -1329,42 +1329,44 @@ case 59: return 65;
|
|||||||
break;
|
break;
|
||||||
case 60: return 94;
|
case 60: return 94;
|
||||||
break;
|
break;
|
||||||
case 61: return 77;
|
case 61: return 95;
|
||||||
break;
|
break;
|
||||||
case 62: return 78;
|
case 62: return 77;
|
||||||
break;
|
break;
|
||||||
case 63: return 94;
|
case 63: return 78;
|
||||||
break;
|
break;
|
||||||
case 64: return 57;
|
case 64: return 94;
|
||||||
break;
|
break;
|
||||||
case 65: return 58;
|
case 65: return 57;
|
||||||
break;
|
break;
|
||||||
case 66: return 20;
|
case 66: return 58;
|
||||||
break;
|
break;
|
||||||
case 67: return 22;
|
case 67: return 20;
|
||||||
break;
|
break;
|
||||||
case 68: return 112;
|
case 68: return 22;
|
||||||
break;
|
break;
|
||||||
case 69: return 113;
|
case 69: return 112;
|
||||||
break;
|
break;
|
||||||
case 70: return 36;
|
case 70: return 113;
|
||||||
break;
|
break;
|
||||||
case 71: return 37;
|
case 71: return 36;
|
||||||
break;
|
break;
|
||||||
case 72: return 29;
|
case 72: return 37;
|
||||||
break;
|
break;
|
||||||
case 73: return 24;
|
case 73: return 29;
|
||||||
break;
|
break;
|
||||||
case 74: return 102;
|
case 74: return 24;
|
||||||
break;
|
break;
|
||||||
case 75: return 5;
|
case 75: return 102;
|
||||||
break;
|
break;
|
||||||
case 76: console.log("INVALID: " + yy_.yytext); return 'INVALID'
|
case 76: return 5;
|
||||||
|
break;
|
||||||
|
case 77: console.log("INVALID: " + yy_.yytext); return 'INVALID'
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/],
|
rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:~)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/],
|
||||||
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76],"inclusive":true}}
|
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],"inclusive":true}}
|
||||||
});
|
});
|
||||||
return lexer;
|
return lexer;
|
||||||
})();
|
})();
|
||||||
|
|||||||
59
src/bigarray.js
Normal file
59
src/bigarray.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
const SUBARRAY_SIZE = 0x10000;
|
||||||
|
|
||||||
|
const BigArrayHandler = {
|
||||||
|
get: function(obj, prop) {
|
||||||
|
if (!isNaN(prop)) {
|
||||||
|
return obj.getElement(prop);
|
||||||
|
} else return obj[prop];
|
||||||
|
},
|
||||||
|
set: function(obj, prop, value) {
|
||||||
|
if (!isNaN(prop)) {
|
||||||
|
return obj.setElement(prop, value);
|
||||||
|
} else {
|
||||||
|
obj[prop] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class _BigArray {
|
||||||
|
constructor (initSize) {
|
||||||
|
this.length = initSize || 0;
|
||||||
|
this.arr = [];
|
||||||
|
|
||||||
|
for (let i=0; i<initSize; i+=SUBARRAY_SIZE) {
|
||||||
|
this.arr[i/SUBARRAY_SIZE] = new Array(Math.min(SUBARRAY_SIZE, initSize - i));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
push (element) {
|
||||||
|
this.setElement (this.length, element);
|
||||||
|
}
|
||||||
|
getElement(idx) {
|
||||||
|
idx = parseInt(idx);
|
||||||
|
const idx1 = Math.floor(idx / SUBARRAY_SIZE);
|
||||||
|
const idx2 = idx % SUBARRAY_SIZE;
|
||||||
|
return this.arr[idx1] ? this.arr[idx1][idx2] : undefined;
|
||||||
|
}
|
||||||
|
setElement(idx, value) {
|
||||||
|
idx = parseInt(idx);
|
||||||
|
const idx1 = Math.floor(idx / SUBARRAY_SIZE);
|
||||||
|
if (!this.arr[idx1]) {
|
||||||
|
this.arr[idx1] = [];
|
||||||
|
}
|
||||||
|
const idx2 = idx % SUBARRAY_SIZE;
|
||||||
|
this.arr[idx1][idx2] = value;
|
||||||
|
if (idx >= this.length) this.length = idx+1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BigArray {
|
||||||
|
constructor( initSize ) {
|
||||||
|
const obj = new _BigArray(initSize);
|
||||||
|
const extObj = new Proxy(obj, BigArrayHandler);
|
||||||
|
return extObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BigArray;
|
||||||
468
src/build.js
Normal file
468
src/build.js
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 0KIMS association.
|
||||||
|
|
||||||
|
This file is part of circom (Zero Knowledge Circuit Compiler).
|
||||||
|
|
||||||
|
circom is a free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
circom is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const assert = require("assert");
|
||||||
|
const bigInt = require("big-integer");
|
||||||
|
const utils = require("./utils");
|
||||||
|
const gen = require("./gencode").gen;
|
||||||
|
const createRefs = require("./gencode").createRefs;
|
||||||
|
|
||||||
|
module.exports = build;
|
||||||
|
|
||||||
|
|
||||||
|
function build(ctx) {
|
||||||
|
ctx.definedFunctions = {};
|
||||||
|
ctx.functionCodes = [];
|
||||||
|
ctx.buildFunction = buildFunction;
|
||||||
|
ctx.conditionalCodeHeader = "";
|
||||||
|
ctx.codes_sizes = [];
|
||||||
|
ctx.definedSizes = {};
|
||||||
|
ctx.addSizes = addSizes;
|
||||||
|
ctx.constantsMap = {};
|
||||||
|
ctx.addConstant = addConstant;
|
||||||
|
ctx.addConstant(bigInt.zero);
|
||||||
|
ctx.addConstant(bigInt.one);
|
||||||
|
|
||||||
|
buildHeader(ctx);
|
||||||
|
buildEntryTables(ctx);
|
||||||
|
ctx.globalNames = ctx.uniqueNames;
|
||||||
|
|
||||||
|
buildCode(ctx);
|
||||||
|
|
||||||
|
buildComponentsArray(ctx);
|
||||||
|
|
||||||
|
buildMapIsInput(ctx);
|
||||||
|
buildWit2Sig(ctx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildEntryTables(ctx) {
|
||||||
|
|
||||||
|
const codes_hashMaps = [];
|
||||||
|
const codes_componentEntries = [];
|
||||||
|
const definedHashMaps = {};
|
||||||
|
for (let i=0; i<ctx.components.length; i++) {
|
||||||
|
const {htName, htMap} = addHashTable(i);
|
||||||
|
|
||||||
|
let code = "";
|
||||||
|
const componentEntriesTableName = ctx.getUniqueName("_entryTable" + ctx.components[i].template);
|
||||||
|
|
||||||
|
const componentEntriesTable = [];
|
||||||
|
for (let j=0; j<htMap.length; j++) {
|
||||||
|
const entry = ctx.components[i].names.o[htMap[j]];
|
||||||
|
const sizeName = ctx.addSizes(entry.sizes);
|
||||||
|
componentEntriesTable.push({
|
||||||
|
offset: entry.offset,
|
||||||
|
sizeName: sizeName,
|
||||||
|
type: entry.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.builder.addComponentEntriesTable(componentEntriesTableName, componentEntriesTable);
|
||||||
|
|
||||||
|
|
||||||
|
code += `Circom_ComponentEntry ${componentEntriesTableName}[${htMap.length}] = {\n`;
|
||||||
|
for (let j=0; j<htMap.length; j++) {
|
||||||
|
const entry = ctx.components[i].names.o[htMap[j]];
|
||||||
|
code += j>0 ? " ," : " ";
|
||||||
|
const sizeName = ctx.addSizes(entry.sizes);
|
||||||
|
|
||||||
|
const ty = entry.type == "S" ? "_typeSignal" : "_typeComponent";
|
||||||
|
code += `{${entry.offset},${sizeName}, ${ty}}\n`;
|
||||||
|
}
|
||||||
|
code += "};\n";
|
||||||
|
codes_componentEntries.push(code);
|
||||||
|
|
||||||
|
ctx.components[i].htName = htName;
|
||||||
|
ctx.components[i].etName = componentEntriesTableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
"// HashMaps\n" ,
|
||||||
|
codes_hashMaps , "\n" ,
|
||||||
|
"\n" ,
|
||||||
|
"// Component Entries\n" ,
|
||||||
|
codes_componentEntries , "\n" ,
|
||||||
|
"\n"
|
||||||
|
];
|
||||||
|
|
||||||
|
function addHashTable(cIdx) {
|
||||||
|
const keys = Object.keys(ctx.components[cIdx].names.o);
|
||||||
|
assert(keys.length<128);
|
||||||
|
keys.sort((a,b) => ((a>b) ? 1 : -1));
|
||||||
|
const h = utils.fnvHash(keys.join(","));
|
||||||
|
if (definedHashMaps[h]) return definedHashMaps[h];
|
||||||
|
definedHashMaps[h] = {};
|
||||||
|
definedHashMaps[h].htName = ctx.getUniqueName("_ht"+ctx.components[cIdx].template);
|
||||||
|
definedHashMaps[h].htMap = [];
|
||||||
|
const t = [];
|
||||||
|
for (let i=0; i<keys.length; i++) {
|
||||||
|
definedHashMaps[h].htMap[i] = keys[i];
|
||||||
|
|
||||||
|
const h2 = utils.fnvHash(keys[i]);
|
||||||
|
let pos = parseInt(h2.slice(-2), 16);
|
||||||
|
while (t[pos]) pos = (pos + 1) % 256;
|
||||||
|
t[pos] = [h2, i, keys[i]];
|
||||||
|
}
|
||||||
|
ctx.builder.addHashMap(definedHashMaps[h].htName, t);
|
||||||
|
|
||||||
|
return definedHashMaps[h];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCode(ctx) {
|
||||||
|
|
||||||
|
const fDefined = {};
|
||||||
|
|
||||||
|
const fnComponents = [];
|
||||||
|
for (let i=0; i<ctx.components.length; i++) {
|
||||||
|
const {h, instanceDef} = hashComponentCall(ctx, i);
|
||||||
|
const fName = ctx.components[i].template+"_"+h;
|
||||||
|
if (!fDefined[fName]) {
|
||||||
|
|
||||||
|
|
||||||
|
ctx.scopes = [{}];
|
||||||
|
ctx.conditionalCode = false;
|
||||||
|
ctx.fnBuilder = ctx.builder.newComponentFunctionBuilder(fName, instanceDef);
|
||||||
|
ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
|
||||||
|
ctx.uniqueNames = Object.assign({},ctx.globalNames);
|
||||||
|
ctx.refs = [];
|
||||||
|
ctx.fileName = ctx.templates[ctx.components[i].template].fileName;
|
||||||
|
ctx.filePath = ctx.templates[ctx.components[i].template].filePath;
|
||||||
|
ctx.getSignalSizesCache = {};
|
||||||
|
ctx.getSignalOffsetCache = {};
|
||||||
|
|
||||||
|
for (let p in ctx.components[i].params) {
|
||||||
|
if (ctx.scopes[0][p]) return ctx.throwError(`Repeated parameter at ${ctx.components[i].template}: ${p}`);
|
||||||
|
const refId = ctx.refs.length;
|
||||||
|
ctx.refs.push({
|
||||||
|
type: "BIGINT",
|
||||||
|
used: false,
|
||||||
|
value: utils.flatArray(ctx.components[i].params[p]),
|
||||||
|
sizes: utils.accSizes(utils.extractSizes(ctx.components[i].params[p])),
|
||||||
|
label: ctx.getUniqueName(p)
|
||||||
|
});
|
||||||
|
ctx.scopes[0][p] = refId;
|
||||||
|
}
|
||||||
|
|
||||||
|
createRefs(ctx, ctx.templates[ctx.components[i].template].block);
|
||||||
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
gen(ctx, ctx.templates[ctx.components[i].template].block);
|
||||||
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
ctx.fnBuilder.setBody(ctx.codeBuilder);
|
||||||
|
|
||||||
|
ctx.builder.addFunction(ctx.fnBuilder);
|
||||||
|
|
||||||
|
fDefined[fName] = true;
|
||||||
|
}
|
||||||
|
ctx.components[i].fnName = fName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fnComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildComponentsArray(ctx) {
|
||||||
|
for (let i=0; i< ctx.components.length; i++) {
|
||||||
|
let newThread;
|
||||||
|
if (ctx.newThreadTemplates) {
|
||||||
|
if (ctx.newThreadTemplates.test(ctx.components[i].template)) {
|
||||||
|
newThread = true;
|
||||||
|
} else {
|
||||||
|
newThread = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newThread = false;
|
||||||
|
}
|
||||||
|
ctx.builder.addComponent({
|
||||||
|
hashMapName: ctx.components[i].htName,
|
||||||
|
entryTableName: ctx.components[i].etName,
|
||||||
|
functionName: ctx.components[i].fnName,
|
||||||
|
nInSignals: ctx.components[i].nInSignals,
|
||||||
|
newThread: newThread
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildHeader(ctx) {
|
||||||
|
ctx.builder.setHeader({
|
||||||
|
NSignals: ctx.signals.length,
|
||||||
|
NComponents: ctx.components.length,
|
||||||
|
NInputs: ctx.components[ ctx.getComponentIdx("main") ].nInSignals,
|
||||||
|
NOutputs: ctx.totals[ ctx.stOUTPUT ],
|
||||||
|
NVars: ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL],
|
||||||
|
P: ctx.field.p
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMapIsInput(ctx) {
|
||||||
|
let i;
|
||||||
|
let map = [];
|
||||||
|
let acc = 0;
|
||||||
|
for (i=0; i<ctx.signals.length; i++) {
|
||||||
|
if (ctx.signals[i].o & ctx.IN) {
|
||||||
|
acc = acc | (1 << (i%32) );
|
||||||
|
}
|
||||||
|
if ((i+1)%32==0) {
|
||||||
|
map.push(acc);
|
||||||
|
acc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((i%32) != 0) {
|
||||||
|
map.push(acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.builder.setMapIsInput(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function buildWit2Sig(ctx) {
|
||||||
|
const NVars =
|
||||||
|
ctx.totals[ctx.stONE] +
|
||||||
|
ctx.totals[ctx.stOUTPUT] +
|
||||||
|
ctx.totals[ctx.stPUBINPUT] +
|
||||||
|
ctx.totals[ctx.stPRVINPUT] +
|
||||||
|
ctx.totals[ctx.stINTERNAL];
|
||||||
|
const arr = Array(NVars);
|
||||||
|
for (let i=0; i<ctx.signals.length; i++) {
|
||||||
|
const outIdx = ctx.signals[i].id;
|
||||||
|
if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
|
||||||
|
assert(typeof outIdx != "undefined", `Signal ${i} does not have index`);
|
||||||
|
if (outIdx>=NVars) continue; // Is a constant or a discarded variable
|
||||||
|
if (typeof arr[ctx.signals[i].id] == "undefined") {
|
||||||
|
arr[outIdx] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.builder.setWit2Sig(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function addSizes(_sizes) {
|
||||||
|
const sizes = _sizes || [];
|
||||||
|
let name = "sizes";
|
||||||
|
for (let i=0; i<sizes.length;i++) {
|
||||||
|
name+="_"+sizes[i];
|
||||||
|
}
|
||||||
|
if (name=="sizes") name="sizes_0";
|
||||||
|
|
||||||
|
if (this.definedSizes[name]) return this.definedSizes[name];
|
||||||
|
const labelName = this.getUniqueName(name);
|
||||||
|
this.definedSizes[name] = labelName;
|
||||||
|
|
||||||
|
const accSizes = utils.accSizes(sizes);
|
||||||
|
|
||||||
|
this.builder.addSizes(labelName, accSizes);
|
||||||
|
|
||||||
|
let code = `Circom_Size ${labelName}[${accSizes.length}] = {`;
|
||||||
|
for (let i=0; i<accSizes.length; i++) {
|
||||||
|
if (i>0) code += ",";
|
||||||
|
code += accSizes[i];
|
||||||
|
}
|
||||||
|
code += "};\n";
|
||||||
|
this.codes_sizes.push(code);
|
||||||
|
|
||||||
|
return labelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildFunction(name, paramValues) {
|
||||||
|
const ctx = this;
|
||||||
|
const {h, instanceDef} = hashFunctionCall(ctx, name, paramValues);
|
||||||
|
|
||||||
|
if (ctx.definedFunctions[h]) return ctx.definedFunctions[h];
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
fnName: `${name}_${h}`
|
||||||
|
};
|
||||||
|
|
||||||
|
const oldRefs = ctx.refs;
|
||||||
|
const oldConditionalCode = ctx.conditionalCode;
|
||||||
|
const oldCodeBuilder = ctx.codeBuilder;
|
||||||
|
const oldFnBuilder = ctx.fnBuilder;
|
||||||
|
|
||||||
|
const oldUniqueNames = ctx.uniqueNames;
|
||||||
|
const oldFileName = ctx.fileName;
|
||||||
|
const oldFilePath = ctx.oldFilePath;
|
||||||
|
const oldReturnSizes = ctx.returnSizes;
|
||||||
|
const oldReturnValue = ctx.returnValue;
|
||||||
|
|
||||||
|
|
||||||
|
ctx.scopes = [{}];
|
||||||
|
ctx.refs = [];
|
||||||
|
ctx.conditionalCode = false;
|
||||||
|
ctx.fnBuilder = ctx.builder.newFunctionBuilder(`${name}_${h}`, instanceDef);
|
||||||
|
ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
|
||||||
|
ctx.uniqueNames = Object.assign({},ctx.globalNames);
|
||||||
|
ctx.returnValue = null;
|
||||||
|
ctx.returnSizes = null;
|
||||||
|
ctx.fileName = ctx.functions[name].fileName;
|
||||||
|
ctx.filePath = ctx.functions[name].filePath;
|
||||||
|
|
||||||
|
let paramLabels = [];
|
||||||
|
|
||||||
|
for (let i=0; i<ctx.functions[name].params.length; i++) {
|
||||||
|
|
||||||
|
if (paramValues[i].used) {
|
||||||
|
paramLabels.push(ctx.functions[name].params[i]);
|
||||||
|
const idRef = ctx.refs.length;
|
||||||
|
ctx.refs.push({
|
||||||
|
type: "BIGINT",
|
||||||
|
used: true,
|
||||||
|
sizes: paramValues[i].sizes,
|
||||||
|
label: ctx.functions[name].params[i],
|
||||||
|
});
|
||||||
|
ctx.scopes[0][ctx.functions[name].params[i]] = idRef;
|
||||||
|
} else {
|
||||||
|
const idRef = ctx.refs.length;
|
||||||
|
ctx.refs.push({
|
||||||
|
type: "BIGINT",
|
||||||
|
used: false,
|
||||||
|
sizes: paramValues[i].sizes,
|
||||||
|
label: ctx.functions[name].params[i],
|
||||||
|
value: paramValues[i].value
|
||||||
|
});
|
||||||
|
ctx.scopes[0][ctx.functions[name].params[i]] = idRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.fnBuilder.setParams(paramLabels);
|
||||||
|
|
||||||
|
createRefs(ctx, ctx.functions[name].block);
|
||||||
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
gen(ctx, ctx.functions[name].block);
|
||||||
|
if (ctx.error) return;
|
||||||
|
|
||||||
|
if (ctx.returnValue == null) {
|
||||||
|
if (ctx.returnSizes == null) assert(false, `Funciont ${name} does not return any value`);
|
||||||
|
|
||||||
|
ctx.fnBuilder.setBody(ctx.codeBuilder);
|
||||||
|
ctx.builder.addFunction(ctx.fnBuilder);
|
||||||
|
|
||||||
|
res.type = "VARVAL_CONSTSIZE";
|
||||||
|
res.returnSizes = ctx.returnSizes;
|
||||||
|
} else {
|
||||||
|
res.type = "CONSTVAL";
|
||||||
|
res.returnValue = ctx.returnValue;
|
||||||
|
res.returnSizes = ctx.returnSizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.refs = oldRefs;
|
||||||
|
ctx.conditionalCode = oldConditionalCode;
|
||||||
|
ctx.codeBuilder = oldCodeBuilder;
|
||||||
|
ctx.fnBuilder = oldFnBuilder;
|
||||||
|
ctx.uniqueNames = oldUniqueNames;
|
||||||
|
ctx.fileName = oldFileName;
|
||||||
|
ctx.filePath = oldFilePath;
|
||||||
|
ctx.returnSizes = oldReturnSizes;
|
||||||
|
ctx.returnValue = oldReturnValue;
|
||||||
|
|
||||||
|
ctx.definedFunctions[h] = res;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function hashComponentCall(ctx, cIdx) {
|
||||||
|
// TODO: At the moment generate a diferent function for each instance of the component
|
||||||
|
const constParams = [];
|
||||||
|
for (let p in ctx.components[cIdx].params) {
|
||||||
|
constParams.push(p + "=" + value2str(ctx.components[cIdx].params[p]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let n in ctx.components[cIdx].names.o) {
|
||||||
|
const entry = ctx.components[cIdx].names.o[n];
|
||||||
|
if ((entry.type == "S")&&(ctx.signals[entry.offset].o & ctx.IN)) {
|
||||||
|
travelSizes(n, entry.offset, entry.sizes, (prefix, offset) => {
|
||||||
|
if (utils.isDefined(ctx.signals[offset].v)) {
|
||||||
|
constParams.push(prefix + "=" + bigInt(ctx.signals[offset].value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let instanceDef = ctx.components[cIdx].template;
|
||||||
|
if (constParams.length>0) {
|
||||||
|
instanceDef += "\n";
|
||||||
|
constParams.sort();
|
||||||
|
instanceDef += constParams.join("\n");
|
||||||
|
}
|
||||||
|
const h = utils.fnvHash(instanceDef);
|
||||||
|
return {h, instanceDef};
|
||||||
|
|
||||||
|
function travelSizes(prefix, offset, sizes, fn) {
|
||||||
|
if (sizes.length == 0) {
|
||||||
|
fn(prefix, offset);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
let o = offset;
|
||||||
|
for (let i=0; i<sizes[0]; i++) {
|
||||||
|
o += travelSizes(prefix + "[" + i + "]", o, sizes.slice(1), fn);
|
||||||
|
}
|
||||||
|
return o-offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashFunctionCall(ctx, name, paramValues) {
|
||||||
|
// TODO
|
||||||
|
const constParams = [];
|
||||||
|
for (let i=0; i<ctx.functions[name].params.length; i++) {
|
||||||
|
if (!paramValues[i].used) {
|
||||||
|
constParams.push(ctx.functions[name].params[i] + utils.accSizes2Str(paramValues[i].sizes) + "=" + value2str(paramValues[i].value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let instanceDef = name;
|
||||||
|
if (constParams.length>0) {
|
||||||
|
instanceDef += "\n";
|
||||||
|
constParams.sort();
|
||||||
|
instanceDef += constParams.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const h = utils.fnvHash(instanceDef);
|
||||||
|
return {h, instanceDef};
|
||||||
|
}
|
||||||
|
|
||||||
|
function value2str(v) {
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
let S="[";
|
||||||
|
for (let i=0; i<v.length; i++) {
|
||||||
|
if (i>0) S+=",";
|
||||||
|
S+=value2str(v[i]);
|
||||||
|
}
|
||||||
|
S+="]";
|
||||||
|
return S;
|
||||||
|
} else {
|
||||||
|
return bigInt(v).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
616
src/builder_c.js
Normal file
616
src/builder_c.js
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
const streamFromMultiArray = require("./stream_from_multiarray");
|
||||||
|
const bigInt = require("big-integer");
|
||||||
|
const utils = require("./utils");
|
||||||
|
const assert = require("assert");
|
||||||
|
|
||||||
|
function ref2src(c) {
|
||||||
|
if (c[0] == "R") {
|
||||||
|
return c[1];
|
||||||
|
} else if (c[0] == "V") {
|
||||||
|
return c[1].toString();
|
||||||
|
} else if (c[0] == "C") {
|
||||||
|
return `(ctx->circuit->constants + ${c[1]})`;
|
||||||
|
} else if (c[0] == "CC") {
|
||||||
|
return "__cIdx";
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CodeBuilderC {
|
||||||
|
constructor() {
|
||||||
|
this.ops = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
addComment(comment) {
|
||||||
|
this.ops.push({op: "COMMENT", comment});
|
||||||
|
}
|
||||||
|
|
||||||
|
addBlock(block) {
|
||||||
|
this.ops.push({op: "BLOCK", block});
|
||||||
|
}
|
||||||
|
|
||||||
|
calcOffset(dLabel, offsets) {
|
||||||
|
this.ops.push({op: "CALCOFFSETS", dLabel, offsets});
|
||||||
|
}
|
||||||
|
|
||||||
|
assign(dLabel, src, sOffset) {
|
||||||
|
this.ops.push({op: "ASSIGN", dLabel, src, sOffset});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubComponentOffset(dLabel, component, hash, hashLabel) {
|
||||||
|
this.ops.push({op: "GETSUBCOMPONENTOFFSET", dLabel, component, hash, hashLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubComponentSizes(dLabel, component, hash, hashLabel) {
|
||||||
|
this.ops.push({op: "GETSUBCOMPONENTSIZES", dLabel, component, hash, hashLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignalOffset(dLabel, component, hash, hashLabel) {
|
||||||
|
this.ops.push({op: "GETSIGNALOFFSET", dLabel, component, hash, hashLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignalSizes(dLabel, component, hash, hashLabel) {
|
||||||
|
this.ops.push({op: "GETSIGNALSIZES", dLabel, component, hash, hashLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
setSignal(component, signal, value) {
|
||||||
|
this.ops.push({op: "SETSIGNAL", component, signal, value});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignal(dLabel, component, signal) {
|
||||||
|
this.ops.push({op: "GETSIGNAL", dLabel, component, signal});
|
||||||
|
}
|
||||||
|
|
||||||
|
copyN(dLabel, offset, src, n) {
|
||||||
|
this.ops.push({op: "COPYN", dLabel, offset, src, n});
|
||||||
|
}
|
||||||
|
|
||||||
|
copyNRet(src, n) {
|
||||||
|
this.ops.push({op: "COPYNRET", src, n});
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldOp(dLabel, fOp, params) {
|
||||||
|
this.ops.push({op: "FOP", dLabel, fOp, params});
|
||||||
|
}
|
||||||
|
|
||||||
|
ret() {
|
||||||
|
this.ops.push({op: "RET"});
|
||||||
|
}
|
||||||
|
|
||||||
|
addLoop(condLabel, body) {
|
||||||
|
this.ops.push({op: "LOOP", condLabel, body});
|
||||||
|
}
|
||||||
|
|
||||||
|
addIf(condLabel, thenCode, elseCode) {
|
||||||
|
this.ops.push({op: "IF", condLabel, thenCode, elseCode});
|
||||||
|
}
|
||||||
|
|
||||||
|
fnCall(fnName, retLabel, params) {
|
||||||
|
this.ops.push({op: "FNCALL", fnName, retLabel, params});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkConstraint(a, b, strErr) {
|
||||||
|
this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
concat(cb) {
|
||||||
|
this.ops.push(...cb.ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCode() {
|
||||||
|
for (let i=0; i<this.ops.length; i++) {
|
||||||
|
if (this.ops[i].op != "COMMENT") return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildOffset(offsets) {
|
||||||
|
let rN=0;
|
||||||
|
let S = "";
|
||||||
|
offsets.forEach((o) => {
|
||||||
|
if ((o[0][0] == "V") && (o[1][0]== "V")) {
|
||||||
|
rN += o[0][1]*o[1][1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let f="";
|
||||||
|
if (o[0][0] == "V") {
|
||||||
|
if (o[0][1]==0) return;
|
||||||
|
f += o[0][1];
|
||||||
|
} else if (o[0][0] == "RI") {
|
||||||
|
if (o[0][1]==0) return;
|
||||||
|
f += o[0][1];
|
||||||
|
} else if (o[0][0] == "R") {
|
||||||
|
f += `Fr_toInt(${o[0][1]})`;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
if (o[1][0] == "V") {
|
||||||
|
if (o[1][1]==0) return;
|
||||||
|
if (o[1][1]>1) {
|
||||||
|
f += "*" + o[1][1];
|
||||||
|
}
|
||||||
|
} else if (o[1][0] == "RS") {
|
||||||
|
f += `*${o[1][1]}[${o[1][2]}]`;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
if (S!="") S+= " + ";
|
||||||
|
S += f;
|
||||||
|
});
|
||||||
|
if (rN>0) {
|
||||||
|
S = `${rN} + ${S}`;
|
||||||
|
}
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(code) {
|
||||||
|
this.ops.forEach( (o) => {
|
||||||
|
if (o.op == "COMMENT") {
|
||||||
|
code.push(`/* ${o.comment} */`);
|
||||||
|
} else if (o.op == "BLOCK") {
|
||||||
|
const codeBlock=[];
|
||||||
|
o.block.build(codeBlock);
|
||||||
|
code.push(utils.ident(codeBlock));
|
||||||
|
} else if (o.op == "CALCOFFSETS") {
|
||||||
|
code.push(`${o.dLabel} = ${this._buildOffset(o.offsets)};`);
|
||||||
|
} else if (o.op == "ASSIGN") {
|
||||||
|
const oS = ref2src(o.sOffset);
|
||||||
|
if (oS != "0") {
|
||||||
|
code.push(`${o.dLabel} = ${ref2src(o.src)} + ${oS};`);
|
||||||
|
} else {
|
||||||
|
code.push(`${o.dLabel} = ${ref2src(o.src)};`);
|
||||||
|
}
|
||||||
|
} else if (o.op == "GETSUBCOMPONENTOFFSET") {
|
||||||
|
code.push(`${o.dLabel} = ctx->getSubComponentOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
||||||
|
} else if (o.op == "GETSUBCOMPONENTSIZES") {
|
||||||
|
code.push(`${o.dLabel} = ctx->getSubComponentSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
||||||
|
} else if (o.op == "GETSIGNALOFFSET") {
|
||||||
|
code.push(`${o.dLabel} = ctx->getSignalOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
||||||
|
} else if (o.op == "GETSIGNALSIZES") {
|
||||||
|
code.push(`${o.dLabel} = ctx->getSignalSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
||||||
|
} else if (o.op == "SETSIGNAL") {
|
||||||
|
code.push(`ctx->setSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${ref2src(o.value)});`);
|
||||||
|
} else if (o.op == "GETSIGNAL") {
|
||||||
|
code.push(`ctx->getSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${o.dLabel});`);
|
||||||
|
} else if (o.op == "COPYN") {
|
||||||
|
const oS = ref2src(o.offset);
|
||||||
|
const dLabel = (oS != "0") ? (o.dLabel + "+" + oS) : o.dLabel;
|
||||||
|
code.push(`Fr_copyn(${dLabel}, ${ref2src(o.src)}, ${o.n});`);
|
||||||
|
} else if (o.op == "COPYNRET") {
|
||||||
|
code.push(`Fr_copyn(__retValue, ${ref2src(o.src)}, ${o.n});`);
|
||||||
|
} else if (o.op == "RET") {
|
||||||
|
code.push("goto returnFunc;");
|
||||||
|
} else if (o.op == "FOP") {
|
||||||
|
let paramsS = "";
|
||||||
|
for (let i=0; i<o.params.length; i++) {
|
||||||
|
if (i>0) paramsS += ", ";
|
||||||
|
paramsS += ref2src(o.params[i]);
|
||||||
|
}
|
||||||
|
code.push(`Fr_${o.fOp}(${o.dLabel}, ${paramsS});`);
|
||||||
|
} else if (o.op == "LOOP") {
|
||||||
|
code.push(`while (Fr_isTrue(${o.condLabel})) {`);
|
||||||
|
const body = [];
|
||||||
|
o.body.build(body);
|
||||||
|
code.push(utils.ident(body));
|
||||||
|
code.push("}");
|
||||||
|
} else if (o.op == "IF") {
|
||||||
|
code.push(`if (Fr_isTrue(${o.condLabel})) {`);
|
||||||
|
const thenCode = [];
|
||||||
|
o.thenCode.build(thenCode);
|
||||||
|
code.push(utils.ident(thenCode));
|
||||||
|
if (o.elseCode) {
|
||||||
|
code.push("} else {");
|
||||||
|
const elseCode = [];
|
||||||
|
o.elseCode.build(elseCode);
|
||||||
|
code.push(utils.ident(elseCode));
|
||||||
|
}
|
||||||
|
code.push("}");
|
||||||
|
} else if (o.op == "FNCALL") {
|
||||||
|
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}");`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionBuilderC {
|
||||||
|
|
||||||
|
constructor(name, instanceDef, type) {
|
||||||
|
this.name = name;
|
||||||
|
this.instanceDef = instanceDef;
|
||||||
|
this.type = type; // "COMPONENT" or "FUNCTIOM"
|
||||||
|
this.definedFrElements = [];
|
||||||
|
this.definedIntElements = [];
|
||||||
|
this.definedSizeElements = [];
|
||||||
|
this.definedPFrElements = [];
|
||||||
|
this.initializedElements = [];
|
||||||
|
this.initializedSignalOffset = [];
|
||||||
|
this.initializedSignalSizes = [];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
defineFrElements(dLabel, size) {
|
||||||
|
this.definedFrElements.push({dLabel, size});
|
||||||
|
}
|
||||||
|
|
||||||
|
defineIntElement(dLabel) {
|
||||||
|
this.definedIntElements.push({dLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
defineSizesElement(dLabel) {
|
||||||
|
this.definedSizeElements.push({dLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
definePFrElement(dLabel) {
|
||||||
|
this.definedPFrElements.push({dLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeFrElement(dLabel, offset, idConstant) {
|
||||||
|
this.initializedElements.push({dLabel, offset, idConstant});
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeSignalOffset(dLabel, component, hash, hashLabel) {
|
||||||
|
this.initializedSignalOffset.push({dLabel, component, hash, hashLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeSignalSizes(dLabel, component, hash, hashLabel) {
|
||||||
|
this.initializedSignalSizes.push({dLabel, component, hash, hashLabel});
|
||||||
|
}
|
||||||
|
|
||||||
|
setParams(params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildHeader(code) {
|
||||||
|
this.definedFrElements.forEach( (o) => {
|
||||||
|
code.push(`FrElement ${o.dLabel}[${o.size}];`);
|
||||||
|
});
|
||||||
|
this.definedIntElements.forEach( (o) => {
|
||||||
|
code.push(`int ${o.dLabel};`);
|
||||||
|
});
|
||||||
|
this.definedSizeElements.forEach( (o) => {
|
||||||
|
code.push(`Circom_Sizes ${o.dLabel};`);
|
||||||
|
});
|
||||||
|
this.definedPFrElements.forEach( (o) => {
|
||||||
|
code.push(`PFrElement ${o.dLabel};`);
|
||||||
|
});
|
||||||
|
this.initializedElements.forEach( (o) => {
|
||||||
|
code.push(`Fr_copy(&(${o.dLabel}[${o.offset}]), ctx->circuit->constants +${o.idConstant});`);
|
||||||
|
});
|
||||||
|
this.initializedSignalOffset.forEach( (o) => {
|
||||||
|
code.push(`${o.dLabel} = ctx->getSignalOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
||||||
|
});
|
||||||
|
this.initializedSignalSizes.forEach( (o) => {
|
||||||
|
code.push(`${o.dLabel} = ctx->getSignalSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildFooter(code) {
|
||||||
|
}
|
||||||
|
|
||||||
|
newCodeBuilder() {
|
||||||
|
return new CodeBuilderC();
|
||||||
|
}
|
||||||
|
|
||||||
|
setBody(body) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(code) {
|
||||||
|
code.push(
|
||||||
|
"/*",
|
||||||
|
this.instanceDef,
|
||||||
|
"*/"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.type=="COMPONENT") {
|
||||||
|
code.push(`void ${this.name}(Circom_CalcWit *ctx, int __cIdx) {`);
|
||||||
|
} else if (this.type=="FUNCTION") {
|
||||||
|
let sParams = "";
|
||||||
|
for (let i=0;i<this.params.length;i++ ) sParams += `, PFrElement ${this.params[i]}`;
|
||||||
|
code.push(`void ${this.name}(Circom_CalcWit *ctx, PFrElement __retValue ${sParams}) {`);
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fnCode = [];
|
||||||
|
this._buildHeader(fnCode);
|
||||||
|
this.body.build(fnCode);
|
||||||
|
if (this.type=="COMPONENT") {
|
||||||
|
fnCode.push("ctx->finished(__cIdx);");
|
||||||
|
} else if (this.type=="FUNCTION") {
|
||||||
|
fnCode.push("returnFunc: ;");
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
this._buildFooter(fnCode);
|
||||||
|
|
||||||
|
code.push(utils.ident(fnCode));
|
||||||
|
code.push("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuilderC {
|
||||||
|
constructor() {
|
||||||
|
this.hashMaps={};
|
||||||
|
this.componentEntriesTables={};
|
||||||
|
this.sizes ={};
|
||||||
|
this.constants = [];
|
||||||
|
this.functions = [];
|
||||||
|
this.components = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
setHeader(header) {
|
||||||
|
this.header=header;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ht is an array of 256 element that can be undefined or [Hash, Idx, KeyName] elements.
|
||||||
|
addHashMap(name, hm) {
|
||||||
|
this.hashMaps[name] = hm;
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponentEntriesTable(name, cet) {
|
||||||
|
this.componentEntriesTables[name] = cet;
|
||||||
|
}
|
||||||
|
|
||||||
|
addSizes(name, accSizes) {
|
||||||
|
this.sizes[name] = accSizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
addConstant(c) {
|
||||||
|
this.constants.push(c);
|
||||||
|
return this.constants.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
addFunction(fnBuilder) {
|
||||||
|
this.functions.push(fnBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponent(component) {
|
||||||
|
this.components.push(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
setMapIsInput(map) {
|
||||||
|
this.mapIsInput = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWit2Sig(wit2sig) {
|
||||||
|
this.wit2sig = wit2sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
newComponentFunctionBuilder(name, instanceDef) {
|
||||||
|
return new FunctionBuilderC(name, instanceDef, "COMPONENT");
|
||||||
|
}
|
||||||
|
|
||||||
|
newFunctionBuilder(name, instanceDef) {
|
||||||
|
return new FunctionBuilderC(name, instanceDef, "FUNCTION");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Body functions
|
||||||
|
|
||||||
|
_buildHeader(code) {
|
||||||
|
code.push(
|
||||||
|
"#include \"circom.h\"",
|
||||||
|
"#include \"calcwit.h\"",
|
||||||
|
`#define NSignals ${this.header.NSignals}`,
|
||||||
|
`#define NComponents ${this.header.NComponents}`,
|
||||||
|
`#define NOutputs ${this.header.NOutputs}`,
|
||||||
|
`#define NInputs ${this.header.NInputs}`,
|
||||||
|
`#define NVars ${this.header.NVars}`,
|
||||||
|
`#define __P__ "${this.header.P.toString()}"`,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildHashMaps(code) {
|
||||||
|
|
||||||
|
code.push("// Hash Maps ");
|
||||||
|
for (let hmName in this.hashMaps ) {
|
||||||
|
const hm = this.hashMaps[hmName];
|
||||||
|
|
||||||
|
let c = `Circom_HashEntry ${hmName}[256] = {`;
|
||||||
|
for (let i=0; i<256; i++) {
|
||||||
|
c += i>0 ? "," : "";
|
||||||
|
if (hm[i]) {
|
||||||
|
c += `{0x${hm[i][0]}LL, ${hm[i][1]}} /* ${hm[i][2]} */`;
|
||||||
|
} else {
|
||||||
|
c += "{0,0}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c += "};";
|
||||||
|
code.push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildComponentEntriesTables(code) {
|
||||||
|
code.push("// Component Entry tables");
|
||||||
|
for (let cetName in this.componentEntriesTables) {
|
||||||
|
const cet = this.componentEntriesTables[cetName];
|
||||||
|
|
||||||
|
code.push(`Circom_ComponentEntry ${cetName}[${cet.length}] = {`);
|
||||||
|
for (let j=0; j<cet.length; j++) {
|
||||||
|
const ty = cet[j].type == "S" ? "_typeSignal" : "_typeComponent";
|
||||||
|
code.push(` ${j>0?",":" "}{${cet[j].offset},${cet[j].sizeName}, ${ty}}`);
|
||||||
|
}
|
||||||
|
code.push("};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildSizes(code) {
|
||||||
|
code.push("// Sizes");
|
||||||
|
for (let sName in this.sizes) {
|
||||||
|
const accSizes = this.sizes[sName];
|
||||||
|
|
||||||
|
let c = `Circom_Size ${sName}[${accSizes.length}] = {`;
|
||||||
|
for (let i=0; i<accSizes.length; i++) {
|
||||||
|
if (i>0) c += ",";
|
||||||
|
c += accSizes[i];
|
||||||
|
}
|
||||||
|
c += "};";
|
||||||
|
code.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildConstants(code) {
|
||||||
|
const self = this;
|
||||||
|
const n64 = Math.floor((self.header.P.bitLength() - 1) / 64)+1;
|
||||||
|
const R = bigInt.one.shiftLeft(n64*64);
|
||||||
|
|
||||||
|
code.push("// Constants");
|
||||||
|
code.push(`FrElement _constants[${self.constants.length}] = {`);
|
||||||
|
for (let i=0; i<self.constants.length; i++) {
|
||||||
|
code.push((i>0 ? "," : " ") + "{" + number2Code(self.constants[i]) + "}");
|
||||||
|
}
|
||||||
|
code.push("};");
|
||||||
|
|
||||||
|
function number2Code(n) {
|
||||||
|
if (n.lt(bigInt("80000000", 16)) ) {
|
||||||
|
return addShortMontgomeryPositive(n);
|
||||||
|
}
|
||||||
|
if (n.geq(self.header.P.minus(bigInt("80000000", 16))) ) {
|
||||||
|
return addShortMontgomeryNegative(n);
|
||||||
|
}
|
||||||
|
return addLongMontgomery(n);
|
||||||
|
|
||||||
|
|
||||||
|
function addShortMontgomeryPositive(a) {
|
||||||
|
return `${a.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addShortMontgomeryNegative(a) {
|
||||||
|
const b = a.minus(self.header.P);
|
||||||
|
return `${b.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLongMontgomery(a) {
|
||||||
|
return `0, 0xC0000000, { ${getLongString(toMontgomery(a))} }`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLongString(a) {
|
||||||
|
let r = bigInt(a);
|
||||||
|
let S = "";
|
||||||
|
let i = 0;
|
||||||
|
while (!r.isZero()) {
|
||||||
|
if (S!= "") S = S+",";
|
||||||
|
S += "0x" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16) + "LL";
|
||||||
|
i++;
|
||||||
|
r = r.shiftRight(64);
|
||||||
|
}
|
||||||
|
while (i<n64) {
|
||||||
|
if (S!= "") S = S+",";
|
||||||
|
S += "0LL";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMontgomery(a) {
|
||||||
|
return a.times(R).mod(self.header.P);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildFunctions(code) {
|
||||||
|
for (let i=0; i<this.functions.length; i++) {
|
||||||
|
const cfb = this.functions[i];
|
||||||
|
cfb.build(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildComponents(code) {
|
||||||
|
code.push("// Components");
|
||||||
|
code.push(`Circom_Component _components[${this.components.length}] = {`);
|
||||||
|
for (let i=0; i<this.components.length; i++) {
|
||||||
|
const c = this.components[i];
|
||||||
|
const sep = i>0 ? " ," : " ";
|
||||||
|
code.push(`${sep}{${c.hashMapName}, ${c.entryTableName}, ${c.functionName}, ${c.nInSignals}, ${c.newThread}}`);
|
||||||
|
}
|
||||||
|
code.push("};");
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildMapIsInput(code) {
|
||||||
|
code.push("// mapIsInput");
|
||||||
|
code.push(`u32 _mapIsInput[${this.mapIsInput.length}] = {`);
|
||||||
|
let line = "";
|
||||||
|
for (let i=0; i<this.mapIsInput.length; i++) {
|
||||||
|
line += i>0 ? ", " : " ";
|
||||||
|
line += toHex(this.mapIsInput[i]);
|
||||||
|
if (((i+1) % 64)==0) {
|
||||||
|
code.push(" "+line);
|
||||||
|
line = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line != "") code.push(" "+line);
|
||||||
|
code.push("};");
|
||||||
|
|
||||||
|
function toHex(number) {
|
||||||
|
if (number < 0) number = 0xFFFFFFFF + number + 1;
|
||||||
|
let S=number.toString(16).toUpperCase();
|
||||||
|
while (S.length<8) S = "0" + S;
|
||||||
|
return "0x"+S;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildWit2Sig(code) {
|
||||||
|
code.push("// Witness to Signal Table");
|
||||||
|
code.push(`int _wit2sig[${this.wit2sig.length}] = {`);
|
||||||
|
let line = "";
|
||||||
|
for (let i=0; i<this.wit2sig.length; i++) {
|
||||||
|
line += i>0 ? "," : " ";
|
||||||
|
line += this.wit2sig[i];
|
||||||
|
if (((i+1) % 64) == 0) {
|
||||||
|
code.push(" "+line);
|
||||||
|
line = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line != "") code.push(" "+line);
|
||||||
|
code.push("};");
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildCircuitVar(code) {
|
||||||
|
|
||||||
|
code.push(
|
||||||
|
"// Circuit Variable",
|
||||||
|
"Circom_Circuit _circuit = {" ,
|
||||||
|
" NSignals,",
|
||||||
|
" NComponents,",
|
||||||
|
" NInputs,",
|
||||||
|
" NOutputs,",
|
||||||
|
" NVars,",
|
||||||
|
" _wit2sig,",
|
||||||
|
" _components,",
|
||||||
|
" _mapIsInput,",
|
||||||
|
" _constants,",
|
||||||
|
" __P__",
|
||||||
|
"};"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
build() {
|
||||||
|
const code=[];
|
||||||
|
this._buildHeader(code);
|
||||||
|
this._buildSizes(code);
|
||||||
|
this._buildConstants(code);
|
||||||
|
this._buildHashMaps(code);
|
||||||
|
this._buildComponentEntriesTables(code);
|
||||||
|
this._buildFunctions(code);
|
||||||
|
this._buildComponents(code);
|
||||||
|
this._buildMapIsInput(code);
|
||||||
|
this._buildWit2Sig(code);
|
||||||
|
this._buildCircuitVar(code);
|
||||||
|
return streamFromMultiArray(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = BuilderC;
|
||||||
28
src/builder_wasm.js
Normal file
28
src/builder_wasm.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
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;
|
||||||
52
src/buildwasm.js
Normal file
52
src/buildwasm.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
186
src/c_tester.js
Normal file
186
src/c_tester.js
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
var tmp = require("tmp-promise");
|
||||||
|
const path = require("path");
|
||||||
|
const compiler = require("./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;
|
||||||
|
|
||||||
|
module.exports = c_tester;
|
||||||
|
|
||||||
|
|
||||||
|
async function c_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.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");
|
||||||
|
await compiler(circomFile, options);
|
||||||
|
|
||||||
|
const cdir = path.join(__dirname, "..", "c");
|
||||||
|
await exec("cp" +
|
||||||
|
` ${path.join(dir.path, baseName + ".cpp")}` +
|
||||||
|
" /tmp/circuit.cpp"
|
||||||
|
);
|
||||||
|
await exec("g++" +
|
||||||
|
` ${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, baseName + ".cpp")} ` +
|
||||||
|
` -o ${path.join(dir.path, baseName)}` +
|
||||||
|
` -I ${cdir}` +
|
||||||
|
" -lgmp -std=c++11 -DSANITY_CHECK"
|
||||||
|
);
|
||||||
|
|
||||||
|
// console.log(dir.path);
|
||||||
|
return new CTester(dir, baseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CTester {
|
||||||
|
|
||||||
|
constructor(dir, baseName) {
|
||||||
|
this.dir=dir;
|
||||||
|
this.baseName = baseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
async release() {
|
||||||
|
await this.dir.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
async calculateWitness(input) {
|
||||||
|
await fs.promises.writeFile(
|
||||||
|
path.join(this.dir.path, "in.json"),
|
||||||
|
JSON.stringify(stringifyBigInts(input), null, 1)
|
||||||
|
);
|
||||||
|
await exec(`${path.join(this.dir.path, this.baseName)}` +
|
||||||
|
` ${path.join(this.dir.path, "in.json")}` +
|
||||||
|
` ${path.join(this.dir.path, "out.json")}`
|
||||||
|
);
|
||||||
|
const resStr = await fs.promises.readFile(
|
||||||
|
path.join(this.dir.path, "out.json")
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = unstringifyBigInts(JSON.parse(resStr));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
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!=3) continue;
|
||||||
|
this.symbols[arr[2]] = {
|
||||||
|
idx: Number(arr[0]),
|
||||||
|
idxWit: Number(arr[1])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.nWires = r1cs.nWires;
|
||||||
|
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].idxWit]).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].idxWit])) {
|
||||||
|
v = witness[self.symbols[n].idxWit].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.a);
|
||||||
|
const b = evalLC(constraint.b);
|
||||||
|
const c = evalLC(constraint.c);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
451
src/compiler.js
451
src/compiler.js
@@ -17,294 +17,383 @@
|
|||||||
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
along with circom. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const bigInt = require("big-integer");
|
const bigInt = require("big-integer");
|
||||||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||||
const __MASK__ = new bigInt(2).pow(253).minus(1);
|
const sONE = 0;
|
||||||
const assert = require("assert");
|
const build = require("./build");
|
||||||
const gen = require("./gencode");
|
const BuilderC = require("./builder_c");
|
||||||
const exec = require("./exec");
|
const BuilderWasm = require("./builder_wasm");
|
||||||
const lc = require("./lcalgebra");
|
const constructionPhase = require("./construction_phase");
|
||||||
|
const Ctx = require("./ctx");
|
||||||
|
const ZqField = require("fflib").ZqField;
|
||||||
|
const utils = require("./utils");
|
||||||
|
const buildR1cs = require("./r1csfile").buildR1cs;
|
||||||
|
const BigArray = require("./bigarray");
|
||||||
|
|
||||||
module.exports = compile;
|
module.exports = compile;
|
||||||
|
|
||||||
const parser = require("../parser/jaz.js").parser;
|
|
||||||
|
|
||||||
const timeout = ms => new Promise(res => setTimeout(res, ms));
|
|
||||||
|
|
||||||
async function compile(srcFile, options) {
|
async function compile(srcFile, options) {
|
||||||
|
options.p = options.p || __P__;
|
||||||
if (!options) {
|
if (!options) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
if (typeof options.reduceConstraints === "undefined") {
|
if (typeof options.reduceConstraints === "undefined") {
|
||||||
options.reduceConstraints = true;
|
options.reduceConstraints = true;
|
||||||
}
|
}
|
||||||
const fullFileName = srcFile;
|
const ctx = new Ctx();
|
||||||
const fullFilePath = path.dirname(fullFileName);
|
ctx.field = new ZqField(options.p);
|
||||||
|
ctx.verbose= options.verbose || false;
|
||||||
|
ctx.mainComponent = options.mainComponent || "main";
|
||||||
|
ctx.newThreadTemplates = options.newThreadTemplates;
|
||||||
|
|
||||||
const src = fs.readFileSync(fullFileName, "utf8");
|
constructionPhase(ctx, srcFile);
|
||||||
const ast = parser.parse(src);
|
|
||||||
|
|
||||||
assert(ast.type == "BLOCK");
|
console.log("NConstraints Before: "+ctx.constraints.length);
|
||||||
|
|
||||||
const ctx = {
|
if (ctx.error) {
|
||||||
scopes: [{}],
|
throw(ctx.error);
|
||||||
signals: {
|
}
|
||||||
one: {
|
|
||||||
fullName: "one",
|
|
||||||
value: bigInt(1),
|
|
||||||
equivalence: "",
|
|
||||||
direction: ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
currentComponent: "",
|
|
||||||
constraints: [],
|
|
||||||
components: {},
|
|
||||||
templates: {},
|
|
||||||
functions: {},
|
|
||||||
functionParams: {},
|
|
||||||
filePath: fullFilePath,
|
|
||||||
fileName: fullFileName
|
|
||||||
};
|
|
||||||
|
|
||||||
|
if (ctx.getComponentIdx(ctx.mainComponent)<0) {
|
||||||
exec(ctx, ast);
|
|
||||||
|
|
||||||
if (!ctx.components["main"]) {
|
|
||||||
throw new Error("A main component must be defined");
|
throw new Error("A main component must be defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.verbose) console.log("Classify Signals");
|
||||||
classifySignals(ctx);
|
classifySignals(ctx);
|
||||||
|
|
||||||
|
if (ctx.verbose) console.log("Reduce Constants");
|
||||||
reduceConstants(ctx);
|
reduceConstants(ctx);
|
||||||
if (options.reduceConstraints) {
|
if (options.reduceConstraints) {
|
||||||
|
|
||||||
|
if (ctx.verbose) console.log("Reduce Constraints");
|
||||||
// Repeat while reductions are performed
|
// Repeat while reductions are performed
|
||||||
let oldNConstrains = -1;
|
let oldNConstrains = -1;
|
||||||
while (ctx.constraints.length != oldNConstrains) {
|
while (ctx.constraints.length != oldNConstrains) {
|
||||||
|
console.log("Reducing constraints: "+ctx.constraints.length);
|
||||||
oldNConstrains = ctx.constraints.length;
|
oldNConstrains = ctx.constraints.length;
|
||||||
reduceConstrains(ctx);
|
reduceConstrains(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("NConstraints After: "+ctx.constraints.length);
|
||||||
|
|
||||||
generateWitnessNames(ctx);
|
generateWitnessNames(ctx);
|
||||||
|
|
||||||
if (ctx.error) {
|
if (ctx.error) {
|
||||||
throw(ctx.error);
|
throw(ctx.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.scopes = [{}];
|
if (options.cSourceWriteStream) {
|
||||||
|
ctx.builder = new BuilderC();
|
||||||
|
build(ctx);
|
||||||
|
const rdStream = ctx.builder.build();
|
||||||
|
rdStream.pipe(options.cSourceWriteStream);
|
||||||
|
|
||||||
const mainCode = gen(ctx,ast);
|
// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.wasmWriteStream) {
|
||||||
|
ctx.builder = new BuilderWasm();
|
||||||
|
build(ctx);
|
||||||
|
const rdStream = ctx.builder.build();
|
||||||
|
rdStream.pipe(options.wasmWriteStream);
|
||||||
|
|
||||||
|
// await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
|
||||||
|
}
|
||||||
|
|
||||||
|
// const mainCode = gen(ctx,ast);
|
||||||
if (ctx.error) throw(ctx.error);
|
if (ctx.error) throw(ctx.error);
|
||||||
|
|
||||||
const def = buildCircuitDef(ctx, mainCode);
|
if (options.r1csFileName) {
|
||||||
|
await buildR1cs(ctx, options.r1csFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.symWriteStream) {
|
||||||
|
buildSyms(ctx, options.symWriteStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const def = buildCircuitDef(ctx, mainCode);
|
||||||
|
|
||||||
return def;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function classifySignals(ctx) {
|
function classifySignals(ctx) {
|
||||||
|
|
||||||
|
const ERROR = 0xFFFF;
|
||||||
|
|
||||||
function priorize(t1, t2) {
|
function priorize(t1, t2) {
|
||||||
if ((t1 == "error") || (t2=="error")) return "error";
|
if ((t1 == ERROR) || (t2==ERROR)) return ERROR;
|
||||||
if (t1 == "internal") {
|
if (t1 == ctx.stINTERNAL) {
|
||||||
return t2;
|
return t2;
|
||||||
} else if (t2=="internal") {
|
} else if (t2==ctx.stINTERNAL) {
|
||||||
return t1;
|
return t1;
|
||||||
}
|
}
|
||||||
if ((t1 == "one") || (t2 == "one")) return "one";
|
if ((t1 == ctx.stONE) || (t2 == ctx.stONE)) return ctx.stONE;
|
||||||
if ((t1 == "constant") || (t2 == "constant")) return "constant";
|
if ((t1 == ctx.stOUTPUT) || (t2 == ctx.stOUTPUT)) return ctx.stOUTPUT;
|
||||||
if (t1!=t2) return "error";
|
if ((t1 == ctx.stCONSTANT) || (t2 == ctx.stCONSTANT)) return ctx.stCONSTANT;
|
||||||
|
if ((t1 == ctx.stDISCARDED) || (t2 == ctx.stDISCARDED)) return ctx.stDISCARDED;
|
||||||
|
if (t1!=t2) return ERROR;
|
||||||
return t1;
|
return t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First classify the signals
|
// First classify the signals
|
||||||
for (let s in ctx.signals) {
|
for (let s=0; s<ctx.signals.length; s++) {
|
||||||
const signal = ctx.signals[s];
|
const signal = ctx.signals[s];
|
||||||
let tAll = "internal";
|
let tAll = ctx.stINTERNAL;
|
||||||
let lSignal = signal;
|
let lSignal = signal;
|
||||||
let end = false;
|
let end = false;
|
||||||
while (!end) {
|
while (!end) {
|
||||||
let t = lSignal.category || "internal";
|
let t = lSignal.c || ctx.stINTERNAL;
|
||||||
if (s == "one") {
|
if (s == 0) {
|
||||||
t = "one";
|
t = ctx.stONE;
|
||||||
} else if (lSignal.value) {
|
} else if (lSignal.o & ctx.MAIN) {
|
||||||
t = "constant";
|
if (lSignal.o & ctx.IN) {
|
||||||
} else if (lSignal.component=="main") {
|
if (lSignal.o & ctx.PRV) {
|
||||||
if (lSignal.direction == "IN") {
|
t = ctx.stPRVINPUT;
|
||||||
if (lSignal.private) {
|
|
||||||
t = "prvInput";
|
|
||||||
} else {
|
} else {
|
||||||
t = "pubInput";
|
t = ctx.stPUBINPUT;
|
||||||
}
|
}
|
||||||
} else if (lSignal.direction == "OUT") {
|
} else if (lSignal.o & ctx.OUT) {
|
||||||
t = "output";
|
t = ctx.stOUTPUT;
|
||||||
}
|
}
|
||||||
|
} else if (utils.isDefined(lSignal.v)) {
|
||||||
|
t = ctx.stCONSTANT;
|
||||||
}
|
}
|
||||||
tAll = priorize(t,tAll);
|
tAll = priorize(t,tAll);
|
||||||
if (lSignal.equivalence) {
|
if (lSignal.e>=0) {
|
||||||
lSignal = ctx.signals[lSignal.equivalence];
|
lSignal = ctx.signals[lSignal.e];
|
||||||
} else {
|
} else {
|
||||||
end=true;
|
end=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tAll == "error") {
|
if (tAll == ERROR) {
|
||||||
throw new Error("Incompatible types in signal: " + s);
|
throw new Error("Incompatible types in signal: " + s);
|
||||||
}
|
}
|
||||||
lSignal.category = tAll;
|
lSignal.c = tAll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function generateWitnessNames(ctx) {
|
function generateWitnessNames(ctx) {
|
||||||
|
const totals = {};
|
||||||
const totals = {
|
totals[ctx.stONE] = 0;
|
||||||
"output": 0,
|
totals[ctx.stOUTPUT] = 0;
|
||||||
"pubInput": 0,
|
totals[ctx.stPUBINPUT] = 0;
|
||||||
"one": 0,
|
totals[ctx.stPRVINPUT] = 0;
|
||||||
"prvInput": 0,
|
totals[ctx.stINTERNAL] = 0;
|
||||||
"internal": 0,
|
totals[ctx.stDISCARDED] = 0;
|
||||||
"constant": 0,
|
totals[ctx.stCONSTANT] = 0;
|
||||||
};
|
|
||||||
const ids = {};
|
const ids = {};
|
||||||
|
|
||||||
const counted = {};
|
|
||||||
|
|
||||||
// First classify the signals
|
// First classify the signals
|
||||||
for (let s in ctx.signals) {
|
for (let s=0; s<ctx.signals.length; s++) {
|
||||||
|
|
||||||
|
if ((ctx.verbose)&&(s%10000 == 0)) console.log("generate witness (counting): ", s);
|
||||||
|
|
||||||
const signal = ctx.signals[s];
|
const signal = ctx.signals[s];
|
||||||
let lSignal = signal;
|
let lSignal = signal;
|
||||||
while (lSignal.equivalence) lSignal = ctx.signals[lSignal.equivalence];
|
while (lSignal.e>=0) lSignal = ctx.signals[lSignal.e];
|
||||||
|
|
||||||
if (!counted[lSignal.fullName]) {
|
if (!( lSignal.o & ctx.COUNTED) ) {
|
||||||
counted[lSignal.fullName] = true;
|
lSignal.o |= ctx.COUNTED;
|
||||||
totals[lSignal.category] ++;
|
totals[lSignal.c] ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ids["one"] = 0;
|
ids[ctx.stONE] = 0;
|
||||||
ids["output"] = 1;
|
ids[ctx.stOUTPUT] = 1;
|
||||||
ids["pubInput"] = ids["output"] + totals["output"];
|
ids[ctx.stPUBINPUT] = ids[ctx.stOUTPUT] + totals[ctx.stOUTPUT];
|
||||||
ids["prvInput"] = ids["pubInput"] + totals["pubInput"];
|
ids[ctx.stPRVINPUT] = ids[ctx.stPUBINPUT] + totals[ctx.stPUBINPUT];
|
||||||
ids["internal"] = ids["prvInput"] + totals["prvInput"];
|
ids[ctx.stINTERNAL] = ids[ctx.stPRVINPUT] + totals[ctx.stPRVINPUT];
|
||||||
ids["constant"] = ids["internal"] + totals["internal"];
|
ids[ctx.stDISCARDED] = ids[ctx.stINTERNAL] + totals[ctx.stINTERNAL];
|
||||||
const nSignals = ids["constant"] + totals["constant"];
|
ids[ctx.stCONSTANT] = ids[ctx.stDISCARDED] + totals[ctx.stDISCARDED];
|
||||||
|
const nSignals = ids[ctx.stCONSTANT] + totals[ctx.stCONSTANT];
|
||||||
|
|
||||||
ctx.signalNames = new Array(nSignals);
|
for (let s=0; s<ctx.signals.length; s++) {
|
||||||
for (let i=0; i< nSignals; i++) ctx.signalNames[i] = [];
|
|
||||||
ctx.signalName2Idx = {};
|
if ((ctx.verbose)&&(s%10000 == 0)) console.log("seting id: ", s);
|
||||||
|
|
||||||
for (let s in ctx.signals) {
|
|
||||||
const signal = ctx.signals[s];
|
const signal = ctx.signals[s];
|
||||||
let lSignal = signal;
|
let lSignal = signal;
|
||||||
while (lSignal.equivalence) {
|
while (lSignal.e>=0) {
|
||||||
lSignal = ctx.signals[lSignal.equivalence];
|
lSignal = ctx.signals[lSignal.e];
|
||||||
}
|
}
|
||||||
if ( typeof(lSignal.id) === "undefined" ) {
|
if ( typeof(lSignal.id) === "undefined" ) {
|
||||||
lSignal.id = ids[lSignal.category] ++;
|
lSignal.id = ids[lSignal.c] ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
signal.id = lSignal.id;
|
signal.id = lSignal.id;
|
||||||
ctx.signalNames[signal.id].push(signal.fullName);
|
|
||||||
ctx.signalName2Idx[signal.fullName] = signal.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.totals = totals;
|
ctx.totals = totals;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reduceConstants(ctx) {
|
function reduceConstants(ctx) {
|
||||||
const newConstraints = [];
|
const newConstraints = new BigArray();
|
||||||
for (let i=0; i<ctx.constraints.length; i++) {
|
for (let i=0; i<ctx.constraints.length; i++) {
|
||||||
const c = lc.canonize(ctx, ctx.constraints[i]);
|
if ((ctx.verbose)&&(i%10000 == 0)) console.log("reducing constants: ", i);
|
||||||
if (!lc.isZero(c)) {
|
const c = ctx.lc.canonize(ctx, ctx.constraints[i]);
|
||||||
|
if (!ctx.lc.isZero(c)) {
|
||||||
newConstraints.push(c);
|
newConstraints.push(c);
|
||||||
}
|
}
|
||||||
|
delete ctx.constraints[i];
|
||||||
}
|
}
|
||||||
ctx.constraints = newConstraints;
|
ctx.constraints = newConstraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reduceConstrains(ctx) {
|
function reduceConstrains(ctx) {
|
||||||
const newConstraints = [];
|
indexVariables();
|
||||||
for (let i=0; i<ctx.constraints.length; i++) {
|
let possibleConstraints = ctx.constraints;
|
||||||
const c = ctx.constraints[i];
|
let ii=0;
|
||||||
|
while (possibleConstraints.length>0) {
|
||||||
|
let nextPossibleConstraints = new BigArray();
|
||||||
|
for (let i=0; i<possibleConstraints.length; i++) {
|
||||||
|
ii++;
|
||||||
|
if ((ctx.verbose)&&(ii%10000 == 0)) console.log("reducing constraints: ", i);
|
||||||
|
if (!ctx.constraints[i]) continue;
|
||||||
|
const c = ctx.constraints[i];
|
||||||
|
|
||||||
// Swap a and b if b has more variables.
|
// Swap a and b if b has more variables.
|
||||||
if (Object.keys(c.b).length > Object.keys(c.a).length) {
|
if (Object.keys(c.b).length > Object.keys(c.a).length) {
|
||||||
const aux = c.a;
|
const aux = c.a;
|
||||||
c.a=c.b;
|
c.a=c.b;
|
||||||
c.b=aux;
|
c.b=aux;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mov to C if possible.
|
// Mov to C if possible.
|
||||||
if (isConstant(c.a)) {
|
if (isConstant(c.a)) {
|
||||||
const ct = {type: "NUMBER", value: c.a.values["one"]};
|
const ct = {t: "N", v: c.a.coefs[sONE]};
|
||||||
c.c = lc.add(lc.mul(c.b, ct), c.c);
|
c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
|
||||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
c.a = { t: "LC", coefs: {} };
|
||||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
c.b = { t: "LC", coefs: {} };
|
||||||
}
|
}
|
||||||
if (isConstant(c.b)) {
|
if (isConstant(c.b)) {
|
||||||
const ct = {type: "NUMBER", value: c.b.values["one"]};
|
const ct = {t: "N", v: c.b.coefs[sONE]};
|
||||||
c.c = lc.add(lc.mul(c.a, ct), c.c);
|
c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
|
||||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
c.a = { t: "LC", coefs: {} };
|
||||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
c.b = { t: "LC", coefs: {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lc.isZero(c.a) || lc.isZero(c.b)) {
|
if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
|
||||||
const isolatedSignal = getFirstInternalSignal(ctx, c.c);
|
const isolatedSignal = getFirstInternalSignal(ctx, c.c);
|
||||||
if (isolatedSignal) {
|
if (isolatedSignal) {
|
||||||
const isolatedSignalEquivalence = {
|
|
||||||
type: "LINEARCOMBINATION",
|
let lSignal = ctx.signals[isolatedSignal];
|
||||||
values: {}
|
while (lSignal.e>=0) {
|
||||||
};
|
lSignal = ctx.signals[lSignal.e];
|
||||||
const invCoef = c.c.values[isolatedSignal].modInv(__P__);
|
}
|
||||||
for (const s in c.c.values) {
|
|
||||||
if (s != isolatedSignal) {
|
|
||||||
const v = __P__.minus(c.c.values[s]).times(invCoef).mod(__P__);
|
const isolatedSignalEquivalence = {
|
||||||
if (!v.isZero()) {
|
t: "LC",
|
||||||
isolatedSignalEquivalence.values[s] = v;
|
coefs: {}
|
||||||
|
};
|
||||||
|
const invCoef = c.c.coefs[isolatedSignal].modInv(__P__);
|
||||||
|
for (const s in c.c.coefs) {
|
||||||
|
if (s != isolatedSignal) {
|
||||||
|
const v = __P__.minus(c.c.coefs[s]).times(invCoef).mod(__P__);
|
||||||
|
if (!v.isZero()) {
|
||||||
|
isolatedSignalEquivalence.coefs[s] = v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (let j=0; j<newConstraints.length; j++) {
|
for (let j in lSignal.inConstraints) {
|
||||||
newConstraints[j] = lc.substitute(newConstraints[j], isolatedSignal, isolatedSignalEquivalence);
|
if ((j!=i)&&(ctx.constraints[j])) {
|
||||||
|
ctx.constraints[j] = ctx.lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
|
||||||
|
linkSignalsConstraint(j);
|
||||||
|
if (j<i) {
|
||||||
|
nextPossibleConstraints.push(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.constraints[i] = null;
|
||||||
|
|
||||||
|
lSignal.c = ctx.stDISCARDED;
|
||||||
|
} else {
|
||||||
|
if (ctx.lc.isZero(c.c)) ctx.constraints[i] = null;
|
||||||
}
|
}
|
||||||
for (let j=i+1; j<ctx.constraints.length; j++ ) {
|
|
||||||
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
|
|
||||||
}
|
|
||||||
c.a={ type: "LINEARCOMBINATION", values: {} };
|
|
||||||
c.b={ type: "LINEARCOMBINATION", values: {} };
|
|
||||||
c.c={ type: "LINEARCOMBINATION", values: {} };
|
|
||||||
isolatedSignal.category = "constant";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
possibleConstraints = nextPossibleConstraints;
|
||||||
|
}
|
||||||
|
unindexVariables();
|
||||||
|
|
||||||
if (!lc.isZero(c)) {
|
// Pack the constraints
|
||||||
newConstraints.push(c);
|
let o = 0;
|
||||||
|
for (let i=0; i<ctx.constraints.length; i++) {
|
||||||
|
if (ctx.constraints[i]) {
|
||||||
|
if (o != i) {
|
||||||
|
ctx.constraints[o] = ctx.constraints[i];
|
||||||
|
}
|
||||||
|
o++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.constraints = newConstraints;
|
ctx.constraints.length = o;
|
||||||
|
|
||||||
|
function indexVariables() {
|
||||||
|
for (let i=0; i<ctx.constraints.length; i++) linkSignalsConstraint(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkSignalsConstraint(cidx) {
|
||||||
|
const ct = ctx.constraints[cidx];
|
||||||
|
for (let k in ct.a.coefs) linkSignal(k, cidx);
|
||||||
|
for (let k in ct.b.coefs) linkSignal(k, cidx);
|
||||||
|
for (let k in ct.c.coefs) linkSignal(k, cidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unindexVariables() {
|
||||||
|
for (let s=0; s<ctx.signals.length; s++) {
|
||||||
|
let lSignal = ctx.signals[s];
|
||||||
|
while (lSignal.e>=0) {
|
||||||
|
lSignal = ctx.signals[lSignal.e];
|
||||||
|
}
|
||||||
|
if (lSignal.inConstraints) delete lSignal.inConstraints;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function unlinkSignal(signalName, cidx) {
|
||||||
|
let lSignal = ctx.signals[signalName];
|
||||||
|
while (lSignal.e>=0) {
|
||||||
|
lSignal = ctx.signals[lSignal.e];
|
||||||
|
}
|
||||||
|
if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) {
|
||||||
|
delete lSignal.inConstraints[cidx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function linkSignal(signalName, cidx) {
|
||||||
|
let lSignal = ctx.signals[signalName];
|
||||||
|
while (lSignal.e>=0) {
|
||||||
|
lSignal = ctx.signals[lSignal.e];
|
||||||
|
}
|
||||||
|
if (!lSignal.inConstraints) lSignal.inConstraints = {};
|
||||||
|
lSignal.inConstraints[cidx] = true;
|
||||||
|
}
|
||||||
|
|
||||||
function getFirstInternalSignal(ctx, l) {
|
function getFirstInternalSignal(ctx, l) {
|
||||||
for (let k in l.values) {
|
for (let k in l.coefs) {
|
||||||
const signal = ctx.signals[k];
|
const signal = ctx.signals[k];
|
||||||
if (signal.category == "internal") return k;
|
if (signal.c == ctx.stINTERNAL) return k;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isConstant(l) {
|
function isConstant(l) {
|
||||||
for (let k in l.values) {
|
for (let k in l.coefs) {
|
||||||
if ((k != "one") && (!l.values[k].isZero())) return false;
|
if ((k != sONE) && (!l.coefs[k].isZero())) return false;
|
||||||
}
|
}
|
||||||
if (!l.values["one"] || l.values["one"].isZero()) return false;
|
if (!l.coefs[sONE] || l.coefs[sONE].isZero()) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
function buildCircuitDef(ctx, mainCode) {
|
function buildCircuitDef(ctx, mainCode) {
|
||||||
const res = {
|
const res = {
|
||||||
@@ -363,6 +452,9 @@ function buildCircuitDef(ctx, mainCode) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Build constraints
|
Build constraints
|
||||||
|
|
||||||
@@ -384,14 +476,14 @@ is converted to
|
|||||||
A B C
|
A B C
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
function buildConstraints(ctx) {
|
function buildConstraints(ctx) {
|
||||||
const res = [];
|
const res = [];
|
||||||
|
|
||||||
function fillLC(dst, src) {
|
function fillLC(dst, src) {
|
||||||
if (src.type != "LINEARCOMBINATION") throw new Error("Constraint is not a LINEARCOMBINATION");
|
if (src.t != "LC") throw new Error("Constraint is not a LINEARCOMBINATION");
|
||||||
for (let s in src.values) {
|
for (let s in src.coefs) {
|
||||||
const v = src.values[s].toString();
|
const v = src.coefs[s].toString();
|
||||||
const id = ctx.signalName2Idx[s];
|
const id = ctx.signalName2Idx[s];
|
||||||
dst[id] = v;
|
dst[id] = v;
|
||||||
}
|
}
|
||||||
@@ -404,13 +496,52 @@ function buildConstraints(ctx) {
|
|||||||
|
|
||||||
fillLC(A, ctx.constraints[i].a);
|
fillLC(A, ctx.constraints[i].a);
|
||||||
fillLC(B, ctx.constraints[i].b);
|
fillLC(B, ctx.constraints[i].b);
|
||||||
fillLC(C, lc.negate(ctx.constraints[i].c));
|
fillLC(C, ctx.lc.negate(ctx.constraints[i].c));
|
||||||
|
|
||||||
res.push([A,B,C]);
|
res.push([A,B,C]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
function buildSyms(ctx, strm) {
|
||||||
|
|
||||||
|
let nSyms;
|
||||||
|
|
||||||
|
addSymbolsComponent(ctx.mainComponent + ".", ctx.getComponentIdx(ctx.mainComponent));
|
||||||
|
|
||||||
|
|
||||||
|
function addSymbolsComponent(prefix, idComponet) {
|
||||||
|
for (let n in ctx.components[idComponet].names.o) {
|
||||||
|
const entrie = ctx.components[idComponet].names.o[n];
|
||||||
|
addSymbolArray(prefix+n, entrie.type, entrie.sizes, entrie.offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSymbolArray(prefix, type, sizes, offset) {
|
||||||
|
if (sizes.length==0) {
|
||||||
|
if (type == "S") {
|
||||||
|
let s=offset;
|
||||||
|
while (ctx.signals[s].e >= 0) s = ctx.signals[s].e;
|
||||||
|
let wId = ctx.signals[s].id;
|
||||||
|
if (typeof(wId) == "undefined") wId=-1;
|
||||||
|
strm.write(`${offset},${wId},${prefix}\n`);
|
||||||
|
nSyms ++;
|
||||||
|
if ((ctx.verbose)&&(nSyms%10000 == 0)) console.log("Symbols saved: "+nSyms);
|
||||||
|
} else {
|
||||||
|
addSymbolsComponent(prefix+".", offset);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
let acc = 0;
|
||||||
|
for (let i=0; i<sizes[0]; i++) {
|
||||||
|
acc += addSymbolArray(`${prefix}[${i}]`, type, sizes.slice(1), offset + acc );
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1070
src/construction_phase.js
Normal file
1070
src/construction_phase.js
Normal file
File diff suppressed because it is too large
Load Diff
227
src/ctx.js
Normal file
227
src/ctx.js
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
const bigInt = require("big-integer");
|
||||||
|
const BigArray = require("./bigarray.js");
|
||||||
|
|
||||||
|
|
||||||
|
class TableName {
|
||||||
|
constructor (ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.o = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_allocElement(name, _sizes, type) {
|
||||||
|
const sizes = _sizes || [];
|
||||||
|
let l = 1;
|
||||||
|
for (let i=0; i<sizes.length; i++) {
|
||||||
|
l = l*sizes[i];
|
||||||
|
}
|
||||||
|
this.o[name] = {
|
||||||
|
sizes: sizes,
|
||||||
|
type: type
|
||||||
|
};
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
addSignal(name, sizes) {
|
||||||
|
const l = this._allocElement(name, sizes, "S");
|
||||||
|
const o = this.ctx.nSignals;
|
||||||
|
this.o[name].offset = o;
|
||||||
|
this.ctx.nSignals += l;
|
||||||
|
if (l>1) {
|
||||||
|
return [o, o+l];
|
||||||
|
} else {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponent(name, sizes) {
|
||||||
|
const l = this._allocElement(name, sizes, "C");
|
||||||
|
const o = this.ctx.nComponents;
|
||||||
|
this.o[name].offset = o;
|
||||||
|
this.ctx.nComponents += l;
|
||||||
|
if (l>1) {
|
||||||
|
return [o, o+l];
|
||||||
|
} else {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getElement(name, _sels, type) {
|
||||||
|
const sels = _sels || [];
|
||||||
|
const s = this.o[name];
|
||||||
|
if (!s) return -1;
|
||||||
|
if (s.type != type) return -1;
|
||||||
|
if (sels.length > s.sizes.length) return -1;
|
||||||
|
let l=1;
|
||||||
|
for (let i = s.sizes.length-1; i>sels.length; i--) {
|
||||||
|
l = l*s.sizes[i];
|
||||||
|
}
|
||||||
|
let o =0;
|
||||||
|
let p=1;
|
||||||
|
for (let i=sels.length-1; i>=0; i--) {
|
||||||
|
if (sels[i] > s.sizes[i]) return -1; // Out of range
|
||||||
|
if (sels[i] < 0) return -1; // Out of range
|
||||||
|
o += p*sels[i];
|
||||||
|
p *= s.sizes[i];
|
||||||
|
}
|
||||||
|
if (l>1) {
|
||||||
|
return [s.offset + o, s.offset + o + l];
|
||||||
|
} else {
|
||||||
|
return s.offset + o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignalIdx(name, sels) {
|
||||||
|
return this._getElement(name, sels, "S");
|
||||||
|
}
|
||||||
|
|
||||||
|
getComponentIdx(name, sels) {
|
||||||
|
return this._getElement(name, sels, "C");
|
||||||
|
}
|
||||||
|
|
||||||
|
getSizes(name) {
|
||||||
|
return this.o[name].sels;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = class Ctx {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
this.stONE = 1;
|
||||||
|
this.stOUTPUT = 2;
|
||||||
|
this.stPUBINPUT = 3;
|
||||||
|
this.stPRVINPUT = 4;
|
||||||
|
this.stINTERNAL = 5;
|
||||||
|
this.stDISCARDED = 6;
|
||||||
|
this.stCONSTANT = 7;
|
||||||
|
|
||||||
|
this.IN = 0x01;
|
||||||
|
this.OUT = 0x02;
|
||||||
|
this.PRV = 0x04;
|
||||||
|
this.ONE = 0x08;
|
||||||
|
this.MAIN = 0x10;
|
||||||
|
this.COUNTED = 0x20;
|
||||||
|
|
||||||
|
this.scopes = [{}];
|
||||||
|
this.signals = new BigArray();
|
||||||
|
|
||||||
|
this.currentComponent= -1;
|
||||||
|
this.constraints= new BigArray();
|
||||||
|
this.components= new BigArray();
|
||||||
|
this.templates= {};
|
||||||
|
this.functions= {};
|
||||||
|
this.functionParams= {};
|
||||||
|
this.nSignals = 0;
|
||||||
|
this.nComponents =0;
|
||||||
|
this.names = new TableName(this);
|
||||||
|
this.main=false;
|
||||||
|
this.error = null;
|
||||||
|
this.warnings = [];
|
||||||
|
|
||||||
|
const oneIdx = this.addSignal("one");
|
||||||
|
this.signals[oneIdx] = {
|
||||||
|
v: bigInt(1),
|
||||||
|
o: this.ONE,
|
||||||
|
e: -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.uniqueNames = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
addSignal(name, sizes) {
|
||||||
|
if (this.currentComponent>=0) {
|
||||||
|
return this.components[this.currentComponent].names.addSignal(name, sizes);
|
||||||
|
} else {
|
||||||
|
return this.names.addSignal(name, sizes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponent(name, sizes) {
|
||||||
|
if (this.currentComponent>=0) {
|
||||||
|
return this.components[this.currentComponent].names.addComponent(name, sizes);
|
||||||
|
} else {
|
||||||
|
return this.names.addComponent(name, sizes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignalIdx(name, sels) {
|
||||||
|
if (this.currentComponent>=0) {
|
||||||
|
return this.components[this.currentComponent].names.getSignalIdx(name, sels);
|
||||||
|
} else {
|
||||||
|
return this.names.getSignalIdx(name, sels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getComponentIdx(name, sels) {
|
||||||
|
if (this.currentComponent>=0) {
|
||||||
|
return this.components[this.currentComponent].names.getComponentIdx(name, sels);
|
||||||
|
} else {
|
||||||
|
return this.names.getComponentIdx(name, sels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSizes(name) {
|
||||||
|
if (this.currentComponent>=0) {
|
||||||
|
return this.components[this.currentComponent].names.getSizes(name);
|
||||||
|
} else {
|
||||||
|
return this.names.getSizes(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newTableName() {
|
||||||
|
return new TableName(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildErr(ast, errStr) {
|
||||||
|
if (typeof ast == "string") {
|
||||||
|
ast = null;
|
||||||
|
errStr = ast;
|
||||||
|
}
|
||||||
|
if (ast) {
|
||||||
|
return {
|
||||||
|
pos: {
|
||||||
|
first_line: ast.first_line,
|
||||||
|
first_column: ast.first_column,
|
||||||
|
last_line: ast.last_line,
|
||||||
|
last_column: ast.last_column
|
||||||
|
},
|
||||||
|
errStr: errStr,
|
||||||
|
ast: ast,
|
||||||
|
message: errStr,
|
||||||
|
errFile: this.fileName
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
errStr: errStr,
|
||||||
|
message: errStr
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throwError(ast, errStr) {
|
||||||
|
const err = this._buildErr(ast, errStr);
|
||||||
|
this.error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
logWarning(ast, errStr) {
|
||||||
|
const w = this._buildErr(ast, errStr);
|
||||||
|
this.warnings.push(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUniqueName(suggestedName) {
|
||||||
|
if (!suggestedName) {
|
||||||
|
suggestedName = "_tmp";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(this.uniqueNames[suggestedName]) == "undefined") {
|
||||||
|
this.uniqueNames[suggestedName] = 1;
|
||||||
|
return suggestedName;
|
||||||
|
} else {
|
||||||
|
const name = suggestedName + "_" + this.uniqueNames[suggestedName];
|
||||||
|
this.uniqueNames[suggestedName]++;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
1119
src/exec.js
1119
src/exec.js
File diff suppressed because it is too large
Load Diff
@@ -1,70 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
module.exports = genOpt;
|
|
||||||
|
|
||||||
|
|
||||||
function genOpt(ctx, ast) {
|
|
||||||
if (ast.type == "OP") {
|
|
||||||
if (ast.op == "=") {
|
|
||||||
return genOptVarAssignement(ctx, ast);
|
|
||||||
} else {
|
|
||||||
error(ctx, ast, "GENOPT -> Invalid operation: " + ast.op);
|
|
||||||
}
|
|
||||||
} else if (ast.type == "TEMPLATEDEF") {
|
|
||||||
return genOptTemplateDef(ctx, ast);
|
|
||||||
} else {
|
|
||||||
error(ctx, ast, "GENOPT -> Invalid AST node type: " + ast.type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function error(ctx, ast, errStr) {
|
|
||||||
ctx.error = {
|
|
||||||
pos: {
|
|
||||||
first_line: ast.first_line,
|
|
||||||
first_column: ast.first_column,
|
|
||||||
last_line: ast.last_line,
|
|
||||||
last_column: ast.last_column
|
|
||||||
},
|
|
||||||
errStr: errStr,
|
|
||||||
errFile: ctx.fileName,
|
|
||||||
ast: ast
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function genOptTemplateDef(ctx, ast) {
|
|
||||||
if (ctx.templates[ast.name]) {
|
|
||||||
return error(ctx, ast, "Template name already exists: "+ast.name);
|
|
||||||
}
|
|
||||||
ctx.templates[ast.name] = {
|
|
||||||
type: "TEMPLATE",
|
|
||||||
params: ast.params,
|
|
||||||
block: ast.block,
|
|
||||||
fileName: ctx.fileName,
|
|
||||||
filePath: ctx.filePath
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function genOptVarAssignement(ctx, ast) {
|
|
||||||
let varName;
|
|
||||||
if (ast.values[0].type == "DECLARE") {
|
|
||||||
varName = genOptCode(ctx, ast.values[0]);
|
|
||||||
if (ctx.error) return;
|
|
||||||
} else {
|
|
||||||
varName = ast.values[0];
|
|
||||||
}
|
|
||||||
const varContent = getScope(ctx, varName.name, varName.selectors);
|
|
||||||
if (ctx.error) return;
|
|
||||||
|
|
||||||
if ((typeof(varContent) != "object")||(varContent == null)) return error(ctx, ast, "Variable not defined");
|
|
||||||
|
|
||||||
if (varContent.type == "COMPONENT") return genOptInstantiateComponet(ctx, varName, ast.values[1]);
|
|
||||||
if (varContent.type == "SIGNAL") return error(ctx, ast, "Cannot assig to a signal with `=` use <-- or <== ops");
|
|
||||||
|
|
||||||
const res = genOpt(ctx, ast.values[1]);
|
|
||||||
if (ctx.error) return;
|
|
||||||
|
|
||||||
setScope(ctx, varName.name, varName.selectors, res);
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
1571
src/gencode.js
1571
src/gencode.js
File diff suppressed because it is too large
Load Diff
75
src/iterateast.js
Normal file
75
src/iterateast.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
const assert = require("assert");
|
||||||
|
|
||||||
|
module.exports = iterateAST;
|
||||||
|
|
||||||
|
|
||||||
|
function iterateAST(ast, fn, _pfx) {
|
||||||
|
if (!ast) return;
|
||||||
|
|
||||||
|
const pfx = _pfx || "";
|
||||||
|
let itPfx = 0;
|
||||||
|
|
||||||
|
function getPfx() {
|
||||||
|
res = pfx+"."+itPfx;
|
||||||
|
itPfx ++;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let res = fn(ast, pfx);
|
||||||
|
if (res) return res;
|
||||||
|
function iterate(arr) {
|
||||||
|
if (arr) {
|
||||||
|
for (let i=0; i<arr.length; i++) {
|
||||||
|
res = iterateAST(arr[i], fn, getPfx());
|
||||||
|
if (res) return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ast.type == "NUMBER")) {
|
||||||
|
//
|
||||||
|
} else if (ast.type == "VARIABLE") {
|
||||||
|
iterate(ast.selectors);
|
||||||
|
} else if (ast.type == "PIN") {
|
||||||
|
iterate(ast.component.selectors);
|
||||||
|
iterate(ast.pin.selectors);
|
||||||
|
} else if (ast.type == "OP") {
|
||||||
|
iterate(ast.values);
|
||||||
|
} else if (ast.type == "DECLARE") {
|
||||||
|
iterate(ast.name.selectors);
|
||||||
|
} else if (ast.type == "FUNCTIONCALL") {
|
||||||
|
iterate(ast.params);
|
||||||
|
} else if (ast.type == "BLOCK") {
|
||||||
|
iterate(ast.statements);
|
||||||
|
} else if (ast.type == "COMPUTE") {
|
||||||
|
iterateAST(ast.body, fn, getPfx());
|
||||||
|
} else if (ast.type == "FOR") {
|
||||||
|
iterateAST(ast.init, fn, getPfx());
|
||||||
|
iterateAST(ast.condition, fn, getPfx());
|
||||||
|
iterateAST(ast.step, fn, getPfx());
|
||||||
|
iterateAST(ast.body, fn, getPfx());
|
||||||
|
} else if (ast.type == "WHILE") {
|
||||||
|
iterateAST(ast.condition, fn, getPfx());
|
||||||
|
iterateAST(ast.body, fn, getPfx());
|
||||||
|
} else if (ast.type == "IF") {
|
||||||
|
iterateAST(ast.condition, fn, getPfx());
|
||||||
|
iterateAST(ast.then, fn, getPfx());
|
||||||
|
iterateAST(ast.else, fn, getPfx());
|
||||||
|
} else if (ast.type == "RETURN") {
|
||||||
|
iterateAST(ast.value, fn, getPfx());
|
||||||
|
} else if (ast.type == "ARRAY") {
|
||||||
|
iterate(ast.values);
|
||||||
|
} else if ((ast.type == "TEMPLATEDEF")) {
|
||||||
|
//
|
||||||
|
} else if ((ast.type == "FUNCTIONDEF")) {
|
||||||
|
//
|
||||||
|
} else if ((ast.type == "INCLUDE")) {
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
assert(false, "GEN -> Invalid AST iteration: " + ast.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
972
src/lcalgebra.js
972
src/lcalgebra.js
File diff suppressed because it is too large
Load Diff
288
src/r1csfile.js
Normal file
288
src/r1csfile.js
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
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 readU32();
|
||||||
|
if (ht == 1) {
|
||||||
|
if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
|
||||||
|
pHeader = p;
|
||||||
|
headerSize = hl;
|
||||||
|
} else if (ht==2) {
|
||||||
|
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
|
||||||
|
pConstraints = p;
|
||||||
|
constraintsSize = hl;
|
||||||
|
} else if (ht==3) {
|
||||||
|
pMap = p;
|
||||||
|
mapSize = hl;
|
||||||
|
}
|
||||||
|
p += hl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof pHeader == "undefined") assert(false, "File has two header");
|
||||||
|
|
||||||
|
// Read Header
|
||||||
|
p = pHeader;
|
||||||
|
const fieldDefSize = await readU32();
|
||||||
|
const pFieldDef = p;
|
||||||
|
|
||||||
|
const defType = await readU32();
|
||||||
|
if (defType != 1) if (typeof pConstraints != "undefined") assert(false, "Field type not supported");
|
||||||
|
|
||||||
|
res.prime = await readBigInt();
|
||||||
|
|
||||||
|
if ( p != pFieldDef + fieldDefSize) assert("Invalid fieldDef size");
|
||||||
|
|
||||||
|
const bigIntFormat = await readU32();
|
||||||
|
if (bigIntFormat != 0) assert(false, "BigInt format not supported");
|
||||||
|
|
||||||
|
const idSize = await readU32();
|
||||||
|
if (idSize != 4) assert(false, "idSize not supported. Mus be 4");
|
||||||
|
|
||||||
|
res.nWires = await readU32();
|
||||||
|
res.nPubOuts = await readU32();
|
||||||
|
res.nPubIns = await readU32();
|
||||||
|
res.nPrvIns = await readU32();
|
||||||
|
res.nLabels = await readU32();
|
||||||
|
res.nConstraints = await readU32();
|
||||||
|
|
||||||
|
if (p != pHeader + headerSize) assert(false, "Invalid header section size");
|
||||||
|
|
||||||
|
if (loadConstraints) {
|
||||||
|
// Read Constraints
|
||||||
|
p = pConstraints;
|
||||||
|
|
||||||
|
res.constraints = [];
|
||||||
|
for (let i=0; i<res.nConstraints; i++) {
|
||||||
|
const c = await readConstraint();
|
||||||
|
res.constraints.push(c);
|
||||||
|
}
|
||||||
|
if (p != pConstraints + constraintsSize) assert(false, "Invalid constraints size");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Labels
|
||||||
|
|
||||||
|
if (loadMap) {
|
||||||
|
p = pMap;
|
||||||
|
|
||||||
|
res.map = [];
|
||||||
|
for (let i=0; i<res.nLabels; i++) {
|
||||||
|
const idx = await readU32();
|
||||||
|
res.map.push(idx);
|
||||||
|
}
|
||||||
|
if (p != pMap + mapSize) assert(false, "Invalid Map size");
|
||||||
|
}
|
||||||
|
|
||||||
|
await fd.close();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
async function readU32() {
|
||||||
|
const b = Buffer.allocUnsafe(4);
|
||||||
|
await fd.read(b, 0, 4, p);
|
||||||
|
|
||||||
|
p+=4;
|
||||||
|
|
||||||
|
return b.readInt32LE(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readBigInt() {
|
||||||
|
const bl = Buffer.allocUnsafe(1);
|
||||||
|
await fd.read(bl, 0, 1, p);
|
||||||
|
p++;
|
||||||
|
|
||||||
|
const l = bl[0];
|
||||||
|
const b = Buffer.allocUnsafe(l);
|
||||||
|
await fd.read(b, 0, l, p);
|
||||||
|
p += l;
|
||||||
|
|
||||||
|
const arr = Uint8Array.from(b);
|
||||||
|
|
||||||
|
const arrr = new Array(arr.length);
|
||||||
|
for (let i=0; i<arr.length; i++) {
|
||||||
|
arrr[i] = arr[arr.length-1-i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const n = bigInt.fromArray(arrr, 256);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readConstraint() {
|
||||||
|
const c = {};
|
||||||
|
c.a = await readLC();
|
||||||
|
c.b = await readLC();
|
||||||
|
c.c = await readLC();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readLC() {
|
||||||
|
const lc= {};
|
||||||
|
const nIdx = await readU32();
|
||||||
|
for (let i=0; i<nIdx; i++) {
|
||||||
|
const idx = await readU32();
|
||||||
|
const val = await readBigInt();
|
||||||
|
lc[idx] = val;
|
||||||
|
}
|
||||||
|
return lc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildR1cs(ctx, fileName) {
|
||||||
|
|
||||||
|
const fd = await fs.promises.open(fileName, "w");
|
||||||
|
|
||||||
|
|
||||||
|
await fd.write("r1cs"); // Magic "r1cs"
|
||||||
|
|
||||||
|
let p = 4;
|
||||||
|
await writeU32(1); // Version
|
||||||
|
await writeU32(3); // Number of Sections
|
||||||
|
|
||||||
|
// Write the header
|
||||||
|
///////////
|
||||||
|
await writeU32(1); // Header type
|
||||||
|
const pHeaderSize = p;
|
||||||
|
await writeU32(0); // Temporally set to 0 length
|
||||||
|
|
||||||
|
|
||||||
|
// Field Def
|
||||||
|
const pFieldDefSize = p;
|
||||||
|
await writeU32(0); // Temporally set to 0 length
|
||||||
|
await writeU32(1);
|
||||||
|
await writeBigInt(ctx.field.p);
|
||||||
|
const fieldDefSize = p - pFieldDefSize - 4;
|
||||||
|
|
||||||
|
await writeU32(0); // Variable bigInt format
|
||||||
|
await writeU32(4); // Id Size
|
||||||
|
|
||||||
|
const NWires =
|
||||||
|
ctx.totals[ctx.stONE] +
|
||||||
|
ctx.totals[ctx.stOUTPUT] +
|
||||||
|
ctx.totals[ctx.stPUBINPUT] +
|
||||||
|
ctx.totals[ctx.stPRVINPUT] +
|
||||||
|
ctx.totals[ctx.stINTERNAL];
|
||||||
|
|
||||||
|
await writeU32(NWires);
|
||||||
|
await writeU32(ctx.totals[ctx.stOUTPUT]);
|
||||||
|
await writeU32(ctx.totals[ctx.stPUBINPUT]);
|
||||||
|
await writeU32(ctx.totals[ctx.stPRVINPUT]);
|
||||||
|
await writeU32(ctx.signals.length);
|
||||||
|
await writeU32(ctx.constraints.length);
|
||||||
|
|
||||||
|
const headerSize = p - pHeaderSize - 4;
|
||||||
|
|
||||||
|
// Write constraints
|
||||||
|
///////////
|
||||||
|
await writeU32(2); // Constraints type
|
||||||
|
const pConstraintsSize = p;
|
||||||
|
await writeU32(0); // Temporally set to 0 length
|
||||||
|
|
||||||
|
for (let i=0; i<ctx.constraints.length; i++) {
|
||||||
|
if ((ctx.verbose)&&(i%10000 == 0)) {
|
||||||
|
if (ctx.verbose) console.log("writing constraint: ", i);
|
||||||
|
await fd.datasync();
|
||||||
|
}
|
||||||
|
await writeConstraint(ctx.constraints[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const constraintsSize = p - pConstraintsSize - 4;
|
||||||
|
|
||||||
|
// Write map
|
||||||
|
///////////
|
||||||
|
await writeU32(3); // wires2label type
|
||||||
|
const pMapSize = p;
|
||||||
|
await writeU32(0); // Temporally set to 0 length
|
||||||
|
|
||||||
|
|
||||||
|
const arr = new Array(NWires);
|
||||||
|
for (let i=0; i<ctx.signals.length; i++) {
|
||||||
|
const outIdx = ctx.signals[i].id;
|
||||||
|
if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
|
||||||
|
assert(typeof outIdx != "undefined", `Signal ${i} does not have index`);
|
||||||
|
if (outIdx>=NWires) continue; // Is a constant or a discarded variable
|
||||||
|
if (typeof arr[ctx.signals[i].id] == "undefined") {
|
||||||
|
arr[outIdx] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i=0; i<arr.length; i++) {
|
||||||
|
await writeU32(arr[i]);
|
||||||
|
if ((ctx.verbose)&&(i%100000)) console.log("writing label2wire map: ", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapSize = p - pMapSize -4;
|
||||||
|
|
||||||
|
// Write sizes
|
||||||
|
await writeU32(headerSize, pHeaderSize);
|
||||||
|
await writeU32(fieldDefSize, pFieldDefSize);
|
||||||
|
await writeU32(constraintsSize, pConstraintsSize);
|
||||||
|
await writeU32(mapSize, pMapSize);
|
||||||
|
|
||||||
|
await fd.sync();
|
||||||
|
await fd.close();
|
||||||
|
|
||||||
|
async function writeU32(v, pos) {
|
||||||
|
const b = Buffer.allocUnsafe(4);
|
||||||
|
b.writeInt32LE(v);
|
||||||
|
|
||||||
|
await fd.write(b, 0, 4, pos);
|
||||||
|
|
||||||
|
if (typeof(pos) == "undefined") p += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeConstraint(c) {
|
||||||
|
await writeLC(c.a);
|
||||||
|
await writeLC(c.b);
|
||||||
|
await writeLC(ctx.lc.neg(c.c));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeLC(lc) {
|
||||||
|
const idxs = Object.keys(lc.coefs);
|
||||||
|
await writeU32(idxs.length);
|
||||||
|
for (let s in lc.coefs) {
|
||||||
|
let lSignal = ctx.signals[s];
|
||||||
|
|
||||||
|
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
|
||||||
|
|
||||||
|
await writeU32(lSignal.id);
|
||||||
|
await writeBigInt(lc.coefs[s]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeBigInt(n) {
|
||||||
|
|
||||||
|
const bytes = bigInt(n).toArray(256).value.reverse();
|
||||||
|
|
||||||
|
await fd.write(Buffer.from([bytes.length, ...bytes ]));
|
||||||
|
|
||||||
|
p += bytes.length+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/stream_from_multiarray.js
Normal file
52
src/stream_from_multiarray.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
const Readable = require("stream").Readable;
|
||||||
|
|
||||||
|
module.exports = function streamFromMultiarray(ma) {
|
||||||
|
const rs = Readable();
|
||||||
|
|
||||||
|
let curIndex = getFirstIdx(ma);
|
||||||
|
|
||||||
|
rs._read = function() {
|
||||||
|
let res;
|
||||||
|
res = objFromIdx(ma, curIndex);
|
||||||
|
curIndex = nextIdx(curIndex);
|
||||||
|
if (res!=null) {
|
||||||
|
rs.push(res + "\n");
|
||||||
|
} else {
|
||||||
|
rs.push(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return rs;
|
||||||
|
|
||||||
|
|
||||||
|
function getFirstIdx(ma) {
|
||||||
|
if (!Array.isArray(ma)) return [];
|
||||||
|
return [0, ...getFirstIdx(ma[0])];
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextIdx(idx) {
|
||||||
|
if (idx == null) return null;
|
||||||
|
if (idx.length == 0) return null;
|
||||||
|
|
||||||
|
const parentIdx = idx.slice(0,-1);
|
||||||
|
|
||||||
|
const itObj = objFromIdx(ma, parentIdx);
|
||||||
|
const newLastIdx = idx[idx.length-1]+1;
|
||||||
|
if (newLastIdx < itObj.length) {
|
||||||
|
const resIdx = idx.slice();
|
||||||
|
resIdx[resIdx.length-1] = newLastIdx;
|
||||||
|
return [...resIdx, ...getFirstIdx(itObj[newLastIdx])];
|
||||||
|
} else {
|
||||||
|
return nextIdx(parentIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function objFromIdx(ma, idx) {
|
||||||
|
if (idx == null) return null;
|
||||||
|
if (idx.length == 0) return ma;
|
||||||
|
if (ma.length == 0) return "";
|
||||||
|
return objFromIdx(ma[idx[0]], idx.slice(1));
|
||||||
|
}
|
||||||
|
};
|
||||||
134
src/utils.js
Normal file
134
src/utils.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
const fnv = require("fnv-plus");
|
||||||
|
const bigInt = require("big-integer");
|
||||||
|
|
||||||
|
module.exports.ident =ident;
|
||||||
|
|
||||||
|
module.exports.extractSizes =extractSizes;
|
||||||
|
module.exports.flatArray = flatArray;
|
||||||
|
module.exports.csArr = csArr;
|
||||||
|
module.exports.accSizes = accSizes;
|
||||||
|
module.exports.fnvHash = fnvHash;
|
||||||
|
module.exports.stringifyBigInts = stringifyBigInts;
|
||||||
|
module.exports.unstringifyBigInts = unstringifyBigInts;
|
||||||
|
module.exports.sameSizes = sameSizes;
|
||||||
|
module.exports.isDefined = isDefined;
|
||||||
|
module.exports.accSizes2Str = accSizes2Str;
|
||||||
|
|
||||||
|
function ident(text) {
|
||||||
|
if (typeof text === "string") {
|
||||||
|
let lines = text.split("\n");
|
||||||
|
for (let i=0; i<lines.length; i++) {
|
||||||
|
if (lines[i]) lines[i] = " "+lines[i];
|
||||||
|
}
|
||||||
|
return lines.join("\n");
|
||||||
|
} else if (Array.isArray(text)) {
|
||||||
|
for (let i=0; i<text.length; i++ ) {
|
||||||
|
text[i] = ident(text[i]);
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractSizes (o) {
|
||||||
|
if (! Array.isArray(o)) return [];
|
||||||
|
return [o.length, ...extractSizes(o[0])];
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatArray(a) {
|
||||||
|
var res = [];
|
||||||
|
fillArray(res, a);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
function fillArray(res, a) {
|
||||||
|
if (Array.isArray(a)) {
|
||||||
|
for (let i=0; i<a.length; i++) {
|
||||||
|
fillArray(res, a[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.push(bigInt(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input [1,2,3]
|
||||||
|
// Returns " ,1 ,2, 3"
|
||||||
|
function csArr(_arr) {
|
||||||
|
let S = "";
|
||||||
|
const arr = _arr || [];
|
||||||
|
for (let i=0; i<arr.length; i++) {
|
||||||
|
S = " ,"+arr[i];
|
||||||
|
}
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
function accSizes(_sizes) {
|
||||||
|
const sizes = _sizes || [];
|
||||||
|
const accSizes = [1, 0];
|
||||||
|
for (let i=sizes.length-1; i>=0; i--) {
|
||||||
|
accSizes.unshift(accSizes[0]*sizes[i]);
|
||||||
|
}
|
||||||
|
return accSizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fnvHash(str) {
|
||||||
|
return fnv.hash(str, 64).hex();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function stringifyBigInts(o) {
|
||||||
|
if ((typeof(o) == "bigint") || o.isZero !== undefined) {
|
||||||
|
return o.toString(10);
|
||||||
|
} else if (Array.isArray(o)) {
|
||||||
|
return o.map(stringifyBigInts);
|
||||||
|
} else if (typeof o == "object") {
|
||||||
|
const res = {};
|
||||||
|
for (let k in o) {
|
||||||
|
res[k] = stringifyBigInts(o[k]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function unstringifyBigInts(o) {
|
||||||
|
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
|
||||||
|
return bigInt(o);
|
||||||
|
} else if (Array.isArray(o)) {
|
||||||
|
return o.map(unstringifyBigInts);
|
||||||
|
} else if (typeof o == "object") {
|
||||||
|
const res = {};
|
||||||
|
for (let k in o) {
|
||||||
|
res[k] = unstringifyBigInts(o[k]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return bigInt(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sameSizes(s1, s2) {
|
||||||
|
if (!Array.isArray(s1)) return false;
|
||||||
|
if (!Array.isArray(s2)) return false;
|
||||||
|
if (s1.length != s2.length) return false;
|
||||||
|
for (let i=0; i<s1.length; i++) {
|
||||||
|
if (s1[i] != s2[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefined(v) {
|
||||||
|
return ((typeof(v) != "undefined")&&(v != null));
|
||||||
|
}
|
||||||
|
|
||||||
|
function accSizes2Str(sizes) {
|
||||||
|
if (sizes.length == 2) return "";
|
||||||
|
return `[${sizes[0]/sizes[1]}]`+accSizes2Str(sizes.slice(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
343
test/basiccases.js
Normal file
343
test/basiccases.js
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const bigInt = require("big-integer");
|
||||||
|
const c_tester = require("../index.js").c_tester;
|
||||||
|
|
||||||
|
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||||
|
|
||||||
|
|
||||||
|
function normalize(o) {
|
||||||
|
if ((typeof(o) == "bigint") || o.isZero !== undefined) {
|
||||||
|
const res = bigInt(o);
|
||||||
|
return norm(res);
|
||||||
|
} else if (Array.isArray(o)) {
|
||||||
|
return o.map(normalize);
|
||||||
|
} else if (typeof o == "object") {
|
||||||
|
const res = {};
|
||||||
|
for (let k in o) {
|
||||||
|
res[k] = normalize(o[k]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
const res = bigInt(o);
|
||||||
|
return norm(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function norm(n) {
|
||||||
|
let res = n.mod(__P__);
|
||||||
|
if (res.isNegative()) res = __P__.add(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function doTest(circuit, testVectors) {
|
||||||
|
const cir = await c_tester(path.join(__dirname, "circuits", circuit));
|
||||||
|
|
||||||
|
for (let i=0; i<testVectors.length; i++) {
|
||||||
|
const w = await cir.calculateWitness(normalize(testVectors[i][0]));
|
||||||
|
await cir.assertOut(w, normalize(testVectors[i][1]) );
|
||||||
|
}
|
||||||
|
|
||||||
|
await cir.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
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}],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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}],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -59,4 +59,9 @@ describe("Sum test", () => {
|
|||||||
assert(witness[1].equals(bigInt(37)));
|
assert(witness[1].equals(bigInt(37)));
|
||||||
assert(witness[2].equals(bigInt(6)));
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
9
test/circuits/add.circom
Normal file
9
test/circuits/add.circom
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
template Add() {
|
||||||
|
signal input in[2];
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
out <== in[0] + in[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Add();
|
||||||
16
test/circuits/addconst1.circom
Normal file
16
test/circuits/addconst1.circom
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
template AddConst(c) {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
var a = 2;
|
||||||
|
var b = 3;
|
||||||
|
a=a+b;
|
||||||
|
a=a+4;
|
||||||
|
a=a+c;
|
||||||
|
|
||||||
|
out <== 5 + a + in;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It should out <== in + 1+2+3+4+5 = in + 15
|
||||||
|
component main = AddConst(1);
|
||||||
40
test/circuits/arrays.circom
Normal file
40
test/circuits/arrays.circom
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// arr1
|
||||||
|
|
||||||
|
|
||||||
|
function Add3(arr1, arr2, arr3) {
|
||||||
|
var res[3];
|
||||||
|
|
||||||
|
res[0] = arr1;
|
||||||
|
res[1] = 0;
|
||||||
|
for (var i=0; i<2; i += 1) {
|
||||||
|
res[1] = res[1] + arr2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
res[2] = 0;
|
||||||
|
for (var i=0; i<2; i++) {
|
||||||
|
for (var j=0; j<3; j += 1) {
|
||||||
|
res[2] = res[2] + arr3[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out[3];
|
||||||
|
|
||||||
|
var c[3] = Add3(1, [2,3], [[4,5,6], [7,8,9]]); // [1, 5, 39];
|
||||||
|
var d[3] = Add3(in, [in+1, in+2], [[in+1, in+2, in+3], [in+1, in+2, in+3]]);
|
||||||
|
|
||||||
|
out[0] <-- d[0] + c[0];
|
||||||
|
out[0] === in+c[0];
|
||||||
|
|
||||||
|
out[1] <-- d[1]+c[1];
|
||||||
|
out[1] === 2*in+3+c[1];
|
||||||
|
|
||||||
|
out[2] <-- d[2]+c[2];
|
||||||
|
out[2] === 6*in+12+c[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
28
test/circuits/componentarray.circom
Normal file
28
test/circuits/componentarray.circom
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
template Square() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
out <== in*in;
|
||||||
|
}
|
||||||
|
|
||||||
|
template Main(n) {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
component squares[n];
|
||||||
|
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
squares[i] = Square();
|
||||||
|
if (i==0) {
|
||||||
|
squares[i].in <== in;
|
||||||
|
} else {
|
||||||
|
squares[i].in <== squares[i-1].out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
squares[n-1].out ==> out;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main(3);
|
||||||
27
test/circuits/componentarray2.circom
Normal file
27
test/circuits/componentarray2.circom
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
template Square() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
out <== in**2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template Main(n, nrounds) {
|
||||||
|
signal input in[n];
|
||||||
|
signal output out[n];
|
||||||
|
|
||||||
|
component squares[n][nrounds];
|
||||||
|
|
||||||
|
for (var i=0; i<n; i++) {
|
||||||
|
for (var r=0; r<nrounds; r++) {
|
||||||
|
squares[i][r] = Square();
|
||||||
|
if (r==0) {
|
||||||
|
squares[i][r].in <== in[i];
|
||||||
|
} else {
|
||||||
|
squares[i][r].in <== squares[i][r-1].out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
squares[i][nrounds-1].out ==> out[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main(2, 3);
|
||||||
15
test/circuits/condternary.circom
Normal file
15
test/circuits/condternary.circom
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
template CondTernary() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var a = 3;
|
||||||
|
var b = a==3 ? 1 : 2; // b is 1
|
||||||
|
var c = a!=3 ? 10 : 20; // c is 20
|
||||||
|
var d = b+c; // d is 21
|
||||||
|
|
||||||
|
|
||||||
|
out <-- ((in & 1) != 1) ? in + d : in; // Add 21 if in is pair
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = CondTernary()
|
||||||
17
test/circuits/constantcircuit.circom
Normal file
17
test/circuits/constantcircuit.circom
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
template H(x) {
|
||||||
|
signal output out[32];
|
||||||
|
var c[8] = [0x6a09e667,
|
||||||
|
0xbb67ae85,
|
||||||
|
0x3c6ef372,
|
||||||
|
0xa54ff53a,
|
||||||
|
0x510e527f,
|
||||||
|
0x9b05688c,
|
||||||
|
0x1f83d9ab,
|
||||||
|
0x5be0cd19];
|
||||||
|
|
||||||
|
for (var i=0; i<32; i++) {
|
||||||
|
out[i] <== (c[x] >> i) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = H(1);
|
||||||
18
test/circuits/constantinternalcircuit.circom
Normal file
18
test/circuits/constantinternalcircuit.circom
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
template Const() {
|
||||||
|
signal output out[2];
|
||||||
|
|
||||||
|
out[0] <== 2;
|
||||||
|
out[1] <== 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
component const = Const();
|
||||||
|
|
||||||
|
out <== const.out[0] + const.out[1] + in;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
39
test/circuits/constants1.circom
Normal file
39
test/circuits/constants1.circom
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template Add(n) {
|
||||||
|
signal input in[n];
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var lc = 0;
|
||||||
|
for (var i=0; i<n; i++) {
|
||||||
|
lc = lc + in[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
out <== lc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function FAdd(a,b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var o = FAdd(3,4);
|
||||||
|
o = o + FAdd(3,4);
|
||||||
|
o = o + FAdd(3,4); // o = 21
|
||||||
|
|
||||||
|
component A1 = Add(2);
|
||||||
|
A1.in[0] <== in;
|
||||||
|
A1.in[1] <== o;
|
||||||
|
|
||||||
|
component A2 = Add(2);
|
||||||
|
A2.in[0] <== A1.out;
|
||||||
|
A2.in[1] <== o;
|
||||||
|
|
||||||
|
out <== A2.out; // in + 42
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
23
test/circuits/dec.circom
Normal file
23
test/circuits/dec.circom
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out[2];
|
||||||
|
|
||||||
|
// First play with variables;
|
||||||
|
|
||||||
|
var c = 3;
|
||||||
|
var d = c--; // d --> 3
|
||||||
|
var e = --c; // e --> 1
|
||||||
|
|
||||||
|
out[0] <== in + e; // in + 1
|
||||||
|
|
||||||
|
// Then play with signals
|
||||||
|
|
||||||
|
c = in;
|
||||||
|
d = c--; //d <-- in;
|
||||||
|
e = --c; // d <-- in-2
|
||||||
|
|
||||||
|
out[1] <== in + e; // 2*in -2
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
14
test/circuits/forrolled.circom
Normal file
14
test/circuits/forrolled.circom
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
template ForRolled() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var acc = 0;
|
||||||
|
|
||||||
|
for (var i=0; i<in; i = i+1) {
|
||||||
|
acc = acc + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out <== acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = ForRolled();
|
||||||
10
test/circuits/forunrolled.circom
Normal file
10
test/circuits/forunrolled.circom
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
template ForUnrolled(n) {
|
||||||
|
signal input in;
|
||||||
|
signal output out[n];
|
||||||
|
|
||||||
|
for (var i=0; i<n; i = i+1) {
|
||||||
|
out[i] <== in + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = ForUnrolled(3);
|
||||||
12
test/circuits/function1.circom
Normal file
12
test/circuits/function1.circom
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
function func1(a,b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
out <== func1(in, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
13
test/circuits/function2.circom
Normal file
13
test/circuits/function2.circom
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
function fnConst(a,b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var a = fnConst(1,2);
|
||||||
|
out <== in +a;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
26
test/circuits/ifrolled.circom
Normal file
26
test/circuits/ifrolled.circom
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out[3];
|
||||||
|
|
||||||
|
if (in == 0) {
|
||||||
|
out[0] <-- 1; // TRUE
|
||||||
|
}
|
||||||
|
if (in != 0) {
|
||||||
|
out[0] <-- 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in == 1) {
|
||||||
|
out[1] <-- 1; // TRUE
|
||||||
|
} else {
|
||||||
|
out[1] <-- 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in == 2) {
|
||||||
|
out[2] <-- 1;
|
||||||
|
} else {
|
||||||
|
out[2] <-- 0; // TRUE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
31
test/circuits/ifunrolled.circom
Normal file
31
test/circuits/ifunrolled.circom
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out[3];
|
||||||
|
|
||||||
|
var c = 1;
|
||||||
|
if (c == 1) {
|
||||||
|
out[0] <== in +1; // TRUE
|
||||||
|
}
|
||||||
|
if (c == 0) {
|
||||||
|
out[0] <== in +2;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = c +1;
|
||||||
|
if (c == 2) {
|
||||||
|
out[1] <== in + 3; // TRUE
|
||||||
|
} else {
|
||||||
|
out[1] <== in + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = c +1;
|
||||||
|
if (c == 2) {
|
||||||
|
out[2] <== in + 5;
|
||||||
|
} else {
|
||||||
|
out[2] <== in + 6; // TRUE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
1
test/circuits/in.bin
Normal file
1
test/circuits/in.bin
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
test/circuits/in.json
Normal file
1
test/circuits/in.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"in1": 1, "in2": [2,3], "in3":[[4,5], [6,7], [8,9]]}
|
||||||
24
test/circuits/inc.circom
Normal file
24
test/circuits/inc.circom
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out[2];
|
||||||
|
|
||||||
|
// First play with variables;
|
||||||
|
|
||||||
|
var c = 3;
|
||||||
|
var d = c++; // d --> 3
|
||||||
|
var e = ++c; // e --> 5
|
||||||
|
|
||||||
|
out[0] <== in + e; // in + 5
|
||||||
|
|
||||||
|
// Then play with signals
|
||||||
|
|
||||||
|
c = in;
|
||||||
|
d = c++; //d <-- in;
|
||||||
|
e = ++c; // d <-- in+2
|
||||||
|
|
||||||
|
out[1] <== in + e; // 2*in +2
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
|
|
||||||
1
test/circuits/inc.json
Normal file
1
test/circuits/inc.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"x": "3"}
|
||||||
16
test/circuits/include.circom
Normal file
16
test/circuits/include.circom
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
include "included.circom";
|
||||||
|
include "included.circom"; // Include twice is fine. The second one is not included
|
||||||
|
|
||||||
|
template Main() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
component t1 = T1();
|
||||||
|
|
||||||
|
var a = F1(3);
|
||||||
|
|
||||||
|
in ==> t1.in;
|
||||||
|
t1.out + a ==> out; /// out <-- in**2/3+3
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Main();
|
||||||
10
test/circuits/included.circom
Normal file
10
test/circuits/included.circom
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
template T1() {
|
||||||
|
signal input in;
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
out <== in**2/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
function F1(a) {
|
||||||
|
return a**2/3;
|
||||||
|
}
|
||||||
54
test/circuits/inout.circom
Normal file
54
test/circuits/inout.circom
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
template Internal() {
|
||||||
|
signal input in1;
|
||||||
|
signal input in2[2];
|
||||||
|
signal input in3[3][2];
|
||||||
|
|
||||||
|
signal output out1;
|
||||||
|
signal output out2[2];
|
||||||
|
signal output out3[3][2];
|
||||||
|
|
||||||
|
out1 <== in1;
|
||||||
|
out2[0] <== in2[0];
|
||||||
|
out2[1] <== in2[1];
|
||||||
|
|
||||||
|
out3[0][0] <== in3[0][0];
|
||||||
|
out3[0][1] <== in3[0][1];
|
||||||
|
out3[1][0] <== in3[1][0];
|
||||||
|
out3[1][1] <== in3[1][1];
|
||||||
|
out3[2][0] <== in3[2][0];
|
||||||
|
out3[2][1] <== in3[2][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
template InOut() {
|
||||||
|
signal input in1;
|
||||||
|
signal input in2[2];
|
||||||
|
signal input in3[3][2];
|
||||||
|
|
||||||
|
signal output out1;
|
||||||
|
signal output out2[2];
|
||||||
|
signal output out3[3][2];
|
||||||
|
|
||||||
|
component internal = Internal();
|
||||||
|
|
||||||
|
internal.in1 <== in1;
|
||||||
|
internal.in2[0] <== in2[0];
|
||||||
|
internal.in2[1] <== in2[1];
|
||||||
|
internal.in3[0][0] <== in3[0][0];
|
||||||
|
internal.in3[0][1] <== in3[0][1];
|
||||||
|
internal.in3[1][0] <== in3[1][0];
|
||||||
|
internal.in3[1][1] <== in3[1][1];
|
||||||
|
internal.in3[2][0] <== in3[2][0];
|
||||||
|
internal.in3[2][1] <== in3[2][1];
|
||||||
|
|
||||||
|
internal.out1 ==> out1;
|
||||||
|
internal.out2[0] ==> out2[0];
|
||||||
|
internal.out2[1] ==> out2[1];
|
||||||
|
internal.out3[0][0] ==> out3[0][0];
|
||||||
|
internal.out3[0][1] ==> out3[0][1];
|
||||||
|
internal.out3[1][0] ==> out3[1][0];
|
||||||
|
internal.out3[1][1] ==> out3[1][1];
|
||||||
|
internal.out3[2][0] ==> out3[2][0];
|
||||||
|
internal.out3[2][1] ==> out3[2][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = InOut();
|
||||||
12
test/circuits/ops.circom
Normal file
12
test/circuits/ops.circom
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
template Ops() {
|
||||||
|
signal input in[2];
|
||||||
|
signal output add;
|
||||||
|
signal output sub;
|
||||||
|
signal output mul;
|
||||||
|
|
||||||
|
add <-- in[0] + in[1];
|
||||||
|
sub <-- in[0] - in[1];
|
||||||
|
mul <-- in[0] * in[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Ops();
|
||||||
12
test/circuits/ops2.circom
Normal file
12
test/circuits/ops2.circom
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
template Ops2() {
|
||||||
|
signal input in[2];
|
||||||
|
signal output div;
|
||||||
|
signal output idiv;
|
||||||
|
signal output mod;
|
||||||
|
|
||||||
|
div <-- in[0] / in[1];
|
||||||
|
idiv <-- in[0] \ in[1];
|
||||||
|
mod <-- in[0] % in[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Ops2();
|
||||||
12
test/circuits/ops3.circom
Normal file
12
test/circuits/ops3.circom
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
template Ops3() {
|
||||||
|
signal input in[2];
|
||||||
|
signal output neg1;
|
||||||
|
signal output neg2;
|
||||||
|
signal output pow;
|
||||||
|
|
||||||
|
neg1 <-- -in[0];
|
||||||
|
neg2 <-- -in[1];
|
||||||
|
pow <-- in[0] ** in[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Ops3();
|
||||||
18
test/circuits/opsbit.circom
Normal file
18
test/circuits/opsbit.circom
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
template OpsBit() {
|
||||||
|
signal input in[2];
|
||||||
|
signal output and;
|
||||||
|
signal output or;
|
||||||
|
signal output xor;
|
||||||
|
signal output not1;
|
||||||
|
signal output shl;
|
||||||
|
signal output shr;
|
||||||
|
|
||||||
|
and <-- in[0] & in[1];
|
||||||
|
or <-- in[0] | in[1];
|
||||||
|
xor <-- in[0] ^ in[1];
|
||||||
|
not1 <-- ~in[0];
|
||||||
|
shl <-- in[0] << in[1];
|
||||||
|
shr <-- in[0] >> in[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = OpsBit();
|
||||||
18
test/circuits/opscmp.circom
Normal file
18
test/circuits/opscmp.circom
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
template OpsCmp() {
|
||||||
|
signal input in[2];
|
||||||
|
signal output lt;
|
||||||
|
signal output leq;
|
||||||
|
signal output eq;
|
||||||
|
signal output neq;
|
||||||
|
signal output geq;
|
||||||
|
signal output gt;
|
||||||
|
|
||||||
|
lt <-- in[0] < in[1];
|
||||||
|
leq <-- in[0] <= in[1];
|
||||||
|
eq <-- in[0] == in[1];
|
||||||
|
neq <-- in[0] != in[1];
|
||||||
|
geq <-- in[0] >= in[1];
|
||||||
|
gt <-- in[0] > in[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = OpsCmp();
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user