Browse Source

Wasm generation finished

c_build
Jordi Baylina 4 years ago
parent
commit
ef899e618b
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
27 changed files with 2794 additions and 551 deletions
  1. +6
    -1
      cli.js
  2. +1
    -0
      index.js
  3. +2
    -2
      ports/c/buildasm/add.asm.ejs
  4. +25
    -2
      ports/c/buildasm/binops.asm.ejs
  5. +2524
    -445
      ports/c/buildasm/fr.asm
  6. +1
    -1
      ports/c/buildasm/fr.asm.ejs
  7. +25
    -8
      ports/c/buildasm/fr.c
  8. +25
    -8
      ports/c/buildasm/fr.c.ejs
  9. BIN
      ports/c/buildasm/fr.o
  10. +13
    -5
      ports/c/buildasm/montgomery.asm.ejs
  11. BIN
      ports/c/buildasm/tester
  12. +2
    -0
      ports/c/buildasm/tester.cpp
  13. +0
    -20
      ports/c/buildasm/tester.dSYM/Contents/Info.plist
  14. BIN
      ports/c/buildasm/tester.dSYM/Contents/Resources/DWARF/tester
  15. +2
    -2
      ports/c/buildasm/utils.asm.ejs
  16. +1
    -1
      ports/c/main.cpp
  17. +5
    -2
      ports/c/tester.js
  18. +7
    -19
      ports/wasm/build_runtime.js
  19. +9
    -1
      ports/wasm/builder.js
  20. +1
    -0
      ports/wasm/tester.js
  21. +38
    -15
      ports/wasm/witness_calculator.js
  22. +1
    -1
      src/compiler.js
  23. +5
    -1
      src/construction_phase.js
  24. +43
    -7
      src/gencode.js
  25. +4
    -4
      test/basiccases.js
  26. +5
    -5
      test/basiccases.json
  27. +49
    -1
      test/fieldasm.js

+ 6
- 1
cli.js

@ -30,7 +30,7 @@ const version = require("./package").version;
const argv = require("yargs") const argv = require("yargs")
.version(version) .version(version)
.usage("circom [input source circuit file] -o [output definition circuit file] -c [output c file]")
.usage("circom [input source circuit file] -r [output r1cs file] -c [output c file] -w [output wasm file] -t [output wat file] -s [output sym file]")
.alias("o", "output") .alias("o", "output")
.alias("c", "csource") .alias("c", "csource")
.alias("w", "wasm") .alias("w", "wasm")
@ -50,6 +50,10 @@ const argv = require("yargs")
type: "boolean", type: "boolean",
description: "Do not optimize constraints" description: "Do not optimize constraints"
}) })
.option("sanityCheck", {
type: "boolean",
description: "Add sanity check code"
})
.epilogue(`Copyright (C) 2018 0kims association .epilogue(`Copyright (C) 2018 0kims association
This program comes with ABSOLUTELY NO WARRANTY; This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
@ -79,6 +83,7 @@ const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym";
const options = {}; const options = {};
options.reduceConstraints = !argv.fast; options.reduceConstraints = !argv.fast;
options.verbose = argv.verbose || false; options.verbose = argv.verbose || false;
options.sanityCheck = argv.sanitycheck;
if (argv.csource) { if (argv.csource) {
options.cSourceWriteStream = fs.createWriteStream(cSourceName); options.cSourceWriteStream = fs.createWriteStream(cSourceName);
} }

+ 1
- 0
index.js

@ -1,3 +1,4 @@
module.exports.compiler = require("./src/compiler.js"); module.exports.compiler = require("./src/compiler.js");
module.exports.c_tester = require("./ports/c/tester.js"); module.exports.c_tester = require("./ports/c/tester.js");
module.exports.wasm_tester = require("./ports/wasm/tester.js"); module.exports.wasm_tester = require("./ports/wasm/tester.js");
module.exports.tester = module.exports.wasm_tester;

+ 2
- 2
ports/c/buildasm/add.asm.ejs

@ -116,14 +116,14 @@ add_l1ms2m:
;;;;;;;; ;;;;;;;;
add_s1l2: add_s1l2:
bt rcx, 62 ; check if montgomery first
bt rcx, 62 ; check if montgomery second
jc add_s1l2m jc add_s1l2m
add_s1l2n: add_s1l2n:
<%= global.setTypeDest("0x80"); %> <%= global.setTypeDest("0x80"); %>
<%= addS1L2(); %> <%= addS1L2(); %>
add_s1l2m: add_s1l2m:
bt rax, 62 ; check if montgomery second
bt rax, 62 ; check if montgomery first
jc add_s1ml2m jc add_s1ml2m
add_s1nl2m: add_s1nl2m:
<%= global.setTypeDest("0xC0"); %> <%= global.setTypeDest("0xC0"); %>

+ 25
- 2
ports/c/buildasm/binops.asm.ejs

@ -1,3 +1,24 @@
<% function binOpSubQIfBigger() { %>
<% const subQ = global.tmpLabel() %>
<% const done = global.tmpLabel() %>
; Compare with q
<% for (let i=0; i<n64; i++) { %>
mov rax, [rdi + <%= (n64-i)*8 %>]
cmp rax, [q + <%= (n64-i-1)*8 %>]
jc <%=done%> ; q is bigget so done.
jnz <%=subQ%> ; q is lower
<% } %>
; If equal substract q
<%=subQ%>:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8 + 8 %>], rax
<% } %>
<%=done%>:
<% } %>
<% function binOpS1S2(op) { %> <% function binOpS1S2(op) { %>
cmp r8d, 0 cmp r8d, 0
<% const s1s2_solveNeg = global.tmpLabel() %> <% const s1s2_solveNeg = global.tmpLabel() %>
@ -35,6 +56,7 @@
<% } %> <% } %>
mov [rdi + <%= (i*8)+8 %> ], rax mov [rdi + <%= (i*8)+8 %> ], rax
<% } %> <% } %>
<% binOpSubQIfBigger() %>
ret ret
<%=s1l2_solveNeg%>: <%=s1l2_solveNeg%>:
@ -59,6 +81,7 @@
<% } %> <% } %>
mov [rdi + <%= (i*8)+8 %> ], rax; mov [rdi + <%= (i*8)+8 %> ], rax;
<% } %> <% } %>
<% binOpSubQIfBigger() %>
ret ret
<%=l1s2_solveNeg%>: <%=l1s2_solveNeg%>:
@ -77,12 +100,11 @@
<% } %> <% } %>
mov [rdi + <%= (i*8)+8 %> ], rax mov [rdi + <%= (i*8)+8 %> ], rax
<% } %> <% } %>
<% binOpSubQIfBigger() %>
ret ret
<% } %> <% } %>
<% function binOp(op) { %> <% function binOp(op) { %>
;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;
; b<%= op %> ; b<%= op %>
@ -212,6 +234,7 @@ bnot_l1n:
<% } %> <% } %>
mov [rdi + <%= i*8 + 8 %>], rax mov [rdi + <%= i*8 + 8 %>], rax
<% } %> <% } %>
<% binOpSubQIfBigger() %>
ret ret

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


+ 1
- 1
ports/c/buildasm/fr.asm.ejs

@ -49,5 +49,5 @@ q dq <%= constantElement(q) %>
half dq <%= constantElement(q.shiftRight(1)) %> half dq <%= constantElement(q.shiftRight(1)) %>
R2 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*2).mod(q)) %> R2 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*2).mod(q)) %>
R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %> R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %>
lboMask dq 0x<%= bigInt("8000000000000000",16).shiftRight(n64*64 - q.bitLength()).minus(bigInt.one).toString(16) %>
lboMask dq 0x<%= bigInt("10000000000000000",16).shiftRight(n64*64 - q.bitLength()).minus(bigInt.one).toString(16) %>

+ 25
- 8
ports/c/buildasm/fr.c

@ -19,6 +19,7 @@ void Fr_toMpz(mpz_t r, PFrElement pE) {
mpz_add(r, r, q); mpz_add(r, r, q);
} }
} else { } else {
Fr_toNormal(pE);
mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal); mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal);
} }
} }
@ -42,7 +43,7 @@ void Fr_init() {
mpz_init_set_ui(one, 1); mpz_init_set_ui(one, 1);
nBits = mpz_sizeinbase (q, 2); nBits = mpz_sizeinbase (q, 2);
mpz_init(mask); mpz_init(mask);
mpz_mul_2exp(mask, one, nBits-1);
mpz_mul_2exp(mask, one, nBits);
mpz_sub(mask, mask, one); mpz_sub(mask, mask, one);
} }
@ -118,11 +119,19 @@ void Fr_shl(PFrElement r, PFrElement a, PFrElement b) {
Fr_toMpz(ma, a); Fr_toMpz(ma, a);
Fr_toMpz(mb, b); Fr_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); mpz_mul_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask); mpz_and(mr, mr, mask);
if (mpz_cmp(mr, q) >= 0) {
mpz_sub(mr, mr, q);
}
} else {
mpz_sub(mb, q, mb);
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb));
} else {
mpz_set(mr, zero);
}
} }
Fr_fromMpz(r, mr); Fr_fromMpz(r, mr);
} }
@ -137,11 +146,19 @@ void Fr_shr(PFrElement r, PFrElement a, PFrElement b) {
Fr_toMpz(ma, a); Fr_toMpz(ma, a);
Fr_toMpz(mb, b); Fr_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
} else {
mpz_sub(mb, q, mb);
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_mul_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
if (mpz_cmp(mr, q) >= 0) {
mpz_sub(mr, mr, q);
}
} else {
mpz_set(mr, zero);
}
} }
Fr_fromMpz(r, mr); Fr_fromMpz(r, mr);
} }

+ 25
- 8
ports/c/buildasm/fr.c.ejs

@ -19,6 +19,7 @@ void <%=name%>_toMpz(mpz_t r, P<%=name%>Element pE) {
mpz_add(r, r, q); mpz_add(r, r, q);
} }
} else { } else {
<%=name%>_toNormal(pE);
mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal); mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal);
} }
} }
@ -42,7 +43,7 @@ void <%=name%>_init() {
mpz_init_set_ui(one, 1); mpz_init_set_ui(one, 1);
nBits = mpz_sizeinbase (q, 2); nBits = mpz_sizeinbase (q, 2);
mpz_init(mask); mpz_init(mask);
mpz_mul_2exp(mask, one, nBits-1);
mpz_mul_2exp(mask, one, nBits);
mpz_sub(mask, mask, one); mpz_sub(mask, mask, one);
} }
@ -118,11 +119,19 @@ void <%=name%>_shl(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b
<%=name%>_toMpz(ma, a); <%=name%>_toMpz(ma, a);
<%=name%>_toMpz(mb, b); <%=name%>_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); mpz_mul_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask); mpz_and(mr, mr, mask);
if (mpz_cmp(mr, q) >= 0) {
mpz_sub(mr, mr, q);
}
} else {
mpz_sub(mb, q, mb);
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb));
} else {
mpz_set(mr, zero);
}
} }
<%=name%>_fromMpz(r, mr); <%=name%>_fromMpz(r, mr);
} }
@ -137,11 +146,19 @@ void <%=name%>_shr(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b
<%=name%>_toMpz(ma, a); <%=name%>_toMpz(ma, a);
<%=name%>_toMpz(mb, b); <%=name%>_toMpz(mb, b);
if (mpz_cmp_ui(mb, nBits) >= 0) {
mpz_set(mr, zero);
} else {
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
} else {
mpz_sub(mb, q, mb);
if (mpz_cmp_ui(mb, nBits) < 0) {
mpz_mul_2exp(mr, ma, mpz_get_ui(mb));
mpz_and(mr, mr, mask);
if (mpz_cmp(mr, q) >= 0) {
mpz_sub(mr, mr, q);
}
} else {
mpz_set(mr, zero);
}
} }
<%=name%>_fromMpz(r, mr); <%=name%>_fromMpz(r, mr);
} }

BIN
ports/c/buildasm/fr.o


+ 13
- 5
ports/c/buildasm/montgomery.asm.ejs

@ -245,23 +245,25 @@ montgomeryTemplate("rawFromMontgomery", function(i, r0, r1, r2) {
;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;
<%=name%>_toMontgomery: <%=name%>_toMontgomery:
mov rax, [rdi] mov rax, [rdi]
bts rax, 62 ; check if montgomery
bt rax, 62 ; check if montgomery
jc toMontgomery_doNothing jc toMontgomery_doNothing
bts rax, 63
bt rax, 63
jc toMontgomeryLong jc toMontgomeryLong
toMontgomeryShort: toMontgomeryShort:
mov [rdi], rax
add rdi, 8 add rdi, 8
push rsi push rsi
push rdx
lea rsi, [R2] lea rsi, [R2]
movsx rdx, eax movsx rdx, eax
cmp rdx, 0 cmp rdx, 0
js negMontgomeryShort js negMontgomeryShort
posMontgomeryShort: posMontgomeryShort:
call rawMontgomeryMul1 call rawMontgomeryMul1
pop rdx
pop rsi pop rsi
sub rdi, 8 sub rdi, 8
<%= global.setTypeDest("0x40"); %>
ret ret
negMontgomeryShort: negMontgomeryShort:
@ -269,8 +271,10 @@ negMontgomeryShort:
call rawMontgomeryMul1 call rawMontgomeryMul1
mov rsi, rdi mov rsi, rdi
call rawNegL call rawNegL
pop rdx
pop rsi pop rsi
sub rdi, 8 sub rdi, 8
<%= global.setTypeDest("0x40"); %>
ret ret
@ -283,6 +287,8 @@ toMontgomeryLong:
call rawMontgomeryMul call rawMontgomeryMul
pop rsi pop rsi
sub rdi, 8 sub rdi, 8
<%= global.setTypeDest("0xC0"); %>
toMontgomery_doNothing: toMontgomery_doNothing:
ret ret
@ -297,16 +303,16 @@ toMontgomery_doNothing:
;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;
<%=name%>_toNormal: <%=name%>_toNormal:
mov rax, [rdi] mov rax, [rdi]
btc rax, 62 ; check if montgomery
bt rax, 62 ; check if montgomery
jnc toNormal_doNothing jnc toNormal_doNothing
bt rax, 63 ; if short, it means it's converted bt rax, 63 ; if short, it means it's converted
jnc toNormal_doNothing jnc toNormal_doNothing
toNormalLong: toNormalLong:
mov [rdi], rax
add rdi, 8 add rdi, 8
call rawFromMontgomery call rawFromMontgomery
sub rdi, 8 sub rdi, 8
<%= global.setTypeDest("0x80"); %>
toNormal_doNothing: toNormal_doNothing:
ret ret
@ -331,6 +337,7 @@ toLongNormal_fromMontgomery:
add rdi, 8 add rdi, 8
call rawFromMontgomery call rawFromMontgomery
sub rdi, 8 sub rdi, 8
<%= global.setTypeDest("0x80"); %>
ret ret
toLongNormal_fromShort: toLongNormal_fromShort:
@ -338,5 +345,6 @@ toLongNormal_fromShort:
movsx rsi, eax movsx rsi, eax
call rawCopyS2L call rawCopyS2L
mov rsi, r8 ; recover rsi mov rsi, r8 ; recover rsi
<%= global.setTypeDest("0x80"); %>
ret ret

BIN
ports/c/buildasm/tester


+ 2
- 0
ports/c/buildasm/tester.cpp

@ -56,6 +56,8 @@ void fillMap() {
addFunction("land", (FuncAny)Fr_land, 2); addFunction("land", (FuncAny)Fr_land, 2);
addFunction("lor", (FuncAny)Fr_lor, 2); addFunction("lor", (FuncAny)Fr_lor, 2);
addFunction("lnot", (FuncAny)Fr_lnot, 1); addFunction("lnot", (FuncAny)Fr_lnot, 1);
addFunction("shl", (FuncAny)Fr_shl, 2);
addFunction("shr", (FuncAny)Fr_shr, 2);
} }
u_int64_t readInt(std::string &s) { u_int64_t readInt(std::string &s) {

+ 0
- 20
ports/c/buildasm/tester.dSYM/Contents/Info.plist

@ -1,20 +0,0 @@
<?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


+ 2
- 2
ports/c/buildasm/utils.asm.ejs

@ -1,8 +1,8 @@
<% global.setTypeDest = function (t) { <% global.setTypeDest = function (t) {
return ( return (
` mov r11b, ${t} ` mov r11b, ${t}
shl r11, 56
mov [rdi], r11`);
shl r11d, 24
mov [rdi+4], r11d`);
} %> } %>

+ 1
- 1
ports/c/main.cpp

@ -184,7 +184,7 @@ int main(int argc, char *argv[]) {
ctx->join(); ctx->join();
printf("Finished!\n");
// printf("Finished!\n");
std::string outfilename = argv[2]; std::string outfilename = argv[2];

+ 5
- 2
ports/c/tester.js

@ -47,7 +47,7 @@ async function c_tester(circomFile, _options) {
` ${path.join(dir.path, baseName + ".cpp")} ` + ` ${path.join(dir.path, baseName + ".cpp")} ` +
` -o ${path.join(dir.path, baseName)}` + ` -o ${path.join(dir.path, baseName)}` +
` -I ${cdir}` + ` -I ${cdir}` +
" -lgmp -std=c++11 -DSANITY_CHECK"
" -lgmp -std=c++11 -DSANITY_CHECK -g"
); );
// console.log(dir.path); // console.log(dir.path);
@ -70,10 +70,13 @@ class CTester {
path.join(this.dir.path, "in.json"), path.join(this.dir.path, "in.json"),
JSON.stringify(stringifyBigInts(input), null, 1) JSON.stringify(stringifyBigInts(input), null, 1)
); );
await exec(`${path.join(this.dir.path, this.baseName)}` +
const r = await exec(`${path.join(this.dir.path, this.baseName)}` +
` ${path.join(this.dir.path, "in.json")}` + ` ${path.join(this.dir.path, "in.json")}` +
` ${path.join(this.dir.path, "out.json")}` ` ${path.join(this.dir.path, "out.json")}`
); );
if (r.stdout) {
console.log(r.stdout);
}
const resStr = await fs.promises.readFile( const resStr = await fs.promises.readFile(
path.join(this.dir.path, "out.json") path.join(this.dir.path, "out.json")
); );

+ 7
- 19
ports/wasm/build_runtime.js

@ -545,15 +545,15 @@ module.exports = function buildRuntime(module, builder) {
f.addCode( f.addCode(
c.call( c.call(
"Fr_eq", "Fr_eq",
c.getLocal(c.i32_const(pTmp)),
c.i32_const(pTmp),
c.getLocal("pA"), c.getLocal("pA"),
c.getLocal("pB") c.getLocal("pB")
), ),
c.if ( c.if (
c.eqz(
c.i32_eqz(
c.call( c.call(
"Fr_isTrue", "Fr_isTrue",
c.getLocal(c.i32_const(pTmp)),
c.i32_const(pTmp),
) )
), ),
c.call( c.call(
@ -658,21 +658,6 @@ module.exports = function buildRuntime(module, builder) {
); );
} }
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"); const fErr = module.addIimportFunction("err", "runtime");
fErr.addParam("code", "i32"); fErr.addParam("code", "i32");
fErr.addParam("pStr", "i32"); fErr.addParam("pStr", "i32");
@ -703,6 +688,9 @@ module.exports = function buildRuntime(module, builder) {
fErr4.addParam("param3", "i32"); fErr4.addParam("param3", "i32");
fErr4.addParam("param4", "i32"); fErr4.addParam("param4", "i32");
const fLog = module.addIimportFunction("log", "runtime");
fLog.addParam("code", "i32");
buildWasmFf(module, "Fr", builder.header.P); buildWasmFf(module, "Fr", builder.header.P);
builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr); builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr);
@ -734,7 +722,7 @@ module.exports = function buildRuntime(module, builder) {
buildGetPWitness(); buildGetPWitness();
buildGetPRawPrime(); buildGetPRawPrime();
buildFrToInt();
// buildFrToInt();
module.exportFunction("init"); module.exportFunction("init");
module.exportFunction("getNVars"); module.exportFunction("getNVars");

+ 9
- 1
ports/wasm/builder.js

@ -104,6 +104,10 @@ class CodeBuilderWasm {
this.ops.push(...cb.ops); this.ops.push(...cb.ops);
} }
log(val) {
this.ops.push({op: "LOG", val});
}
hasCode() { hasCode() {
for (let i=0; i<this.ops.length; i++) { for (let i=0; i<this.ops.length; i++) {
if (this.ops[i].op != "COMMENT") return true; if (this.ops[i].op != "COMMENT") return true;
@ -111,6 +115,7 @@ class CodeBuilderWasm {
return false; return false;
} }
_buildOffset(c, offsets) { _buildOffset(c, offsets) {
let rN=0; let rN=0;
let S = null; let S = null;
@ -671,7 +676,7 @@ class FunctionBuilderWasm {
} }
class BuilderWasm { class BuilderWasm {
constructor() {
constructor(sanityCheck) {
this.hashMaps={}; this.hashMaps={};
this.componentEntriesTables={}; this.componentEntriesTables={};
this.sizes ={}; this.sizes ={};
@ -679,6 +684,7 @@ class BuilderWasm {
this.usedConstants = {}; this.usedConstants = {};
this.functions = []; this.functions = [];
this.components = []; this.components = [];
this.sanityCheck = sanityCheck;
this.TYPE_SIGNAL = 1; this.TYPE_SIGNAL = 1;
this.TYPE_COMPONENT = 2; this.TYPE_COMPONENT = 2;
@ -989,6 +995,8 @@ class BuilderWasm {
this._buildMapIsInput(module); this._buildMapIsInput(module);
this._buildWit2Sig(module); this._buildWit2Sig(module);
this._buildCircuitVar(module); this._buildCircuitVar(module);
module.setMemory(2000);
if (outType == "wasm") { if (outType == "wasm") {
return streamFromArrayBin(module.build()); return streamFromArrayBin(module.build());
} else if (outType == "wat") { } else if (outType == "wat") {

+ 1
- 0
ports/wasm/tester.js

@ -33,6 +33,7 @@ async function wasm_tester(circomFile, _options) {
options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm")); options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm"));
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym")); options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
options.r1csFileName = path.join(dir.path, baseName + ".r1cs"); options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
options.sanityCheck = true;
const promisesArr = []; const promisesArr = [];
promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill))); promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill)));

+ 38
- 15
ports/wasm/witness_calculator.js

@ -17,33 +17,55 @@ module.exports.fromBuffer = async function(code) {
const memory = new WebAssembly.Memory({initial:20000}); const memory = new WebAssembly.Memory({initial:20000});
const wasmModule = await WebAssembly.compile(code); const wasmModule = await WebAssembly.compile(code);
let wc;
const instance = await WebAssembly.instantiate(wasmModule, { const instance = await WebAssembly.instantiate(wasmModule, {
env: { env: {
"memory": memory "memory": memory
}, },
runtime: { runtime: {
err: function(code, pstr) { err: function(code, pstr) {
console.log("ERROR", code, p2str(pstr));
const errStr=p2str(pstr);
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
}, },
err1: function(code, pstr, a) { err1: function(code, pstr, a) {
console.log("ERROR: ", code, p2str(pstr), a);
const errStr=p2str(pstr)+ " " + a;
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
}, },
err2: function(code, pstr, a, b) { err2: function(code, pstr, a, b) {
console.log("ERROR: ", code, p2str(pstr), a, b);
const errStr=p2str(pstr)+ " " + a + " " + b;
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
}, },
err3: function(code, pstr, a, b, c) { err3: function(code, pstr, a, b, c) {
console.log("ERROR: ", code, p2str(pstr), a, b, c);
const errStr=p2str(pstr)+ " " + a + " " + b + " " + c;
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
}, },
err4: function(code, pstr, a,b,c,d) { err4: function(code, pstr, a,b,c,d) {
console.log("ERROR: ", code, p2str(pstr), a, b, c, d);
const errStr=p2str(pstr) + " " + wc.getFr(b).toString() + " != " + wc.getFr(c).toString() + " " +p2str(d);
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
},
log: function(a) {
console.log(wc.getFr(a).toString());
}, },
} }
}); });
return new WitnessCalculator(memory, instance);
wc = new WitnessCalculator(memory, instance);
return wc;
function p2str(p) { function p2str(p) {
return "TODO"+p;
const i8 = new Uint8Array(memory.buffer);
const bytes = [];
for (let i=0; i8[p+i]>0; i++) bytes.push(i8[p+i]);
return String.fromCharCode.apply(null, bytes);
} }
}; };
@ -120,30 +142,31 @@ class WitnessCalculator {
} }
getFr(p) { getFr(p) {
const self = this;
const idx = (p>>2); const idx = (p>>2);
if (this.i32[idx + 1] & 0x80000000) {
if (self.i32[idx + 1] & 0x80000000) {
let res= bigInt(0); let res= bigInt(0);
for (let i=this.n32-1; i>=0; i--) {
for (let i=self.n32-1; i>=0; i--) {
res = res.shiftLeft(32); res = res.shiftLeft(32);
res = res.add(bigInt(this.i32[idx+2+i]));
res = res.add(bigInt(self.i32[idx+2+i]));
} }
if (this.i32[idx + 1] & 0x40000000) {
if (self.i32[idx + 1] & 0x40000000) {
return fromMontgomery(res); return fromMontgomery(res);
} else { } else {
return res; return res;
} }
} else { } else {
if (this.i32[idx] & 0x80000000) {
return this.prime.add( bigInt(this.i32[idx]).minus(bigInt(0x100000000)) );
if (self.i32[idx] & 0x80000000) {
return self.prime.add( bigInt(self.i32[idx]).minus(bigInt(0x100000000)) );
} else { } else {
return bigInt(this.i32[idx]);
return bigInt(self.i32[idx]);
} }
} }
function fromMontgomery(n) { function fromMontgomery(n) {
return n.times(this.RInv).mod(this.prime);
return n.times(self.RInv).mod(self.prime);
} }
} }

+ 1
- 1
src/compiler.js

@ -94,7 +94,7 @@ async function compile(srcFile, options) {
} }
if ((options.wasmWriteStream)||(options.watWriteStream)) { if ((options.wasmWriteStream)||(options.watWriteStream)) {
ctx.builder = new BuilderWasm();
ctx.builder = new BuilderWasm(options.sanityCheck);
build(ctx); build(ctx);
if (options.wasmWriteStream) { if (options.wasmWriteStream) {
const rdStream = ctx.builder.build("wasm"); const rdStream = ctx.builder.build("wasm");

+ 5
- 1
src/construction_phase.js

@ -558,7 +558,11 @@ function execFunctionCall(ctx, ast) {
if (ast.name == "log") { if (ast.name == "log") {
const v = exec(ctx, ast.params[0]); const v = exec(ctx, ast.params[0]);
const ev = val(ctx, v, ast); const ev = val(ctx, v, ast);
console.log(ev.v.toString());
if (ev.v) {
console.log(ev.v.toString());
} else {
console.log(JSON.stringify(ev));
}
return; return;
} }
if (ast.name == "assert") { if (ast.name == "assert") {

+ 43
- 7
src/gencode.js

@ -423,13 +423,21 @@ function genVariable(ctx, ast) {
} else if (v.type == "BIGINT") { } else if (v.type == "BIGINT") {
const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors ); const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
const offset = ctx.refs[refOffset]; const offset = ctx.refs[refOffset];
let ot;
if (offset.type == "BIGINT") {
ot = "R";
} else if (offset.type == "INT") {
ot= "RI";
} else {
assert(false);
}
if (v.used) { if (v.used) {
if (offset.used) { if (offset.used) {
const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
const res = ctx.refs[refRes]; const res = ctx.refs[refRes];
res.used = true; res.used = true;
ctx.fnBuilder.definePFrElement(res.label); ctx.fnBuilder.definePFrElement(res.label);
ctx.codeBuilder.assign(res.label, ["R", v.label], ["R", offset.label]);
ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
return refRes; return refRes;
} else if ((offset.value[0]>0)||(l>0)) { } else if ((offset.value[0]>0)||(l>0)) {
const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
@ -448,7 +456,7 @@ function genVariable(ctx, ast) {
const res = ctx.refs[resRef]; const res = ctx.refs[resRef];
res.used = true; res.used = true;
ctx.fnBuilder.definePFrElement(res.label); ctx.fnBuilder.definePFrElement(res.label);
ctx.codeBuilder.assign(res.label, ["R", v.label], ["R", offset.label]);
ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
return resRef; return resRef;
} else { } else {
// return newSubRef(ctx, ast.name, ast.selectors); // return newSubRef(ctx, ast.name, ast.selectors);
@ -499,7 +507,13 @@ function genGetSubComponentOffset(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label];
if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@ -520,7 +534,13 @@ function genGetSubComponentSizes(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label];
if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@ -553,7 +573,13 @@ function genGetSignalOffset(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label];
if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@ -590,7 +616,13 @@ function genGetSignalSizes(ctx, cIdxRef, label) {
if (cIdxRef>=0) { if (cIdxRef>=0) {
const cIdx = ctx.refs[cIdxRef]; const cIdx = ctx.refs[cIdxRef];
if (cIdx.used) { if (cIdx.used) {
c = ["R", cIdx.label];
if (cIdx.type == "BIGINT") {
c = ["R", cIdx.label];
} else if (cIdx.type == "INT") {
c = ["RI", cIdx.label];
} else {
assert(false);
}
} else { } else {
c = ["V", cIdx.value[0]]; c = ["V", cIdx.value[0]];
} }
@ -743,7 +775,11 @@ function toRefA_Fr1(ctx, ast, aRef) {
const a = ctx.refs[aRef]; const a = ctx.refs[aRef];
if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element"); if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
if (a.used) { if (a.used) {
return ["R", a.label];
if (a.type == "BIGINT") {
return ["R", a.label];
} else {
assert(false);
}
} else { } else {
return ["C", ctx.addConstant(a.value[0])]; return ["C", ctx.addConstant(a.value[0])];
} }

+ 4
- 4
test/basiccases.js

@ -49,18 +49,18 @@ async function doTest(tester, circuit, testVectors) {
describe("basic cases", function () { describe("basic cases", function () {
this.timeout(100000); this.timeout(100000);
/*
for (let i=0; i<basicCases.length; i++) { for (let i=0; i<basicCases.length; i++) {
it("c/c++ " + basicCases[i].name, async () => { it("c/c++ " + basicCases[i].name, async () => {
await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv); await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv);
}); });
} }
*/
for (let i=16; i<17; i++) {
/*
for (let i=0; i<basicCases.length; i++) {
it("wasm " + basicCases[i].name, async () => { it("wasm " + basicCases[i].name, async () => {
await doTest(wasm_tester, basicCases[i].circuit, basicCases[i].tv); await doTest(wasm_tester, basicCases[i].circuit, basicCases[i].tv);
}); });
} }
*/
}); });

+ 5
- 5
test/basiccases.json

@ -198,7 +198,7 @@
"and": 1, "and": 1,
"or": 7, "or": 7,
"xor":6, "xor":6,
"not1": "14474011154664524427946373126085988481658748083205070504932198000989141204986",
"not1": "7059779437489773633646340506914701874769131765994106666166191815402473914361",
"shl": 40, "shl": 40,
"shr":0 "shr":0
} }
@ -211,7 +211,7 @@
"and": 0, "and": 0,
"or": 0, "or": 0,
"xor":0, "xor":0,
"not1":"14474011154664524427946373126085988481658748083205070504932198000989141204991",
"not1":"7059779437489773633646340506914701874769131765994106666166191815402473914366",
"shl": 0, "shl": 0,
"shr":0 "shr":0
} }
@ -222,10 +222,10 @@
}, },
{ {
"and": 0, "and": 0,
"or": "7414231717174750794300032619171286606889616317210963838766006185586667290625",
"xor":"7414231717174750794300032619171286606889616317210963838766006185586667290625",
"or": 0,
"xor": 0,
"not1": "7059779437489773633646340506914701874769131765994106666166191815402473914367", "not1": "7059779437489773633646340506914701874769131765994106666166191815402473914367",
"shl": "354452279684977160653692112256584732120484551216857172599814370184193376256",
"shl": "14828463434349501588600065238342573213779232634421927677532012371173334581248",
"shr": "10944121435919637611123202872628637544274182200208017171849102093287904247808" "shr": "10944121435919637611123202872628637544274182200208017171849102093287904247808"
} }
] ]

+ 49
- 1
test/fieldasm.js

@ -17,6 +17,7 @@ describe("field asm test", function () {
const tv = buildTestVector2(bn128r, "add"); const tv = buildTestVector2(bn128r, "add");
await tester(bn128r, tv); await tester(bn128r, tv);
}); });
/*
it("secp256k1q add", async () => { it("secp256k1q add", async () => {
const tv = buildTestVector2(secp256k1q, "add"); const tv = buildTestVector2(secp256k1q, "add");
await tester(secp256k1q, tv); await tester(secp256k1q, tv);
@ -37,7 +38,6 @@ describe("field asm test", function () {
const tv = buildTestVector2(mnt6753q, "sub"); const tv = buildTestVector2(mnt6753q, "sub");
await tester(mnt6753q, tv); await tester(mnt6753q, tv);
}); });
it("bn128r neg", async () => { it("bn128r neg", async () => {
const tv = buildTestVector1(bn128r, "neg"); const tv = buildTestVector1(bn128r, "neg");
await tester(bn128r, tv); await tester(bn128r, tv);
@ -266,6 +266,51 @@ describe("field asm test", function () {
const tv = buildTestVector1(mnt6753q, "square"); const tv = buildTestVector1(mnt6753q, "square");
await tester(mnt6753q, tv); await tester(mnt6753q, tv);
}); });
*/
it("bn128r shl", async () => {
const tv = buildTestVector2(bn128r, "shl");
await tester(bn128r, tv);
});
/*
it("secp256k1q shl", async () => {
const tv = buildTestVector2(secp256k1q, "shl");
await tester(secp256k1q, tv);
});
it("mnt6753q shl", async () => {
const tv = buildTestVector2(mnt6753q, "shl");
await tester(mnt6753q, tv);
});
*/
it("bn128r shr", async () => {
const tv = buildTestVector2(bn128r, "shr");
await tester(bn128r, tv);
});
/*
it("secp256k1q shr", async () => {
const tv = buildTestVector2(secp256k1q, "shr");
await tester(secp256k1q, tv);
});
it("mnt6753q shr", async () => {
const tv = buildTestVector2(mnt6753q, "shr");
await tester(mnt6753q, tv);
});
it("mnt6753q band", async () => {
const tv = buildTestVector2(mnt6753q, "band");
await tester(mnt6753q, tv);
});
it("mnt6753q bor", async () => {
const tv = buildTestVector2(mnt6753q, "bor");
await tester(mnt6753q, tv);
});
it("mnt6753q bxor", async () => {
const tv = buildTestVector2(mnt6753q, "bxor");
await tester(mnt6753q, tv);
});
it("mnt6753q bnot", async () => {
const tv = buildTestVector1(mnt6753q, "bnot");
await tester(mnt6753q, tv);
});
*/
}); });
function buildTestVector2(p, op) { function buildTestVector2(p, op) {
@ -310,6 +355,9 @@ function getCriticalNumbers(p, lim) {
const numbers = []; const numbers = [];
addFrontier(0); addFrontier(0);
addFrontier(bigInt(32));
addFrontier(bigInt(64));
addFrontier(bigInt(p.bitLength()));
addFrontier(bigInt.one.shiftLeft(31)); addFrontier(bigInt.one.shiftLeft(31));
addFrontier(p.minus(bigInt.one.shiftLeft(31))); addFrontier(p.minus(bigInt.one.shiftLeft(31)));
addFrontier(bigInt.one.shiftLeft(32)); addFrontier(bigInt.one.shiftLeft(32));

Loading…
Cancel
Save