Browse Source

Use native big int

master
Jordi Baylina 4 years ago
parent
commit
767ca60008
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
18 changed files with 276 additions and 518 deletions
  1. +2
    -2
      cli.js
  2. +14
    -14
      package-lock.json
  3. +4
    -5
      package.json
  4. +29
    -137
      parser/jaz.jison
  5. +30
    -138
      parser/jaz.js
  6. +38
    -25
      ports/c/builder.js
  7. +11
    -9
      ports/c/tester.js
  8. +38
    -31
      ports/wasm/builder.js
  9. +6
    -7
      ports/wasm/tester.js
  10. +9
    -10
      src/build.js
  11. +10
    -13
      src/compiler.js
  12. +22
    -21
      src/construction_phase.js
  13. +5
    -4
      src/ctx.js
  14. +11
    -11
      src/gencode.js
  15. +35
    -36
      src/lcalgebra.js
  16. +4
    -4
      src/r1csfile.js
  17. +1
    -40
      src/utils.js
  18. +7
    -11
      test/basiccases.js

+ 2
- 2
cli.js

@ -23,7 +23,7 @@
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const bigInt = require("big-integer");
const Scalar = require("ffjavascript").Scalar;
const compiler = require("./src/compiler"); const compiler = require("./src/compiler");
@ -82,7 +82,7 @@ const options = {};
options.reduceConstraints = !argv.fast; options.reduceConstraints = !argv.fast;
options.verbose = argv.verbose || false; options.verbose = argv.verbose || false;
options.sanityCheck = argv.sanitycheck; options.sanityCheck = argv.sanitycheck;
options.prime = argv.prime || bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
options.prime = argv.prime ? Scalar.fromString(argv.prime) : Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
if (argv.csource) { if (argv.csource) {
options.cSourceWriteStream = fs.createWriteStream(cSourceName); options.cSourceWriteStream = fs.createWriteStream(cSourceName);

+ 14
- 14
package-lock.json

@ -221,11 +221,11 @@
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
}, },
"circom_runtime": { "circom_runtime": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.0.3.tgz",
"integrity": "sha512-z4ypbs9cTQn7+2FHZNTnccMj6kQCcKT2agYqCrm2kdLBJh9LDoxU1JVu5mSnVuOtgc7BclQ7r0xclG0zP2rxhw==",
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.0.5.tgz",
"integrity": "sha512-WEZHnRO1AJIDI2w1yX6rq4G1/MMKnExT3qirjBQR7x43i9Ww3E/wusBHTbXWLb8aYyxsBU07LGy0YXPywPGYvA==",
"requires": { "requires": {
"big-integer": "^1.6.48",
"ffjavascript": "0.1.0",
"fnv-plus": "^1.3.1" "fnv-plus": "^1.3.1"
} }
}, },
@ -592,17 +592,17 @@
} }
}, },
"ffjavascript": { "ffjavascript": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.0.5.tgz",
"integrity": "sha512-7je6PydOWLDUj3vU8JeCUgeezg4yrG/6qjlukQNuPHeeavnM4REcrN9LA2+xtqIMIPdx/wdUkPMQpixsz+CdIw==",
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz",
"integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==",
"requires": { "requires": {
"big-integer": "^1.6.48" "big-integer": "^1.6.48"
} }
}, },
"ffwasm": { "ffwasm": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/ffwasm/-/ffwasm-0.0.6.tgz",
"integrity": "sha512-bEBKYANozdyZBCGE6XLg4s/CaJRZdFGQgbthy7EZ4OhNCIpycgklS5mlf88Bw4fXSddlU1V9iYXI4JwfGO3BhQ==",
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ffwasm/-/ffwasm-0.0.7.tgz",
"integrity": "sha512-17cTLzv7HHAKqZbX8MvHxjSrR0yDdn1sh4TVsTbAvO9e6klhFicnyoVXc/sCuViV/M8g65sCmVrAmoPCZp1YkQ==",
"requires": { "requires": {
"big-integer": "^1.6.48", "big-integer": "^1.6.48",
"wasmbuilder": "0.0.10" "wasmbuilder": "0.0.10"
@ -1123,11 +1123,11 @@
"dev": true "dev": true
}, },
"r1csfile": { "r1csfile": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.3.tgz",
"integrity": "sha512-TNrodnbHw5yAMv2gj0Ezf22XS3q8zGEjdPHZLBmJauIPFxm6QmyzxlB92yZ5WNkjEtJiS7p1hvkO9/RsJXRDjw==",
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.4.tgz",
"integrity": "sha512-1Y/zzzEjQVTR/gPlduRaKi2K+yU+UxqtsS+obDLEEb4WAzwCkKGybRfp037CUW5OApeleS1WdGmtKv9K9FPhsA==",
"requires": { "requires": {
"big-integer": "^1.6.48"
"ffjavascript": "0.1.0"
} }
}, },
"regexpp": { "regexpp": {

+ 4
- 5
package.json

@ -29,14 +29,13 @@
"url": "https://github.com/iden3/circom.git" "url": "https://github.com/iden3/circom.git"
}, },
"dependencies": { "dependencies": {
"big-integer": "^1.6.32",
"chai": "^4.2.0", "chai": "^4.2.0",
"circom_runtime": "0.0.3",
"circom_runtime": "0.0.5",
"ffiasm": "0.0.2", "ffiasm": "0.0.2",
"ffjavascript": "0.0.5",
"ffwasm": "0.0.6",
"ffjavascript": "0.1.0",
"ffwasm": "0.0.7",
"fnv-plus": "^1.3.1", "fnv-plus": "^1.3.1",
"r1csfile": "0.0.3",
"r1csfile": "0.0.4",
"tmp-promise": "^2.0.2", "tmp-promise": "^2.0.2",
"wasmbuilder": "0.0.10" "wasmbuilder": "0.0.10"
}, },

+ 29
- 137
parser/jaz.jison

@ -132,10 +132,8 @@ include { return 'include'; }
%{ %{
const bigInt = require('big-integer');
const Scalar = require('ffjavascript').Scalar;
const util = require('util'); const util = require('util');
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const __MASK__ = new bigInt(2).pow(253).minus(1);
function setLines(dst, first, last) { function setLines(dst, first, last) {
last = last || first; last = last || first;
@ -266,20 +264,12 @@ identifierList
ifStatment ifStatment
: 'if' '(' expression ')' statment 'else' statment : 'if' '(' expression ')' statment 'else' statment
{ {
if ($3.type == "NUMBER") {
$$ = !$3.value.eq(0) ? $5 : $7;
} else {
$$ = { type: "IF", condition: $3, then: $5, else: $7 };
}
$$ = { type: "IF", condition: $3, then: $5, else: $7 };
setLines($$, @1, @7); setLines($$, @1, @7);
} }
| 'if' '(' expression ')' statment | 'if' '(' expression ')' statment
{ {
if ($3.type == "NUMBER") {
$$ = !$3.value.eq(0) ? $5 : { type: "NUMBER", value: bigInt(0) };
} else {
$$ = { type: "IF", condition: $3, then: $5 };
}
$$ = { type: "IF", condition: $3, then: $5 };
setLines($$, @1, @5); setLines($$, @1, @5);
} }
; ;
@ -451,11 +441,7 @@ e17
} }
| e17 '?' e17 ':' e17 %prec TERCOND | e17 '?' e17 ':' e17 %prec TERCOND
{ {
if ($1.type == "NUMBER") {
$$ = !$1.value.eq(0) ? $3 : $5;
} else {
$$ = { type: "OP", op: "?", values: [$1, $3, $5] };
}
$$ = { type: "OP", op: "?", values: [$1, $3, $5] };
setLines($$, @1, @5); setLines($$, @1, @5);
} }
| e16 %prec EMPTY | e16 %prec EMPTY
@ -478,11 +464,7 @@ e16
e15 e15
: e15 '||' e14 : e15 '||' e14
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: !$1.value.eq(0) || !$3.value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "||", values: [$1, $3] };
}
$$ = { type: "OP", op: "||", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e14 %prec EMPTY | e14 %prec EMPTY
@ -494,11 +476,7 @@ e15
e14 e14
: e14 '&&' e13 : e14 '&&' e13
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: !$1.value.eq(0) && !$3.value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "&&", values: [$1, $3] };
}
$$ = { type: "OP", op: "&&", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e13 %prec EMPTY | e13 %prec EMPTY
@ -510,11 +488,7 @@ e14
e13 e13
: e13 '|' e12 : e13 '|' e12
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.or($3.value).and(__MASK__) };
} else {
$$ = { type: "OP", op: "|", values: [$1, $3] };
}
$$ = { type: "OP", op: "|", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e12 %prec EMPTY | e12 %prec EMPTY
@ -527,11 +501,7 @@ e13
e12 e12
: e12 '^' e11 : e12 '^' e11
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.xor($3.value).and(__MASK__) };
} else {
$$ = { type: "OP", op: "^", values: [$1, $3] };
}
$$ = { type: "OP", op: "^", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e11 %prec EMPTY | e11 %prec EMPTY
@ -543,11 +513,7 @@ e12
e11 e11
: e11 '&' e10 : e11 '&' e10
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.and($3.value).and(__MASK__) };
} else {
$$ = { type: "OP", op: "&", values: [$1, $3] };
}
$$ = { type: "OP", op: "&", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e10 %prec EMPTY | e10 %prec EMPTY
@ -562,20 +528,12 @@ e11
e10 e10
: e10 '==' e9 : e10 '==' e9
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.equals($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "==", values: [$1, $3] };
}
$$ = { type: "OP", op: "==", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e10 '!=' e9 | e10 '!=' e9
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.eq($3.value) ? bigInt(0) : bigInt(1) };
} else {
$$ = { type: "OP", op: "!=", values: [$1, $3] };
}
$$ = { type: "OP", op: "!=", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 %prec EMPTY | e9 %prec EMPTY
@ -587,38 +545,22 @@ e10
e9 e9
: e9 '<=' e7 : e9 '<=' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.lesserOrEquals($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "<=", values: [$1, $3] };
}
$$ = { type: "OP", op: "<=", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 '>=' e7 | e9 '>=' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.greaterOrEquals($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: ">=", values: [$1, $3] };
}
$$ = { type: "OP", op: ">=", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 '<' e7 | e9 '<' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.lesser($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "<", values: [$1, $3] };
}
$$ = { type: "OP", op: "<", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e9 '>' e7 | e9 '>' e7
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.greater($3.value) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: ">", values: [$1, $3] };
}
$$ = { type: "OP", op: ">", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e7 %prec EMPTY | e7 %prec EMPTY
@ -630,22 +572,12 @@ e9
e7 e7
: e7 '<<' e6 : e7 '<<' e6
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
let v = $3.value.greater(256) ? 256 : $3.value.value;
$$ = { type: "NUMBER", value: $1.value.shiftLeft(v).and(__MASK__) };
} else {
$$ = { type: "OP", op: "<<", values: [$1, $3] };
}
$$ = { type: "OP", op: "<<", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e7 '>>' e6 | e7 '>>' e6
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
let v = $3.value.greater(256) ? 256 : $3.value.value;
$$ = {type: "NUMBER", value: $1.value.shiftRight(v).and(__MASK__) };
} else {
$$ = { type: "OP", op: ">>", values: [$1, $3] };
}
$$ = { type: "OP", op: ">>", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e6 %prec EMPTY | e6 %prec EMPTY
@ -657,20 +589,12 @@ e7
e6 e6
: e6 '+' e5 : e6 '+' e5
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: ($1.value.plus($3.value)).mod(__P__) };
} else {
$$ = { type: "OP", op: "+", values: [$1, $3] };
}
$$ = { type: "OP", op: "+", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e6 '-' e5 | e6 '-' e5
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: ($1.value.plus(__P__).minus($3.value)).mod(__P__) };
} else {
$$ = { type: "OP", op: "-", values: [$1, $3] };
}
$$ = { type: "OP", op: "-", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 %prec EMPTY | e5 %prec EMPTY
@ -683,38 +607,22 @@ e6
e5 e5
: e5 '*' e4 : e5 '*' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: ($1.value.times($3.value)).mod(__P__) };
} else {
$$ = { type: "OP", op: "*", values: [$1, $3] };
}
$$ = { type: "OP", op: "*", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 '/' e4 | e5 '/' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: ($1.value.times($3.value.modInv(__P__))).mod(__P__) };
} else {
$$ = { type: "OP", op: "/", values: [$1, $3] };
}
$$ = { type: "OP", op: "/", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 '\\' e4 | e5 '\\' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: ($1.value.divide($3.value)) };
} else {
$$ = { type: "OP", op: "\\", values: [$1, $3] };
}
$$ = { type: "OP", op: "\\", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e5 '%' e4 | e5 '%' e4
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.mod($3.value) };
} else {
$$ = { type: "OP", op: "%", values: [$1, $3] };
}
$$ = { type: "OP", op: "%", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e4 %prec EMPTY | e4 %prec EMPTY
@ -726,11 +634,7 @@ e5
e4 e4
: e4 '**' e3 : e4 '**' e3
{ {
if (($1.type == "NUMBER") && ($3.type == "NUMBER")) {
$$ = { type: "NUMBER", value: $1.value.modPow($3.value, __P__) };
} else {
$$ = { type: "OP", op: "**", values: [$1, $3] };
}
$$ = { type: "OP", op: "**", values: [$1, $3] };
setLines($$, @1, @3); setLines($$, @1, @3);
} }
| e3 %prec EMPTY | e3 %prec EMPTY
@ -758,29 +662,17 @@ e3
} }
| '-' e3 %prec UMINUS | '-' e3 %prec UMINUS
{ {
if ($2.type == "NUMBER") {
$$ = { type: "NUMBER", value: __P__.minus($2.value).mod(__P__) };
} else {
$$ = { type: "OP", op: "UMINUS", values: [$2] };
}
$$ = { type: "OP", op: "UMINUS", values: [$2] };
setLines($$, @1, @2); setLines($$, @1, @2);
} }
| '!' e3 | '!' e3
{ {
if ($2.type == "NUMBER") {
$$ = { type: "NUMBER", value: $2.value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
$$ = { type: "OP", op: "!", values: [$2] };
}
$$ = { type: "OP", op: "!", values: [$2] };
setLines($$, @1, @2); setLines($$, @1, @2);
} }
| '~' e3 | '~' e3
{ {
if ($2.type == "NUMBER") {
$$ = { type: "NUMBER", value: $2.value.xor(__MASK__) };
} else {
$$ = { type: "OP", op: "~", values: [$2] };
}
$$ = { type: "OP", op: "~", values: [$2] };
setLines($$, @1, @2); setLines($$, @1, @2);
} }
| e2 %prec EMPTY | e2 %prec EMPTY
@ -817,12 +709,12 @@ e0
} }
| DECNUMBER | DECNUMBER
{ {
$$ = {type: "NUMBER", value: bigInt($1).mod(__P__) }
$$ = {type: "NUMBER", value: Scalar.fromString($1) }
setLines($$, @1); setLines($$, @1);
} }
| HEXNUMBER | HEXNUMBER
{ {
$$ = {type: "NUMBER", value: bigInt($1.substr(2).toUpperCase(), 16).mod(__P__) }
$$ = {type: "NUMBER", value: Scalar.fromString($1.substr(2).toUpperCase(), 16) }
setLines($$, @1); setLines($$, @1);
} }
| '(' expression ')' %prec EMPTY | '(' expression ')' %prec EMPTY

+ 30
- 138
parser/jaz.js

@ -146,21 +146,13 @@ case 20:
break; break;
case 21: case 21:
if ($$[$0-4].type == "NUMBER") {
this.$ = !$$[$0-4].value.eq(0) ? $$[$0-2] : $$[$0];
} else {
this.$ = { type: "IF", condition: $$[$0-4], then: $$[$0-2], else: $$[$0] };
}
this.$ = { type: "IF", condition: $$[$0-4], then: $$[$0-2], else: $$[$0] };
setLines(this.$, _$[$0-6], _$[$0]); setLines(this.$, _$[$0-6], _$[$0]);
break; break;
case 22: case 22:
if ($$[$0-2].type == "NUMBER") {
this.$ = !$$[$0-2].value.eq(0) ? $$[$0] : { type: "NUMBER", value: bigInt(0) };
} else {
this.$ = { type: "IF", condition: $$[$0-2], then: $$[$0] };
}
this.$ = { type: "IF", condition: $$[$0-2], then: $$[$0] };
setLines(this.$, _$[$0-4], _$[$0]); setLines(this.$, _$[$0-4], _$[$0]);
break; break;
@ -321,11 +313,7 @@ case 50:
break; break;
case 51: case 51:
if ($$[$0-4].type == "NUMBER") {
this.$ = !$$[$0-4].value.eq(0) ? $$[$0-2] : $$[$0];
} else {
this.$ = { type: "OP", op: "?", values: [$$[$0-4], $$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "?", values: [$$[$0-4], $$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-4], _$[$0]); setLines(this.$, _$[$0-4], _$[$0]);
break; break;
@ -336,71 +324,43 @@ case 52: case 53: case 54: case 56: case 58: case 60:
break; break;
case 55: case 55:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: !$$[$0-2].value.eq(0) || !$$[$0].value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "||", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "||", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 57: case 57:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: !$$[$0-2].value.eq(0) && !$$[$0].value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "&&", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "&&", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 59: case 59:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.or($$[$0].value).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "|", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "|", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 61: case 61:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.xor($$[$0].value).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "^", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "^", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 63: case 63:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.and($$[$0].value).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "&", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "&", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 65: case 65:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.equals($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "==", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "==", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 66: case 66:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.eq($$[$0].value) ? bigInt(0) : bigInt(1) };
} else {
this.$ = { type: "OP", op: "!=", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "!=", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
@ -411,63 +371,37 @@ case 67: case 72:
break; break;
case 68: case 68:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.lesserOrEquals($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "<=", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "<=", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 69: case 69:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.greaterOrEquals($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: ">=", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: ">=", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 70: case 70:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.lesser($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "<", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "<", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 71: case 71:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.greater($$[$0].value) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: ">", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: ">", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 73: case 73:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
let v = $$[$0].value.greater(256) ? 256 : $$[$0].value.value;
this.$ = { type: "NUMBER", value: $$[$0-2].value.shiftLeft(v).and(__MASK__) };
} else {
this.$ = { type: "OP", op: "<<", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "<<", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 74: case 74:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
let v = $$[$0].value.greater(256) ? 256 : $$[$0].value.value;
this.$ = {type: "NUMBER", value: $$[$0-2].value.shiftRight(v).and(__MASK__) };
} else {
this.$ = { type: "OP", op: ">>", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: ">>", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
@ -478,71 +412,43 @@ case 75:
break; break;
case 76: case 76:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: ($$[$0-2].value.plus($$[$0].value)).mod(__P__) };
} else {
this.$ = { type: "OP", op: "+", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "+", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 77: case 77:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: ($$[$0-2].value.plus(__P__).minus($$[$0].value)).mod(__P__) };
} else {
this.$ = { type: "OP", op: "-", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "-", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 79: case 79:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: ($$[$0-2].value.times($$[$0].value)).mod(__P__) };
} else {
this.$ = { type: "OP", op: "*", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "*", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 80: case 80:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: ($$[$0-2].value.times($$[$0].value.modInv(__P__))).mod(__P__) };
} else {
this.$ = { type: "OP", op: "/", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "/", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 81: case 81:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: ($$[$0-2].value.divide($$[$0].value)) };
} else {
this.$ = { type: "OP", op: "\\", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "\\", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 82: case 82:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.mod($$[$0].value) };
} else {
this.$ = { type: "OP", op: "%", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "%", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
case 84: case 84:
if (($$[$0-2].type == "NUMBER") && ($$[$0].type == "NUMBER")) {
this.$ = { type: "NUMBER", value: $$[$0-2].value.modPow($$[$0].value, __P__) };
} else {
this.$ = { type: "OP", op: "**", values: [$$[$0-2], $$[$0]] };
}
this.$ = { type: "OP", op: "**", values: [$$[$0-2], $$[$0]] };
setLines(this.$, _$[$0-2], _$[$0]); setLines(this.$, _$[$0-2], _$[$0]);
break; break;
@ -566,31 +472,19 @@ case 88:
break; break;
case 89: case 89:
if ($$[$0].type == "NUMBER") {
this.$ = { type: "NUMBER", value: __P__.minus($$[$0].value).mod(__P__) };
} else {
this.$ = { type: "OP", op: "UMINUS", values: [$$[$0]] };
}
this.$ = { type: "OP", op: "UMINUS", values: [$$[$0]] };
setLines(this.$, _$[$0-1], _$[$0]); setLines(this.$, _$[$0-1], _$[$0]);
break; break;
case 90: case 90:
if ($$[$0].type == "NUMBER") {
this.$ = { type: "NUMBER", value: $$[$0].value.eq(0) ? bigInt(1) : bigInt(0) };
} else {
this.$ = { type: "OP", op: "!", values: [$$[$0]] };
}
this.$ = { type: "OP", op: "!", values: [$$[$0]] };
setLines(this.$, _$[$0-1], _$[$0]); setLines(this.$, _$[$0-1], _$[$0]);
break; break;
case 91: case 91:
if ($$[$0].type == "NUMBER") {
this.$ = { type: "NUMBER", value: $$[$0].value.xor(__MASK__) };
} else {
this.$ = { type: "OP", op: "~", values: [$$[$0]] };
}
this.$ = { type: "OP", op: "~", values: [$$[$0]] };
setLines(this.$, _$[$0-1], _$[$0]); setLines(this.$, _$[$0-1], _$[$0]);
break; break;
@ -613,13 +507,13 @@ case 97: case 102: case 103:
break; break;
case 98: case 98:
this.$ = {type: "NUMBER", value: bigInt($$[$0]).mod(__P__) }
this.$ = {type: "NUMBER", value: Scalar.fromString($$[$0]) }
setLines(this.$, _$[$0]); setLines(this.$, _$[$0]);
break; break;
case 99: case 99:
this.$ = {type: "NUMBER", value: bigInt($$[$0].substr(2).toUpperCase(), 16).mod(__P__) }
this.$ = {type: "NUMBER", value: Scalar.fromString($$[$0].substr(2).toUpperCase(), 16) }
setLines(this.$, _$[$0]); setLines(this.$, _$[$0]);
break; break;
@ -866,10 +760,8 @@ parse: function parse(input) {
return true; return true;
}}; }};
const bigInt = require('big-integer');
const Scalar = require('ffjavascript').Scalar;
const util = require('util'); const util = require('util');
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const __MASK__ = new bigInt(2).pow(253).minus(1);
function setLines(dst, first, last) { function setLines(dst, first, last) {
last = last || first; last = last || first;
@ -1365,7 +1257,7 @@ case 77: console.log("INVALID: " + yy_.yytext); return 'INVALID'
break; break;
} }
}, },
rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:~)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/],
rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:~)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/],
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],"inclusive":true}} conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],"inclusive":true}}
}); });
return lexer; return lexer;

+ 38
- 25
ports/c/builder.js

@ -1,7 +1,8 @@
const streamFromMultiArray = require("../../src/streamfromarray_txt.js"); const streamFromMultiArray = require("../../src/streamfromarray_txt.js");
const bigInt = require("big-integer");
const utils = require("../../src/utils"); const utils = require("../../src/utils");
const assert = require("assert"); const assert = require("assert");
const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field;
function ref2src(c) { function ref2src(c) {
if ((c[0] == "R")||(c[0] == "RI")) { if ((c[0] == "R")||(c[0] == "RI")) {
@ -340,7 +341,9 @@ class FunctionBuilderC {
} }
class BuilderC { class BuilderC {
constructor() {
constructor(p) {
this.F = new F1Field(p);
this.hashMaps={}; this.hashMaps={};
this.componentEntriesTables={}; this.componentEntriesTables={};
this.sizes ={}; this.sizes ={};
@ -348,7 +351,6 @@ class BuilderC {
this.functions = []; this.functions = [];
this.components = []; this.components = [];
this.usedConstants = {}; this.usedConstants = {};
} }
setHeader(header) { setHeader(header) {
@ -369,9 +371,9 @@ class BuilderC {
} }
addConstant(c) { addConstant(c) {
c = bigInt(c);
c = this.F.e(c);
const cS = c.toString(); const cS = c.toString();
if (this.usedConstants[cS]) return this.usedConstants[cS];
if (typeof this.usedConstants[cS] != "undefined") return this.usedConstants[cS];
this.constants.push(c); this.constants.push(c);
this.usedConstants[cS] = this.constants.length - 1; this.usedConstants[cS] = this.constants.length - 1;
return this.constants.length - 1; return this.constants.length - 1;
@ -471,8 +473,6 @@ class BuilderC {
_buildConstants(code) { _buildConstants(code) {
const self = this; const self = this;
const n64 = Math.floor((self.header.P.bitLength() - 1) / 64)+1;
const R = bigInt.one.shiftLeft(n64*64);
code.push("// Constants"); code.push("// Constants");
code.push(`FrElement _constants[${self.constants.length}] = {`); code.push(`FrElement _constants[${self.constants.length}] = {`);
@ -482,12 +482,19 @@ class BuilderC {
code.push("};"); code.push("};");
function number2Code(n) { function number2Code(n) {
if (n.lt(bigInt("80000000", 16)) ) {
return addShortMontgomeryPositive(n);
}
if (n.geq(self.header.P.minus(bigInt("80000000", 16))) ) {
return addShortMontgomeryNegative(n);
const minShort = self.F.neg(self.F.e("80000000"));
const maxShort = self.F.e("7FFFFFFF", 16);
if ( (self.F.geq(n, minShort))
&&(self.F.leq(n, maxShort)))
{
if (self.F.geq(n, self.F.zero)) {
return addShortMontgomeryPositive(n);
} else {
return addShortMontgomeryNegative(n);
}
} }
return addLongMontgomery(n); return addLongMontgomery(n);
@ -506,25 +513,31 @@ class BuilderC {
} }
function getLongString(a) { function getLongString(a) {
let r = bigInt(a);
let S = ""; let S = "";
let i = 0;
while (!r.isZero()) {
if (S!= "") S = S+",";
S += "0x" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16) + "LL";
i++;
r = r.shiftRight(64);
}
while (i<n64) {
if (S!= "") S = S+",";
S += "0LL";
i++;
const arr = Scalar.toArray(a, 0x100000000);
for (let i=0; i<self.F.n64*2; i+=2) {
const idx = arr.length-2-i;
if (i>0) S = S + ",";
if ( idx >=0) {
let msb = arr[idx].toString(16);
while (msb.length<8) msb = "0" + msb;
let lsb = arr[idx+1].toString(16);
while (lsb.length<8) lsb = "0" + lsb;
S += "0x" + msb + lsb + "LL";
} else {
S += "0LL";
}
} }
return S; return S;
} }
function toMontgomery(a) { function toMontgomery(a) {
return a.times(R).mod(self.header.P);
return self.F.mul(a, self.F.R);
} }
} }

+ 11
- 9
ports/c/tester.js

@ -8,12 +8,14 @@ const compiler = require("../../src/compiler");
const util = require("util"); const util = require("util");
const exec = util.promisify(require("child_process").exec); const exec = util.promisify(require("child_process").exec);
const bigInt = require("big-integer");
const Scalar = require("ffjavascript").Scalar;
const utils = require("../../src/utils"); const utils = require("../../src/utils");
const loadR1cs = require("r1csfile").load; const loadR1cs = require("r1csfile").load;
const ZqField = require("ffjavascript").ZqField; const ZqField = require("ffjavascript").ZqField;
const buildZqField = require("ffiasm").buildZqField; const buildZqField = require("ffiasm").buildZqField;
const {stringifyBigInts, unstringifyBigInts } = require("ffjavascript").utils;
module.exports = c_tester; module.exports = c_tester;
@ -31,7 +33,7 @@ async function c_tester(circomFile, _options) {
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.p = options.p || bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
options.p = options.p || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
await compiler(circomFile, options); await compiler(circomFile, options);
const source = await buildZqField(options.p, "Fr"); const source = await buildZqField(options.p, "Fr");
@ -87,7 +89,7 @@ class CTester {
async calculateWitness(input) { async calculateWitness(input) {
await fs.promises.writeFile( await fs.promises.writeFile(
path.join(this.dir.path, "in.json"), path.join(this.dir.path, "in.json"),
JSON.stringify(utils.stringifyBigInts(input), null, 1)
JSON.stringify(stringifyBigInts(input), null, 1)
); );
const r = 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")}` +
@ -100,7 +102,7 @@ class CTester {
path.join(this.dir.path, "out.json") path.join(this.dir.path, "out.json")
); );
const res = utils.unstringifyBigInts(JSON.parse(resStr));
const res = unstringifyBigInts(JSON.parse(resStr));
return res; return res;
} }
@ -127,7 +129,7 @@ class CTester {
const self = this; const self = this;
if (this.constraints) return; if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false); const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.field = new ZqField(r1cs.prime);
self.F = new ZqField(r1cs.prime);
self.nVars = r1cs.nVars; self.nVars = r1cs.nVars;
self.constraints = r1cs.constraints; self.constraints = r1cs.constraints;
} }
@ -152,8 +154,8 @@ class CTester {
if (typeof self.symbols[prefix] == "undefined") { if (typeof self.symbols[prefix] == "undefined") {
assert(false, "Output variable not defined: "+ prefix); assert(false, "Output variable not defined: "+ prefix);
} }
const ba = bigInt(actualOut[self.symbols[prefix].varIdx]).toString();
const be = bigInt(eOut).toString();
const ba = actualOut[self.symbols[prefix].varIdx].toString();
const be = eOut.toString();
assert.strictEqual(ba, be, prefix); assert.strictEqual(ba, be, prefix);
} }
} }
@ -183,7 +185,7 @@ class CTester {
} }
function checkConstraint(constraint) { function checkConstraint(constraint) {
const F = self.field;
const F = self.F;
const a = evalLC(constraint[0]); const a = evalLC(constraint[0]);
const b = evalLC(constraint[1]); const b = evalLC(constraint[1]);
const c = evalLC(constraint[2]); const c = evalLC(constraint[2]);
@ -192,7 +194,7 @@ class CTester {
} }
function evalLC(lc) { function evalLC(lc) {
const F = self.field;
const F = self.F;
let v = F.zero; let v = F.zero;
for (let w in lc) { for (let w in lc) {
v = F.add( v = F.add(

+ 38
- 31
ports/wasm/builder.js

@ -1,10 +1,11 @@
const streamFromArrayTxt = require("../../src/streamfromarray_txt"); const streamFromArrayTxt = require("../../src/streamfromarray_txt");
const streamFromArrayBin = require("../../src/streamfromarray_bin"); const streamFromArrayBin = require("../../src/streamfromarray_bin");
const bigInt = require("big-integer");
const assert = require("assert"); const assert = require("assert");
const ModuleBuilder = require("wasmbuilder").ModuleBuilder; const ModuleBuilder = require("wasmbuilder").ModuleBuilder;
const ModuleBuilderWat = require("wasmbuilder").ModuleBuilderWat; const ModuleBuilderWat = require("wasmbuilder").ModuleBuilderWat;
const buildRuntime = require("./build_runtime"); const buildRuntime = require("./build_runtime");
const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field;
const errs = require("./errs"); const errs = require("./errs");
@ -689,7 +690,8 @@ class FunctionBuilderWasm {
} }
class BuilderWasm { class BuilderWasm {
constructor() {
constructor(p) {
this.F = new F1Field(p);
this.hashMaps={}; this.hashMaps={};
this.componentEntriesTables={}; this.componentEntriesTables={};
this.sizes ={}; this.sizes ={};
@ -701,8 +703,8 @@ class BuilderWasm {
this.TYPE_SIGNAL = 1; this.TYPE_SIGNAL = 1;
this.TYPE_COMPONENT = 2; this.TYPE_COMPONENT = 2;
this.addConstant(bigInt(0)); // constants[0] = 0;
this.addConstant(bigInt(1)); // constants[1] = 1;
this.addConstant(Scalar.fromString("0")); // constants[0] = 0;
this.addConstant(Scalar.fromString("1")); // constants[1] = 1;
this.offsetComponentNInputSignals = 12; this.offsetComponentNInputSignals = 12;
this.sizeofComponent = 20; this.sizeofComponent = 20;
@ -710,7 +712,8 @@ class BuilderWasm {
setHeader(header) { setHeader(header) {
this.header=header; this.header=header;
this.n64 = Math.floor((this.header.P.bitLength() - 1) / 64)+1;
this.n64 = Math.floor((Scalar.bitLength(this.header.P) - 1) / 64)+1;
this.sizeFr = this.n64*8 + 8; this.sizeFr = this.n64*8 + 8;
} }
@ -728,9 +731,9 @@ class BuilderWasm {
} }
addConstant(c) { addConstant(c) {
c = bigInt(c);
c = this.F.e(c);
const cS = c.toString(); const cS = c.toString();
if (this.usedConstants[cS]) return this.usedConstants[cS];
if (typeof this.usedConstants[cS] != "undefined") return this.usedConstants[cS];
this.constants.push(c); this.constants.push(c);
this.usedConstants[cS] = this.constants.length - 1; this.usedConstants[cS] = this.constants.length - 1;
return this.constants.length - 1; return this.constants.length - 1;
@ -842,7 +845,6 @@ class BuilderWasm {
_buildConstants(module) { _buildConstants(module) {
const self = this; const self = this;
const R = bigInt.one.shiftLeft(this.n64*64);
const bytes = []; const bytes = [];
for (let i=0; i<self.constants.length; i++) { for (let i=0; i<self.constants.length; i++) {
@ -852,19 +854,27 @@ class BuilderWasm {
const fBytes = [].concat(...bytes); const fBytes = [].concat(...bytes);
this.pConstants = module.alloc(fBytes); this.pConstants = module.alloc(fBytes);
function Fr2Bytes(n) { function Fr2Bytes(n) {
if (n.lt(bigInt("80000000", 16)) ) {
return shortMontgomeryPositive(n);
}
if (n.geq(self.header.P.minus(bigInt("80000000", 16))) ) {
return shortMontgomeryNegative(n);
const minShort = self.F.neg(self.F.e("80000000"));
const maxShort = self.F.e("7FFFFFFF", 16);
if ( (self.F.geq(n, minShort))
&&(self.F.leq(n, maxShort)))
{
if (self.F.geq(n, self.F.zero)) {
return shortMontgomeryPositive(n);
} else {
return shortMontgomeryNegative(n);
}
} }
return longMontgomery(n); return longMontgomery(n);
function shortMontgomeryPositive(a) { function shortMontgomeryPositive(a) {
return [ return [
...intToBytes32(parseInt(a)),
...intToBytes32(Scalar.toNumber(a)),
...intToBytes32(0x40000000), ...intToBytes32(0x40000000),
...long(toMontgomery(a)) ...long(toMontgomery(a))
]; ];
@ -872,9 +882,9 @@ class BuilderWasm {
function shortMontgomeryNegative(a) { function shortMontgomeryNegative(a) {
const b = a.minus(self.header.P);
const b = -Scalar.toNumber(self.F.neg(a));
return [ return [
...intToBytes32(parseInt(b)),
...intToBytes32(b),
...intToBytes32(0x40000000), ...intToBytes32(0x40000000),
...long(toMontgomery(a)) ...long(toMontgomery(a))
]; ];
@ -889,27 +899,24 @@ class BuilderWasm {
} }
function long(a) { function long(a) {
const bytes = []; const bytes = [];
let r = bigInt(a);
let S = "";
let i = 0;
while (!r.isZero()) {
S = ("0000000000000000" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16)).substr(-16);
bytes.push(hexToBytesR(S));
i++;
r = r.shiftRight(64);
}
while (i<self.n64) {
bytes.push(hexToBytesR("0000000000000000"));
i++;
const arr = Scalar.toArray(a, 0x100000000);
for (let i=0; i<self.F.n64*2; i++) {
const idx = arr.length-1-i;
if ( idx >=0) {
bytes.push(...intToBytes32(arr[idx]));
} else {
bytes.push(...intToBytes32(0));
}
} }
const fBytes = [].concat(...bytes);
return fBytes;
return bytes;
} }
function toMontgomery(a) { function toMontgomery(a) {
return a.times(R).mod(self.header.P);
return self.F.mul(a, self.F.R);
} }
} }

+ 6
- 7
ports/wasm/tester.js

@ -6,7 +6,6 @@ var tmp = require("tmp-promise");
const path = require("path"); const path = require("path");
const compiler = require("../../src/compiler"); const compiler = require("../../src/compiler");
const bigInt = require("big-integer");
const utils = require("../../src/utils"); const utils = require("../../src/utils");
const loadR1cs = require("r1csfile").load; const loadR1cs = require("r1csfile").load;
const ZqField = require("ffjavascript").ZqField; const ZqField = require("ffjavascript").ZqField;
@ -82,7 +81,7 @@ class WasmTester {
const self = this; const self = this;
if (this.constraints) return; if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false); const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.field = new ZqField(r1cs.prime);
self.F = new ZqField(r1cs.prime);
self.nVars = r1cs.nVars; self.nVars = r1cs.nVars;
self.constraints = r1cs.constraints; self.constraints = r1cs.constraints;
} }
@ -107,8 +106,8 @@ class WasmTester {
if (typeof self.symbols[prefix] == "undefined") { if (typeof self.symbols[prefix] == "undefined") {
assert(false, "Output variable not defined: "+ prefix); assert(false, "Output variable not defined: "+ prefix);
} }
const ba = bigInt(actualOut[self.symbols[prefix].varIdx]).toString();
const be = bigInt(eOut).toString();
const ba = actualOut[self.symbols[prefix].varIdx].toString();
const be = eOut.toString();
assert.strictEqual(ba, be, prefix); assert.strictEqual(ba, be, prefix);
} }
} }
@ -138,16 +137,16 @@ class WasmTester {
} }
function checkConstraint(constraint) { function checkConstraint(constraint) {
const F = self.field;
const F = self.F;
const a = evalLC(constraint[0]); const a = evalLC(constraint[0]);
const b = evalLC(constraint[1]); const b = evalLC(constraint[1]);
const c = evalLC(constraint[2]); const c = evalLC(constraint[2]);
assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match");
assert (F.isZero(F.sub(F.mul(a,b), c)), "Constraint doesn't match");
} }
function evalLC(lc) { function evalLC(lc) {
const F = self.field;
const F = self.F;
let v = F.zero; let v = F.zero;
for (let w in lc) { for (let w in lc) {
v = F.add( v = F.add(

+ 9
- 10
src/build.js

@ -18,7 +18,6 @@
*/ */
const assert = require("assert"); const assert = require("assert");
const bigInt = require("big-integer");
const utils = require("./utils"); const utils = require("./utils");
const gen = require("./gencode").gen; const gen = require("./gencode").gen;
const createRefs = require("./gencode").createRefs; const createRefs = require("./gencode").createRefs;
@ -35,8 +34,8 @@ function build(ctx) {
ctx.definedSizes = {}; ctx.definedSizes = {};
ctx.addSizes = addSizes; ctx.addSizes = addSizes;
ctx.addConstant = addConstant; ctx.addConstant = addConstant;
ctx.addConstant(bigInt.zero);
ctx.addConstant(bigInt.one);
ctx.addConstant(ctx.F.zero);
ctx.addConstant(ctx.F.one);
buildHeader(ctx); buildHeader(ctx);
buildEntryTables(ctx); buildEntryTables(ctx);
@ -209,7 +208,7 @@ function buildHeader(ctx) {
NInputs: ctx.components[ ctx.getComponentIdx("main") ].nInSignals, NInputs: ctx.components[ ctx.getComponentIdx("main") ].nInSignals,
NOutputs: ctx.totals[ ctx.stOUTPUT ], NOutputs: ctx.totals[ ctx.stOUTPUT ],
NVars: ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL], NVars: ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL],
P: ctx.field.p
P: ctx.F.p
}); });
} }
@ -391,7 +390,7 @@ function hashComponentCall(ctx, cIdx) {
// TODO: At the moment generate a diferent function for each instance of the component // TODO: At the moment generate a diferent function for each instance of the component
const constParams = []; const constParams = [];
for (let p in ctx.components[cIdx].params) { for (let p in ctx.components[cIdx].params) {
constParams.push(p + "=" + value2str(ctx.components[cIdx].params[p]));
constParams.push(p + "=" + value2str(ctx.F, ctx.components[cIdx].params[p]));
} }
for (let n in ctx.components[cIdx].names.o) { for (let n in ctx.components[cIdx].names.o) {
@ -399,7 +398,7 @@ function hashComponentCall(ctx, cIdx) {
if ((entry.type == "S")&&(ctx.signals[entry.offset].o & ctx.IN)) { if ((entry.type == "S")&&(ctx.signals[entry.offset].o & ctx.IN)) {
travelSizes(n, entry.offset, entry.sizes, (prefix, offset) => { travelSizes(n, entry.offset, entry.sizes, (prefix, offset) => {
if (utils.isDefined(ctx.signals[offset].v)) { if (utils.isDefined(ctx.signals[offset].v)) {
constParams.push(prefix + "=" + bigInt(ctx.signals[offset].value));
constParams.push(prefix + "=" + ctx.F.e(ctx.signals[offset].v));
} }
}); });
} }
@ -433,7 +432,7 @@ function hashFunctionCall(ctx, name, paramValues) {
const constParams = []; const constParams = [];
for (let i=0; i<ctx.functions[name].params.length; i++) { for (let i=0; i<ctx.functions[name].params.length; i++) {
if (!paramValues[i].used) { if (!paramValues[i].used) {
constParams.push(ctx.functions[name].params[i] + utils.accSizes2Str(paramValues[i].sizes) + "=" + value2str(paramValues[i].value));
constParams.push(ctx.functions[name].params[i] + utils.accSizes2Str(paramValues[i].sizes) + "=" + value2str(ctx.F, paramValues[i].value));
} }
} }
let instanceDef = name; let instanceDef = name;
@ -447,16 +446,16 @@ function hashFunctionCall(ctx, name, paramValues) {
return {h, instanceDef}; return {h, instanceDef};
} }
function value2str(v) {
function value2str(F, v) {
if (Array.isArray(v)) { if (Array.isArray(v)) {
let S="["; let S="[";
for (let i=0; i<v.length; i++) { for (let i=0; i<v.length; i++) {
if (i>0) S+=","; if (i>0) S+=",";
S+=value2str(v[i]);
S+=value2str(F, v[i]);
} }
S+="]"; S+="]";
return S; return S;
} else { } else {
return bigInt(v).toString();
return F.toString(F.e(v));
} }
} }

+ 10
- 13
src/compiler.js

@ -17,15 +17,13 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
const bigInt = require("big-integer");
const __P__ = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const Scalar = require("ffjavascript").Scalar;
const sONE = 0; const sONE = 0;
const build = require("./build"); const build = require("./build");
const BuilderC = require("../ports/c/builder.js"); const BuilderC = require("../ports/c/builder.js");
const BuilderWasm = require("../ports/wasm/builder.js"); const BuilderWasm = require("../ports/wasm/builder.js");
const constructionPhase = require("./construction_phase"); const constructionPhase = require("./construction_phase");
const Ctx = require("./ctx"); const Ctx = require("./ctx");
const ZqField = require("ffjavascript").ZqField;
const utils = require("./utils"); const utils = require("./utils");
const buildR1cs = require("./r1csfile").buildR1cs; const buildR1cs = require("./r1csfile").buildR1cs;
const BigArray = require("./bigarray"); const BigArray = require("./bigarray");
@ -34,15 +32,14 @@ const buildSyms = require("./buildsyms");
module.exports = compile; module.exports = compile;
async function compile(srcFile, options) { async function compile(srcFile, options) {
options.p = options.p || __P__;
options.p = options.p || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
if (!options) { if (!options) {
options = {}; options = {};
} }
if (typeof options.reduceConstraints === "undefined") { if (typeof options.reduceConstraints === "undefined") {
options.reduceConstraints = true; options.reduceConstraints = true;
} }
const ctx = new Ctx();
ctx.field = new ZqField(options.p);
const ctx = new Ctx(options.p);
ctx.verbose= options.verbose || false; ctx.verbose= options.verbose || false;
ctx.mainComponent = options.mainComponent || "main"; ctx.mainComponent = options.mainComponent || "main";
ctx.newThreadTemplates = options.newThreadTemplates; ctx.newThreadTemplates = options.newThreadTemplates;
@ -85,7 +82,7 @@ async function compile(srcFile, options) {
} }
if (options.cSourceWriteStream) { if (options.cSourceWriteStream) {
ctx.builder = new BuilderC();
ctx.builder = new BuilderC(options.p);
build(ctx); build(ctx);
const rdStream = ctx.builder.build(); const rdStream = ctx.builder.build();
rdStream.pipe(options.cSourceWriteStream); rdStream.pipe(options.cSourceWriteStream);
@ -94,7 +91,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.p);
build(ctx); build(ctx);
if (options.wasmWriteStream) { if (options.wasmWriteStream) {
const rdStream = ctx.builder.build("wasm"); const rdStream = ctx.builder.build("wasm");
@ -299,11 +296,11 @@ function reduceConstrains(ctx) {
t: "LC", t: "LC",
coefs: {} coefs: {}
}; };
const invCoef = c.c.coefs[isolatedSignal].modInv(__P__);
const invCoef = ctx.F.inv(c.c.coefs[isolatedSignal]);
for (const s in c.c.coefs) { for (const s in c.c.coefs) {
if (s != isolatedSignal) { if (s != isolatedSignal) {
const v = __P__.minus(c.c.coefs[s]).times(invCoef).mod(__P__);
if (!v.isZero()) {
const v = ctx.F.mul( ctx.F.neg(c.c.coefs[s]), invCoef);
if (!ctx.F.isZero(v)) {
isolatedSignalEquivalence.coefs[s] = v; isolatedSignalEquivalence.coefs[s] = v;
} }
} }
@ -395,9 +392,9 @@ function reduceConstrains(ctx) {
function isConstant(l) { function isConstant(l) {
for (let k in l.coefs) { for (let k in l.coefs) {
if ((k != sONE) && (!l.coefs[k].isZero())) return false;
if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
} }
if (!l.coefs[sONE] || l.coefs[sONE].isZero()) return false;
if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
return true; return true;
} }

+ 22
- 21
src/construction_phase.js

@ -49,10 +49,11 @@ const assert = require("assert");
const iterateAST = require("./iterateast"); const iterateAST = require("./iterateast");
const utils = require("./utils"); const utils = require("./utils");
const bigInt = require("big-integer");
const LCAlgebra = require("./lcalgebra"); const LCAlgebra = require("./lcalgebra");
const parser = require("../parser/jaz.js").parser; const parser = require("../parser/jaz.js").parser;
const Scalar = require("ffjavascript").Scalar;
const {stringifyBigInts} = require("ffjavascript").utils;
/* TODO: Add lines information /* TODO: Add lines information
@ -79,7 +80,7 @@ function constructionPhase(ctx, srcFile) {
assert(ctx.ast.type == "BLOCK"); assert(ctx.ast.type == "BLOCK");
ctx.lc = new LCAlgebra(ctx.field);
ctx.lc = new LCAlgebra(ctx.F);
ctx.filePath= fullFilePath; ctx.filePath= fullFilePath;
ctx.fileName= fullFileName; ctx.fileName= fullFileName;
ctx.includedFiles = {}; ctx.includedFiles = {};
@ -218,7 +219,7 @@ function execNumber(ctx, ast) {
s:[1,0], s:[1,0],
v: [{ v: [{
t: "N", t: "N",
v: bigInt(ast.value)
v: ctx.F.e(ast.value)
}] }]
}; };
} }
@ -253,7 +254,7 @@ function execDeclareComponent(ctx, ast) {
const size = val(ctx, sizeRef); const size = val(ctx, sizeRef);
if (size.t != "N") return ctx.throwError( ast.name.selectors[i], "expected a number"); if (size.t != "N") return ctx.throwError( ast.name.selectors[i], "expected a number");
sizes.push( size.v.toJSNumber() );
sizes.push( Scalar.toNumber(size.v) );
} }
let cIdx = ctx.addComponent(ast.name.name, sizes); let cIdx = ctx.addComponent(ast.name.name, sizes);
@ -277,7 +278,7 @@ function execDeclareSignal(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array"); if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array");
if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time"); if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time");
sizes.push( size.v[0].v.toJSNumber() );
sizes.push( Scalar.toNumber(size.v[0].v) );
} }
let sIdx = ctx.addSignal(ast.name.name, sizes); let sIdx = ctx.addSignal(ast.name.name, sizes);
@ -322,7 +323,7 @@ function execDeclareVariable(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array"); if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array");
if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time"); if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time");
sizes.push( size.v[0].v.toJSNumber() );
sizes.push( Scalar.toNumber(size.v[0].v) );
} }
const v = ctx.refs[ast.refId]; const v = ctx.refs[ast.refId];
@ -353,7 +354,7 @@ function execAssignement(ctx, ast) {
if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array");
if (sel.v[0].t != "N") return {t: "NQ"}; if (sel.v[0].t != "N") return {t: "NQ"};
leftSels.push( sel.v[0].v.toJSNumber() );
leftSels.push( Scalar.toNumber(sel.v[0].v) );
} }
} }
@ -380,7 +381,7 @@ function execAssignement(ctx, ast) {
} else if (right.t == "S") { } else if (right.t == "S") {
for (let i=0; i<right.s[0]; i++) { for (let i=0; i<right.s[0]; i++) {
left.v[o+i]={t: "LC", coefs: {}}; left.v[o+i]={t: "LC", coefs: {}};
left.v[o+i].coefs[right.sIdx+i] = ctx.field.one;
left.v[o+i].coefs[right.sIdx+i] = ctx.F.one;
} }
} }
} else if ( left.t == "S") { } else if ( left.t == "S") {
@ -561,14 +562,14 @@ function execFunctionCall(ctx, ast) {
if (ev.v) { if (ev.v) {
console.log(ev.v.toString()); console.log(ev.v.toString());
} else { } else {
console.log(JSON.stringify(ev));
console.log(JSON.stringify(stringifyBigInts(ev)));
} }
return; return;
} }
if (ast.name == "assert") { if (ast.name == "assert") {
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);
if (ev.isZero()) return ctx.throwError(ast, "Assertion failed");
if (ctx.F.isZero(ev)) return ctx.throwError(ast, "Assertion failed");
} }
const fnc = ctx.functions[ast.name]; const fnc = ctx.functions[ast.name];
@ -634,7 +635,7 @@ function execVariable(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (sel.s[0] != 1) return ctx.throwError(ast, "Variable selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Variable selector cannot be an array");
if (sel.v[0].t != "N") return NQVAL; if (sel.v[0].t != "N") return NQVAL;
sels.push(sel.v[0].v.toJSNumber());
sels.push(Scalar.toNumber(sel.v[0].v));
} }
let o = 0; let o = 0;
@ -682,7 +683,7 @@ function execPin(ctx, ast) {
if (sel.s[0] != 1) return ctx.throwError(ast, "Component selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Component selector cannot be an array");
if (sel.v[0].t != "N") return NQVAL; if (sel.v[0].t != "N") return NQVAL;
selsC.push(sel.v[0].v.toJSNumber());
selsC.push(Scalar.toNumber(sel.v[0].v));
} }
const cIdx = ctx.getComponentIdx(ast.component.name, selsC); const cIdx = ctx.getComponentIdx(ast.component.name, selsC);
@ -694,7 +695,7 @@ function execPin(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
if (sel.s[0] != 1) return ctx.throwError(ast, "Signal selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Signal selector cannot be an array");
if (sel.v[0].t != "N") return NQVAL; if (sel.v[0].t != "N") return NQVAL;
selsP.push(sel.v[0].v.toJSNumber());
selsP.push(Scalar.toNumber(sel.v[0].v));
} }
const sIdx = ctx.components[cIdx].names.getSignalIdx(ast.pin.name, selsP); const sIdx = ctx.components[cIdx].names.getSignalIdx(ast.pin.name, selsP);
@ -741,7 +742,7 @@ function execLoop(ctx, ast) {
return; return;
} }
while ((!v.v[0].v.isZero())&&(!ctx.returnValue)) {
while ((! ctx.F.isZero(v.v[0].v))&&(!ctx.returnValue)) {
exec(ctx, ast.body); exec(ctx, ast.body);
if (ctx.error) return; if (ctx.error) return;
@ -784,7 +785,7 @@ function execIf(ctx, ast) {
return; return;
} }
if (!v.v[0].v.isZero()) {
if (!ctx.F.isZero(v.v[0].v)) {
exec(ctx, ast.then); exec(ctx, ast.then);
} else { } else {
if (ast.else) { if (ast.else) {
@ -811,7 +812,7 @@ function execTerCon(ctx, ast) {
return NQVAL; return NQVAL;
} }
if (!v.v[0].v.isZero()) {
if (!ctx.F.isZero(v.v[0].v)) {
return exec(ctx, ast.values[1]); return exec(ctx, ast.values[1]);
} else { } else {
return exec(ctx, ast.values[2]); return exec(ctx, ast.values[2]);
@ -850,7 +851,7 @@ function execOpOp(ctx, ast, op, lr) {
if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array"); if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array");
if (sel.v[0].t != "N") return {t: "NQ"}; if (sel.v[0].t != "N") return {t: "NQ"};
leftSels.push( sel.v[0].v.toJSNumber() );
leftSels.push( Scalar.toNumber(sel.v[0].v) );
} }
} }
if (!left.s) return ctx.throwError(ast, "variable. not defined yet"); if (!left.s) return ctx.throwError(ast, "variable. not defined yet");
@ -870,7 +871,7 @@ function execOpOp(ctx, ast, op, lr) {
if (ctx.error) return; if (ctx.error) return;
right = val(ctx, rightRef); right = val(ctx, rightRef);
} else { } else {
right = {t:"N", v: ctx.field.one};
right = {t:"N", v: ctx.F.one};
} }
if (!right) return ctx.throwError(ast, "adding a no number"); if (!right) return ctx.throwError(ast, "adding a no number");
@ -907,7 +908,7 @@ function val(ctx, a, ast) {
}; };
let sIdx = a.sIdx; let sIdx = a.sIdx;
while (ctx.signals[sIdx].e >= 0) sIdx = ctx.signals[sIdx].e; while (ctx.signals[sIdx].e >= 0) sIdx = ctx.signals[sIdx].e;
res.coefs[sIdx] = ctx.field.one;
res.coefs[sIdx] = ctx.F.one;
return res; return res;
} else { } else {
ctx.throwError(ast, "Invalid type: " + a.t); ctx.throwError(ast, "Invalid type: " + a.t);
@ -979,7 +980,7 @@ function execArray(ctx, ast) {
} else if (e.t == "S") { } else if (e.t == "S") {
for (let j=0; j<e.v.length;j++) { for (let j=0; j<e.v.length;j++) {
const sv = {t: "LC", coefs: {}}; const sv = {t: "LC", coefs: {}};
sv.coefs[e.sIdx+j] = ctx.field.one;
sv.coefs[e.sIdx+j] = ctx.F.one;
res.v.push(sv); res.v.push(sv);
} }
} else { } else {

+ 5
- 4
src/ctx.js

@ -1,6 +1,5 @@
const bigInt = require("big-integer");
const BigArray = require("./bigarray.js"); const BigArray = require("./bigarray.js");
const F1Field = require("ffjavascript").F1Field;
class TableName { class TableName {
constructor (ctx) { constructor (ctx) {
@ -86,7 +85,9 @@ class TableName {
module.exports = class Ctx { module.exports = class Ctx {
constructor() {
constructor(p) {
this.F = new F1Field(p);
this.stONE = 1; this.stONE = 1;
this.stOUTPUT = 2; this.stOUTPUT = 2;
@ -121,7 +122,7 @@ module.exports = class Ctx {
const oneIdx = this.addSignal("one"); const oneIdx = this.addSignal("one");
this.signals[oneIdx] = { this.signals[oneIdx] = {
v: bigInt(1),
v: this.F.one,
o: this.ONE, o: this.ONE,
e: -1, e: -1,
}; };

+ 11
- 11
src/gencode.js

@ -1,7 +1,7 @@
const bigInt = require("big-integer");
const utils = require("./utils"); const utils = require("./utils");
const assert = require("assert"); const assert = require("assert");
const iterateAST = require("./iterateast"); const iterateAST = require("./iterateast");
const Scalar = require("ffjavascript").Scalar;
module.exports.gen = gen; module.exports.gen = gen;
module.exports.newRef = newRef; module.exports.newRef = newRef;
@ -300,7 +300,7 @@ function genDeclareVariable(ctx, ast) {
const size = ctx.refs[sizeRef]; const size = ctx.refs[sizeRef];
if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array"); if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
if (size.used) return ctx.throwError(ast, "Variable size variables not allowed"); if (size.used) return ctx.throwError(ast, "Variable size variables not allowed");
sizes.push(size.value[0]);
sizes.push(Scalar.toNumber(size.value[0]));
} }
sizes = utils.accSizes(sizes); sizes = utils.accSizes(sizes);
} else { } else {
@ -320,7 +320,7 @@ function genDeclareVariable(ctx, ast) {
} }
function genNumber(ctx, ast) { function genNumber(ctx, ast) {
return newRef(ctx, "BIGINT", "_num", bigInt(ast.value));
return newRef(ctx, "BIGINT", "_num", ctx.F.e(ast.value));
} }
@ -950,7 +950,7 @@ function genLoop(ctx, ast) {
ctx.codeBuilder.assign(loopCond.label, ["R", cond.label], ["V", 0]); ctx.codeBuilder.assign(loopCond.label, ["R", cond.label], ["V", 0]);
} else { } else {
if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned"); if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
if (cond.value[0].isZero()) end=true;
if (ctx.F.isZero(cond.value[0])) end=true;
} }
@ -993,7 +993,7 @@ function genLoop(ctx, ast) {
} else { } else {
oldCodeBuilder.concat(ctx.codeBuilder); oldCodeBuilder.concat(ctx.codeBuilder);
ctx.codeBuilder = oldCodeBuilder; ctx.codeBuilder = oldCodeBuilder;
if (cond2.value[0].isZero()) end=true;
if (ctx.F.isZero(cond2.value[0])) end=true;
} }
} else { } else {
ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]); ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]);
@ -1042,7 +1042,7 @@ function genIf(ctx, ast) {
} else { } else {
if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned"); if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
if (!cond.value[0].isZero()) {
if (!ctx.F.isZero(cond.value[0])) {
gen(ctx, ast.then); gen(ctx, ast.then);
} else { } else {
if (ast.else) { if (ast.else) {
@ -1109,9 +1109,9 @@ function genOpOp(ctx, ast, op, lr) {
const res = ctx.refs[resRef]; const res = ctx.refs[resRef];
if (veval.used) { if (veval.used) {
instantiateRef(ctx, resRef); instantiateRef(ctx, resRef);
ctx.codeBuilder.fieldOp(res.label, op, [["R", veval.label], ["C", ctx.addConstant(bigInt.one)]]);
ctx.codeBuilder.fieldOp(res.label, op, [["R", veval.label], ["C", ctx.addConstant(ctx.F.one)]]);
} else { } else {
res.value = [ctx.field[op](veval.value[0], bigInt(1))];
res.value = [ctx.F[op](veval.value[0], ctx.F.one)];
} }
genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef); genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef);
if (lr == "RIGHT") { if (lr == "RIGHT") {
@ -1157,10 +1157,10 @@ function genOp(ctx, ast, op, nOps, adjustBool) {
} else { } else {
const params = []; const params = [];
for (let i=0; i<nOps; i++) { for (let i=0; i<nOps; i++) {
params.push(vals[i].value[0]);
params.push(ctx.F.e(vals[i].value[0]));
} }
rRef = newRef(ctx, "BIGINT", "_tmp", adjustBool ? (ctx.field[op](...params)?bigInt.one:bigInt.zero) : ctx.field[op](...params));
rRef = newRef(ctx, "BIGINT", "_tmp", adjustBool ? (ctx.F[op](...params)?ctx.F.one:ctx.F.zero) : ctx.F[op](...params));
} }
return rRef; return rRef;
} }
@ -1242,7 +1242,7 @@ function genTerCon(ctx, ast) {
} else { } else {
if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned"); if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
if (!cond.value[0].isZero()) {
if (!ctx.F.isZero(cond.value[0])) {
return gen(ctx, ast.values[1]); return gen(ctx, ast.values[1]);
} else { } else {
return gen(ctx, ast.values[2]); return gen(ctx, ast.values[2]);

+ 35
- 36
src/lcalgebra.js

@ -76,14 +76,13 @@ QEX QEX NQ NQ NQ
NQ NQ NQ NQ NQ NQ NQ NQ NQ NQ
*/ */
const bigInt = require("big-integer");
const utils = require("./utils"); const utils = require("./utils");
const sONE = 0; const sONE = 0;
class LCAlgebra { class LCAlgebra {
constructor (aField) { constructor (aField) {
const self = this; const self = this;
this.field= aField;
this.F= aField;
[ [
["idiv",2], ["idiv",2],
["mod",2], ["mod",2],
@ -118,7 +117,7 @@ class LCAlgebra {
} }
return { return {
t: "N", t: "N",
v: adjustBool ? ( self.field[op](...operands) ? bigInt.one: bigInt.zero) : self.field[op](...operands)
v: adjustBool ? ( self.F[op](...operands) ? self.F.one: self.F.zero) : self.F[op](...operands)
}; };
}; };
} }
@ -129,7 +128,7 @@ class LCAlgebra {
t: "LC", t: "LC",
coefs: {} coefs: {}
}; };
lc.coefs[a.sIdx] = bigInt(1);
lc.coefs[a.sIdx] = self.F.one;
return lc; return lc;
} else { } else {
return a; return a;
@ -200,17 +199,17 @@ class LCAlgebra {
function add_N_N(a,b) { function add_N_N(a,b) {
return { return {
t: "N", t: "N",
v: self.field.add(a.v, b.v)
v: self.F.add(a.v, b.v)
}; };
} }
function add_LC_N(a,b) { function add_LC_N(a,b) {
let res = self._clone(a); let res = self._clone(a);
if (b.v.isZero()) return res;
if (self.F.isZero(b.v)) return res;
if (!utils.isDefined(res.coefs[sONE])) { if (!utils.isDefined(res.coefs[sONE])) {
res.coefs[sONE]= b.v; res.coefs[sONE]= b.v;
} else { } else {
res.coefs[sONE]= self.field.add(res.coefs[sONE], b.v);
res.coefs[sONE]= self.F.add(res.coefs[sONE], b.v);
} }
return res; return res;
} }
@ -221,7 +220,7 @@ class LCAlgebra {
if (!utils.isDefined(res.coefs[k])) { if (!utils.isDefined(res.coefs[k])) {
res.coefs[k]=b.coefs[k]; res.coefs[k]=b.coefs[k];
} else { } else {
res.coefs[k]= self.field.add(res.coefs[k], b.coefs[k]);
res.coefs[k]= self.F.add(res.coefs[k], b.coefs[k]);
} }
} }
return res; return res;
@ -283,14 +282,14 @@ class LCAlgebra {
function mul_N_N(a,b) { function mul_N_N(a,b) {
return { return {
t: "N", t: "N",
v: self.field.mul(a.v, b.v)
v: self.F.mul(a.v, b.v)
}; };
} }
function mul_LC_N(a,b) { function mul_LC_N(a,b) {
let res = self._clone(a); let res = self._clone(a);
for (let k in res.coefs) { for (let k in res.coefs) {
res.coefs[k] = self.field.mul(res.coefs[k], b.v);
res.coefs[k] = self.F.mul(res.coefs[k], b.v);
} }
return res; return res;
} }
@ -318,10 +317,10 @@ class LCAlgebra {
const a = this._signal2lc(_a); const a = this._signal2lc(_a);
let res = this._clone(a); let res = this._clone(a);
if (res.t == "N") { if (res.t == "N") {
res.v = this.field.neg(a.v);
res.v = this.F.neg(a.v);
} else if (res.t == "LC") { } else if (res.t == "LC") {
for (let k in res.coefs) { for (let k in res.coefs) {
res.coefs[k] = this.field.neg(res.coefs[k]);
res.coefs[k] = this.F.neg(res.coefs[k]);
} }
} else if (res.t == "QEX") { } else if (res.t == "QEX") {
res.a = this.neg(res.a); res.a = this.neg(res.a);
@ -338,10 +337,10 @@ class LCAlgebra {
div(a, b) { div(a, b) {
if (b.t == "N") { if (b.t == "N") {
if (b.v.isZero()) throw new Error("Division by zero");
if (this.F.isZero(b.v)) throw new Error("Division by zero");
const inv = { const inv = {
t: "N", t: "N",
v: this.field.inv(b.v)
v: this.F.inv(b.v)
}; };
return this.mul(a, inv); return this.mul(a, inv);
} else { } else {
@ -351,23 +350,23 @@ class LCAlgebra {
pow(a, b) { pow(a, b) {
if (b.t == "N") { if (b.t == "N") {
if (b.v.isZero()) {
if (this.F.isZero(b.v)) {
if (this.isZero(a)) { if (this.isZero(a)) {
throw new Error("Zero to the Zero"); throw new Error("Zero to the Zero");
} }
return { return {
t: "N", t: "N",
v: this.field.one
v: this.F.one
}; };
} else if (b.v.eq(this.field.one)) {
} else if (this.F.eq(b.v, this.F.one)) {
return a; return a;
} else if (b.v.eq(bigInt(2))) {
} else if (this.F.eq(b.v, this.F.two)) {
return this.mul(a,a); return this.mul(a,a);
} else { } else {
if (a.t=="N") { if (a.t=="N") {
return { return {
t: "N", t: "N",
v: this.field.pow(a.v, b.v)
v: this.F.pow(a.v, b.v)
}; };
} else { } else {
return {t: "NQ"}; return {t: "NQ"};
@ -381,18 +380,18 @@ class LCAlgebra {
substitute(where, signal, equivalence) { substitute(where, signal, equivalence) {
if (equivalence.t != "LC") throw new Error("Equivalence must be a Linear Combination"); if (equivalence.t != "LC") throw new Error("Equivalence must be a Linear Combination");
if (where.t == "LC") { if (where.t == "LC") {
if (!utils.isDefined(where.coefs[signal]) || where.coefs[signal].isZero()) return where;
if (!utils.isDefined(where.coefs[signal]) || this.F.isZero(where.coefs[signal])) return where;
const res=this._clone(where); const res=this._clone(where);
const coef = res.coefs[signal]; const coef = res.coefs[signal];
for (let k in equivalence.coefs) { for (let k in equivalence.coefs) {
if (k != signal) { if (k != signal) {
const v = this.field.mul( coef, equivalence.coefs[k] );
const v = this.F.mul( coef, equivalence.coefs[k] );
if (!utils.isDefined(res.coefs[k])) { if (!utils.isDefined(res.coefs[k])) {
res.coefs[k]=v; res.coefs[k]=v;
} else { } else {
res.coefs[k]= this.field.add(res.coefs[k],v);
res.coefs[k]= this.F.add(res.coefs[k],v);
} }
if (res.coefs[k].isZero()) delete res.coefs[k];
if (this.F.isZero(res.coefs[k])) delete res.coefs[k];
} }
} }
delete res.coefs[signal]; delete res.coefs[signal];
@ -436,10 +435,10 @@ class LCAlgebra {
isZero(a) { isZero(a) {
if (a.t == "N") { if (a.t == "N") {
return a.v.isZero();
return this.F.isZero(a.v);
} else if (a.t == "LC") { } else if (a.t == "LC") {
for (let k in a.coefs) { for (let k in a.coefs) {
if (!a.coefs[k].isZero()) return false;
if (!this.F.isZero(a.coefs[k])) return false;
} }
return true; return true;
} else if (a.t == "QEX") { } else if (a.t == "QEX") {
@ -455,16 +454,16 @@ class LCAlgebra {
} else if (a.t == "LC") { } else if (a.t == "LC") {
let S=""; let S="";
for (let k in a.coefs) { for (let k in a.coefs) {
if (!a.coefs[k].isZero()) {
if (!this.F.isZero(a.coefs[k])) {
let c; let c;
if (a.coefs[k].greater(this.field.p.divide(2))) {
if (a.coefs[k].greater(this.F.p.divide(2))) {
S = S + "-"; S = S + "-";
c = this.field.p.minus(a.coefs[k]);
c = this.F.p.minus(a.coefs[k]);
} else { } else {
if (S!="") S=S+" + "; if (S!="") S=S+" + ";
c = a.coefs[k]; c = a.coefs[k];
} }
if (!c.equals(bigInt.one)) {
if (!c.equals(this.F.one)) {
S = S + c.toString() + "*"; S = S + c.toString() + "*";
} }
let sIdx = k; let sIdx = k;
@ -491,11 +490,11 @@ class LCAlgebra {
} else if (n.t == "SIGNAL") { } else if (n.t == "SIGNAL") {
return getSignalValue(ctx, n.sIdx); return getSignalValue(ctx, n.sIdx);
} else if (n.t == "LC") { } else if (n.t == "LC") {
let v= this.field.zero;
let v= this.F.zero;
for (let k in n.coefs) { for (let k in n.coefs) {
const s = getSignalValue(ctx, k); const s = getSignalValue(ctx, k);
if (s === null) return null; if (s === null) return null;
v = this.field.add(v, this.field.mul( n.coefs[k], s));
v = this.F.add(v, this.F.mul( n.coefs[k], s));
} }
return v; return v;
} else if (n.type == "QEX") { } else if (n.type == "QEX") {
@ -506,7 +505,7 @@ class LCAlgebra {
const c = this.evaluate(ctx, n.c); const c = this.evaluate(ctx, n.c);
if (c === null) return null; if (c === null) return null;
return this.field.add(this.field.mul(a,b), c);
return this.F.add(this.F.mul(a,b), c);
} else { } else {
return null; return null;
} }
@ -529,24 +528,24 @@ class LCAlgebra {
let s = k; let s = k;
while (ctx.signals[s].e>=0) s= ctx.signals[s].e; while (ctx.signals[s].e>=0) s= ctx.signals[s].e;
if (utils.isDefined(ctx.signals[s].v)&&(k != sONE)) { if (utils.isDefined(ctx.signals[s].v)&&(k != sONE)) {
const v = this.field.mul(res.coefs[k], ctx.signals[s].v);
const v = this.F.mul(res.coefs[k], ctx.signals[s].v);
if (!utils.isDefined(res.coefs[sONE])) { if (!utils.isDefined(res.coefs[sONE])) {
res.coefs[sONE]=v; res.coefs[sONE]=v;
} else { } else {
res.coefs[sONE]= this.field.add(res.coefs[sONE], v);
res.coefs[sONE]= this.F.add(res.coefs[sONE], v);
} }
delete res.coefs[k]; delete res.coefs[k];
} else if (s != k) { } else if (s != k) {
if (!utils.isDefined(res.coefs[s])) { if (!utils.isDefined(res.coefs[s])) {
res.coefs[s]=res.coefs[k]; res.coefs[s]=res.coefs[k];
} else { } else {
res.coefs[s]= this.field.add(res.coefs[s], res.coefs[k]);
res.coefs[s]= this.F.add(res.coefs[s], res.coefs[k]);
} }
delete res.coefs[k]; delete res.coefs[k];
} }
} }
for (let k in res.coefs) { for (let k in res.coefs) {
if (res.coefs[k].isZero()) delete res.coefs[k];
if (this.F.isZero(res.coefs[k])) delete res.coefs[k];
} }
return res; return res;
} else if (a.t == "QEX") { } else if (a.t == "QEX") {

+ 4
- 4
src/r1csfile.js

@ -1,7 +1,7 @@
const fs = require("fs"); const fs = require("fs");
const assert = require("assert"); const assert = require("assert");
const bigInt = require("big-integer");
const Scalar = require("ffjavascript").Scalar;
module.exports.buildR1cs = buildR1cs; module.exports.buildR1cs = buildR1cs;
@ -23,10 +23,10 @@ async function buildR1cs(ctx, fileName) {
await writeU64(0); // Temporally set to 0 length await writeU64(0); // Temporally set to 0 length
const n8 = (Math.floor( (ctx.field.p.bitLength() - 1) / 64) +1)*8;
const n8 = (Math.floor( (ctx.F.bitLength - 1) / 64) +1)*8;
// Field Def // Field Def
await writeU32(n8); // Temporally set to 0 length await writeU32(n8); // Temporally set to 0 length
await writeBigInt(ctx.field.p);
await writeBigInt(ctx.F.p);
const NWires = const NWires =
ctx.totals[ctx.stONE] + ctx.totals[ctx.stONE] +
@ -136,7 +136,7 @@ async function buildR1cs(ctx, fileName) {
async function writeBigInt(n, pos) { async function writeBigInt(n, pos) {
const b = Buffer.allocUnsafe(n8); const b = Buffer.allocUnsafe(n8);
const dwords = bigInt(n).toArray(0x100000000).value;
const dwords = Scalar.toArray(n, 0x100000000);
for (let i=0; i<dwords.length; i++) { for (let i=0; i<dwords.length; i++) {
b.writeUInt32LE(dwords[dwords.length-1-i], i*4, 4 ); b.writeUInt32LE(dwords[dwords.length-1-i], i*4, 4 );

+ 1
- 40
src/utils.js

@ -1,5 +1,4 @@
const fnv = require("fnv-plus"); const fnv = require("fnv-plus");
const bigInt = require("big-integer");
module.exports.ident =ident; module.exports.ident =ident;
@ -8,8 +7,6 @@ module.exports.flatArray = flatArray;
module.exports.csArr = csArr; module.exports.csArr = csArr;
module.exports.accSizes = accSizes; module.exports.accSizes = accSizes;
module.exports.fnvHash = fnvHash; module.exports.fnvHash = fnvHash;
module.exports.stringifyBigInts = stringifyBigInts;
module.exports.unstringifyBigInts = unstringifyBigInts;
module.exports.sameSizes = sameSizes; module.exports.sameSizes = sameSizes;
module.exports.isDefined = isDefined; module.exports.isDefined = isDefined;
module.exports.accSizes2Str = accSizes2Str; module.exports.accSizes2Str = accSizes2Str;
@ -45,7 +42,7 @@ function flatArray(a) {
fillArray(res, a[i]); fillArray(res, a[i]);
} }
} else { } else {
res.push(bigInt(a));
res.push(a);
} }
} }
} }
@ -74,42 +71,6 @@ function fnvHash(str) {
return fnv.hash(str, 64).hex(); return fnv.hash(str, 64).hex();
} }
function stringifyBigInts(o) {
if ((typeof(o) == "bigint") || o.eq !== undefined) {
return o.toString(10);
} else if (Array.isArray(o)) {
return o.map(stringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = stringifyBigInts(o[k]);
}
return res;
} else {
return o;
}
}
function unstringifyBigInts(o) {
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
return bigInt(o);
} else if (Array.isArray(o)) {
return o.map(unstringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = unstringifyBigInts(o[k]);
}
return res;
} else {
return bigInt(o);
}
}
function sameSizes(s1, s2) { function sameSizes(s1, s2) {
if (!Array.isArray(s1)) return false; if (!Array.isArray(s1)) return false;
if (!Array.isArray(s2)) return false; if (!Array.isArray(s2)) return false;

+ 7
- 11
test/basiccases.js

@ -1,17 +1,19 @@
const path = require("path"); const path = require("path");
const bigInt = require("big-integer");
const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field;
const c_tester = require("../index.js").c_tester; const c_tester = require("../index.js").c_tester;
const wasm_tester = require("../index.js").wasm_tester; const wasm_tester = require("../index.js").wasm_tester;
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const __P__ = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const Fr = new F1Field(__P__);
const basicCases = require("./basiccases.json"); const basicCases = require("./basiccases.json");
function normalize(o) { function normalize(o) {
if ((typeof(o) == "bigint") || o.isZero !== undefined) { if ((typeof(o) == "bigint") || o.isZero !== undefined) {
const res = bigInt(o);
return norm(res);
return Fr.e(o);
} else if (Array.isArray(o)) { } else if (Array.isArray(o)) {
return o.map(normalize); return o.map(normalize);
} else if (typeof o == "object") { } else if (typeof o == "object") {
@ -21,15 +23,9 @@ function normalize(o) {
} }
return res; return res;
} else { } else {
const res = bigInt(o);
return norm(res);
return Fr.e(o);
} }
function norm(n) {
let res = n.mod(__P__);
if (res.isNegative()) res = __P__.add(res);
return res;
}
} }

Loading…
Cancel
Save