Browse Source

Begining of wasm

c_build
Jordi Baylina 4 years ago
parent
commit
8f63d18ff4
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
70 changed files with 3910 additions and 1128 deletions
  1. BIN
      c/buildasm/fr.o
  2. BIN
      c/mainjson
  3. +15
    -1
      cli.js
  4. +2
    -2
      index.js
  5. +8
    -0
      package-lock.json
  6. +1
    -0
      package.json
  7. +0
    -0
      ports/c/buildasm/add.asm.ejs
  8. +0
    -0
      ports/c/buildasm/binops.asm.ejs
  9. +0
    -0
      ports/c/buildasm/buildzqfield.js
  10. +0
    -0
      ports/c/buildasm/buildzqfieldtester.js
  11. +439
    -0
      ports/c/buildasm/cmpops.asm.ejs
  12. +1
    -1
      ports/c/buildasm/cmpops_old.asm.ejs
  13. +6
    -0
      ports/c/buildasm/copy.asm.ejs
  14. +399
    -712
      ports/c/buildasm/fr.asm
  15. +0
    -0
      ports/c/buildasm/fr.asm.ejs
  16. +0
    -1
      ports/c/buildasm/fr.c
  17. +0
    -0
      ports/c/buildasm/fr.c.ejs
  18. +0
    -0
      ports/c/buildasm/fr.h
  19. +0
    -0
      ports/c/buildasm/fr.h.ejs
  20. BIN
      ports/c/buildasm/fr.o
  21. +0
    -0
      ports/c/buildasm/logicalops.asm.ejs
  22. +0
    -0
      ports/c/buildasm/main.c
  23. +0
    -0
      ports/c/buildasm/montgomery.asm.ejs
  24. +0
    -0
      ports/c/buildasm/mul.asm.ejs
  25. +0
    -0
      ports/c/buildasm/neg.asm.ejs
  26. +0
    -0
      ports/c/buildasm/old/buildfieldasm.js
  27. +0
    -0
      ports/c/buildasm/old/buildzqfield.js
  28. +0
    -0
      ports/c/buildasm/old/buildzqfieldtester.js
  29. +0
    -0
      ports/c/buildasm/old/fr.asm.ejs.old
  30. +0
    -0
      ports/c/buildasm/old/mul.asm.ejs
  31. +0
    -0
      ports/c/buildasm/sub.asm.ejs
  32. BIN
      ports/c/buildasm/tester
  33. +0
    -0
      ports/c/buildasm/tester.cpp
  34. +20
    -0
      ports/c/buildasm/tester.dSYM/Contents/Info.plist
  35. BIN
      ports/c/buildasm/tester.dSYM/Contents/Resources/DWARF/tester
  36. +0
    -1
      ports/c/buildasm/utils.asm.ejs
  37. +14
    -3
      ports/c/builder.js
  38. +5
    -0
      ports/c/calcwit.cpp
  39. +0
    -0
      ports/c/calcwit.h
  40. +0
    -0
      ports/c/circom.h
  41. +0
    -0
      ports/c/fr.c
  42. +0
    -0
      ports/c/fr.h
  43. +0
    -0
      ports/c/fr.o
  44. +0
    -0
      ports/c/main.cpp
  45. +0
    -0
      ports/c/mainjson.cpp
  46. +5
    -5
      ports/c/tester.js
  47. +0
    -0
      ports/c/utils.cpp
  48. +0
    -0
      ports/c/utils.h
  49. +0
    -0
      ports/c/zqfield.cpp
  50. +0
    -0
      ports/c/zqfield.h
  51. +748
    -0
      ports/wasm/build_runtime.js
  52. +1003
    -0
      ports/wasm/builder.js
  53. +10
    -0
      ports/wasm/errs.js
  54. +167
    -0
      ports/wasm/tester.js
  55. +186
    -0
      ports/wasm/witness_calculator.js
  56. +2
    -8
      src/build.js
  57. +0
    -28
      src/builder_wasm.js
  58. +156
    -0
      src/buildsyms.js
  59. +0
    -52
      src/buildwasm.js
  60. +19
    -7
      src/compiler.js
  61. +8
    -4
      src/gencode.js
  62. +1
    -1
      src/r1csfile.js
  63. +21
    -0
      src/streamfromarray_bin.js
  64. +2
    -2
      src/streamfromarray_txt.js
  65. +19
    -296
      test/basiccases.js
  66. +343
    -0
      test/basiccases.js.old
  67. +307
    -0
      test/basiccases.json
  68. +2
    -0
      test/circuits/arrays.circom
  69. +0
    -1
      test/circuits/inc.json
  70. +1
    -3
      test/fieldasm.js

BIN
c/buildasm/fr.o


BIN
c/mainjson


+ 15
- 1
cli.js

@ -34,6 +34,7 @@ const argv = require("yargs")
.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.csource) {
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 @@ compiler(fullFileName, options).then( () => {
} else {
wasmDone = true;
}
if (options.watWriteStream) {
options.watWriteStream.on("finish", () => {
watDone = true;
finishIfDone();
});
} else {
watDone = true;
}
if (options.symWriteStream) {
options.symWriteStream.on("finish", () => {
symDone = true;
@ -122,7 +136,7 @@ compiler(fullFileName, options).then( () => {
symDone = true;
}
function finishIfDone() {
if ((cSourceDone)&&(symDone)&&(wasmDone)) {
if ((cSourceDone)&&(symDone)&&(wasmDone)&&(watDone)) {
setTimeout(() => {
process.exit(0);
}, 300);

+ 2
- 2
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");

+ 8
- 0
package-lock.json

@ -1482,6 +1482,14 @@
"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",

+ 1
- 0
package.json

@ -36,6 +36,7 @@
"optimist": "^0.6.1",
"rimraf-promise": "^2.0.0",
"tmp-promise": "^2.0.2",
"wasmbuilder": "0.0.8",
"yargs": "^12.0.2"
},
"devDependencies": {

c/buildasm/add.asm.ejs → ports/c/buildasm/add.asm.ejs


c/buildasm/binops.asm.ejs → ports/c/buildasm/binops.asm.ejs


c/buildasm/buildzqfield.js → ports/c/buildasm/buildzqfield.js


c/buildasm/buildzqfieldtester.js → ports/c/buildasm/buildzqfieldtester.js


+ 439
- 0
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

c/buildasm/cmpops.asm.ejs → ports/c/buildasm/cmpops_old.asm.ejs

@ -40,7 +40,7 @@
;;;;;;;;;;;;;;;;;;;;;;
; <%= op %>
;;;;;;;;;;;;;;;;;;;;;;
; Adds two elements of any kind
; Compares two elements of any kind
; Params:
; rsi <= Pointer to element 1
; rdx <= Pointer to element 2

c/buildasm/copy.asm.ejs → ports/c/buildasm/copy.asm.ejs

@ -97,6 +97,12 @@ u64toLong_adjust_neg:
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

ports/c/buildasm/fr.asm
File diff suppressed because it is too large
View File


c/buildasm/fr.asm.ejs → ports/c/buildasm/fr.asm.ejs


c/buildasm/fr.c → ports/c/buildasm/fr.c

@ -63,7 +63,6 @@ char *Fr_element2str(PFrElement pE) {
} else {
mpz_init_set_si(r, pE->shortVal);
mpz_add(r, r, q);
mpz_clear(q);
}
} else {
Fr_toNormal(pE);

c/buildasm/fr.c.ejs → ports/c/buildasm/fr.c.ejs


c/buildasm/fr.h → ports/c/buildasm/fr.h


c/buildasm/fr.h.ejs → ports/c/buildasm/fr.h.ejs


BIN
ports/c/buildasm/fr.o


c/buildasm/logicalops.asm.ejs → ports/c/buildasm/logicalops.asm.ejs


c/buildasm/main.c → ports/c/buildasm/main.c


c/buildasm/montgomery.asm.ejs → ports/c/buildasm/montgomery.asm.ejs


c/buildasm/mul.asm.ejs → ports/c/buildasm/mul.asm.ejs


c/buildasm/neg.asm.ejs → ports/c/buildasm/neg.asm.ejs


c/buildasm/old/buildfieldasm.js → ports/c/buildasm/old/buildfieldasm.js


c/buildasm/old/buildzqfield.js → ports/c/buildasm/old/buildzqfield.js


c/buildasm/old/buildzqfieldtester.js → ports/c/buildasm/old/buildzqfieldtester.js


c/buildasm/old/fr.asm.ejs.old → ports/c/buildasm/old/fr.asm.ejs.old


c/buildasm/old/mul.asm.ejs → ports/c/buildasm/old/mul.asm.ejs


c/buildasm/sub.asm.ejs → ports/c/buildasm/sub.asm.ejs


BIN
ports/c/buildasm/tester


c/buildasm/tester.cpp → ports/c/buildasm/tester.cpp


+ 20
- 0
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>

BIN
ports/c/buildasm/tester.dSYM/Contents/Resources/DWARF/tester


c/buildasm/utils.asm.ejs → ports/c/buildasm/utils.asm.ejs

@ -70,4 +70,3 @@ return (
pop rdi`);
} %>

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 @@ class CodeBuilderC {
this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
}
log(val) {
this.ops.push({op: "LOG", val});
}
concat(cb) {
this.ops.push(...cb.ops);
@ -211,6 +214,8 @@ class CodeBuilderC {
code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`);
} else if (o.op == "CHECKCONSTRAINT") {
code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`);
} else if (o.op == "LOG") {
code.push(`ctx->log(${ref2src(o.val)});`);
}
});
}
@ -342,6 +347,8 @@ class BuilderC {
this.constants = [];
this.functions = [];
this.components = [];
this.usedConstants = {};
}
setHeader(header) {
@ -362,7 +369,11 @@ class BuilderC {
}
addConstant(c) {
c = bigInt(c);
const cS = c.toString();
if (this.usedConstants[cS]) return this.usedConstants[cS];
this.constants.push(c);
this.usedConstants[cS] = this.constants.length - 1;
return this.constants.length - 1;
}

c/calcwit.cpp → ports/c/calcwit.cpp

@ -63,6 +63,8 @@ void Circom_CalcWit::reset() {
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 @@ void Circom_CalcWit::setSignal(int currentComponentIdx, int cIdx, int sIdx, PFrE
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);
}
}

c/calcwit.h → ports/c/calcwit.h


c/circom.h → ports/c/circom.h


c/fr.c → ports/c/fr.c


c/fr.h → ports/c/fr.h


c/fr.o → ports/c/fr.o


c/main.cpp → ports/c/main.cpp


c/mainjson.cpp → ports/c/mainjson.cpp


src/c_tester.js → ports/c/tester.js

@ -4,15 +4,15 @@ const assert = chai.assert;
const fs = require("fs");
var tmp = require("tmp-promise");
const path = require("path");
const compiler = require("./compiler");
const compiler = require("../../src/compiler");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const stringifyBigInts = require("./utils").stringifyBigInts;
const unstringifyBigInts = require("./utils").unstringifyBigInts;
const 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;

c/utils.cpp → ports/c/utils.cpp


c/utils.h → ports/c/utils.h


c/zqfield.cpp → ports/c/zqfield.cpp


c/zqfield.h → ports/c/zqfield.h


+ 748
- 0
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");
};

+ 1003
- 0
ports/wasm/builder.js
File diff suppressed because it is too large
View File


+ 10
- 0
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"},
};

+ 167
- 0
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;
}
}
}

+ 186
- 0
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);
}
}
}
}

+ 2
- 8
src/build.js

@ -34,7 +34,6 @@ function build(ctx) {
ctx.codes_sizes = [];
ctx.definedSizes = {};
ctx.addSizes = addSizes;
ctx.constantsMap = {};
ctx.addConstant = addConstant;
ctx.addConstant(bigInt.zero);
ctx.addConstant(bigInt.one);
@ -287,12 +286,7 @@ function addSizes(_sizes) {
}
function addConstant(c) {
c = bigInt(c);
const s = c.toString();
if (typeof (this.constantsMap[s]) !== "undefined") return this.constantsMap[s];
const cIdx = this.builder.addConstant(c);
this.constantsMap[s] = cIdx;
return cIdx;
return this.builder.addConstant(c);
}
function buildFunction(name, paramValues) {
@ -320,7 +314,7 @@ function buildFunction(name, paramValues) {
ctx.scopes = [{}];
ctx.refs = [];
ctx.conditionalCode = false;
ctx.fnBuilder = ctx.builder.newFunctionBuilder(`${name}_${h}`, instanceDef);
ctx.fnBuilder = ctx.builder.newFunctionBuilder(`${name}_${h}`, instanceDef, ctx.functions[name].params);
ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
ctx.uniqueNames = Object.assign({},ctx.globalNames);
ctx.returnValue = null;

+ 0
- 28
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;

+ 156
- 0
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;
}
}
}

+ 0
- 52
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) {
}

+ 19
- 7
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 @@ async function compile(srcFile, options) {
// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
}
if (options.wasmWriteStream) {
if ((options.wasmWriteStream)||(options.watWriteStream)) {
ctx.builder = new BuilderWasm();
build(ctx);
const rdStream = ctx.builder.build();
rdStream.pipe(options.wasmWriteStream);
if (options.wasmWriteStream) {
const rdStream = ctx.builder.build("wasm");
rdStream.pipe(options.wasmWriteStream);
}
if (options.watWriteStream) {
const rdStream = ctx.builder.build("wat");
rdStream.pipe(options.watWriteStream);
}
// await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
}
@ -109,7 +116,10 @@ async function compile(srcFile, options) {
}
if (options.symWriteStream) {
buildSyms(ctx, options.symWriteStream);
const rdStream = buildSyms(ctx);
rdStream.pipe(options.symWriteStream);
// await new Promise(fulfill => options.symWriteStream.on("finish", fulfill));
}
// const def = buildCircuitDef(ctx, mainCode);
@ -504,6 +514,8 @@ function buildConstraints(ctx) {
return res;
}
*/
/*
function buildSyms(ctx, strm) {
let nSyms;
@ -543,5 +555,5 @@ function buildSyms(ctx, strm) {
}
*/

+ 8
- 4
src/gencode.js

@ -754,7 +754,13 @@ function toRefA_Int1(ctx, ast, aRef) {
const a = ctx.refs[aRef];
if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
if (a.used) {
return ["R", a.label];
if (a.type == "INT") {
return ["RI", a.label];
} else if (a.type == "BIGINT") {
return ["R", a.label];
} else {
assert(false);
}
} else {
return ["V", a.value[0]];
}
@ -818,9 +824,7 @@ function genArray(ctx, ast) {
function genFunctionCall(ctx, ast) {
if (ast.name == "log") {
const vRef = gen(ctx, ast.params[0]);
const val = ctx.refs[vRef];
instantiateRef(ctx, vRef, val.value);
ctx.code+=`ctx->log(${val.label});`;
ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef));
return vRef;
}
const params = [];

+ 1
- 1
src/r1csfile.js

@ -235,7 +235,7 @@ async function buildR1cs(ctx, fileName) {
}
for (let i=0; i<arr.length; i++) {
await writeU32(arr[i]);
if ((ctx.verbose)&&(i%100000)) console.log("writing label2wire map: ", i);
if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i);
}
const mapSize = p - pMapSize -4;

+ 21
- 0
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;
};

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 @@ module.exports = function streamFromMultiarray(ma) {
let res;
res = objFromIdx(ma, curIndex);
curIndex = nextIdx(curIndex);
if (res!=null) {
if (res!==null) {
rs.push(res + "\n");
} else {
rs.push(null);

+ 19
- 296
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 @@ function normalize(o) {
}
async function doTest(circuit, testVectors) {
const cir = await c_tester(path.join(__dirname, "circuits", circuit));
async function doTest(tester, circuit, testVectors) {
const cir = await tester(path.join(__dirname, "circuits", circuit));
for (let i=0; i<testVectors.length; i++) {
const w = await cir.calculateWitness(normalize(testVectors[i][0]));
// console.log(testVectors[i][0]);
// console.log(w);
// console.log(testVectors[i][1]);
await cir.assertOut(w, normalize(testVectors[i][1]) );
}
@ -44,300 +49,18 @@ async function doTest(circuit, testVectors) {
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);
});
}
});

+ 343
- 0
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}],
]
);
});
});

+ 307
- 0
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}]
]
}
]

+ 2
- 0
test/circuits/arrays.circom

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

+ 0
- 1
test/circuits/inc.json

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

+ 1
- 3
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 @@ describe("field asm test", function () {
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 @@ describe("field asm test", function () {
const tv = buildTestVector1(mnt6753q, "square");
await tester(mnt6753q, tv);
});
});
function buildTestVector2(p, op) {

Loading…
Cancel
Save