arnaucube
arnaucube/circomPublic Self-hosted repository
Begining of wasm
Jordi Baylina jordi@baylina.cat
Mon, 09 Mar 2020 21:16:56 +0100
commit

8f63d18ff4029ba070d32ee8b6d0bf3d3a88ea53

parent

6c1a3e768773d81f67c0b686a0c6b824e1c537ad

70 files changed, 3910 insertions(+), 1128 deletions(-)

jump to
M c/buildasm/cmpops.asm.ejs → ports/c/buildasm/cmpops_old.asm.ejs

@@ -40,7 +40,7 @@ <% function cmpOp(op) { %>

;;;;;;;;;;;;;;;;;;;;;; ; <%= op %> ;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind +; Compares two elements of any kind ; Params: ; rsi <= Pointer to element 1 ; rdx <= Pointer to element 2
M c/buildasm/copy.asm.ejs → ports/c/buildasm/copy.asm.ejs

@@ -97,6 +97,12 @@ movsx rax, eax

ret <%=name%>_long: + bt rax, 62 + jnc <%=name%>_longNormal +<%=name%>_longMontgomery: + call <%=name%>_toLongNormal + +<%=name%>_longNormal: mov rax, [rdi + 8] mov rcx, rax shr rcx, 31
M c/buildasm/fr.asm → ports/c/buildasm/fr.asm

@@ -46,7 +46,6 @@

- ;;;;;;;;;;;;;;;;;;;;;; ; copy ;;;;;;;;;;;;;;;;;;;;;;

@@ -170,6 +169,12 @@ movsx rax, eax

ret Fr_long: + bt rax, 62 + jnc Fr_longNormal +Fr_longMontgomery: + call Fr_toLongNormal + +Fr_longNormal: mov rax, [rdi + 8] mov rcx, rax shr rcx, 31

@@ -4713,787 +4718,469 @@

- - - - - - - ;;;;;;;;;;;;;;;;;;;;;; -; eq +; rgt - Raw Greater Than ;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind +; returns in ax 1 id *rsi > *rdx ; Params: ; rsi <= Pointer to element 1 ; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. +; rax <= Return 1 or 0 ; Modified Registers: -; r8, r9, 10, r11, rax, rcx +; r8, r9, rax ;;;;;;;;;;;;;;;;;;;;;; -Fr_eq: - sub rsp, 40 ; 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 Fr_sub ; Do a substraction - call Fr_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 eq_longCmp - -eq_shortCmp: - cmp eax, 0 - je eq_s_eq - js eq_s_lt -eq_s_gt: - - mov qword [rdi], 0 - add rsp, 40 - ret - -eq_s_lt: - - mov qword [rdi], 0 - add rsp, 40 - ret - -eq_s_eq: - - mov qword [rdi], 1 - add rsp, 40 - ret - - -eq_longCmp: - - - cmp qword [rsp + 32], 0 - jnz eq_neq - - cmp qword [rsp + 24], 0 - jnz eq_neq - - cmp qword [rsp + 16], 0 - jnz eq_neq - - cmp qword [rsp + 8], 0 - jnz eq_neq - -eq_eq: - - mov qword [rdi], 1 - add rsp, 40 - ret +Fr_rgt: + mov r8, [rsi] + mov r9, [rdx] + bt r8, 63 ; Check if is short first operand + jc rgt_l1 + bt r9, 63 ; Check if is short second operand + jc rgt_s1l2 -eq_neq: +rgt_s1s2: ; Both operands are short + cmp r8d, r9d + jg rgt_ret1 + jmp rgt_ret0 - mov qword [rdi], 0 - add rsp, 40 - ret +rgt_l1: + bt r9, 63 ; Check if is short second operand + jc rgt_l1l2 +;;;;;;;; +rgt_l1s2: + bt r8, 62 ; check if montgomery first + jc rgt_l1ms2 +rgt_l1ns2: + push rdi + push rsi + mov rdi, rdx + movsx rsi, r9d + call rawCopyS2L + mov rdx, rdi + pop rsi + pop rdi + jmp rgtL1L2 +rgt_l1ms2: + push rdi + push rsi + mov rdi, rdx + movsx rsi, r9d + call rawCopyS2L + mov rdx, rdi + pop rsi + pop rdi + push rdi + mov rdi, rsi + mov rsi, rdx + call Fr_toNormal + mov rdx, rsi + mov rsi, rdi + pop rdi + jmp rgtL1L2 -;;;;;;;;;;;;;;;;;;;;;; -; neq -;;;;;;;;;;;;;;;;;;;;;; -; 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 -;;;;;;;;;;;;;;;;;;;;;; -Fr_neq: - sub rsp, 40 ; 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 Fr_sub ; Do a substraction - call Fr_toNormal ; Convert it to normal - pop rdi +;;;;;;;; +rgt_s1l2: + bt r9, 62 ; check if montgomery second + jc rgt_s1l2m +rgt_s1l2n: + push rdi + push rdx + mov rdi, rsi + movsx rsi, r8d + call rawCopyS2L + mov rsi, rdi + pop rdx + pop rdi + jmp rgtL1L2 - mov rax, [rsp] ; We already poped do no need to add 8 - bt rax, 63 ; check is result is long - jc neq_longCmp +rgt_s1l2m: + push rdi + push rdx + mov rdi, rsi + movsx rsi, r8d + call rawCopyS2L + mov rsi, rdi + pop rdx + pop rdi + push rdi + mov rdi, rdx + call Fr_toNormal + mov rdx, rdi + pop rdi + jmp rgtL1L2 -neq_shortCmp: - cmp eax, 0 - je neq_s_eq - js neq_s_lt -neq_s_gt: +;;;; +rgt_l1l2: + bt r8, 62 ; check if montgomery first + jc rgt_l1ml2 +rgt_l1nl2: + bt r9, 62 ; check if montgomery second + jc rgt_l1nl2m +rgt_l1nl2n: + jmp rgtL1L2 - mov qword [rdi], 1 - add rsp, 40 - ret +rgt_l1nl2m: + push rdi + mov rdi, rdx + call Fr_toNormal + mov rdx, rdi + pop rdi + jmp rgtL1L2 -neq_s_lt: +rgt_l1ml2: + bt r9, 62 ; check if montgomery second + jc rgt_l1ml2m +rgt_l1ml2n: + push rdi + mov rdi, rsi + mov rsi, rdx + call Fr_toNormal + mov rdx, rsi + mov rsi, rdi + pop rdi + jmp rgtL1L2 - mov qword [rdi], 1 - add rsp, 40 - ret +rgt_l1ml2m: + push rdi + mov rdi, rsi + mov rsi, rdx + call Fr_toNormal + mov rdx, rsi + mov rsi, rdi + pop rdi + push rdi + mov rdi, rdx + call Fr_toNormal + mov rdx, rdi + pop rdi + jmp rgtL1L2 -neq_s_eq: - mov qword [rdi], 0 - add rsp, 40 - ret +;;;;;; +; rgtL1L2 +;;;;;; +rgtL1L2: -neq_longCmp: + mov rax, [rsi + 32] + cmp [half + 24], rax ; comare with (q-1)/2 + jc rgtl1l2_n1 ; half<rax => e1-e2 is neg => e1 < e2 - cmp qword [rsp + 32], 0 - jnz neq_neq + jnz rgtl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - cmp qword [rsp + 24], 0 - jnz neq_neq - cmp qword [rsp + 16], 0 - jnz neq_neq + mov rax, [rsi + 24] + cmp [half + 16], rax ; comare with (q-1)/2 + jc rgtl1l2_n1 ; half<rax => e1-e2 is neg => e1 < e2 - cmp qword [rsp + 8], 0 - jnz neq_neq + jnz rgtl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 -neq_eq: - mov qword [rdi], 0 - add rsp, 40 - ret + mov rax, [rsi + 16] + cmp [half + 8], rax ; comare with (q-1)/2 + jc rgtl1l2_n1 ; half<rax => e1-e2 is neg => e1 < e2 -neq_neq: + jnz rgtl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - mov qword [rdi], 1 - add rsp, 40 - ret + mov rax, [rsi + 8] + cmp [half + 0], rax ; comare with (q-1)/2 + jc rgtl1l2_n1 ; half<rax => e1-e2 is neg => e1 < e2 + jmp rgtl1l2_p1 -;;;;;;;;;;;;;;;;;;;;;; -; lt -;;;;;;;;;;;;;;;;;;;;;; -; 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 -;;;;;;;;;;;;;;;;;;;;;; -Fr_lt: - sub rsp, 40 ; 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 Fr_sub ; Do a substraction - call Fr_toNormal ; Convert it to normal - pop rdi +rgtl1l2_p1: - mov rax, [rsp] ; We already poped do no need to add 8 - bt rax, 63 ; check is result is long - jc lt_longCmp -lt_shortCmp: - cmp eax, 0 - je lt_s_eq - js lt_s_lt -lt_s_gt: + mov rax, [rdx + 32] + cmp [half + 24], rax ; comare with (q-1)/2 + jc rgt_ret1 ; half<rax => e1-e2 is neg => e1 < e2 - mov qword [rdi], 0 - add rsp, 40 - ret + jnz rgtRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 -lt_s_lt: - mov qword [rdi], 1 - add rsp, 40 - ret + mov rax, [rdx + 24] + cmp [half + 16], rax ; comare with (q-1)/2 + jc rgt_ret1 ; half<rax => e1-e2 is neg => e1 < e2 -lt_s_eq: + jnz rgtRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - mov qword [rdi], 0 - add rsp, 40 - ret + mov rax, [rdx + 16] + cmp [half + 8], rax ; comare with (q-1)/2 + jc rgt_ret1 ; half<rax => e1-e2 is neg => e1 < e2 -lt_longCmp: + jnz rgtRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - cmp qword [rsp + 32], 0 - jnz lt_neq + mov rax, [rdx + 8] + cmp [half + 0], rax ; comare with (q-1)/2 + jc rgt_ret1 ; half<rax => e1-e2 is neg => e1 < e2 - cmp qword [rsp + 24], 0 - jnz lt_neq + jmp rgtRawL1L2 - cmp qword [rsp + 16], 0 - jnz lt_neq - cmp qword [rsp + 8], 0 - jnz lt_neq -lt_eq: +rgtl1l2_n1: - mov qword [rdi], 0 - add rsp, 40 - ret + mov rax, [rdx + 32] + cmp [half + 24], rax ; comare with (q-1)/2 + jc rgtRawL1L2 ; half<rax => e1-e2 is neg => e1 < e2 + jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rdx + 24] + cmp [half + 16], rax ; comare with (q-1)/2 + jc rgtRawL1L2 ; half<rax => e1-e2 is neg => e1 < e2 + jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_29 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_28 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rdx + 16] + cmp [half + 8], rax ; comare with (q-1)/2 + jc rgtRawL1L2 ; half<rax => e1-e2 is neg => e1 < e2 - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_29 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_28 ; half>rax => e1 -e2 is pos => e1 > e2 + jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_29 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_28 ; half>rax => e1 -e2 is pos => e1 > e2 - mov rax, [rsp + 8] + mov rax, [rdx + 8] cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_29 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_28 ; half>rax => e1 -e2 is pos => e1 > e2 + jc rgtRawL1L2 ; half<rax => e1-e2 is neg => e1 < e2 - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_28: + jmp rgt_ret0 - mov qword [rdi], 0 - add rsp, 40 - ret -tmp_29: - mov qword [rdi], 1 - add rsp, 40 - ret -lt_neq: +rgtRawL1L2: + mov rax, [rsi + 32] + cmp [rdx + 32], rax ; comare with (q-1)/2 + jc rgt_ret1 ; rsi<rdi => 1st > 2nd + jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rsi + 24] + cmp [rdx + 24], rax ; comare with (q-1)/2 + jc rgt_ret1 ; rsi<rdi => 1st > 2nd + jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rsi + 16] + cmp [rdx + 16], rax ; comare with (q-1)/2 + jc rgt_ret1 ; rsi<rdi => 1st > 2nd - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_31 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_30 ; half>rax => e1 -e2 is pos => e1 > e2 + jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_31 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_30 ; half>rax => e1 -e2 is pos => e1 > e2 - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_31 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_30 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rsi + 8] + cmp [rdx + 8], rax ; comare with (q-1)/2 + jc rgt_ret1 ; rsi<rdi => 1st > 2nd - mov rax, [rsp + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_31 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_30 ; half>rax => e1 -e2 is pos => e1 > e2 - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_30: - mov qword [rdi], 0 - add rsp, 40 +rgt_ret0: + xor rax, rax ret - -tmp_31: - - mov qword [rdi], 1 - add rsp, 40 +rgt_ret1: + mov rax, 1 ret - - - ;;;;;;;;;;;;;;;;;;;;;; -; gt +; req - Raw Eq ;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind +; returns in ax 1 id *rsi == *rdx ; Params: ; rsi <= Pointer to element 1 ; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. +; rax <= Return 1 or 0 ; Modified Registers: -; r8, r9, 10, r11, rax, rcx +; r8, r9, rax ;;;;;;;;;;;;;;;;;;;;;; -Fr_gt: - sub rsp, 40 ; 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 Fr_sub ; Do a substraction - call Fr_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 gt_longCmp - -gt_shortCmp: - cmp eax, 0 - je gt_s_eq - js gt_s_lt -gt_s_gt: - - mov qword [rdi], 1 - add rsp, 40 - ret - -gt_s_lt: - - mov qword [rdi], 0 - add rsp, 40 - ret - -gt_s_eq: - - mov qword [rdi], 0 - add rsp, 40 - ret - - -gt_longCmp: - - - cmp qword [rsp + 32], 0 - jnz gt_neq - - cmp qword [rsp + 24], 0 - jnz gt_neq - - cmp qword [rsp + 16], 0 - jnz gt_neq - - cmp qword [rsp + 8], 0 - jnz gt_neq - -gt_eq: - - - - mov qword [rdi], 0 - add rsp, 40 - ret +Fr_req: + mov r8, [rsi] + mov r9, [rdx] + bt r8, 63 ; Check if is short first operand + jc req_l1 + bt r9, 63 ; Check if is short second operand + jc req_s1l2 +req_s1s2: ; Both operands are short + cmp r8d, r9d + je req_ret1 + jmp req_ret0 +req_l1: + bt r9, 63 ; Check if is short second operand + jc req_l1l2 +;;;;;;;; +req_l1s2: + bt r8, 62 ; check if montgomery first + jc req_l1ms2 +req_l1ns2: + push rdi + push rsi + mov rdi, rdx + movsx rsi, r9d + call rawCopyS2L + mov rdx, rdi + pop rsi + pop rdi + jmp reqL1L2 - - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_33 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_32 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_33 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_32 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_33 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_32 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_33 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_32 ; half>rax => e1 -e2 is pos => e1 > e2 +req_l1ms2: + push rdi + mov rdi, rdx + call Fr_toMontgomery + mov rdx, rdi + pop rdi + jmp reqL1L2 - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_32: - - mov qword [rdi], 1 - add rsp, 40 - ret - -tmp_33: - - mov qword [rdi], 0 - add rsp, 40 - ret +;;;;;;;; +req_s1l2: + bt r9, 62 ; check if montgomery second + jc req_s1l2m +req_s1l2n: + push rdi + push rdx + mov rdi, rsi + movsx rsi, r8d + call rawCopyS2L + mov rsi, rdi + pop rdx + pop rdi + jmp reqL1L2 -gt_neq: +req_s1l2m: + push rdi + mov rdi, rsi + mov rsi, rdx + call Fr_toMontgomery + mov rdx, rsi + mov rsi, rdi + pop rdi + jmp reqL1L2 +;;;; +req_l1l2: + bt r8, 62 ; check if montgomery first + jc req_l1ml2 +req_l1nl2: + bt r9, 62 ; check if montgomery second + jc req_l1nl2m +req_l1nl2n: + jmp reqL1L2 +req_l1nl2m: + push rdi + mov rdi, rsi + mov rsi, rdx + call Fr_toMontgomery + mov rdx, rsi + mov rsi, rdi + pop rdi + jmp reqL1L2 +req_l1ml2: + bt r9, 62 ; check if montgomery second + jc req_l1ml2m +req_l1ml2n: + push rdi + mov rdi, rdx + call Fr_toMontgomery + mov rdx, rdi + pop rdi + jmp reqL1L2 +req_l1ml2m: + jmp reqL1L2 +;;;;;; +; eqL1L2 +;;;;;; +reqL1L2: - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_35 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_34 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rsi + 8] + cmp [rdx + 8], rax + jne req_ret0 ; rsi<rdi => 1st > 2nd - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_35 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_34 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rsi + 16] + cmp [rdx + 16], rax + jne req_ret0 ; rsi<rdi => 1st > 2nd - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_35 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_34 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rsi + 24] + cmp [rdx + 24], rax + jne req_ret0 ; rsi<rdi => 1st > 2nd - mov rax, [rsp + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_35 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_34 ; half>rax => e1 -e2 is pos => e1 > e2 + mov rax, [rsi + 32] + cmp [rdx + 32], rax + jne req_ret0 ; rsi<rdi => 1st > 2nd - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_34: - mov qword [rdi], 1 - add rsp, 40 +req_ret1: + mov rax, 1 ret -tmp_35: - - mov qword [rdi], 0 - add rsp, 40 +req_ret0: + xor rax, rax ret - - - - ;;;;;;;;;;;;;;;;;;;;;; -; leq +; gt ;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind +; Compares 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 +; rax, rcx ;;;;;;;;;;;;;;;;;;;;;; -Fr_leq: - sub rsp, 40 ; 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 Fr_sub ; Do a substraction - call Fr_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 leq_longCmp - -leq_shortCmp: - cmp eax, 0 - je leq_s_eq - js leq_s_lt -leq_s_gt: - - mov qword [rdi], 0 - add rsp, 40 - ret - -leq_s_lt: - - mov qword [rdi], 1 - add rsp, 40 - ret - -leq_s_eq: - - mov qword [rdi], 1 - add rsp, 40 - ret - - -leq_longCmp: - - - cmp qword [rsp + 32], 0 - jnz leq_neq - - cmp qword [rsp + 24], 0 - jnz leq_neq - - cmp qword [rsp + 16], 0 - jnz leq_neq - - cmp qword [rsp + 8], 0 - jnz leq_neq - -leq_eq: - - - - mov qword [rdi], 1 - add rsp, 40 - ret - - - - - - - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_37 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_36 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_37 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_36 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_37 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_36 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_37 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_36 ; half>rax => e1 -e2 is pos => e1 > e2 - - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_36: - - mov qword [rdi], 0 - add rsp, 40 - ret - -tmp_37: - - mov qword [rdi], 1 - add rsp, 40 - ret - - -leq_neq: - - - - - - - - - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_39 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_38 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_39 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_38 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_39 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_38 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_39 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_38 ; half>rax => e1 -e2 is pos => e1 > e2 - - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_38: - - mov qword [rdi], 0 - add rsp, 40 +Fr_gt: + call Fr_rgt + mov [rdi], rax ret -tmp_39: - - mov qword [rdi], 1 - add rsp, 40 - ret - - - - - - ;;;;;;;;;;;;;;;;;;;;;; -; geq +; eq ;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind +; Compares 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 +; rax, rcx ;;;;;;;;;;;;;;;;;;;;;; -Fr_geq: - sub rsp, 40 ; 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 Fr_sub ; Do a substraction - call Fr_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 geq_longCmp - -geq_shortCmp: - cmp eax, 0 - je geq_s_eq - js geq_s_lt -geq_s_gt: - - mov qword [rdi], 1 - add rsp, 40 - ret - -geq_s_lt: - - mov qword [rdi], 0 - add rsp, 40 - ret - -geq_s_eq: - - mov qword [rdi], 1 - add rsp, 40 - ret - - -geq_longCmp: - - - cmp qword [rsp + 32], 0 - jnz geq_neq - - cmp qword [rsp + 24], 0 - jnz geq_neq - - cmp qword [rsp + 16], 0 - jnz geq_neq - - cmp qword [rsp + 8], 0 - jnz geq_neq - -geq_eq: - - - - mov qword [rdi], 1 - add rsp, 40 - ret - - - - - - - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_41 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_40 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_41 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_40 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_41 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_40 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_41 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_40 ; half>rax => e1 -e2 is pos => e1 > e2 - - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_40: - - mov qword [rdi], 1 - add rsp, 40 +Fr_eq: + call Fr_req + mov [rdi], rax ret -tmp_41: - - mov qword [rdi], 0 - add rsp, 40 - ret - - -geq_neq: - - - - - - - - - mov rax, [rsp + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc tmp_43 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_42 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc tmp_43 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_42 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc tmp_43 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_42 ; half>rax => e1 -e2 is pos => e1 > e2 - - mov rax, [rsp + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc tmp_43 ; half<rax => e1-e2 is neg => e1 < e2 - jnz tmp_42 ; half>rax => e1 -e2 is pos => e1 > e2 - - ; half == rax => e1-e2 is pos => e1 > e2 -tmp_42: - - mov qword [rdi], 1 - add rsp, 40 - ret - -tmp_43: - - mov qword [rdi], 0 - add rsp, 40 - ret - - - - - - +Fr_geq: +Fr_leq: +Fr_lt: +Fr_neq:

@@ -5525,39 +5212,39 @@

mov rax, [rsi] bt rax, 63 - jc tmp_44 + jc tmp_28 test eax, eax - jz retZero_46 - jmp retOne_45 + jz retZero_30 + jmp retOne_29 -tmp_44: +tmp_28: mov rax, [rsi + 8] test rax, rax - jnz retOne_45 + jnz retOne_29 mov rax, [rsi + 16] test rax, rax - jnz retOne_45 + jnz retOne_29 mov rax, [rsi + 24] test rax, rax - jnz retOne_45 + jnz retOne_29 mov rax, [rsi + 32] test rax, rax - jnz retOne_45 + jnz retOne_29 -retZero_46: +retZero_30: mov qword r8, 0 - jmp done_47 + jmp done_31 -retOne_45: +retOne_29: mov qword r8, 1 -done_47: +done_31:

@@ -5567,39 +5254,39 @@

mov rax, [rdx] bt rax, 63 - jc tmp_48 + jc tmp_32 test eax, eax - jz retZero_50 - jmp retOne_49 + jz retZero_34 + jmp retOne_33 -tmp_48: +tmp_32: mov rax, [rdx + 8] test rax, rax - jnz retOne_49 + jnz retOne_33 mov rax, [rdx + 16] test rax, rax - jnz retOne_49 + jnz retOne_33 mov rax, [rdx + 24] test rax, rax - jnz retOne_49 + jnz retOne_33 mov rax, [rdx + 32] test rax, rax - jnz retOne_49 + jnz retOne_33 -retZero_50: +retZero_34: mov qword rcx, 0 - jmp done_51 + jmp done_35 -retOne_49: +retOne_33: mov qword rcx, 1 -done_51: +done_35: and rcx, r8 mov [rdi], rcx

@@ -5626,39 +5313,39 @@

mov rax, [rsi] bt rax, 63 - jc tmp_52 + jc tmp_36 test eax, eax - jz retZero_54 - jmp retOne_53 + jz retZero_38 + jmp retOne_37 -tmp_52: +tmp_36: mov rax, [rsi + 8] test rax, rax - jnz retOne_53 + jnz retOne_37 mov rax, [rsi + 16] test rax, rax - jnz retOne_53 + jnz retOne_37 mov rax, [rsi + 24] test rax, rax - jnz retOne_53 + jnz retOne_37 mov rax, [rsi + 32] test rax, rax - jnz retOne_53 + jnz retOne_37 -retZero_54: +retZero_38: mov qword r8, 0 - jmp done_55 + jmp done_39 -retOne_53: +retOne_37: mov qword r8, 1 -done_55: +done_39:

@@ -5668,39 +5355,39 @@

mov rax, [rdx] bt rax, 63 - jc tmp_56 + jc tmp_40 test eax, eax - jz retZero_58 - jmp retOne_57 + jz retZero_42 + jmp retOne_41 -tmp_56: +tmp_40: mov rax, [rdx + 8] test rax, rax - jnz retOne_57 + jnz retOne_41 mov rax, [rdx + 16] test rax, rax - jnz retOne_57 + jnz retOne_41 mov rax, [rdx + 24] test rax, rax - jnz retOne_57 + jnz retOne_41 mov rax, [rdx + 32] test rax, rax - jnz retOne_57 + jnz retOne_41 -retZero_58: +retZero_42: mov qword rcx, 0 - jmp done_59 + jmp done_43 -retOne_57: +retOne_41: mov qword rcx, 1 -done_59: +done_43: or rcx, r8 mov [rdi], rcx

@@ -5726,39 +5413,39 @@

mov rax, [rsi] bt rax, 63 - jc tmp_60 + jc tmp_44 test eax, eax - jz retZero_62 - jmp retOne_61 + jz retZero_46 + jmp retOne_45 -tmp_60: +tmp_44: mov rax, [rsi + 8] test rax, rax - jnz retOne_61 + jnz retOne_45 mov rax, [rsi + 16] test rax, rax - jnz retOne_61 + jnz retOne_45 mov rax, [rsi + 24] test rax, rax - jnz retOne_61 + jnz retOne_45 mov rax, [rsi + 32] test rax, rax - jnz retOne_61 + jnz retOne_45 -retZero_62: +retZero_46: mov qword rcx, 0 - jmp done_63 + jmp done_47 -retOne_61: +retOne_45: mov qword rcx, 1 -done_63: +done_47: test rcx, rcx

@@ -5789,39 +5476,39 @@

mov rax, [rdi] bt rax, 63 - jc tmp_64 + jc tmp_48 test eax, eax - jz retZero_66 - jmp retOne_65 + jz retZero_50 + jmp retOne_49 -tmp_64: +tmp_48: mov rax, [rdi + 8] test rax, rax - jnz retOne_65 + jnz retOne_49 mov rax, [rdi + 16] test rax, rax - jnz retOne_65 + jnz retOne_49 mov rax, [rdi + 24] test rax, rax - jnz retOne_65 + jnz retOne_49 mov rax, [rdi + 32] test rax, rax - jnz retOne_65 + jnz retOne_49 -retZero_66: +retZero_50: mov qword rax, 0 - jmp done_67 + jmp done_51 -retOne_65: +retOne_49: mov qword rax, 1 -done_67: +done_51: ret
M c/buildasm/fr.c → ports/c/buildasm/fr.c

@@ -63,7 +63,6 @@ return r;

} else { mpz_init_set_si(r, pE->shortVal); mpz_add(r, r, q); - mpz_clear(q); } } else { Fr_toNormal(pE);
M c/buildasm/utils.asm.ejs → ports/c/buildasm/utils.asm.ejs

@@ -70,4 +70,3 @@ pop rsi

pop rdi`); } %> -
M c/calcwit.cpp → ports/c/calcwit.cpp

@@ -63,6 +63,8 @@ #endif

for (int i=0; i<circuit->NComponents; i++) { inputSignalsToTrigger[i] = circuit->components[i].inputSignals; + } + for (int i=0; i<circuit->NComponents; i++) { if (inputSignalsToTrigger[i] == 0) triggerComponent(i); } }

@@ -171,6 +173,9 @@ if ( BITMAP_ISSET(circuit->mapIsInput, sIdx) ) {

if (inputSignalsToTrigger[cIdx]>0) { inputSignalsToTrigger[cIdx]--; if (inputSignalsToTrigger[cIdx] == 0) triggerComponent(cIdx); + } else { + fprintf(stderr, "Input signals does not match with map: %d\n", sIdx); + assert(false); } }
M cli.js → cli.js

@@ -34,6 +34,7 @@ .usage("circom [input source circuit file] -o [output definition circuit file] -c [output c file]")

.alias("o", "output") .alias("c", "csource") .alias("w", "wasm") + .alias("t", "wat") .alias("s", "sym") .alias("r", "r1cs") .alias("n", "newThreadTemplates")

@@ -71,6 +72,7 @@ const fullFileName = path.resolve(process.cwd(), inputFile);

const fileName = path.basename(fullFileName, ".circom"); const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp"; const wasmName = typeof(argv.wasm) === "string" ? argv.wasm : fileName + ".wasm"; +const watName = typeof(argv.wat) === "string" ? argv.wat : fileName + ".wat"; const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs"; const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym";

@@ -83,6 +85,9 @@ }

if (argv.wasm) { options.wasmWriteStream = fs.createWriteStream(wasmName); } +if (argv.wat) { + options.watWriteStream = fs.createWriteStream(watName); +} if (argv.r1cs) { options.r1csFileName = r1csName; }

@@ -97,6 +102,7 @@ compiler(fullFileName, options).then( () => {

let cSourceDone = false; let wasmDone = false; let symDone = false; + let watDone = false; if (options.cSourceWriteStream) { options.cSourceWriteStream.on("finish", () => { cSourceDone = true;

@@ -113,6 +119,14 @@ });

} else { wasmDone = true; } + if (options.watWriteStream) { + options.watWriteStream.on("finish", () => { + watDone = true; + finishIfDone(); + }); + } else { + watDone = true; + } if (options.symWriteStream) { options.symWriteStream.on("finish", () => { symDone = true;

@@ -122,7 +136,7 @@ } else {

symDone = true; } function finishIfDone() { - if ((cSourceDone)&&(symDone)&&(wasmDone)) { + if ((cSourceDone)&&(symDone)&&(wasmDone)&&(watDone)) { setTimeout(() => { process.exit(0); }, 300);
M index.js → index.js

@@ -1,3 +1,3 @@

module.exports.compiler = require("./src/compiler.js"); -module.exports.c_tester = require("./src/c_tester.js"); -module.exports.tester = require("./src/c_tester.js"); +module.exports.c_tester = require("./ports/c/tester.js"); +module.exports.wasm_tester = require("./ports/wasm/tester.js");
M package-lock.json → package-lock.json

@@ -1482,6 +1482,14 @@ "requires": {

"punycode": "^2.1.0" } }, + "wasmbuilder": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.8.tgz", + "integrity": "sha512-d63cIsDmHnybA5hTlRRLadgys5r3Tl4W8SbcBRh13FauEPOo48dqjgzdL1xefpZkpKKybDRlFqgm+9cX04B3+w==", + "requires": { + "big-integer": "^1.6.43" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
M package.json → package.json

@@ -36,6 +36,7 @@ "fnv-plus": "^1.3.1",

"optimist": "^0.6.1", "rimraf-promise": "^2.0.0", "tmp-promise": "^2.0.2", + "wasmbuilder": "0.0.8", "yargs": "^12.0.2" }, "devDependencies": {
A ports/c/buildasm/cmpops.asm.ejs

@@ -0,0 +1,439 @@

+<% function signL(reg, label_pos, label_neg) { %> +<% for (let i=n64-1; i>=0; i--) { %> + mov rax, [<%=reg%> + <%= 8+(i*8) %>] + cmp [half + <%= (i*8) %>], rax ; comare with (q-1)/2 + jc <%=label_neg%> ; half<rax => e1-e2 is neg => e1 < e2 +<% if (i>0) { %> + jnz <%=label_pos%> ; half>rax => e1 -e2 is pos => e1 > e2 +<% } else { %> + jmp <%=label_pos%> +<% } %> +<% } %> +<% } %> + + +;;;;;;;;;;;;;;;;;;;;;; +; rgt - Raw Greater Than +;;;;;;;;;;;;;;;;;;;;;; +; returns in ax 1 id *rsi > *rdx +; Params: +; rsi <= Pointer to element 1 +; rdx <= Pointer to element 2 +; rax <= Return 1 or 0 +; Modified Registers: +; r8, r9, rax +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_rgt: + mov r8, [rsi] + mov r9, [rdx] + bt r8, 63 ; Check if is short first operand + jc rgt_l1 + bt r9, 63 ; Check if is short second operand + jc rgt_s1l2 + +rgt_s1s2: ; Both operands are short + cmp r8d, r9d + jg rgt_ret1 + jmp rgt_ret0 + + +rgt_l1: + bt r9, 63 ; Check if is short second operand + jc rgt_l1l2 + +;;;;;;;; +rgt_l1s2: + bt r8, 62 ; check if montgomery first + jc rgt_l1ms2 +rgt_l1ns2: +<%= global.toLong_b() %> + jmp rgtL1L2 + +rgt_l1ms2: +<%= global.toLong_b() %> +<%= global.fromMont_a() %> + jmp rgtL1L2 + + +;;;;;;;; +rgt_s1l2: + bt r9, 62 ; check if montgomery second + jc rgt_s1l2m +rgt_s1l2n: +<%= global.toLong_a() %> + jmp rgtL1L2 + +rgt_s1l2m: +<%= global.toLong_a() %> +<%= global.fromMont_b() %> + jmp rgtL1L2 + +;;;; +rgt_l1l2: + bt r8, 62 ; check if montgomery first + jc rgt_l1ml2 +rgt_l1nl2: + bt r9, 62 ; check if montgomery second + jc rgt_l1nl2m +rgt_l1nl2n: + jmp rgtL1L2 + +rgt_l1nl2m: +<%= global.fromMont_b() %> + jmp rgtL1L2 + +rgt_l1ml2: + bt r9, 62 ; check if montgomery second + jc rgt_l1ml2m +rgt_l1ml2n: +<%= global.fromMont_a() %> + jmp rgtL1L2 + +rgt_l1ml2m: +<%= global.fromMont_a() %> +<%= global.fromMont_b() %> + jmp rgtL1L2 + + +;;;;;; +; rgtL1L2 +;;;;;; + +rgtL1L2: +<%= signL("rsi", "rgtl1l2_p1", "rgtl1l2_n1") %> +rgtl1l2_p1: +<%= signL("rdx", "rgtRawL1L2", "rgt_ret1") %> + +rgtl1l2_n1: +<%= signL("rdx", "rgt_ret0", "rgtRawL1L2") %> + + +rgtRawL1L2: +<% for (let i=n64-1; i>=0; i--) { %> + mov rax, [rsi + <%= 8+(i*8) %>] + cmp [rdx + <%= 8+(i*8) %>], rax ; comare with (q-1)/2 + jc rgt_ret1 ; rsi<rdx => 1st > 2nd +<% if (i>0) { %> + jnz rgt_ret0 +<% } %> +<% } %> + +rgt_ret0: + xor rax, rax + ret +rgt_ret1: + mov rax, 1 + ret + + + +;;;;;;;;;;;;;;;;;;;;;; +; rlt - Raw Less Than +;;;;;;;;;;;;;;;;;;;;;; +; returns in ax 1 id *rsi > *rdx +; Params: +; rsi <= Pointer to element 1 +; rdx <= Pointer to element 2 +; rax <= Return 1 or 0 +; Modified Registers: +; r8, r9, rax +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_rlt: + mov r8, [rsi] + mov r9, [rdx] + bt r8, 63 ; Check if is short first operand + jc rlt_l1 + bt r9, 63 ; Check if is short second operand + jc rlt_s1l2 + +rlt_s1s2: ; Both operands are short + cmp r8d, r9d + jl rlt_ret1 + jmp rlt_ret0 + + +rlt_l1: + bt r9, 63 ; Check if is short second operand + jc rlt_l1l2 + +;;;;;;;; +rlt_l1s2: + bt r8, 62 ; check if montgomery first + jc rlt_l1ms2 +rlt_l1ns2: +<%= global.toLong_b() %> + jmp rltL1L2 + +rlt_l1ms2: +<%= global.toLong_b() %> +<%= global.fromMont_a() %> + jmp rltL1L2 + + +;;;;;;;; +rlt_s1l2: + bt r9, 62 ; check if montgomery second + jc rlt_s1l2m +rlt_s1l2n: +<%= global.toLong_a() %> + jmp rltL1L2 + +rlt_s1l2m: +<%= global.toLong_a() %> +<%= global.fromMont_b() %> + jmp rltL1L2 + +;;;; +rlt_l1l2: + bt r8, 62 ; check if montgomery first + jc rlt_l1ml2 +rlt_l1nl2: + bt r9, 62 ; check if montgomery second + jc rlt_l1nl2m +rlt_l1nl2n: + jmp rltL1L2 + +rlt_l1nl2m: +<%= global.fromMont_b() %> + jmp rltL1L2 + +rlt_l1ml2: + bt r9, 62 ; check if montgomery second + jc rlt_l1ml2m +rlt_l1ml2n: +<%= global.fromMont_a() %> + jmp rltL1L2 + +rlt_l1ml2m: +<%= global.fromMont_a() %> +<%= global.fromMont_b() %> + jmp rltL1L2 + + +;;;;;; +; rltL1L2 +;;;;;; + +rltL1L2: +<%= signL("rsi", "rltl1l2_p1", "rltl1l2_n1") %> +rltl1l2_p1: +<%= signL("rdx", "rltRawL1L2", "rlt_ret0") %> + +rltl1l2_n1: +<%= signL("rdx", "rlt_ret1", "rltRawL1L2") %> + + +rltRawL1L2: +<% for (let i=n64-1; i>=0; i--) { %> + mov rax, [rsi + <%= 8+(i*8) %>] + cmp [rdx + <%= 8+(i*8) %>], rax ; comare with (q-1)/2 + jc rlt_ret0 ; rsi<rdx => 1st > 2nd + jnz rlt_ret1 +<% } %> + +rlt_ret0: + xor rax, rax + ret +rlt_ret1: + mov rax, 1 + ret + + + +;;;;;;;;;;;;;;;;;;;;;; +; req - Raw Eq +;;;;;;;;;;;;;;;;;;;;;; +; returns in ax 1 id *rsi == *rdx +; Params: +; rsi <= Pointer to element 1 +; rdx <= Pointer to element 2 +; rax <= Return 1 or 0 +; Modified Registers: +; r8, r9, rax +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_req: + mov r8, [rsi] + mov r9, [rdx] + bt r8, 63 ; Check if is short first operand + jc req_l1 + bt r9, 63 ; Check if is short second operand + jc req_s1l2 + +req_s1s2: ; Both operands are short + cmp r8d, r9d + je req_ret1 + jmp req_ret0 + + +req_l1: + bt r9, 63 ; Check if is short second operand + jc req_l1l2 + +;;;;;;;; +req_l1s2: + bt r8, 62 ; check if montgomery first + jc req_l1ms2 +req_l1ns2: +<%= global.toLong_b() %> + jmp reqL1L2 + +req_l1ms2: +<%= global.toMont_b() %> + jmp reqL1L2 + + +;;;;;;;; +req_s1l2: + bt r9, 62 ; check if montgomery second + jc req_s1l2m +req_s1l2n: +<%= global.toLong_a() %> + jmp reqL1L2 + +req_s1l2m: +<%= global.toMont_a() %> + jmp reqL1L2 + +;;;; +req_l1l2: + bt r8, 62 ; check if montgomery first + jc req_l1ml2 +req_l1nl2: + bt r9, 62 ; check if montgomery second + jc req_l1nl2m +req_l1nl2n: + jmp reqL1L2 + +req_l1nl2m: +<%= global.toMont_a() %> + jmp reqL1L2 + +req_l1ml2: + bt r9, 62 ; check if montgomery second + jc req_l1ml2m +req_l1ml2n: +<%= global.toMont_b() %> + jmp reqL1L2 + +req_l1ml2m: + jmp reqL1L2 + + +;;;;;; +; eqL1L2 +;;;;;; + +reqL1L2: +<% for (let i=0; i<n64; i++) { %> + mov rax, [rsi + <%= 8+(i*8) %>] + cmp [rdx + <%= 8+(i*8) %>], rax + jne req_ret0 ; rsi<rdi => 1st > 2nd +<% } %> + +req_ret1: + mov rax, 1 + ret + +req_ret0: + xor rax, rax + ret + + +;;;;;;;;;;;;;;;;;;;;;; +; gt +;;;;;;;;;;;;;;;;;;;;;; +; Compares 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: +; rax, rcx +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_gt: + call <%=name%>_rgt + mov [rdi], rax + ret + +;;;;;;;;;;;;;;;;;;;;;; +; lt +;;;;;;;;;;;;;;;;;;;;;; +; Compares 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: +; rax, rcx +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_lt: + call <%=name%>_rlt + mov [rdi], rax + ret + +;;;;;;;;;;;;;;;;;;;;;; +; eq +;;;;;;;;;;;;;;;;;;;;;; +; Compares 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: +; rax, rcx +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_eq: + call <%=name%>_req + mov [rdi], rax + ret + +;;;;;;;;;;;;;;;;;;;;;; +; neq +;;;;;;;;;;;;;;;;;;;;;; +; Compares 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: +; rax, rcx +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_neq: + call <%=name%>_req + xor rax, 1 + mov [rdi], rax + ret + +;;;;;;;;;;;;;;;;;;;;;; +; geq +;;;;;;;;;;;;;;;;;;;;;; +; Compares 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: +; rax, rcx +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_geq: + call <%=name%>_rlt + xor rax, 1 + mov [rdi], rax + ret + +;;;;;;;;;;;;;;;;;;;;;; +; leq +;;;;;;;;;;;;;;;;;;;;;; +; Compares 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: +; rax, rcx +;;;;;;;;;;;;;;;;;;;;;; +<%=name%>_leq: + call <%=name%>_rgt + xor rax, 1 + mov [rdi], rax + ret
A ports/c/buildasm/tester.dSYM/Contents/Info.plist

@@ -0,0 +1,20 @@

+<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> + <dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleIdentifier</key> + <string>com.apple.xcode.dsym.tester</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>dSYM</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + </dict> +</plist>
A ports/wasm/build_runtime.js

@@ -0,0 +1,748 @@

+const errs = require("./errs"); + + +const buildWasmFf = require("fflib").buildWasmFf; + + +module.exports = function buildRuntime(module, builder) { + + function buildInit() { + const f = module.addFunction("init"); + f.addLocal("i", "i32"); + + const c = f.getCodeBuilder(); + + // Set the stack to current memory + f.addCode( + c.i32_store( + c.i32_const(4), + c.i32_shl( + c.i32_and( + c.current_memory(), + c.i32_const(0xFFFFFFF8) + ), + c.i32_const(16) + ) + ) + ); + + f.addCode( + // i=0 + c.setLocal("i", c.i32_const(0)), + c.block(c.loop( + // if (i==NComponents) break + c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))), + + // inputSignalsToTrigger[i] = components[i].nInputSignals + c.i32_store( + c.i32_add( + c.i32_const(builder.pInputSignalsToTrigger), + c.i32_mul( + c.getLocal("i"), + c.i32_const(4) + ) + ), + c.i32_load( + c.i32_add( + c.i32_load(c.i32_const(builder.ppComponents)), + c.i32_mul( + c.getLocal("i"), + c.i32_const(builder.sizeofComponent) // Sizeof component + ) + ), + builder.offsetComponentNInputSignals + ) + ), + + // i=i+1 + c.setLocal( + "i", + c.i32_add( + c.getLocal("i"), + c.i32_const(1) + ) + ), + c.br(0) + )) + ); + + if (builder.sanityCheck) { + f.addCode( + // i=0 + c.setLocal("i", c.i32_const(0)), + c.block(c.loop( + // if (i==NSignals) break + c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NSignals))), + + // signalsAssigned[i] = false + c.i32_store( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( + c.getLocal("i"), + c.i32_const(4) + ) + ), + c.i32_const(0) + ), + + // i=i+1 + c.setLocal( + "i", + c.i32_add( + c.getLocal("i"), + c.i32_const(1) + ) + ), + c.br(0) + )) + ); + } + + f.addCode( + c.call( + "Fr_copy", + c.i32_const(builder.pSignals), + c.i32_add( + c.i32_load(c.i32_const(builder.ppConstants)), + c.i32_const(builder.addConstant(1) * builder.sizeFr) + ) + ) + ); + if (builder.sanityCheck) { + f.addCode( + c.i32_store( + c.i32_const(builder.pSignalsAssigned), + c.i32_const(1) + ) + ); + } + + f.addCode( + // i=0 + c.setLocal("i", c.i32_const(0)), + c.block(c.loop( + // if (i==NComponents) break + c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))), + + // if (inputSignalsToTrigger[i] == 0) triggerComponent(i) + c.if( + c.i32_eqz( + c.i32_load( + c.i32_add( + c.i32_const(builder.pInputSignalsToTrigger), + c.i32_mul( + c.getLocal("i"), + c.i32_const(4) + ) + ) + ) + ), + c.call( + "triggerComponent", + c.getLocal("i") + ) + ), + + // i=i+1 + c.setLocal( + "i", + c.i32_add( + c.getLocal("i"), + c.i32_const(1) + ) + ), + c.br(0) + )) + ); + + } + + + function buildTriggerComponent() { + const f = module.addFunction("triggerComponent"); + f.addParam("component", "i32"); + + const c = f.getCodeBuilder(); + + f.addCode( + c.call_indirect( + c.getLocal("component"), // Idx in table + c.getLocal("component") // Parameter + ) + ); + + } + + + function buildHash2ComponentEntry() { + const f = module.addFunction("hash2ComponentEntry"); + f.addParam("component", "i32"); + f.addParam("hash", "i64"); + f.setReturnType("i32"); + + f.addLocal("pComponent", "i32"); + f.addLocal("pHashTable", "i32"); + f.addLocal("hIdx", "i32"); + f.addLocal("h", "i64"); + + const c = f.getCodeBuilder(); + + f.addCode( + c.setLocal( + "pComponent", + c.i32_add( + c.i32_load(c.i32_const(builder.ppComponents)), // pComponents + c.i32_mul( + c.getLocal("component"), + c.i32_const(20) // sizeof(Component) + ) + ) + ), + c.setLocal( + "pHashTable", + c.i32_load(c.getLocal("pComponent")) + ), + c.setLocal( + "hIdx", + c.i32_and( + c.i32_wrap_i64(c.getLocal("hash")), + c.i32_const(0xFF) + ) + ), + c.block(c.loop( + c.setLocal( + "h", + c.i64_load( + c.i32_add( + c.getLocal("pHashTable"), + c.i32_mul( + c.getLocal("hIdx"), + c.i32_const(12) + ) + ) + ) + ), + c.br_if(1, c.i64_eq(c.getLocal("h"), c.getLocal("hash"))), + c.if( + c.i64_eqz(c.getLocal("h")), + c.call( + "err", + c.i32_const(errs.HASH_NOT_FOUND.code), + c.i32_const(errs.HASH_NOT_FOUND.pointer) + ) + ), + c.setLocal( + "hIdx", + c.i32_and( + c.i32_add( + c.getLocal("hIdx"), + c.i32_const(1) + ), + c.i32_const(0xFF) + ) + ), + c.br(0) + )), + + c.i32_add( // pComponentEntry + c.i32_load( // pComponentEntryTable + c.i32_add( + c.getLocal("pComponent"), + c.i32_const(4) + ) + ), + c.i32_mul( + c.i32_load( // idx to the componentEntry + c.i32_add( + c.getLocal("pHashTable"), + c.i32_mul( + c.getLocal("hIdx"), + c.i32_const(12) + ) + ), + 8 + ), + c.i32_const(12) + ) + ) + ); + } + + function buildGetFromComponentEntry(fnName, offset, type) { + const f = module.addFunction(fnName); + f.addParam("pR", "i32"); + f.addParam("component", "i32"); + f.addParam("hash", "i64"); + f.addLocal("pComponentEntry", "i32"); + + const c = f.getCodeBuilder(); + + f.addCode( + c.setLocal( + "pComponentEntry", + c.call( + "hash2ComponentEntry", + c.getLocal("component"), + c.getLocal("hash") + ) + ), + c.if( // If type is not signal + c.i32_ne( + c.i32_load( + c.getLocal("pComponentEntry"), + 8 // type offset + ), + c.i32_const(type) + ), + c.call( + "err", + c.i32_const(errs.INVALID_TYPE.code), + c.i32_const(errs.INVALID_TYPE.pointer) + ) + ), + c.i32_store( + c.getLocal("pR"), + c.i32_load( + c.getLocal("pComponentEntry"), + offset + ) + ) + ); + + const f2 = module.addFunction(fnName + "32"); + f2.addParam("pR", "i32"); + f2.addParam("component", "i32"); + f2.addParam("hashMSB", "i32"); + f2.addParam("hashLSB", "i32"); + + const c2 = f2.getCodeBuilder(); + + f2.addCode( + c2.call( + fnName, + c2.getLocal("pR"), + c2.getLocal("component"), + c2.i64_or( + c2.i64_shl( + c2.i64_extend_i32_u(c2.getLocal("hashMSB")), + c2.i64_const(32) + ), + c2.i64_extend_i32_u(c2.getLocal("hashLSB")) + ) + ) + ); + + } + + + function buildGetSignal() { + const f = module.addFunction("getSignal"); + f.addParam("cIdx", "i32"); + f.addParam("pR", "i32"); + f.addParam("component", "i32"); + f.addParam("signal", "i32"); + + const c = f.getCodeBuilder(); + + if (builder.sanityCheck) { + f.addCode( + c.if( + c.i32_eqz( + c.i32_load( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(4) + ) + ), + ) + ), + c.call( + "err", + c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), + c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer) + ) + ) + ); + } + + f.addCode( + c.call( + "Fr_copy", + c.getLocal("pR"), + c.i32_add( + c.i32_const(builder.pSignals), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(builder.sizeFr) + ) + ) + ) + ); + } + + + function buildSetSignal() { + const f = module.addFunction("setSignal"); + f.addParam("cIdx", "i32"); + f.addParam("component", "i32"); + f.addParam("signal", "i32"); + f.addParam("pVal", "i32"); + f.addLocal("signalsToTrigger", "i32"); + + const c = f.getCodeBuilder(); + + + if (builder.sanityCheck) { + f.addCode( + c.if( + c.i32_load( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(4) + ) + ), + ), + c.call( + "err", + c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code), + c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer) + ) + ), + c.i32_store( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(4) + ) + ), + c.i32_const(1) + ), + ); + } + + f.addCode( + c.call( + "Fr_copy", + c.i32_add( + c.i32_const(builder.pSignals), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(builder.sizeFr) + ) + ), + c.getLocal("pVal"), + ) + ); + + f.addCode( + c.if( // If ( mapIsInput[s >> 5] & 1 << (s & 0x1f) ) + c.i32_and( + c.i32_load( + c.i32_add( + c.i32_load(c.i32_const(builder.ppMapIsInput)), + c.i32_shl( + c.i32_shr_u( + c.getLocal("signal"), + c.i32_const(5) + ), + c.i32_const(2) + ) + ) + ), + c.i32_shl( + c.i32_const(1), + c.i32_and( + c.getLocal("signal"), + c.i32_const(0x1F) + ) + ) + ), + [ + + ...c.setLocal( + "signalsToTrigger", + c.i32_load( + c.i32_add( + c.i32_const(builder.pInputSignalsToTrigger), + c.i32_mul( + c.getLocal("component"), + c.i32_const(4) + ) + ) + ) + ), + + ...c.if( // if (signalsToTrigger > 0) + c.i32_gt_u( + c.getLocal("signalsToTrigger"), + c.i32_const(0) + ), + [ + ...c.setLocal( // signalsToTrigger-- + "signalsToTrigger", + c.i32_sub( + c.getLocal("signalsToTrigger"), + c.i32_const(1) + ) + ), + ...c.i32_store( + c.i32_add( + c.i32_const(builder.pInputSignalsToTrigger), + c.i32_mul( + c.getLocal("component"), + c.i32_const(4) + ) + ), + c.getLocal("signalsToTrigger"), + ), + ...c.if( // if (signalsToTrigger==0) triggerCompomnent(component) + c.i32_eqz(c.getLocal("signalsToTrigger")), + c.call( + "triggerComponent", + c.getLocal("component") + ) + ) + ], + c.call( + "err2", + c.i32_const(errs.MAPISINPUT_DONT_MATCH.code), + c.i32_const(errs.MAPISINPUT_DONT_MATCH.pointer), + c.getLocal("component"), + c.getLocal("signal") + ) + ) + ] + ) + ); + } + + function buildComponentFinished() { + const f = module.addFunction("componentFinished"); + f.addParam("cIdx", "i32"); + + const c = f.getCodeBuilder(); + + f.addCode(c.ret([])); + } + + function buildCheckConstraint() { + const pTmp = module.alloc(builder.sizeFr); + const f = module.addFunction("checkConstraint"); + f.addParam("cIdx", "i32"); + f.addParam("pA", "i32"); + f.addParam("pB", "i32"); + f.addParam("pStr", "i32"); + + const c = f.getCodeBuilder(); + + if (builder.sanityCheck) { + f.addCode( + c.call( + "Fr_eq", + c.getLocal(c.i32_const(pTmp)), + c.getLocal("pA"), + c.getLocal("pB") + ), + c.if ( + c.eqz( + c.call( + "Fr_isTrue", + c.getLocal(c.i32_const(pTmp)), + ) + ), + c.call( + "err4", + c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.code), + c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.pointer), + c.getLocal("cIdx"), + c.getLocal("pA"), + c.getLocal("pB"), + c.getLocal("pStr"), + ) + ) + ); + } + } + + function buildGetNVars() { + const f = module.addFunction("getNVars"); + f.setReturnType("i32"); + + const c = f.getCodeBuilder(); + + f.addCode(c.i32_const(builder.header.NVars)); + } + + function buildGetFrLen() { + const f = module.addFunction("getFrLen"); + f.setReturnType("i32"); + + const c = f.getCodeBuilder(); + + f.addCode( + c.i32_const(builder.sizeFr)); + } + + function buildGetPRawPrime() { + const f = module.addFunction("getPRawPrime"); + f.setReturnType("i32"); + + const c = f.getCodeBuilder(); + + f.addCode( + c.i32_const(module.modules["Fr_F1m"].pq)); + } + + function buildGetPWitness() { + const f = module.addFunction("getPWitness"); + f.addParam("w", "i32"); + f.addLocal("signal", "i32"); + f.setReturnType("i32"); + + const c = f.getCodeBuilder(); + + + f.addCode( + c.setLocal( + "signal", + c.i32_load( // wit2sig[w] + c.i32_add( + c.i32_load( c.i32_const(builder.ppWit2sig)), + c.i32_mul( + c.getLocal("w"), + c.i32_const(4) + ) + ) + ) + ) + ); + + if (builder.sanityCheck) { + f.addCode( + c.if( + c.i32_eqz( + c.i32_load( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(4) + ) + ), + ) + ), + c.call( + "err", + c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), + c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer) + ) + ) + ); + } + + f.addCode( + c.i32_add( + c.i32_const(builder.pSignals), + + c.i32_mul( + c.getLocal("signal"), + c.i32_const(builder.sizeFr) + ) + ) + ); + } + + function buildFrToInt() { + const f = module.addFunction("Fr_toInt"); + f.addParam("p", "i32"); + f.setReturnType("i32"); + + const c = f.getCodeBuilder(); + + f.addCode( + c.i32_load(c.getLocal("p")) + ); + + // TODO Handle long and montgomery. + } + + + const fErr = module.addIimportFunction("err", "runtime"); + fErr.addParam("code", "i32"); + fErr.addParam("pStr", "i32"); + + const fErr1 = module.addIimportFunction("err1", "runtime"); + fErr1.addParam("code", "i32"); + fErr1.addParam("pStr", "i32"); + fErr1.addParam("param1", "i32"); + + const fErr2 = module.addIimportFunction("err2", "runtime"); + fErr2.addParam("code", "i32"); + fErr2.addParam("pStr", "i32"); + fErr2.addParam("param1", "i32"); + fErr2.addParam("param2", "i32"); + + const fErr3 = module.addIimportFunction("err3", "runtime"); + fErr3.addParam("code", "i32"); + fErr3.addParam("pStr", "i32"); + fErr3.addParam("param1", "i32"); + fErr3.addParam("param2", "i32"); + fErr3.addParam("param3", "i32"); + + const fErr4 = module.addIimportFunction("err4", "runtime"); + fErr4.addParam("code", "i32"); + fErr4.addParam("pStr", "i32"); + fErr4.addParam("param1", "i32"); + fErr4.addParam("param2", "i32"); + fErr4.addParam("param3", "i32"); + fErr4.addParam("param4", "i32"); + + buildWasmFf(module, "Fr", builder.header.P); + + builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr); + builder.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4); + if (builder.sanityCheck) { + builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4); + } + + buildHash2ComponentEntry(); + + buildTriggerComponent(); + buildInit(); + + buildGetFromComponentEntry("getSubComponentOffset", 0 /* offset */, builder.TYPE_COMPONENT); + buildGetFromComponentEntry("getSubComponentSizes", 4 /* offset */, builder.TYPE_COMPONENT); + + buildGetFromComponentEntry("getSignalOffset", 0 /* offset */, builder.TYPE_SIGNAL); + buildGetFromComponentEntry("getSignalSizes", 4 /* offset */, builder.TYPE_SIGNAL); + + buildGetSignal(); + buildSetSignal(); + + buildComponentFinished(); + + buildCheckConstraint(); + + buildGetNVars(); + buildGetFrLen(); + buildGetPWitness(); + buildGetPRawPrime(); + + buildFrToInt(); + + module.exportFunction("init"); + module.exportFunction("getNVars"); + module.exportFunction("getFrLen"); + module.exportFunction("getSignalOffset32"); + module.exportFunction("setSignal"); + module.exportFunction("getPWitness"); + module.exportFunction("Fr_toInt"); + module.exportFunction("getPRawPrime"); + +};
A ports/wasm/builder.js

@@ -0,0 +1,1003 @@

+const streamFromArrayTxt = require("../../src/streamfromarray_txt"); +const streamFromArrayBin = require("../../src/streamfromarray_bin"); +const bigInt = require("big-integer"); +const assert = require("assert"); +const ModuleBuilder = require("wasmbuilder").ModuleBuilder; +const ModuleBuilderWat = require("wasmbuilder").ModuleBuilderWat; +const buildRuntime = require("./build_runtime"); + + +const errs = require("./errs"); + +function hexToBytesR(hex) { + for (var bytes = [], c = hex.length-2; c >=0; c -= 2) + bytes.push(parseInt(hex.substr(c, 2), 16)); + return bytes; +} + + +function intToBytes32(v) { + return [ v &0xFF, (v>>8) & 0xFF, (v>>16) & 0xFF, (v>>24) & 0xFF ]; +} + + +class CodeBuilderWasm { + constructor(fnBuilder) { + this.fnBuilder = fnBuilder; + 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(c, offsets) { + let rN=0; + let S = null; + 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") { + f = c.i32_const(o[0][1]); + } else if (o[0][0] == "RI") { + f = c.i32_load(this.fnBuilder._getPtr(c, o[0][1])); + } else if (o[0][0] == "R") { + f = c.call("Fr_toInt", this.fnBuilder._getPtr(c, o[0][1])); + } else { + assert(false); + } + if (o[1][0] == "V") { + if (o[1][1]==0) return; + if (o[1][1]>1) { + f = c.i32_mul(f, c.i32_const(o[1][1])); + } + } else if (o[1][0] == "RS") { + f = c.i32_mul( + f, + c.i32_load( + c.i32_add( + c.i32_load(this.fnBuilder._getPtr(c, o[1][1])), + c.i32_const(o[1][2]*4) + ) + ) + ); + } else { + assert(false); + } + if (S!=null) { + S = c.i32_add( S, f); + } else { + S = f; + } + }); + if (rN>0) { + if (S!=null) { + S = c.i32_add( S, c.i32_const(rN)); + } else { + S = c.i32_const(rN); + } + } + return S; + } + + build(c) { + const code = []; + this.ops.forEach( (o) => { + if (o.op == "COMMENT") { + code.push( + c.comment(o.comment) + ); + // DO nothing + } else if (o.op == "BLOCK") { + code.push( + o.block.build(c) + ); + } else if (o.op == "CALCOFFSETS") { + code.push( + c.i32_store( + this.fnBuilder._getPtr(c, o.dLabel), + this._buildOffset(c, o.offsets) + ) + ); + } else if (o.op == "ASSIGN") { + code.push( + c.i32_store( + this.fnBuilder._getPtr(c, o.dLabel), + c.i32_add( + this.fnBuilder._deRefFr(c, o.src), + c.i32_mul( + this.fnBuilder._deRefInt(c, o.sOffset), + c.i32_const(this.fnBuilder.builder.sizeFr) + ) + ) + ) + ); + } else if (o.op == "GETSUBCOMPONENTOFFSET") { + code.push( + c.call( + "getSubComponentOffset", + this.fnBuilder._getPtr(c, o.dLabel), + this.fnBuilder._deRefInt(c, o.component), + c.i64_const("0x" + o.hash) + ) + ); + } else if (o.op == "GETSUBCOMPONENTSIZES") { + code.push( + c.call( + "getSubComponentSizes", + this.fnBuilder._getPtr(c, o.dLabel), + this.fnBuilder._deRefInt(c, o.component), + c.i64_const("0x" + o.hash) + ) + ); + } else if (o.op == "GETSIGNALOFFSET") { + code.push( + c.call( + "getSignalOffset", + this.fnBuilder._getPtr(c, o.dLabel), + this.fnBuilder._deRefInt(c, o.component), + c.i64_const("0x" + o.hash) + ) + ); + } else if (o.op == "GETSIGNALSIZES") { + code.push( + c.call( + "getSignalSizes", + this.fnBuilder._getPtr(c, o.dLabel), + this.fnBuilder._deRefInt(c, o.component), + c.i64_const("0x" + o.hash) + ) + ); + } else if (o.op == "SETSIGNAL") { + code.push( + c.call( + "setSignal", + c.getLocal("cIdx"), + this.fnBuilder._deRefInt(c, o.component), + this.fnBuilder._deRefInt(c, o.signal), + this.fnBuilder._deRefFr(c, o.value) + ) + ); + } else if (o.op == "GETSIGNAL") { + code.push( + c.call( + "getSignal", + c.getLocal("cIdx"), + this.fnBuilder._getPtr(c, o.dLabel), + this.fnBuilder._deRefInt(c, o.component), + this.fnBuilder._deRefInt(c, o.signal) + ) + ); + } else if (o.op == "COPYN") { + code.push( + c.call( + "Fr_copyn", + c.i32_add( + this.fnBuilder._getPtr(c, o.dLabel), + c.i32_mul( + this.fnBuilder._deRefInt(c, o.offset), + c.i32_const(this.fnBuilder.builder.sizeFr) + ) + ), + this.fnBuilder._deRefFr(c, o.src), + c.i32_const(o.n) + ) + ); + } else if (o.op == "COPYNRET") { + code.push( + c.call( + "Fr_copyn", + c.getLocal("pRet"), + this.fnBuilder._deRefFr(c, o.src), + c.i32_const(o.n) + ) + ); + } else if (o.op == "RET") { + code.push(this.fnBuilder._freeStack(c)); + code.push(c.ret([])); + } else if (o.op == "FOP") { + let params = []; + for (let i=0; i<o.params.length; i++) { + params.push( this.fnBuilder._deRefFr(c, o.params[i])); + } + code.push( + c.call( + "Fr_" + o.fOp, + this.fnBuilder._getPtr(c, o.dLabel), + ...params + ) + ); + } else if (o.op == "LOOP") { + code.push( + c.block(c.loop( + c.br_if(1, c.i32_eqz(c.call("Fr_isTrue", this.fnBuilder._deRefFr(c, ["R", o.condLabel])))), + o.body.build(c), + c.br(0) + )) + ); + } else if (o.op == "IF") { + code.push( + c.if( + c.call("Fr_isTrue", this.fnBuilder._deRefFr(c, ["R", o.condLabel])), + o.thenCode.build(c), + o.elseCode ? o.elseCode.build(c) : undefined + ) + ); + } else if (o.op == "FNCALL") { + const params = []; + for (let i=0; i<o.params.length; i++) { + params.push(this.fnBuilder._deRefFr(c, ["R", o.params[i]])); + } + code.push( + c.call( + o.fnName, + this.fnBuilder._getPtr(c, o.retLabel), + ...params + ) + ); + } else if (o.op == "CHECKCONSTRAINT") { + code.push( + c.call( + "checkConstraint", + c.getLocal("cIdx"), + this.fnBuilder._deRefFr(c, o.a), + this.fnBuilder._deRefFr(c, o.b), + c.i32_const(this.fnBuilder.builder.module.allocString(o.strErr)) + ) + ); + } else if (o.op == "LOG") { + code.push( + c.call( + "log", + this.fnBuilder._deRefFr(c, o.val) + ) + ); + } + }); + return code; + } +} + +class FunctionBuilderWasm { + + constructor(builder, name, instanceDef, type, params) { + this.builder = builder; + this.name = name; + this.instanceDef = instanceDef; + this.type = type; // "COMPONENT" or "FUNCTION" + this.definedFrElements = []; + this.definedIntElements = []; + this.definedSizeElements = []; + this.definedPFrElements = []; + this.initializedElements = []; + this.initializedSignalOffset = []; + this.initializedSignalSizes = []; + + this.refs = {}; + + this.nFr = 0; + this.nInt = 0; + this.nSizes = 0; + this.nPFr = 0; + + } + + defineFrElements(dLabel, size) { + this.refs[dLabel] = { + t: "Fr", + n: size, + idx: this.nFr + }; + this.nFr += size; + } + + defineIntElement(dLabel) { + this.refs[dLabel] = { + t: "I", + idx: this.nInt + }; + this.nInt++; + } + + defineSizesElement(dLabel) { + this.refs[dLabel] = { + t: "S", + idx: this.nSizes + }; + this.nSizes++; + } + + definePFrElement(dLabel) { + this.refs[dLabel] = { + t: "PFr", + idx: this.nPFr + }; + this.nPFr++; + } + + 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) { + assert(typeof this.params === "undefined"); + assert(this.type === "FUNCTION"); + this.params=params; + for (let i=0; i<this.params.length; i++) { + assert(typeof this.refs[this.params[i]] === "undefined"); + this.refs[this.params[i]] = { + t: "P", + l: this.params[i] + }; + } + } + + _getPtr(c, label, offset) { + offset = offset || 0; + assert (typeof this.refs[label] !== "undefined"); + if (this.refs[label].t == "Fr") { + return c.i32_add( + c.getLocal("sp"), + c.i32_const((this.refs[label].idx + offset) * this.builder.sizeFr) + ); + } else if (this.refs[label].t == "I") { + assert(offset == 0); + return c.i32_add( + c.getLocal("sp"), + c.i32_const( + this.nFr * this.builder.sizeFr + + this.refs[label].idx * 4) + ); + } else if (this.refs[label].t == "S") { + assert(offset == 0); + return c.i32_add( + c.getLocal("sp"), + c.i32_const( + this.nFr * this.builder.sizeFr + + this.nInt * 4 + + this.refs[label].idx * 4) + ); + } else if (this.refs[label].t == "PFr") { + assert(offset == 0); + return c.i32_add( + c.getLocal("sp"), + c.i32_const( + this.nFr * this.builder.sizeFr + + this.nInt * 4 + + this.nSizes * 4 + + this.refs[label].idx * 4) + ); + } else if (this.refs[label].t == "P") { + return c.i32_add( + c.getLocal(this.refs[label].l), + c.i32_const( offset * this.builder.sizeFr ) + ); + } + } + + _getPtrConstant(c, idConstant) { + return c.i32_const( this.builder.pConstants + idConstant * this.builder.sizeFr ); + } + + _deRefInt(c, ref) { + if (ref[0] == "R") { + return c.call( + "Fr_toInt", + this._getPtr(c, ref[1]) + ); + } else if (ref[0] == "RI") { + return c.i32_load(this._getPtr(c, ref[1])); + } else if (ref[0] == "V") { + return c.i32_const(ref[1]); + } else if (ref[0] == "C") { + return c.call( + "Fr_toInt", + this._getPtrConstant(c, ref[1]) + ); + } else if (ref[0] == "CC") { + return c.getLocal("cIdx"); + } else { + assert(false); + } + } + + _deRefFr(c, ref) { + if (ref[0] == "R") { + if (this.refs[ref[1]].t == "Fr") { + return this._getPtr(c, ref[1]); + } else if (this.refs[ref[1]].t == "PFr") { + return c.i32_load(this._getPtr(c, ref[1])); + } else if (this.refs[ref[1]].t == "P") { + return c.getLocal(ref[1]); + } else { + assert(false); + } + } else if (ref[0] == "C") { + return this._getPtrConstant(c, ref[1]); + } else { + assert(false); + } + } + + _reserveStack(c) { + const code = []; + code.push( + // Load SP + c.setLocal("sp", c.i32_load(c.i32_const(4))), + + // Check we have enough memory + c.if( + c.i32_gt_u( + c.i32_const(this.nStackSize), + c.getLocal("sp") + ), + c.call( + "err", + c.i32_const(errs.STACK_OUT_OF_MEM.code), + c.i32_const(errs.STACK_OUT_OF_MEM.pointer) + ) + ), + + // Reserve space in sp + c.setLocal( + "sp", + c.i32_sub( + c.getLocal("sp"), + c.i32_const(this.nStackSize) + ) + ), + + // Check if we have enought free memory + c.if( + c.i32_gt_u( + c.i32_load(c.i32_const(0)), + c.getLocal("sp") + ), + c.call( + "err", + c.i32_const(errs.STACK_TOO_SMALL.code), + c.i32_const(errs.STACK_TOO_SMALL.pointer) + ) + ), + + // Save sp + c.i32_store(c.i32_const(4), c.getLocal("sp")) + ); + return code; + } + + _freeStack(c) { + const code = []; + code.push( + c.i32_store( + c.i32_const(4), + c.i32_add( + c.getLocal("sp"), + c.i32_const(this.nStackSize) + ) + ) + ); + return code; + } + + _buildHeader(c) { + const code = []; + this.nStackSize = + this.nFr * this.builder.sizeFr + + this.nInt * 4 + + this.nSizes * 4 + + this.nPFr * 4; + + + code.push( this._reserveStack(c)); + + this.initializedElements.forEach( (o) => { + code.push( + c.call( + "Fr_copy", + this._getPtr(c, o.dLabel, o.offset), + this._getPtrConstant(c, o.idConstant) + ) + ); + }); + this.initializedSignalOffset.forEach( (o) => { + code.push( + c.call( + "getSignalOffset", + this._getPtr(c, o.dLabel, o.offset), + this._deRefInt(c, o.component), + c.i64_const("0x" + o.hash) + ) + ); + }); + this.initializedSignalSizes.forEach( (o) => { + code.push( + c.call( + "getSignalSizes", + this._getPtr(c, o.dLabel, o.offset), + this._deRefInt(c, o.component), + c.i64_const("0x" + o.hash) + ) + ); + }); + return code; + } + + _buildFooter(c) { + return this._freeStack(c); + } + + newCodeBuilder() { + return new CodeBuilderWasm(this); + } + + setBody(body) { + this.body = body; + } + + build(module) { + + + const f = module.addFunction(this.name, this.instanceDef); + + if (this.type=="COMPONENT") { + f.addParam("cIdx", "i32"); + } else if (this.type=="FUNCTION") { + f.addParam("pRet", "i32"); + for (let i=0;i<this.params.length;i++ ) { + f.addParam(this.params[i], "i32"); + } + } else { + assert(false); + } + f.addLocal("sp", "i32"); + + const c = f.getCodeBuilder(); + + const code = []; + code.push(this._buildHeader(c)); + code.push(this.body.build(c)); + if (this.type=="COMPONENT") { + code.push(c.call("componentFinished", c.getLocal("cIdx"))); + } + code.push(this._buildFooter(c)); + + f.addCode(flatArray(code)); + + function flatArray(c) { + const res=[]; + for (let i=0; i<c.length; i++) { + if (Array.isArray(c[i])) { + res.push(...flatArray(c[i])); + } else { + res.push(c[i]); + } + } + return res; + } + } + +} + +class BuilderWasm { + constructor() { + this.hashMaps={}; + this.componentEntriesTables={}; + this.sizes ={}; + this.constants = []; + this.usedConstants = {}; + this.functions = []; + this.components = []; + + this.TYPE_SIGNAL = 1; + this.TYPE_COMPONENT = 2; + + this.addConstant(bigInt(0)); // constants[0] = 0; + this.addConstant(bigInt(1)); // constants[1] = 1; + + this.offsetComponentNInputSignals = 12; + this.sizeofComponent = 20; + } + + setHeader(header) { + this.header=header; + this.n64 = Math.floor((this.header.P.bitLength() - 1) / 64)+1; + this.sizeFr = this.n64*8 + 8; + } + + // ht is an array of 256 element that can be undefined or [Hash, Idx, KeyName] elements. + addHashMap(name, table) { + this.hashMaps[name] = {table}; + } + + addComponentEntriesTable(name, cet) { + this.componentEntriesTables[name] = cet; + } + + addSizes(name, table) { + this.sizes[name] = {table}; + } + + addConstant(c) { + c = bigInt(c); + const cS = c.toString(); + if (this.usedConstants[cS]) return this.usedConstants[cS]; + this.constants.push(c); + this.usedConstants[cS] = this.constants.length - 1; + return this.constants.length - 1; + } + + 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 FunctionBuilderWasm(this, name, instanceDef, "COMPONENT"); + } + + newFunctionBuilder(name, instanceDef, params) { + return new FunctionBuilderWasm(this, name, instanceDef, "FUNCTION", params); + } + + + // Body functions + + _buildHeader(module) { + + this.pCircuit = module.alloc(48); + + this.pNSignals = this.pCircuit; + this.pNComponents = this.pCircuit + 4; + this.pNInputs = this.pCircuit + 8; + this.pNOutputs = this.pCircuit + 12; + this.pNVars = this.pCircuit + 16; + this.ppWit2sig = this.pCircuit + 20; + this.ppComponents = this.pCircuit + 24; + this.ppMapIsInput = this.pCircuit + 28; + this.ppConstants = this.pCircuit + 32; + this.ppSignals = this.pCircuit + 36; + this.ppInputSignalsToTrigger = this.pCircuit + 40; + this.ppSignalsAssigned = this.pCircuit + 44; + } + + _buildSizes(module) { + for (let sName in this.sizes) { + const accSizes = this.sizes[sName]; + + const bytes = []; + + for (let i=0; i<accSizes.table.length; i++) { + bytes.push(intToBytes32(accSizes.table[i])); + } + + const fBytes = [].concat(...bytes); + accSizes.pointer = module.alloc(fBytes); + } + } + + + _buildHashMaps(module) { + + for (let hmName in this.hashMaps ) { + const hm = this.hashMaps[hmName]; + + const bytes = []; + + for (let i=0; i<256; i++) { + if (hm.table[i]) { + bytes.push(hexToBytesR(hm.table[i][0])); + bytes.push(intToBytes32(hm.table[i][1])); + } else { + bytes.push([0,0,0,0,0,0,0,0,0,0,0,0]); + } + } + + const fBytes = [].concat(...bytes); + hm.pointer = module.alloc(fBytes); + } + + } + + _buildComponentEntriesTables(module) { + + for (let cetName in this.componentEntriesTables) { + const cet = this.componentEntriesTables[cetName]; + + const bytes = []; + + for (let j=0; j<cet.length; j++) { + const ty = cet[j].type == "S" ? this.TYPE_SIGNAL : this.TYPE_COMPONENT; + bytes.push(intToBytes32(cet[j].offset)); + bytes.push(intToBytes32(this.sizes[cet[j].sizeName].pointer)); + bytes.push(intToBytes32(ty)); + } + + const fBytes = [].concat(...bytes); + this.componentEntriesTables[cetName].pointer = module.alloc(fBytes); + } + } + + + _buildConstants(module) { + const self = this; + const R = bigInt.one.shiftLeft(this.n64*64); + + const bytes = []; + for (let i=0; i<self.constants.length; i++) { + bytes.push(Fr2Bytes(self.constants[i])); + } + + const fBytes = [].concat(...bytes); + this.pConstants = module.alloc(fBytes); + + function Fr2Bytes(n) { + if (n.lt(bigInt("80000000", 16)) ) { + return shortMontgomeryPositive(n); + } + if (n.geq(self.header.P.minus(bigInt("80000000", 16))) ) { + return shortMontgomeryNegative(n); + } + return longMontgomery(n); + + + function shortMontgomeryPositive(a) { + return [ + ...intToBytes32(parseInt(a)), + ...intToBytes32(0x40000000), + ...long(toMontgomery(a)) + ]; + } + + + function shortMontgomeryNegative(a) { + const b = a.minus(self.header.P); + return [ + ...intToBytes32(parseInt(b)), + ...intToBytes32(0x40000000), + ...long(toMontgomery(a)) + ]; + } + + function longMontgomery(a) { + return [ + ...intToBytes32(0), + ...intToBytes32(0xC0000000), + ...long(toMontgomery(a)) + ]; + } + + function long(a) { + const bytes = []; + let r = bigInt(a); + let S = ""; + let i = 0; + while (!r.isZero()) { + S = ("0000000000000000" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16)).substr(-16); + bytes.push(hexToBytesR(S)); + i++; + r = r.shiftRight(64); + } + while (i<self.n64) { + bytes.push(hexToBytesR("0000000000000000")); + i++; + } + + const fBytes = [].concat(...bytes); + return fBytes; + } + + function toMontgomery(a) { + return a.times(R).mod(self.header.P); + } + + } + } + + _buildFunctions(module) { + for (let i=0; i<this.functions.length; i++) { + const cfb = this.functions[i]; + cfb.build(module); + } + } + + _buildComponents(module) { + const bytes = []; + for (let i=0; i<this.components.length; i++) { + const c = this.components[i]; + + bytes.push(intToBytes32(this.hashMaps[c.hashMapName].pointer)); + bytes.push(intToBytes32(this.componentEntriesTables[c.entryTableName].pointer)); + bytes.push(intToBytes32(i)); + bytes.push(intToBytes32(c.nInSignals)); + bytes.push(intToBytes32(c.newThread ? 1 : 0)); + + module.addFunctionToTable(c.functionName); + } + + const fBytes = [].concat(...bytes); + this.pComponents = module.alloc(fBytes); + } + + _buildMapIsInput(module) { + const bytes = []; + for (let i=0; i<this.mapIsInput.length; i++) { + bytes.push(intToBytes32(this.mapIsInput[i])); + } + + const fBytes = [].concat(...bytes); + this.pMapIsInput = module.alloc(fBytes); + } + + _buildWit2Sig(module) { + const bytes = []; + for (let i=0; i<this.wit2sig.length; i++) { + bytes.push(intToBytes32(this.wit2sig[i])); + } + + const fBytes = [].concat(...bytes); + this.pWit2sig = module.alloc(fBytes); + } + + _buildCircuitVar(module) { + module.addData(this.pNSignals, intToBytes32(this.header.NSignals)); + module.addData(this.pNComponents, intToBytes32(this.header.NComponents)); + module.addData(this.pNInputs, intToBytes32(this.header.NInputs)); + module.addData(this.pNOutputs, intToBytes32(this.header.NOutputs)); + module.addData(this.pNVars, intToBytes32(this.header.NVars)); + module.addData(this.ppWit2sig, intToBytes32(this.pWit2sig)); + module.addData(this.ppComponents, intToBytes32(this.pComponents)); + module.addData(this.ppMapIsInput, intToBytes32(this.pMapIsInput)); + module.addData(this.ppConstants, intToBytes32(this.pConstants)); + module.addData(this.ppSignals, intToBytes32(this.pSignals)); + module.addData(this.ppInputSignalsToTrigger, intToBytes32(this.pInputSignalsToTrigger)); + module.addData(this.ppSignalsAssigned, intToBytes32(this.pSignalsAssigned)); + + } + + _buildErrors(module) { + for (let e in errs) { + errs[e].pointer = module.allocString(errs[e].str); + } + } + + + build(outType) { + let module; + if (outType == "wasm") { + module=new ModuleBuilder(); + } else if (outType == "wat") { + module=new ModuleBuilderWat(); + } else { + assert(false); + } + this.module = module; + + // First of all reseve the space for the header so this has a fixed position starting at 8. + this._buildHeader(module); + this._buildErrors(module); + buildRuntime(module, this); + this._buildSizes(module); + this._buildConstants(module); + this._buildHashMaps(module); + this._buildComponentEntriesTables(module); + this._buildFunctions(module); + this._buildComponents(module); + this._buildMapIsInput(module); + this._buildWit2Sig(module); + this._buildCircuitVar(module); + if (outType == "wasm") { + return streamFromArrayBin(module.build()); + } else if (outType == "wat") { + return streamFromArrayTxt(module.build()); + } else { + assert(false); + } + } +} + + +module.exports = BuilderWasm;
A ports/wasm/errs.js

@@ -0,0 +1,10 @@

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

@@ -0,0 +1,167 @@

+const chai = require("chai"); +const assert = chai.assert; + +const fs = require("fs"); +var tmp = require("tmp-promise"); +const path = require("path"); +const compiler = require("../../src/compiler"); +const util = require("util"); +const exec = util.promisify(require("child_process").exec); + +const stringifyBigInts = require("../../src/utils").stringifyBigInts; +const unstringifyBigInts = require("../../src/utils").unstringifyBigInts; +const bigInt = require("big-integer"); +const utils = require("../../src/utils"); +const loadR1cs = require("../../src/r1csfile").loadR1cs; +const ZqField = require("fflib").ZqField; + +const WitnessCalculator = require("./witness_calculator"); + +module.exports = wasm_tester; + + +async function wasm_tester(circomFile, _options) { + tmp.setGracefulCleanup(); + + const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true }); + + // console.log(dir.path); + + const baseName = path.basename(circomFile, ".circom"); + const options = Object.assign({}, _options); + + options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm")); + options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym")); + options.r1csFileName = path.join(dir.path, baseName + ".r1cs"); + + const promisesArr = []; + promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill))); + + await compiler(circomFile, options); + + await Promise.all(promisesArr); + + const wc = await WitnessCalculator.fromFile(path.join(dir.path, baseName + ".wasm")); + + return new WasmTester(dir, baseName, wc); +} + +class WasmTester { + + constructor(dir, baseName, witnessCalculator) { + this.dir=dir; + this.baseName = baseName; + this.witnessCalculator = witnessCalculator; + } + + async release() { + await this.dir.cleanup(); + } + + async calculateWitness(input) { + + return await this.witnessCalculator.calculateWitness(input); + } + + 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; + } + } + +} + +
A ports/wasm/witness_calculator.js

@@ -0,0 +1,186 @@

+/* globals WebAssembly */ + +const fs = require("fs"); +const utils = require("../../src/utils"); +const bigInt = require("big-integer"); + +module.exports.fromFile = async function(file) { + + + const code = await fs.promises.readFile(file); + + return await module.exports.fromBuffer(code); +}; + +module.exports.fromBuffer = async function(code) { + + const memory = new WebAssembly.Memory({initial:20000}); + const wasmModule = await WebAssembly.compile(code); + + const instance = await WebAssembly.instantiate(wasmModule, { + env: { + "memory": memory + }, + runtime: { + err: function(code, pstr) { + console.log("ERROR", code, p2str(pstr)); + }, + err1: function(code, pstr, a) { + console.log("ERROR: ", code, p2str(pstr), a); + }, + err2: function(code, pstr, a, b) { + console.log("ERROR: ", code, p2str(pstr), a, b); + }, + err3: function(code, pstr, a, b, c) { + console.log("ERROR: ", code, p2str(pstr), a, b, c); + }, + err4: function(code, pstr, a,b,c,d) { + console.log("ERROR: ", code, p2str(pstr), a, b, c, d); + }, + } + }); + + return new WitnessCalculator(memory, instance); + + function p2str(p) { + return "TODO"+p; + } +}; + +class WitnessCalculator { + constructor(memory, instance) { + this.memory = memory; + this.i32 = new Uint32Array(memory.buffer); + this.instance = instance; + + this.n32 = (this.instance.exports.getFrLen() >> 2) - 2; + const pRawPrime = this.instance.exports.getPRawPrime(); + + this.prime = bigInt(0); + for (let i=this.n32-1; i>=0; i--) { + this.prime = this.prime.shiftLeft(32); + this.prime = this.prime.add(bigInt(this.i32[(pRawPrime >> 2) + i])); + } + + this.mask32 = bigInt("FFFFFFFF", 16); + this.NVars = this.instance.exports.getNVars(); + this.n64 = Math.floor((this.prime.bitLength() - 1) / 64)+1; + this.R = bigInt.one.shiftLeft(this.n64*64); + this.RInv = this.R.modInv(this.prime); + + } + + async calculateWitness(input) { + const w = []; + const old0 = this.i32[0]; + this.instance.exports.init(); + const pSigOffset = this.allocInt(); + const pFr = this.allocFr(); + for (let k in input) { + const h = utils.fnvHash(k); + const hMSB = parseInt(h.slice(0,8), 16); + const hLSB = parseInt(h.slice(8,16), 16); + this.instance.exports.getSignalOffset32(pSigOffset, 0, hMSB, hLSB); + const sigOffset = this.getInt(pSigOffset); + const fArr = utils.flatArray(input[k]); + for (let i=0; i<fArr.length; i++) { + this.setFr(pFr, fArr[i]); + this.instance.exports.setSignal(0, 0, sigOffset + i, pFr); + } + } + + + for (let i=0; i<this.NVars; i++) { + const pWitness = this.instance.exports.getPWitness(i); + w.push(this.getFr(pWitness)); + } + + this.i32[0] = old0; + return w; + } + + allocInt() { + const p = this.i32[0]; + this.i32[0] = p+8; + return p; + } + + allocFr() { + const p = this.i32[0]; + this.i32[0] = p+this.n32*4 + 8; + return p; + } + + getInt(p) { + return this.i32[p>>2]; + } + + setInt(p, v) { + this.i32[p>>2] = v; + } + + getFr(p) { + const idx = (p>>2); + + if (this.i32[idx + 1] & 0x80000000) { + let res= bigInt(0); + for (let i=this.n32-1; i>=0; i--) { + res = res.shiftLeft(32); + res = res.add(bigInt(this.i32[idx+2+i])); + } + if (this.i32[idx + 1] & 0x40000000) { + return fromMontgomery(res); + } else { + return res; + } + + } else { + if (this.i32[idx] & 0x80000000) { + return this.prime.add( bigInt(this.i32[idx]).minus(bigInt(0x100000000)) ); + } else { + return bigInt(this.i32[idx]); + } + } + + function fromMontgomery(n) { + return n.times(this.RInv).mod(this.prime); + } + + } + + + setFr(p, v) { + const self = this; + v = bigInt(v); + + if (v.lt(bigInt("80000000", 16)) ) { + return setShortPositive(v); + } + if (v.geq(self.prime.minus(bigInt("80000000", 16))) ) { + return setShortNegative(v); + } + return setLongNormal(v); + + function setShortPositive(a) { + self.i32[(p >> 2)] = parseInt(a); + self.i32[(p >> 2) + 1] = 0; + } + + function setShortNegative(a) { + const b = bigInt("80000000", 16 ).add(a.minus( self.prime.minus(bigInt("80000000", 16 )))); + self.i32[(p >> 2)] = parseInt(b); + self.i32[(p >> 2) + 1] = 0; + } + + function setLongNormal(a) { + self.i32[(p >> 2)] = 0; + self.i32[(p >> 2) + 1] = 0x80000000; + for (let i=0; i<self.n32; i++) { + self.i32[(p >> 2) + 2 + i] = a.shiftRight(i*32).and(self.mask32); + } + } + } +} + + +
M src/build.js → src/build.js

@@ -34,7 +34,6 @@ ctx.conditionalCodeHeader = "";

ctx.codes_sizes = []; ctx.definedSizes = {}; ctx.addSizes = addSizes; - ctx.constantsMap = {}; ctx.addConstant = addConstant; ctx.addConstant(bigInt.zero); ctx.addConstant(bigInt.one);

@@ -287,12 +286,7 @@ 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; + return this.builder.addConstant(c); } function buildFunction(name, paramValues) {

@@ -320,7 +314,7 @@

ctx.scopes = [{}]; ctx.refs = []; ctx.conditionalCode = false; - ctx.fnBuilder = ctx.builder.newFunctionBuilder(`${name}_${h}`, instanceDef); + ctx.fnBuilder = ctx.builder.newFunctionBuilder(`${name}_${h}`, instanceDef, ctx.functions[name].params); ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder(); ctx.uniqueNames = Object.assign({},ctx.globalNames); ctx.returnValue = null;
M src/builder_c.js → ports/c/builder.js

@@ -1,10 +1,10 @@

-const streamFromMultiArray = require("./stream_from_multiarray"); +const streamFromMultiArray = require("../../src/streamfromarray_txt.js"); const bigInt = require("big-integer"); -const utils = require("./utils"); +const utils = require("../../src/utils"); const assert = require("assert"); function ref2src(c) { - if (c[0] == "R") { + if ((c[0] == "R")||(c[0] == "RI")) { return c[1]; } else if (c[0] == "V") { return c[1].toString();

@@ -94,6 +94,9 @@ checkConstraint(a, b, strErr) {

this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr}); } + log(val) { + this.ops.push({op: "LOG", val}); + } concat(cb) { this.ops.push(...cb.ops);

@@ -211,6 +214,8 @@ } 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}");`); + } else if (o.op == "LOG") { + code.push(`ctx->log(${ref2src(o.val)});`); } }); }

@@ -342,6 +347,8 @@ this.sizes ={};

this.constants = []; this.functions = []; this.components = []; + this.usedConstants = {}; + } setHeader(header) {

@@ -362,7 +369,11 @@ this.sizes[name] = accSizes;

} addConstant(c) { + c = bigInt(c); + const cS = c.toString(); + if (this.usedConstants[cS]) return this.usedConstants[cS]; this.constants.push(c); + this.usedConstants[cS] = this.constants.length - 1; return this.constants.length - 1; }
D src/builder_wasm.js

@@ -1,28 +0,0 @@

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

@@ -0,0 +1,156 @@

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

@@ -1,52 +0,0 @@

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

@@ -4,15 +4,15 @@

const fs = require("fs"); var tmp = require("tmp-promise"); const path = require("path"); -const compiler = require("./compiler"); +const compiler = require("../../src/compiler"); const util = require("util"); const exec = util.promisify(require("child_process").exec); -const stringifyBigInts = require("./utils").stringifyBigInts; -const unstringifyBigInts = require("./utils").unstringifyBigInts; +const stringifyBigInts = require("../../src/utils").stringifyBigInts; +const unstringifyBigInts = require("../../src/utils").unstringifyBigInts; const bigInt = require("big-integer"); -const utils = require("./utils"); -const loadR1cs = require("./r1csfile").loadR1cs; +const utils = require("../../src/utils"); +const loadR1cs = require("../../src/r1csfile").loadR1cs; const ZqField = require("fflib").ZqField; module.exports = c_tester;
M src/compiler.js → src/compiler.js

@@ -21,14 +21,15 @@ const bigInt = require("big-integer");

const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const sONE = 0; const build = require("./build"); -const BuilderC = require("./builder_c"); -const BuilderWasm = require("./builder_wasm"); +const BuilderC = require("../ports/c/builder.js"); +const BuilderWasm = require("../ports/wasm/builder.js"); const constructionPhase = require("./construction_phase"); const Ctx = require("./ctx"); const ZqField = require("fflib").ZqField; const utils = require("./utils"); const buildR1cs = require("./r1csfile").buildR1cs; const BigArray = require("./bigarray"); +const buildSyms = require("./buildsyms"); module.exports = compile;

@@ -92,11 +93,17 @@

// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill)); } - if (options.wasmWriteStream) { + if ((options.wasmWriteStream)||(options.watWriteStream)) { ctx.builder = new BuilderWasm(); build(ctx); - const rdStream = ctx.builder.build(); - rdStream.pipe(options.wasmWriteStream); + if (options.wasmWriteStream) { + const rdStream = ctx.builder.build("wasm"); + rdStream.pipe(options.wasmWriteStream); + } + if (options.watWriteStream) { + const rdStream = ctx.builder.build("wat"); + rdStream.pipe(options.watWriteStream); + } // await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill)); }

@@ -109,7 +116,10 @@ await buildR1cs(ctx, options.r1csFileName);

} if (options.symWriteStream) { - buildSyms(ctx, options.symWriteStream); + const rdStream = buildSyms(ctx); + rdStream.pipe(options.symWriteStream); + + // await new Promise(fulfill => options.symWriteStream.on("finish", fulfill)); } // const def = buildCircuitDef(ctx, mainCode);

@@ -504,6 +514,8 @@

return res; } */ + +/* function buildSyms(ctx, strm) { let nSyms;

@@ -543,5 +555,5 @@ }

} - +*/
M src/gencode.js → src/gencode.js

@@ -754,7 +754,13 @@ if (aRef <0) return ["CC"];

const a = ctx.refs[aRef]; if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element"); if (a.used) { - return ["R", a.label]; + if (a.type == "INT") { + return ["RI", a.label]; + } else if (a.type == "BIGINT") { + return ["R", a.label]; + } else { + assert(false); + } } else { return ["V", a.value[0]]; }

@@ -818,9 +824,7 @@

function genFunctionCall(ctx, ast) { if (ast.name == "log") { const vRef = gen(ctx, ast.params[0]); - const val = ctx.refs[vRef]; - instantiateRef(ctx, vRef, val.value); - ctx.code+=`ctx->log(${val.label});`; + ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef)); return vRef; } const params = [];
M src/r1csfile.js → src/r1csfile.js

@@ -235,7 +235,7 @@ }

} for (let i=0; i<arr.length; i++) { await writeU32(arr[i]); - if ((ctx.verbose)&&(i%100000)) console.log("writing label2wire map: ", i); + if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i); } const mapSize = p - pMapSize -4;
M src/stream_from_multiarray.js → src/streamfromarray_txt.js

@@ -1,7 +1,7 @@

const Readable = require("stream").Readable; -module.exports = function streamFromMultiarray(ma) { +module.exports = function streamFromArrayTxt(ma) { const rs = Readable(); let curIndex = getFirstIdx(ma);

@@ -10,7 +10,7 @@ rs._read = function() {

let res; res = objFromIdx(ma, curIndex); curIndex = nextIdx(curIndex); - if (res!=null) { + if (res!==null) { rs.push(res + "\n"); } else { rs.push(null);
A src/streamfromarray_bin.js

@@ -0,0 +1,21 @@

+ +const Readable = require("stream").Readable; + +module.exports = function streamFromArrayBin(a) { + const rs = Readable(); + + let curIndex = 0; + + rs._read = function(size) { + if (curIndex >= a.length) { + rs.push(null); + return; + } + const start = curIndex; + const end = Math.min(a.length, curIndex+size); + curIndex = end; + rs.push(a.slice(start, end)); + }; + + return rs; +};
M test/basiccases.js → test/basiccases.js

@@ -2,9 +2,11 @@ const path = require("path");

const bigInt = require("big-integer"); const c_tester = require("../index.js").c_tester; +const wasm_tester = require("../index.js").wasm_tester; const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +const basicCases = require("./basiccases.json"); function normalize(o) { if ((typeof(o) == "bigint") || o.isZero !== undefined) {

@@ -31,11 +33,14 @@ }

} -async function doTest(circuit, testVectors) { - const cir = await c_tester(path.join(__dirname, "circuits", circuit)); +async function doTest(tester, circuit, testVectors) { + const cir = await tester(path.join(__dirname, "circuits", circuit)); for (let i=0; i<testVectors.length; i++) { const w = await cir.calculateWitness(normalize(testVectors[i][0])); +// console.log(testVectors[i][0]); +// console.log(w); +// console.log(testVectors[i][1]); await cir.assertOut(w, normalize(testVectors[i][1]) ); }

@@ -44,300 +49,18 @@ }

describe("basic cases", function () { this.timeout(100000); +/* + for (let i=0; i<basicCases.length; i++) { + it("c/c++ " + basicCases[i].name, async () => { + await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv); + }); + } +*/ - it("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}], - ] - ); - }); + for (let i=16; i<17; i++) { + it("wasm " + basicCases[i].name, async () => { + await doTest(wasm_tester, basicCases[i].circuit, basicCases[i].tv); + }); + } });
A test/basiccases.js.old

@@ -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}], + ] + ); + }); + +});
A test/basiccases.json

@@ -0,0 +1,307 @@

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

@@ -31,9 +31,11 @@ out[0] <-- d[0] + c[0];

out[0] === in+c[0]; out[1] <-- d[1]+c[1]; + // out[1] === (in+in)+3+c[1]; out[1] === 2*in+3+c[1]; out[2] <-- d[2]+c[2]; + // out[2] === (in+in+in+in+in+in)+12+c[2]; out[2] === 6*in+12+c[2]; }
D test/circuits/inc.json

@@ -1,1 +0,0 @@

-{"x": "3"}
M test/fieldasm.js → test/fieldasm.js

@@ -1,4 +1,4 @@

-const tester = require("../c/buildasm/buildzqfieldtester.js"); +const tester = require("../ports/c/buildasm/buildzqfieldtester.js"); const ZqField = require("fflib").ZqField;

@@ -17,7 +17,6 @@ it("bn128r add", async () => {

const tv = buildTestVector2(bn128r, "add"); await tester(bn128r, tv); }); - it("secp256k1q add", async () => { const tv = buildTestVector2(secp256k1q, "add"); await tester(secp256k1q, tv);

@@ -267,7 +266,6 @@ it("mnt6753q square", async () => {

const tv = buildTestVector1(mnt6753q, "square"); await tester(mnt6753q, tv); }); - }); function buildTestVector2(p, op) {