Compare commits

..

28 Commits

Author SHA1 Message Date
Jordi Baylina
0a2aee9932 0.5.25 2020-09-17 10:34:57 +02:00
Jordi Baylina
bad8fad3d0 Optimize optimize constraints not BigArray for small circuits 2020-09-17 10:34:49 +02:00
Jordi Baylina
0a707648fc 0.5.24 2020-09-17 01:09:31 +02:00
Jordi Baylina
263dc73906 FIX Bad optimization 2020-09-17 01:09:24 +02:00
Jordi Baylina
8e730d93a4 64 size r1cs 2020-09-04 09:10:49 +02:00
Jordi Baylina
bbe10438e0 0.5.23 2020-08-31 11:28:23 +02:00
Jordi Baylina
c2cef8d80c deps 2020-08-31 11:28:11 +02:00
Jordi Baylina
2200408986 0.5.22 2020-08-31 11:18:06 +02:00
Jordi Baylina
5f13d37fdc Better info in signal not assigned 2020-08-31 11:13:26 +02:00
Jordi Baylina
3b46b74d4a 0.5.21 2020-08-24 09:31:42 +02:00
Jordi Baylina
aa2d768465 assert working 2020-08-24 09:31:35 +02:00
Jordi Baylina
f02ceb2508 Big component entry tables 2020-08-17 12:02:24 +02:00
Jordi Baylina
d014d67032 0.5.20 2020-08-17 11:22:40 +02:00
Jordi Baylina
2e1b35a94d Fix Offset referenced by an iteger 2020-08-17 11:22:21 +02:00
Jordi Baylina
7cef1be2c3 0.5.19 2020-08-13 18:56:39 +02:00
Jordi Baylina
4b631994ca c to cpp 2020-08-13 18:56:30 +02:00
Jordi Baylina
7239abcef1 0.5.18 2020-08-12 02:26:33 +02:00
Jordi Baylina
633f755e34 Fix testers with fastfile 2020-08-12 02:26:15 +02:00
Jordi Baylina
923b19c414 Fix: Error description function not found 2020-08-12 01:36:01 +02:00
Jordi Baylina
90cc7d5072 Remove streams c and wasm gen 2020-08-07 17:10:30 +02:00
Jordi Baylina
145d5a21ad BigArray in wit2sig 2020-08-06 22:59:19 +02:00
Jordi Baylina
cbb0b229bc Big array in r1cs labels 2020-08-05 14:32:05 +02:00
Jordi Baylina
1d14e8c603 BigArray require 2020-07-30 05:06:58 +02:00
Jordi Baylina
1e2fb12631 BigArray in code 2020-07-30 05:04:15 +02:00
Jordi Baylina
0e1a1bcc23 BigArray in CBuild 2020-07-29 19:40:24 +02:00
Jordi Baylina
989987bfc2 deps 2020-07-29 09:16:43 +02:00
Jordi Baylina
5f3ef322a7 Simplify buildC 2020-07-28 12:50:23 +02:00
Jordi Baylina
3c8e61b9a4 log buildC 2020-07-27 05:00:47 +02:00
17 changed files with 590 additions and 707 deletions

122
cli.js
View File

@@ -24,6 +24,8 @@
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const Scalar = require("ffjavascript").Scalar; const Scalar = require("ffjavascript").Scalar;
const stringifyBigInts = require("ffjavascript").utils.stringifyBigInts;
const fastFile = require("fastfile");
const compiler = require("./src/compiler"); const compiler = require("./src/compiler");
@@ -60,87 +62,68 @@ const argv = require("yargs")
.argv; .argv;
let inputFile; async function run() {
if (argv._.length == 0) { let inputFile;
if (argv._.length == 0) {
inputFile = "circuit.circom"; inputFile = "circuit.circom";
} else if (argv._.length == 1) { } else if (argv._.length == 1) {
inputFile = argv._[0]; inputFile = argv._[0];
} else { } else {
console.log("Only one circuit at a time is permited"); console.log("Only one circuit at a time is permited");
process.exit(1); process.exit(1);
} }
const fullFileName = path.resolve(process.cwd(), inputFile); const fullFileName = path.resolve(process.cwd(), inputFile);
const fileName = path.basename(fullFileName, ".circom"); const fileName = path.basename(fullFileName, ".circom");
const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp"; const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp";
const wasmName = typeof(argv.wasm) === "string" ? argv.wasm : fileName + ".wasm"; const wasmName = typeof(argv.wasm) === "string" ? argv.wasm : fileName + ".wasm";
const watName = typeof(argv.wat) === "string" ? argv.wat : fileName + ".wat"; const watName = typeof(argv.wat) === "string" ? argv.wat : fileName + ".wat";
const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs"; const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs";
const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym"; 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; options.sanityCheck = argv.sanitycheck;
if (argv.csource) { if (argv.csource) {
options.cSourceWriteStream = fs.createWriteStream(cSourceName); options.cSourceFile = await fastFile.createOverride(cSourceName);
} const noExt = cSourceName.substr(0, cSourceName.lastIndexOf(".")) || cSourceName;
if (argv.wasm) { options.dataFile = await fastFile.createOverride(noExt+".dat");
options.wasmWriteStream = fs.createWriteStream(wasmName); }
} if (argv.wasm) {
if (argv.wat) { options.wasmFile = await fastFile.createOverride(wasmName);
options.watWriteStream = fs.createWriteStream(watName); }
} if (argv.wat) {
if (argv.r1cs) { options.watFile = await fastFile.createOverride(watName);
}
if (argv.r1cs) {
options.r1csFileName = r1csName; options.r1csFileName = r1csName;
} }
if (argv.sym) { if (argv.sym) {
options.symWriteStream = fs.createWriteStream(symName); options.symWriteStream = fs.createWriteStream(symName);
} }
if (argv.newThreadTemplates) { if (argv.newThreadTemplates) {
options.newThreadTemplates = new RegExp(argv.newThreadTemplates); options.newThreadTemplates = new RegExp(argv.newThreadTemplates);
} }
if (!argv.prime) { if (!argv.prime) {
options.prime = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"); options.prime = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
} else if (["BLS12-381", "BLS12381"]. indexOf(argv.prime.toUpperCase()) >=0) { } else if (["BLS12-381", "BLS12381"]. indexOf(argv.prime.toUpperCase()) >=0) {
options.prime = Scalar.fromString("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001",16); options.prime = Scalar.fromString("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001",16);
} else if (["BN-128", "BN128", "BN254", "BN-254"]. indexOf(argv.prime.toUpperCase()) >=0) { } else if (["BN-128", "BN128", "BN254", "BN-254"]. indexOf(argv.prime.toUpperCase()) >=0) {
options.prime = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"); options.prime = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
} else { } else {
options.prime = Scalar.fromString(argv.prime); options.prime = Scalar.fromString(argv.prime);
} }
compiler(fullFileName, options).then( () => { await compiler(fullFileName, options);
let cSourceDone = false;
let wasmDone = false; if (options.cSourceFile) await options.cSourceFile.close();
if (options.dataFile) await options.dataFile.close();
if (options.wasmFile) await options.wasmFile.close();
if (options.watFile) await options.watFile.close();
let symDone = false; let symDone = false;
let watDone = false;
if (options.cSourceWriteStream) {
options.cSourceWriteStream.on("finish", () => {
cSourceDone = true;
finishIfDone();
});
} else {
cSourceDone = true;
}
if (options.wasmWriteStream) {
options.wasmWriteStream.on("finish", () => {
wasmDone = true;
finishIfDone();
});
} else {
wasmDone = true;
}
if (options.watWriteStream) {
options.watWriteStream.on("finish", () => {
watDone = true;
finishIfDone();
});
} else {
watDone = true;
}
if (options.symWriteStream) { if (options.symWriteStream) {
options.symWriteStream.on("finish", () => { options.symWriteStream.on("finish", () => {
symDone = true; symDone = true;
@@ -150,12 +133,17 @@ compiler(fullFileName, options).then( () => {
symDone = true; symDone = true;
} }
function finishIfDone() { function finishIfDone() {
if ((cSourceDone)&&(symDone)&&(wasmDone)&&(watDone)) { if (symDone) {
setTimeout(() => { setTimeout(() => {
process.exit(0); process.exit(0);
}, 300); }, 300);
} }
} }
}
run().then(()=> {
process.exit(0);
}, (err) => { }, (err) => {
// console.log(err); // console.log(err);
console.log(err.stack); console.log(err.stack);
@@ -166,11 +154,9 @@ compiler(fullFileName, options).then( () => {
if (argv.verbose) console.log(err.stack); if (argv.verbose) console.log(err.stack);
} }
if (err.ast) { if (err.ast) {
console.error(JSON.stringify(err.ast, null, 1)); console.error(JSON.stringify(stringifyBigInts(err.ast), null, 1));
} }
process.exit(1); process.exit(1);
}); });

143
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.5.17", "version": "0.5.25",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -48,9 +48,9 @@
"dev": true "dev": true
}, },
"acorn": { "acorn": {
"version": "7.3.1", "version": "7.4.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
"integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
"dev": true "dev": true
}, },
"acorn-jsx": { "acorn-jsx": {
@@ -60,9 +60,9 @@
"dev": true "dev": true
}, },
"ajv": { "ajv": {
"version": "6.12.2", "version": "6.12.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
"integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
"dev": true, "dev": true,
"requires": { "requires": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
@@ -203,22 +203,12 @@
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
}, },
"circom_runtime": { "circom_runtime": {
"version": "0.0.6", "version": "0.1.5",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.0.6.tgz", "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.5.tgz",
"integrity": "sha512-o0T5MuWzxnxinWG3+CygS/kZouoP+z5ZrufUwqKJy3gsVFJhkbqMpfKmcBGjhExB3uatA7cKyOiRAOLOz5+t5w==", "integrity": "sha512-BT3d9VCrH/rBRbThDXG731JwezKyskxyE46nACO6Tt/jaorn27LDxFDORdAAjyD0RAoBt+6FpaTp3qlYSx7Pjg==",
"requires": { "requires": {
"ffjavascript": "0.1.0", "ffjavascript": "0.2.10",
"fnv-plus": "^1.3.1" "fnv-plus": "^1.3.1"
},
"dependencies": {
"ffjavascript": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz",
"integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==",
"requires": {
"big-integer": "^1.6.48"
}
}
} }
}, },
"cjson": { "cjson": {
@@ -240,9 +230,9 @@
} }
}, },
"cli-width": { "cli-width": {
"version": "2.2.1", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
"dev": true "dev": true
}, },
"cliui": { "cliui": {
@@ -344,9 +334,9 @@
"dev": true "dev": true
}, },
"ejs": { "ejs": {
"version": "3.1.3", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.5.tgz",
"integrity": "sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg==", "integrity": "sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w==",
"requires": { "requires": {
"jake": "^10.6.1" "jake": "^10.6.1"
} }
@@ -507,9 +497,9 @@
}, },
"dependencies": { "dependencies": {
"estraverse": { "estraverse": {
"version": "5.1.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
"integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
"dev": true "dev": true
} }
} }
@@ -576,14 +566,14 @@
"dev": true "dev": true
}, },
"fastfile": { "fastfile": {
"version": "0.0.9", "version": "0.0.16",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.9.tgz", "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.16.tgz",
"integrity": "sha512-njh6lH2SJiS0u0JofJQf2YfEOSgGfbYPtmFnpEXXy6OilWoX1wGw3klaSKIwhq8+E5MqYpqJXMiaqmptaU2wig==" "integrity": "sha512-2sX5M4JQWAVmS2GojuRPA759aTOs5PyUEpZHjaecNtWBU9CfRFlTf2aBqFG2PJJnrcrawBBAQ1s0QSO+qQ4Zmg=="
}, },
"ffiasm": { "ffiasm": {
"version": "0.0.2", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/ffiasm/-/ffiasm-0.0.2.tgz", "resolved": "https://registry.npmjs.org/ffiasm/-/ffiasm-0.1.1.tgz",
"integrity": "sha512-o/CL7F4IodB7eRHCOQL1SrqN2DIPHrQbEwjPY7NIyeBRdnB3G0xo6b6Mj44SKiWFnvpQMb3n4N7acjD3vv4NVQ==", "integrity": "sha512-irMMHiR9JJ7BVBrAhtliUawxVdPYSdyl81taUYJ4C1mJ0iw2ueThE/qtr0J8B83tsIY8HJvh0lg5F+6ClK4xpA==",
"requires": { "requires": {
"big-integer": "^1.6.48", "big-integer": "^1.6.48",
"ejs": "^3.0.1", "ejs": "^3.0.1",
@@ -591,13 +581,24 @@
} }
}, },
"ffjavascript": { "ffjavascript": {
"version": "0.2.4", "version": "0.2.10",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.4.tgz", "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.10.tgz",
"integrity": "sha512-XFeWcjUDFPavN+DDOxhE8p5MOhZQJc9oO1Sj4ml1pyjqNhS1ujEamcjFyK0cctdnat61i7lvpTYzdtS3RYDC8w==", "integrity": "sha512-GQI6gHYYG5/iD4Kt3VzezzK7fARJzP0zkc82V/+JAdjfeKBXhDSo5rpKFuK3cDcrdW0Fu2emuYNMEAuFqhEQvQ==",
"requires": { "requires": {
"big-integer": "^1.6.48", "big-integer": "^1.6.48",
"wasmcurves": "0.0.4", "wasmcurves": "0.0.5",
"worker-threads": "^1.0.0" "worker-threads": "^1.0.0"
},
"dependencies": {
"wasmcurves": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.0.5.tgz",
"integrity": "sha512-BmI4GXLjLawGg2YkvHa8zRsnWec+d1uwoxE+Iov8cqOpDL7GA5XO2pk2yuDbXHMzwIug2exnKot3baRZ86R0pA==",
"requires": {
"big-integer": "^1.6.42",
"blakejs": "^1.1.0"
}
}
} }
}, },
"ffwasm": { "ffwasm": {
@@ -780,21 +781,21 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}, },
"inquirer": { "inquirer": {
"version": "7.2.0", "version": "7.3.3",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.2.0.tgz", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
"integrity": "sha512-E0c4rPwr9ByePfNlTIB8z51kK1s2n6jrHuJeEHENl/sbq2G/S1auvibgEwNR4uSyiU+PiYHqSwsgGiXjG8p5ZQ==", "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
"dev": true, "dev": true,
"requires": { "requires": {
"ansi-escapes": "^4.2.1", "ansi-escapes": "^4.2.1",
"chalk": "^3.0.0", "chalk": "^4.1.0",
"cli-cursor": "^3.1.0", "cli-cursor": "^3.1.0",
"cli-width": "^2.0.0", "cli-width": "^3.0.0",
"external-editor": "^3.0.3", "external-editor": "^3.0.3",
"figures": "^3.0.0", "figures": "^3.0.0",
"lodash": "^4.17.15", "lodash": "^4.17.19",
"mute-stream": "0.0.8", "mute-stream": "0.0.8",
"run-async": "^2.4.0", "run-async": "^2.4.0",
"rxjs": "^6.5.3", "rxjs": "^6.6.0",
"string-width": "^4.1.0", "string-width": "^4.1.0",
"strip-ansi": "^6.0.0", "strip-ansi": "^6.0.0",
"through": "^2.3.6" "through": "^2.3.6"
@@ -811,9 +812,9 @@
} }
}, },
"chalk": { "chalk": {
"version": "3.0.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true, "dev": true,
"requires": { "requires": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
@@ -986,9 +987,9 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.15", "version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true "dev": true
}, },
"mimic-fn": { "mimic-fn": {
@@ -1063,9 +1064,9 @@
} }
}, },
"onetime": { "onetime": {
"version": "5.1.0", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true, "dev": true,
"requires": { "requires": {
"mimic-fn": "^2.1.0" "mimic-fn": "^2.1.0"
@@ -1173,6 +1174,16 @@
"version": "0.0.7", "version": "0.0.7",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.7.tgz", "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.7.tgz",
"integrity": "sha512-Zk7sdqsV6DsN/rhjULDfCCowPiMDsziTMFicdkrKN80yybr/6YFf9H91ELXN85dVEf6EYkVR5EHkZNc0dMqZKA==" "integrity": "sha512-Zk7sdqsV6DsN/rhjULDfCCowPiMDsziTMFicdkrKN80yybr/6YFf9H91ELXN85dVEf6EYkVR5EHkZNc0dMqZKA=="
},
"ffjavascript": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.4.tgz",
"integrity": "sha512-XFeWcjUDFPavN+DDOxhE8p5MOhZQJc9oO1Sj4ml1pyjqNhS1ujEamcjFyK0cctdnat61i7lvpTYzdtS3RYDC8w==",
"requires": {
"big-integer": "^1.6.48",
"wasmcurves": "0.0.4",
"worker-threads": "^1.0.0"
}
} }
} }
}, },
@@ -1223,9 +1234,9 @@
"dev": true "dev": true
}, },
"rxjs": { "rxjs": {
"version": "6.6.0", "version": "6.6.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
"integrity": "sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==", "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
"dev": true, "dev": true,
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
@@ -1323,9 +1334,9 @@
} }
}, },
"strip-json-comments": { "strip-json-comments": {
"version": "3.1.0", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true "dev": true
}, },
"supports-color": { "supports-color": {
@@ -1559,9 +1570,9 @@
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
}, },
"yargs": { "yargs": {
"version": "15.3.1", "version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"requires": { "requires": {
"cliui": "^6.0.0", "cliui": "^6.0.0",
"decamelize": "^1.2.0", "decamelize": "^1.2.0",
@@ -1573,7 +1584,7 @@
"string-width": "^4.2.0", "string-width": "^4.2.0",
"which-module": "^2.0.0", "which-module": "^2.0.0",
"y18n": "^4.0.0", "y18n": "^4.0.0",
"yargs-parser": "^18.1.1" "yargs-parser": "^18.1.2"
} }
}, },
"yargs-parser": { "yargs-parser": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.5.17", "version": "0.5.25",
"description": "Language to generate logic circuits", "description": "Language to generate logic circuits",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@@ -30,10 +30,10 @@
}, },
"dependencies": { "dependencies": {
"chai": "^4.2.0", "chai": "^4.2.0",
"circom_runtime": "0.0.6", "circom_runtime": "0.1.5",
"fastfile": "0.0.9", "fastfile": "0.0.16",
"ffiasm": "0.0.2", "ffiasm": "0.1.1",
"ffjavascript": "0.2.4", "ffjavascript": "0.2.10",
"ffwasm": "0.0.7", "ffwasm": "0.0.7",
"fnv-plus": "^1.3.1", "fnv-plus": "^1.3.1",
"r1csfile": "0.0.14", "r1csfile": "0.0.14",

View File

@@ -1,8 +1,8 @@
const streamFromMultiArray = require("../../src/streamfromarray_txt.js");
const utils = require("../../src/utils"); const utils = require("../../src/utils");
const assert = require("assert"); const assert = require("assert");
const Scalar = require("ffjavascript").Scalar; const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field; const F1Field = require("ffjavascript").F1Field;
const BigArray = require("../../src/bigarray");
function ref2src(c) { function ref2src(c) {
if ((c[0] == "R")||(c[0] == "RI")) { if ((c[0] == "R")||(c[0] == "RI")) {
@@ -95,6 +95,10 @@ class CodeBuilderC {
this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr}); this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
} }
checkAssert(a, strErr) {
this.ops.push({op: "CHECKASSERT", a, strErr});
}
log(val) { log(val) {
this.ops.push({op: "LOG", val}); this.ops.push({op: "LOG", val});
} }
@@ -215,6 +219,8 @@ class CodeBuilderC {
code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`); code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`);
} else if (o.op == "CHECKCONSTRAINT") { } else if (o.op == "CHECKCONSTRAINT") {
code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`); code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`);
} else if (o.op == "CHECKASSERT") {
code.push(`ctx->checkAssert(__cIdx, ${ref2src(o.a)}, "${o.strErr}");`);
} else if (o.op == "LOG") { } else if (o.op == "LOG") {
code.push(`ctx->log(${ref2src(o.val)});`); code.push(`ctx->log(${ref2src(o.val)});`);
} }
@@ -341,16 +347,23 @@ class FunctionBuilderC {
} }
class BuilderC { class BuilderC {
constructor(p) { constructor(p, verbose) {
this.F = new F1Field(p); this.F = new F1Field(p);
this.hashMaps={}; this.hashMaps={};
this.componentEntriesTables={}; this.componentEntriesTables=new BigArray();
this.sizes ={}; this.sizes ={};
this.constants = []; this.constants = [];
this.functions = []; this.functions = [];
this.components = []; this.components = new BigArray();
this.usedConstants = {}; this.usedConstants = {};
this.verbose = verbose;
this.sizePointers = {};
this.hashMapPointers = {};
this.functionIdx = {};
this.nCets = 0;
} }
setHeader(header) { setHeader(header) {
@@ -362,8 +375,11 @@ class BuilderC {
this.hashMaps[name] = hm; this.hashMaps[name] = hm;
} }
addComponentEntriesTable(name, cet) { addComponentEntriesTable(name, cet, idComponent) {
this.componentEntriesTables[name] = cet; this.componentEntriesTables[idComponent] = {
name: name,
cet: cet
};
} }
addSizes(name, accSizes) { addSizes(name, accSizes) {
@@ -409,8 +425,8 @@ class BuilderC {
_buildHeader(code) { _buildHeader(code) {
code.push( code.push(
"#include \"circom.h\"", "#include \"circom.hpp\"",
"#include \"calcwit.h\"", "#include \"calcwit.hpp\"",
`#define NSignals ${this.header.NSignals}`, `#define NSignals ${this.header.NSignals}`,
`#define NComponents ${this.header.NComponents}`, `#define NComponents ${this.header.NComponents}`,
`#define NOutputs ${this.header.NOutputs}`, `#define NOutputs ${this.header.NOutputs}`,
@@ -421,67 +437,91 @@ class BuilderC {
); );
} }
_buildHashMaps(code) { async _buildHashMaps(fdData) {
code.push("// Hash Maps "); while (fdData.pos % 8) fdData.pos++;
this.pHashMaps = fdData.pos;
const buff = new Uint8Array(256*12);
const buffV = new DataView(buff.buffer);
for (let hmName in this.hashMaps ) { for (let hmName in this.hashMaps ) {
while (fdData.pos % 8) fdData.pos++;
this.hashMapPointers[hmName] = fdData.pos;
const hm = this.hashMaps[hmName]; const hm = this.hashMaps[hmName];
let c = `Circom_HashEntry ${hmName}[256] = {`;
for (let i=0; i<256; i++) { for (let i=0; i<256; i++) {
c += i>0 ? "," : ""; buffV.setUint32(i*12, hm[i] ? parseInt( hm[i][0].slice(8), 16 ) : 0, true);
if (hm[i]) { buffV.setUint32(i*12+4, hm[i] ? parseInt( hm[i][0].slice(0,8), 16 ) : 0, true);
c += `{0x${hm[i][0]}LL, ${hm[i][1]}} /* ${hm[i][2]} */`; buffV.setUint32(i*12+8, hm[i] ? hm[i][1] : 0, true);
} else {
c += "{0,0}";
} }
}
c += "};"; await fdData.write(buff);
code.push(c);
} }
} }
_buildComponentEntriesTables(code) { async _buildComponentEntriesTables(fdData) {
code.push("// Component Entry tables");
for (let cetName in this.componentEntriesTables) { while (fdData.pos % 8) fdData.pos++;
const cet = this.componentEntriesTables[cetName]; this.pCets = fdData.pos;
for (let i=0; i< this.componentEntriesTables.length; i++) {
if ((this.verbose)&&(i%100000 ==0)) console.log(`_buildComponentEntriesTables ${i}/${this.componentEntriesTables.length}`);
const cet = this.componentEntriesTables[i].cet;
this.components[i].entryTablePointer = fdData.pos;
const buff = new Uint8Array(16*cet.length);
const buffV = new DataView(buff.buffer);
code.push(`Circom_ComponentEntry ${cetName}[${cet.length}] = {`);
for (let j=0; j<cet.length; j++) { for (let j=0; j<cet.length; j++) {
const ty = cet[j].type == "S" ? "_typeSignal" : "_typeComponent"; utils.setUint64(buffV, 16*j+0, this.sizePointers[ cet[j].sizeName]);
code.push(` ${j>0?",":" "}{${cet[j].offset},${cet[j].sizeName}, ${ty}}`); buffV.setUint32(16*j+8, cet[j].offset, true);
buffV.setUint32(16*j+12, cet[j].type == "S" ? 0 : 1, true); // Size type 0-> Signal, 1->Component
this.nCets ++;
} }
code.push("};");
await fdData.write(buff);
} }
} }
_buildSizes(code) { async _buildSizes(fdData) {
code.push("// Sizes");
for (let sName in this.sizes) { for (let sName in this.sizes) {
const accSizes = this.sizes[sName]; const accSizes = this.sizes[sName];
let c = `Circom_Size ${sName}[${accSizes.length}] = {`; while (fdData.pos % 8) fdData.pos++;
this.sizePointers[sName] = fdData.pos;
const buff = new Uint8Array(4*accSizes.length);
const buffV = new DataView(buff.buffer);
for (let i=0; i<accSizes.length; i++) { for (let i=0; i<accSizes.length; i++) {
if (i>0) c += ","; buffV.setUint32(i*4, accSizes[i], true);
c += accSizes[i];
} }
c += "};"; await fdData.write(buff);
code.push(c);
} }
} }
_buildConstants(code) {
async _buildConstants(fdData) {
const self = this; const self = this;
code.push("// Constants"); const frSize = (8 + self.F.n64*8);
code.push(`FrElement _constants[${self.constants.length}] = {`); const buff = new Uint8Array(self.constants.length* frSize);
for (let i=0; i<self.constants.length; i++) { const buffV = new DataView(buff.buffer);
code.push((i>0 ? "," : " ") + "{" + number2Code(self.constants[i]) + "}");
}
code.push("};");
function number2Code(n) {
while (fdData.pos % 8) fdData.pos++;
this.pConstants = fdData.pos;
let o = 0;
for (let i=0; i<self.constants.length; i++) {
Fr2Bytes(buffV, o, self.constants[i]);
o += frSize;
}
await fdData.write(buff);
function Fr2Bytes(buffV, offset, n) {
const minShort = self.F.neg(self.F.e("80000000")); const minShort = self.F.neg(self.F.e("80000000"));
const maxShort = self.F.e("7FFFFFFF", 16); const maxShort = self.F.e("7FFFFFFF", 16);
@@ -489,51 +529,49 @@ class BuilderC {
&&(self.F.leq(n, maxShort))) &&(self.F.leq(n, maxShort)))
{ {
if (self.F.geq(n, self.F.zero)) { if (self.F.geq(n, self.F.zero)) {
return addShortMontgomeryPositive(n); return shortMontgomeryPositive(n);
} else { } else {
return addShortMontgomeryNegative(n); return shortMontgomeryNegative(n);
} }
} }
return addLongMontgomery(n); return longMontgomery(n);
function addShortMontgomeryPositive(a) { function shortMontgomeryPositive(a) {
return `${a.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`; buffV.setUint32(offset, Scalar.toNumber(a) , true );
buffV.setUint32(offset + 4, 0x40000000 , true );
long(buffV, offset + 8, toMontgomery(a));
} }
function addShortMontgomeryNegative(a) { function shortMontgomeryNegative(a) {
const b = -Scalar.toNumber(self.F.neg(a)); const b = -Scalar.toNumber(self.F.neg(a));
return `${b.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`; buffV.setUint32(offset, b , true );
buffV.setUint32(offset + 4, 0x40000000 , true );
long(buffV, offset + 8, toMontgomery(a));
} }
function addLongMontgomery(a) { function longMontgomery(a) {
return `0, 0xC0000000, { ${getLongString(toMontgomery(a))} }`; buffV.setUint32(offset, 0 , true );
buffV.setUint32(offset + 4, 0xC0000000 , true );
long(buffV, offset + 8, toMontgomery(a));
} }
function getLongString(a) { function long(buffV, offset, a) {
let S = "";
let p = offset;
const arr = Scalar.toArray(a, 0x100000000); const arr = Scalar.toArray(a, 0x100000000);
for (let i=0; i<self.F.n64*2; i+=2) { for (let i=0; i<self.F.n64*2; i++) {
const idx = arr.length-2-i; const idx = arr.length-1-i;
if (i>0) S = S + ",";
if ( idx >=0) { if ( idx >=0) {
let msb = arr[idx].toString(16); buffV.setUint32(p, arr[idx], true);
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 { } else {
S += "0LL"; buffV.setUint32(p, 0, true);
} }
p+= 4;
} }
return S;
} }
function toMontgomery(a) { function toMontgomery(a) {
@@ -541,98 +579,143 @@ class BuilderC {
} }
} }
} }
_buildFunctions(code) { _buildFunctions(code) {
const listedFunctions = [];
for (let i=0; i<this.functions.length; i++) { for (let i=0; i<this.functions.length; i++) {
const cfb = this.functions[i]; const cfb = this.functions[i];
cfb.build(code); cfb.build(code);
if (this.functions[i].type == "COMPONENT") {
this.functionIdx[this.functions[i].name] = listedFunctions.length;
listedFunctions.push(i);
} }
} }
_buildComponents(code) { code.push("// Function Table");
code.push("// Components"); code.push(`Circom_ComponentFunction _functionTable[${listedFunctions.length}] = {`);
code.push(`Circom_Component _components[${this.components.length}] = {`); for (let i=0; i<listedFunctions.length; i++) {
for (let i=0; i<this.components.length; i++) {
const c = this.components[i];
const sep = i>0 ? " ," : " "; const sep = i>0 ? " ," : " ";
code.push(`${sep}{${c.hashMapName}, ${c.entryTableName}, ${c.functionName}, ${c.nInSignals}, ${c.newThread}}`); code.push(`${sep}${this.functions[listedFunctions[i]].name}`);
} }
code.push("};"); code.push("};");
} }
_buildMapIsInput(code) {
code.push("// mapIsInput"); async _buildComponents(fdData) {
code.push(`u32 _mapIsInput[${this.mapIsInput.length}] = {`);
let line = ""; const buff = new Uint8Array(32);
const buffV = new DataView(buff.buffer);
while (fdData.pos % 8) fdData.pos++;
this.pComponents = fdData.pos;
for (let i=0; i<this.components.length; i++) {
if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildComponents ${i}/${this.components.length}`);
const c = this.components[i];
utils.setUint64(buffV, 0, this.hashMapPointers[c.hashMapName], true);
utils.setUint64(buffV, 8, c.entryTablePointer, true);
utils.setUint64(buffV, 16, this.functionIdx[c.functionName], true);
buffV.setUint32(24, c.nInSignals, true);
buffV.setUint32(28, c.newThread ? 1 : 0, true);
await fdData.write(buff);
}
}
async _buildMapIsInput(fdData) {
const buff = new Uint8Array(this.mapIsInput.length * 4);
const buffV = new DataView(buff.buffer);
while (fdData.pos % 8) fdData.pos++;
this.pMapIsInput = fdData.pos;
for (let i=0; i<this.mapIsInput.length; i++) { for (let i=0; i<this.mapIsInput.length; i++) {
line += i>0 ? ", " : " "; if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildMapIsInput ${i}/${this.mapIsInput.length}`);
line += toHex(this.mapIsInput[i]);
if (((i+1) % 64)==0) {
code.push(" "+line);
line = "";
}
}
if (line != "") code.push(" "+line);
code.push("};");
function toHex(number) { buffV.setUint32(4*i, this.mapIsInput[i], true);
if (number < 0) number = 0xFFFFFFFF + number + 1;
let S=number.toString(16).toUpperCase();
while (S.length<8) S = "0" + S;
return "0x"+S;
}
} }
_buildWit2Sig(code) { await fdData.write(buff);
code.push("// Witness to Signal Table"); }
code.push(`int _wit2sig[${this.wit2sig.length}] = {`);
let line = ""; async _buildWit2Sig(fdData) {
const buff = new Uint8Array(this.wit2sig.length * 4);
const buffV = new DataView(buff.buffer);
while (fdData.pos % 8) fdData.pos++;
this.pWit2Sig = fdData.pos;
for (let i=0; i<this.wit2sig.length; i++) { for (let i=0; i<this.wit2sig.length; i++) {
line += i>0 ? "," : " "; if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildWit2Sig ${i}/${this.wit2sig.length}`);
line += this.wit2sig[i];
if (((i+1) % 64) == 0) { buffV.setUint32(4*i, this.wit2sig[i], true);
code.push(" "+line);
line = "";
}
}
if (line != "") code.push(" "+line);
code.push("};");
} }
_buildCircuitVar(code) { await fdData.write(buff);
}
code.push( async _buildCircuitVar(fdData) {
"// Circuit Variable",
"Circom_Circuit _circuit = {" , const pP = fdData.pos;
" NSignals,",
" NComponents,", const strBuff = new TextEncoder("utf-8").encode(this.header.P.toString());
" NInputs,", await fdData.write(strBuff);
" NOutputs,",
" NVars,", const buff = new Uint8Array(72);
" _wit2sig,", const buffV = new DataView(buff.buffer);
" _components,",
" _mapIsInput,", utils.setUint64(buffV, 0, this.pWit2Sig, true);
" _constants,", utils.setUint64(buffV, 8, this.pComponents, true);
" __P__", utils.setUint64(buffV, 16, this.pMapIsInput, true);
"};" utils.setUint64(buffV, 24, this.pConstants, true);
); utils.setUint64(buffV, 32, pP, true);
utils.setUint64(buffV, 40, this.pCets, true);
buffV.setUint32(48, this.header.NSignals, true);
buffV.setUint32(52, this.header.NComponents, true);
buffV.setUint32(56, this.header.NOutputs, true);
buffV.setUint32(60, this.header.NInputs, true);
buffV.setUint32(64, this.header.NVars, true);
buffV.setUint32(68, this.nCets, true);
fdData.pos = 0;
await fdData.write(buff);
} }
build() { async build(fdCode, fdData) {
const code=[]; const encoder = new TextEncoder("utf-8");
fdData.pos = 72;
while (fdData.pos % 8) fdData.pos++;
const code=new BigArray();
this._buildHeader(code); this._buildHeader(code);
this._buildSizes(code); await this._buildSizes(fdData);
this._buildConstants(code); await this._buildConstants(fdData);
this._buildHashMaps(code); await this._buildHashMaps(fdData);
this._buildComponentEntriesTables(code); await this._buildComponentEntriesTables(fdData);
this._buildFunctions(code); this._buildFunctions(code);
this._buildComponents(code); await this._buildComponents(fdData);
this._buildMapIsInput(code); await this._buildMapIsInput(fdData);
this._buildWit2Sig(code); await this._buildWit2Sig(fdData);
this._buildCircuitVar(code); await this._buildCircuitVar(fdData);
return streamFromMultiArray(code); await writeCode(code);
async function writeCode(c) {
if (c.push) {
for (let i=0; i<c.length; i++) {
await writeCode(c[i]);
}
} else if (typeof c === "string") {
await fdCode.write(encoder.encode(c + "\n"));
}
}
} }
} }

View File

@@ -13,6 +13,7 @@ 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 fastFile = require("fastfile");
const {stringifyBigInts, unstringifyBigInts } = require("ffjavascript").utils; const {stringifyBigInts, unstringifyBigInts } = require("ffjavascript").utils;
@@ -29,20 +30,24 @@ async function c_tester(circomFile, _options) {
const baseName = path.basename(circomFile, ".circom"); const baseName = path.basename(circomFile, ".circom");
const options = Object.assign({}, _options); const options = Object.assign({}, _options);
options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp")); options.cSourceFile = await fastFile.createOverride(path.join(dir.path, baseName + ".cpp"));
options.dataFile = await fastFile.createOverride(path.join(dir.path, baseName + ".dat"));
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 || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"); options.p = options.p || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
await compiler(circomFile, options); await compiler(circomFile, options);
await options.cSourceFile.close();
await options.dataFile.close();
const source = await buildZqField(options.p, "Fr"); const source = await buildZqField(options.p, "Fr");
// console.log(dir.path); // console.log(dir.path);
await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8"); await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8");
await fs.promises.writeFile(path.join(dir.path, "fr.h"), source.h, "utf8"); await fs.promises.writeFile(path.join(dir.path, "fr.hpp"), source.hpp, "utf8");
await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8"); await fs.promises.writeFile(path.join(dir.path, "fr.cpp"), source.cpp, "utf8");
let pThread = ""; let pThread = "";
@@ -63,7 +68,7 @@ async function c_tester(circomFile, _options) {
` ${path.join(cdir, "main.cpp")}` + ` ${path.join(cdir, "main.cpp")}` +
` ${path.join(cdir, "calcwit.cpp")}` + ` ${path.join(cdir, "calcwit.cpp")}` +
` ${path.join(cdir, "utils.cpp")}` + ` ${path.join(cdir, "utils.cpp")}` +
` ${path.join(dir.path, "fr.c")}` + ` ${path.join(dir.path, "fr.cpp")}` +
` ${path.join(dir.path, "fr.o")}` + ` ${path.join(dir.path, "fr.o")}` +
` ${path.join(dir.path, baseName + ".cpp")} ` + ` ${path.join(dir.path, baseName + ".cpp")} ` +
` -o ${path.join(dir.path, baseName)}` + ` -o ${path.join(dir.path, baseName)}` +

View File

@@ -384,9 +384,9 @@ module.exports = function buildRuntime(module, builder) {
"error", "error",
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer), c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
c.i32_const(0), c.getLocal("cIdx"),
c.i32_const(0), c.getLocal("component"),
c.i32_const(0), c.getLocal("signal"),
c.i32_const(0) c.i32_const(0)
) )
) )
@@ -619,6 +619,35 @@ module.exports = function buildRuntime(module, builder) {
)); ));
} }
function buildCheckAssert() {
const f = module.addFunction("checkAssert");
f.addParam("cIdx", "i32");
f.addParam("pA", "i32");
f.addParam("pStr", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c,
c.if (
c.i32_eqz(
c.call(
"Fr_isTrue",
c.getLocal("pA"),
)
),
c.call(
"error",
c.i32_const(errs.ASSERT_DOES_NOT_MATCH.code),
c.i32_const(errs.ASSERT_DOES_NOT_MATCH.pointer),
c.getLocal("cIdx"),
c.getLocal("pA"),
c.getLocal("pStr"),
c.i32_const(0)
)
)
));
}
function buildGetNVars() { function buildGetNVars() {
const f = module.addFunction("getNVars"); const f = module.addFunction("getNVars");
f.setReturnType("i32"); f.setReturnType("i32");
@@ -823,6 +852,7 @@ module.exports = function buildRuntime(module, builder) {
buildComponentFinished(); buildComponentFinished();
buildCheckConstraint(); buildCheckConstraint();
buildCheckAssert();
buildGetNVars(); buildGetNVars();
buildGetFrLen(); buildGetFrLen();

View File

@@ -1,5 +1,3 @@
const streamFromArrayTxt = require("../../src/streamfromarray_txt");
const streamFromArrayBin = require("../../src/streamfromarray_bin");
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;
@@ -100,6 +98,9 @@ class CodeBuilderWasm {
this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr}); this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
} }
checkAssert(a, strErr) {
this.ops.push({op: "CHECKASSERT", a, strErr});
}
concat(cb) { concat(cb) {
this.ops.push(...cb.ops); this.ops.push(...cb.ops);
@@ -334,6 +335,15 @@ class CodeBuilderWasm {
c.i32_const(this.fnBuilder.builder.module.allocString(o.strErr)) c.i32_const(this.fnBuilder.builder.module.allocString(o.strErr))
) )
); );
} else if (o.op == "CHECKASSERT") {
code.push(
c.call(
"checkAssert",
c.getLocal("cIdx"),
this.fnBuilder._deRefFr(c, o.a),
c.i32_const(this.fnBuilder.builder.module.allocString(o.strErr))
)
);
} else if (o.op == "LOG") { } else if (o.op == "LOG") {
code.push( code.push(
c.call( c.call(
@@ -990,7 +1000,8 @@ class BuilderWasm {
} }
build(outType) { async build(fd, outType) {
const encoder = new TextEncoder("utf-8");
let module; let module;
if (outType == "wasm") { if (outType == "wasm") {
module=new ModuleBuilder(); module=new ModuleBuilder();
@@ -1017,12 +1028,25 @@ class BuilderWasm {
module.setMemory(2000); module.setMemory(2000);
if (outType == "wasm") { if (outType == "wasm") {
return streamFromArrayBin(module.build()); const bytes = module.build();
const bytesArr = new Uint8Array(bytes);
await fd.write(bytesArr);
} else if (outType == "wat") { } else if (outType == "wat") {
return streamFromArrayTxt(module.build()); const code = module.build();
await writeCode(code);
} else { } else {
assert(false); assert(false);
} }
async function writeCode(c) {
if (c.push) {
for (let i=0; i<c.length; i++) {
await writeCode(c[i]);
}
} else if (typeof c === "string") {
await fd.write(encoder.encode(c + "\n"));
}
}
} }
} }

View File

@@ -7,4 +7,5 @@ module.exports = {
SIGNAL_ASSIGNED_TWICE: {code: 6, str: "Signal assigned twice"}, SIGNAL_ASSIGNED_TWICE: {code: 6, str: "Signal assigned twice"},
CONSTRAIN_DOES_NOT_MATCH: {code: 7, str: "Constraint doesn't match"}, CONSTRAIN_DOES_NOT_MATCH: {code: 7, str: "Constraint doesn't match"},
MAPISINPUT_DONT_MATCH: {code: 8, str: "MapIsInput don't match"}, MAPISINPUT_DONT_MATCH: {code: 8, str: "MapIsInput don't match"},
ASSERT_DOES_NOT_MATCH: {code: 9, str: "Assert not satisfied"},
}; };

View File

@@ -9,6 +9,7 @@ const compiler = require("../../src/compiler");
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 fastFile = require("fastfile");
const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder; const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder;
@@ -24,16 +25,14 @@ async function wasm_tester(circomFile, _options) {
const baseName = path.basename(circomFile, ".circom"); const baseName = path.basename(circomFile, ".circom");
const options = Object.assign({}, _options); const options = Object.assign({}, _options);
options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm")); options.wasmFile = await fastFile.createOverride(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");
const promisesArr = [];
promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill)));
await compiler(circomFile, options); await compiler(circomFile, options);
await Promise.all(promisesArr); await options.wasmFile.close();
const wasm = await fs.promises.readFile(path.join(dir.path, baseName + ".wasm")); const wasm = await fs.promises.readFile(path.join(dir.path, baseName + ".wasm"));

View File

@@ -26,8 +26,10 @@ class _BigArray {
} }
return this; return this;
} }
push (element) { push () {
this.setElement (this.length, element); for (let i=0; i<arguments.length; i++) {
this.setElement (this.length, arguments[i]);
}
} }
getElement(idx) { getElement(idx) {
idx = parseInt(idx); idx = parseInt(idx);

View File

@@ -21,6 +21,7 @@ const assert = require("assert");
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;
const BigArray = require("./bigarray");
module.exports = build; module.exports = build;
@@ -37,28 +38,33 @@ function build(ctx) {
ctx.addConstant(ctx.F.zero); ctx.addConstant(ctx.F.zero);
ctx.addConstant(ctx.F.one); ctx.addConstant(ctx.F.one);
if (ctx.verbose) console.log("buildHeader...");
buildHeader(ctx); buildHeader(ctx);
if (ctx.verbose) console.log("buildEntryTables...");
buildEntryTables(ctx); buildEntryTables(ctx);
ctx.globalNames = ctx.uniqueNames; ctx.globalNames = ctx.uniqueNames;
if (ctx.verbose) console.log("buildCode...");
buildCode(ctx); buildCode(ctx);
if (ctx.verbose) console.log("buildComponentsArray...");
buildComponentsArray(ctx); buildComponentsArray(ctx);
if (ctx.verbose) console.log("buildMapIsInput...");
buildMapIsInput(ctx); buildMapIsInput(ctx);
if (ctx.verbose) console.log("buildWit2Sig...");
buildWit2Sig(ctx); buildWit2Sig(ctx);
} }
function buildEntryTables(ctx) { function buildEntryTables(ctx) {
const codes_hashMaps = [];
const codes_componentEntries = [];
const definedHashMaps = {}; const definedHashMaps = {};
for (let i=0; i<ctx.components.length; i++) { for (let i=0; i<ctx.components.length; i++) {
if (ctx.verbose && (i%100000 ==0)) console.log(`buildEntryTables component: ${i}/${ctx.components.length}`);
const {htName, htMap} = addHashTable(i); const {htName, htMap} = addHashTable(i);
let code = "";
const componentEntriesTableName = ctx.getUniqueName("_entryTable" + ctx.components[i].template); const componentEntriesTableName = ctx.getUniqueName("_entryTable" + ctx.components[i].template);
const componentEntriesTable = []; const componentEntriesTable = [];
@@ -72,34 +78,14 @@ function buildEntryTables(ctx) {
}); });
} }
ctx.builder.addComponentEntriesTable(componentEntriesTableName, componentEntriesTable); ctx.builder.addComponentEntriesTable(componentEntriesTableName, componentEntriesTable, i);
code += `Circom_ComponentEntry ${componentEntriesTableName}[${htMap.length}] = {\n`;
for (let j=0; j<htMap.length; j++) {
const entry = ctx.components[i].names.o[htMap[j]];
code += j>0 ? " ," : " ";
const sizeName = ctx.addSizes(entry.sizes);
const ty = entry.type == "S" ? "_typeSignal" : "_typeComponent";
code += `{${entry.offset},${sizeName}, ${ty}}\n`;
}
code += "};\n";
codes_componentEntries.push(code);
ctx.components[i].htName = htName; ctx.components[i].htName = htName;
ctx.components[i].etName = componentEntriesTableName; ctx.components[i].etName = componentEntriesTableName;
} }
return [ return;
"// HashMaps\n" ,
codes_hashMaps , "\n" ,
"\n" ,
"// Component Entries\n" ,
codes_componentEntries , "\n" ,
"\n"
];
function addHashTable(cIdx) { function addHashTable(cIdx) {
const keys = Object.keys(ctx.components[cIdx].names.o); const keys = Object.keys(ctx.components[cIdx].names.o);
@@ -131,6 +117,7 @@ function buildCode(ctx) {
const fnComponents = []; const fnComponents = [];
for (let i=0; i<ctx.components.length; i++) { for (let i=0; i<ctx.components.length; i++) {
if (ctx.verbose && (i%100000 ==0)) console.log(`buildCode component: ${i}/${ctx.components.length}`);
const {h, instanceDef} = hashComponentCall(ctx, i); const {h, instanceDef} = hashComponentCall(ctx, i);
const fName = ctx.components[i].template+"_"+h; const fName = ctx.components[i].template+"_"+h;
if (!fDefined[fName]) { if (!fDefined[fName]) {
@@ -180,6 +167,7 @@ function buildCode(ctx) {
function buildComponentsArray(ctx) { function buildComponentsArray(ctx) {
for (let i=0; i< ctx.components.length; i++) { for (let i=0; i< ctx.components.length; i++) {
if (ctx.verbose && (i%1000000 ==0)) console.log(`buildComponentsArray component: ${i}/${ctx.components.length}`);
let newThread; let newThread;
if (ctx.newThreadTemplates) { if (ctx.newThreadTemplates) {
if (ctx.newThreadTemplates.test(ctx.components[i].template)) { if (ctx.newThreadTemplates.test(ctx.components[i].template)) {
@@ -217,6 +205,7 @@ function buildMapIsInput(ctx) {
let map = []; let map = [];
let acc = 0; let acc = 0;
for (i=0; i<ctx.signals.length; i++) { for (i=0; i<ctx.signals.length; i++) {
if (ctx.verbose && (i%1000000 ==0)) console.log(`buildMapIsInput signal: ${i}/${ctx.signals.length}`);
if (ctx.signals[i].o & ctx.IN) { if (ctx.signals[i].o & ctx.IN) {
acc = acc | (1 << (i%32) ); acc = acc | (1 << (i%32) );
} }
@@ -241,8 +230,9 @@ function buildWit2Sig(ctx) {
ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPUBINPUT] +
ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stPRVINPUT] +
ctx.totals[ctx.stINTERNAL]; ctx.totals[ctx.stINTERNAL];
const arr = Array(NVars); const arr = new BigArray(NVars);
for (let i=0; i<ctx.signals.length; i++) { for (let i=0; i<ctx.signals.length; i++) {
if (ctx.verbose && (i%1000000 ==0)) console.log(`buildWit2Sig signal: ${i}/${ctx.signals.length}`);
const outIdx = ctx.signals[i].id; const outIdx = ctx.signals[i].id;
if (ctx.signals[i].e>=0) continue; // If has an alias, continue.. if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
assert(typeof outIdx != "undefined", `Signal ${i} does not have index`); assert(typeof outIdx != "undefined", `Signal ${i} does not have index`);

View File

@@ -119,45 +119,44 @@ async function compile(srcFile, options) {
throw(ctx.error); throw(ctx.error);
} }
if (options.cSourceWriteStream) {
if (ctx.verbose) console.log("Generating c...");
measures.generateC = -performance.now();
ctx.builder = new BuilderC(options.prime);
build(ctx);
const rdStream = ctx.builder.build();
rdStream.pipe(options.cSourceWriteStream);
measures.generateC += performance.now();
// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
}
if ((options.wasmWriteStream)||(options.watWriteStream)) {
if (ctx.verbose) console.log("Generating wasm...");
measures.generateWasm = -performance.now();
ctx.builder = new BuilderWasm(options.prime);
build(ctx);
if (options.wasmWriteStream) {
const rdStream = ctx.builder.build("wasm");
rdStream.pipe(options.wasmWriteStream);
}
if (options.watWriteStream) {
const rdStream = ctx.builder.build("wat");
rdStream.pipe(options.watWriteStream);
}
measures.generateWasm += performance.now();
// await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
}
// const mainCode = gen(ctx,ast);
if (ctx.error) throw(ctx.error);
if (options.r1csFileName) { if (options.r1csFileName) {
measures.generateR1cs = -performance.now(); measures.generateR1cs = -performance.now();
await buildR1cs(ctx, options.r1csFileName); await buildR1cs(ctx, options.r1csFileName);
measures.generateR1cs += performance.now(); measures.generateR1cs += performance.now();
} }
if (ctx.error) throw(ctx.error);
delete ctx.constraints; // Liberate memory.
if (options.cSourceFile) {
if (ctx.verbose) console.log("Generating c...");
measures.generateC = -performance.now();
ctx.builder = new BuilderC(options.prime, ctx.verbose);
build(ctx);
await ctx.builder.build(options.cSourceFile, options.dataFile);
measures.generateC += performance.now();
}
if (ctx.error) throw(ctx.error);
if ((options.wasmFile)||(options.watFile)) {
if (ctx.verbose) console.log("Generating wasm...");
measures.generateWasm = -performance.now();
ctx.builder = new BuilderWasm(options.prime);
build(ctx);
if (options.wasmFile) {
await ctx.builder.build(options.wasmFile, "wasm");
}
if (options.watFile) {
await ctx.builder.build(options.watFile, "wat");
}
measures.generateWasm += performance.now();
}
// const mainCode = gen(ctx,ast);
if (ctx.error) throw(ctx.error);
if (options.symWriteStream) { if (options.symWriteStream) {
measures.generateSyms = -performance.now(); measures.generateSyms = -performance.now();
const rdStream = buildSyms(ctx); const rdStream = buildSyms(ctx);
@@ -319,30 +318,34 @@ async function reduceConstrains(ctx) {
const c = ctx.constraints[i]; const c = ctx.constraints[i];
for (let s in c.a.coefs) { for (let s in c.a.coefs) {
if (!insertedSig[s]) { if (!insertedSig[s]) {
if (!sig2constraint[s]) sig2constraint[s] = []; if (!sig2constraint[s]) sig2constraint[s] = {};
sig2constraint[s].push(i); sig2constraint[s][i] = true;
insertedSig[s] = true; insertedSig[s] = true;
} }
} }
for (let s in c.b.coefs) { for (let s in c.b.coefs) {
if (!insertedSig[s]) { if (!insertedSig[s]) {
if (!sig2constraint[s]) sig2constraint[s] = []; if (!sig2constraint[s]) sig2constraint[s] = {};
sig2constraint[s].push(i); sig2constraint[s][i] = true;
insertedSig[s] = true; insertedSig[s] = true;
} }
} }
for (let s in c.c.coefs) { for (let s in c.c.coefs) {
if (!insertedSig[s]) { if (!insertedSig[s]) {
if (!sig2constraint[s]) sig2constraint[s] = []; if (!sig2constraint[s]) sig2constraint[s] = {};
sig2constraint[s].push(i); sig2constraint[s][i] = true;
insertedSig[s] = true; insertedSig[s] = true;
} }
} }
possibleConstraints[i] = i; possibleConstraints[i] = ctx.constraints.length - i -1;
} }
while (possibleConstraints.length >0) { while (possibleConstraints.length >0) {
if (possibleConstraints.length>1<<20) {
nextPossibleConstraints = new BigArray(); nextPossibleConstraints = new BigArray();
} else {
nextPossibleConstraints = {};
}
removedSignals = new BigArray(); removedSignals = new BigArray();
nRemoved = 0; nRemoved = 0;
lIdx = new BigArray(); lIdx = new BigArray();
@@ -379,27 +382,37 @@ async function reduceConstrains(ctx) {
const freeC = substituteRemoved(c.c); const freeC = substituteRemoved(c.c);
const isolatedSignal = getFirstInternalSignal(ctx, freeC); const isolatedSignal = getFirstInternalSignal(ctx, freeC);
if (isolatedSignal) { if (isolatedSignal) {
// console.log(isolatedSignal);
// console.log(freeC);
removedSignals[isolatedSignal] = isolateSignal(freeC, isolatedSignal); removedSignals[isolatedSignal] = isolateSignal(freeC, isolatedSignal);
if (lIdx[isolatedSignal]) { if (lIdx[isolatedSignal]) {
lIdx[isolatedSignal].forEach( (s) => { const sigs = Object.keys(lIdx[isolatedSignal]);
for (let k=0; k<sigs.length; k++) {
const s = sigs[k];
const oldLC = removedSignals[s];
removedSignals[s] = substitute(removedSignals[s], isolatedSignal, removedSignals[isolatedSignal]); removedSignals[s] = substitute(removedSignals[s], isolatedSignal, removedSignals[isolatedSignal]);
}); if (oldLC !== removedSignals[s]) addTolIdx(removedSignals[s], s);
}
} }
addTolIdx(removedSignals[isolatedSignal], isolatedSignal); addTolIdx(removedSignals[isolatedSignal], isolatedSignal);
ctx.constraints[possibleConstraints[i]] = null; ctx.constraints[possibleConstraints[i]] = null;
nRemoved ++; nRemoved ++;
sig2constraint[isolatedSignal].forEach( (s) => { delete lIdx[isolatedSignal];
nextPossibleConstraints[s] = true;
}); const cts = Object.keys(sig2constraint[isolatedSignal]);
for (let k=0; k<cts.length; k++) {
nextPossibleConstraints[cts[k]] = true;
}
} }
} }
} }
if (nextPossibleConstraints.getKeys) {
nextPossibleConstraints = nextPossibleConstraints.getKeys(); nextPossibleConstraints = nextPossibleConstraints.getKeys();
} else {
nextPossibleConstraints = Object.keys(nextPossibleConstraints);
}
for (let i=0; i<nextPossibleConstraints.length;i++) { for (let i=0; i<nextPossibleConstraints.length;i++) {
if ((ctx.verbose)&&(i%10000 == 0)) { if ((ctx.verbose)&&(i%10000 == 0)) {
@@ -409,9 +422,9 @@ async function reduceConstrains(ctx) {
const c = ctx.constraints[nextPossibleConstraints[i]]; const c = ctx.constraints[nextPossibleConstraints[i]];
if (c) { if (c) {
const nc = { const nc = {
a: substituteRemoved(c.a), a: substituteRemoved(c.a, nextPossibleConstraints[i]),
b: substituteRemoved(c.b), b: substituteRemoved(c.b, nextPossibleConstraints[i]),
c: substituteRemoved(c.c) c: substituteRemoved(c.c, nextPossibleConstraints[i])
}; };
if (ctx.lc.isZero(nc)) { if (ctx.lc.isZero(nc)) {
delete ctx.constraints[nextPossibleConstraints[i]]; delete ctx.constraints[nextPossibleConstraints[i]];
@@ -421,7 +434,7 @@ async function reduceConstrains(ctx) {
} }
} }
const removedSignalsList = removedSignals.getKeys; const removedSignalsList = removedSignals.getKeys();
for (let i=0; i<removedSignalsList.length; i++) { for (let i=0; i<removedSignalsList.length; i++) {
if ((ctx.verbose )&&(i%100000 == 0)) console.log(`removing signals: ${i}/${removedSignalsList.length}`); if ((ctx.verbose )&&(i%100000 == 0)) console.log(`removing signals: ${i}/${removedSignalsList.length}`);
@@ -435,9 +448,17 @@ async function reduceConstrains(ctx) {
lSignal.c = ctx.stDISCARDED; lSignal.c = ctx.stDISCARDED;
} }
/*
possibleConstraints = new BigArray();
// Reverse
for (let i=0; i<nextPossibleConstraints.length; i++) {
possibleConstraints[i] = nextPossibleConstraints[nextPossibleConstraints.length -1 -i];
}
*/
possibleConstraints = nextPossibleConstraints; possibleConstraints = nextPossibleConstraints;
} }
let o=0; let o=0;
for (let i=0; i<ctx.constraints.length;i++) { for (let i=0; i<ctx.constraints.length;i++) {
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`reordering constraints: ${i}/${ctx.constraints.length}`); if ((ctx.verbose)&&(i%100000 == 0)) console.log(`reordering constraints: ${i}/${ctx.constraints.length}`);
@@ -477,7 +498,7 @@ async function reduceConstrains(ctx) {
return eq; return eq;
} }
function substituteRemoved(lc) { function substituteRemoved(lc, idxConstraint) {
const newLc = ctx.lc._clone(lc); const newLc = ctx.lc._clone(lc);
for (let k in lc.coefs) { for (let k in lc.coefs) {
if (removedSignals[k]) { if (removedSignals[k]) {
@@ -492,6 +513,10 @@ async function reduceConstrains(ctx) {
newLc.coefs[k2] = newP; newLc.coefs[k2] = newP;
} }
} }
if ((typeof idxConstraint != "undefined")&&(k2!=0)) {
if (!sig2constraint[k2]) sig2constraint[k2] = {};
sig2constraint[k2][idxConstraint] = true;
}
} }
} }
} }
@@ -525,318 +550,16 @@ async function reduceConstrains(ctx) {
} }
function addTolIdx(lc, newS) { function addTolIdx(lc, newS) {
for (let s in lc.coefs) { const sigs = Object.keys(lc.coefs);
if (!lIdx[s]) lIdx[s] = []; for (let k=0; k<sigs.length; k++) {
lIdx[s].push(newS); const s = sigs[k];
if (s) {
if (!lIdx[s]) lIdx[s] = {};
lIdx[s][newS] = true;
} }
} }
}
function reduceConstrains_old(ctx) {
indexVariables();
let possibleConstraints = ctx.constraints;
let ii=0;
while (possibleConstraints.length>0) {
let nextPossibleConstraints = new BigArray();
for (let i=0; i<possibleConstraints.length; i++) {
ii++;
if ((ctx.verbose)&&(ii%10000 == 0)) console.log("reducing constraints: ", i);
if (!ctx.constraints[i]) continue;
const c = ctx.constraints[i];
// Swap a and b if b has more variables.
if (Object.keys(c.b).length > Object.keys(c.a).length) {
const aux = c.a;
c.a=c.b;
c.b=aux;
}
// Mov to C if possible.
if (isConstant(c.a)) {
const ct = {t: "N", v: c.a.coefs[sONE]};
c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
c.a = { t: "LC", coefs: {} };
c.b = { t: "LC", coefs: {} };
}
if (isConstant(c.b)) {
const ct = {t: "N", v: c.b.coefs[sONE]};
c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
c.a = { t: "LC", coefs: {} };
c.b = { t: "LC", coefs: {} };
}
if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
const isolatedSignal = getFirstInternalSignal(ctx, c.c);
if (isolatedSignal) {
let lSignal = ctx.signals[isolatedSignal];
while (lSignal.e>=0) {
lSignal = ctx.signals[lSignal.e];
}
const isolatedSignalEquivalence = {
t: "LC",
coefs: {}
};
const invCoef = ctx.F.inv(c.c.coefs[isolatedSignal]);
for (const s in c.c.coefs) {
if (s != isolatedSignal) {
const v = ctx.F.mul( ctx.F.neg(c.c.coefs[s]), invCoef);
if (!ctx.F.isZero(v)) {
isolatedSignalEquivalence.coefs[s] = v;
}
}
}
for (let j in lSignal.inConstraints) {
if ((j!=i)&&(ctx.constraints[j])) {
ctx.constraints[j] = ctx.lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
linkSignalsConstraint(j);
if (j<i) {
nextPossibleConstraints.push(j);
}
}
}
ctx.constraints[i] = null;
lSignal.c = ctx.stDISCARDED;
} else {
if (ctx.lc.isZero(c.c)) ctx.constraints[i] = null;
}
}
}
possibleConstraints = nextPossibleConstraints;
}
unindexVariables();
// Pack the constraints
let o = 0;
for (let i=0; i<ctx.constraints.length; i++) {
if (ctx.constraints[i]) {
if (o != i) {
ctx.constraints[o] = ctx.constraints[i];
}
o++;
}
}
ctx.constraints.length = o;
function indexVariables() {
for (let i=0; i<ctx.constraints.length; i++) linkSignalsConstraint(i);
}
function linkSignalsConstraint(cidx) {
const ct = ctx.constraints[cidx];
for (let k in ct.a.coefs) linkSignal(k, cidx);
for (let k in ct.b.coefs) linkSignal(k, cidx);
for (let k in ct.c.coefs) linkSignal(k, cidx);
}
function unindexVariables() {
for (let s=0; s<ctx.signals.length; s++) {
let lSignal = ctx.signals[s];
while (lSignal.e>=0) {
lSignal = ctx.signals[lSignal.e];
}
if (lSignal.inConstraints) delete lSignal.inConstraints;
}
}
/*
function unlinkSignal(signalName, cidx) {
let lSignal = ctx.signals[signalName];
while (lSignal.e>=0) {
lSignal = ctx.signals[lSignal.e];
}
if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) {
delete lSignal.inConstraints[cidx];
}
}
*/
function linkSignal(signalName, cidx) {
let lSignal = ctx.signals[signalName];
while (lSignal.e>=0) {
lSignal = ctx.signals[lSignal.e];
}
if (!lSignal.inConstraints) lSignal.inConstraints = {};
lSignal.inConstraints[cidx] = true;
}
function getFirstInternalSignal(ctx, l) {
for (let k in l.coefs) {
const signal = ctx.signals[k];
if (signal.c == ctx.stINTERNAL) return k;
}
return null;
}
function isConstant(l) {
for (let k in l.coefs) {
if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
}
if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
return true;
}
}
/*
function buildCircuitDef(ctx, mainCode) {
const res = {
mainCode: mainCode
};
res.signalName2Idx = ctx.signalName2Idx;
res.components = [];
res.componentName2Idx = {};
for (let c in ctx.components) {
const idCoponent = res.components.length;
res.components.push({
name: c,
params: ctx.components[c].params,
template: ctx.components[c].template,
inputSignals: 0
});
res.componentName2Idx[c] = idCoponent;
}
res.signals = new Array(ctx.signalNames.length);
for (let i=0; i<ctx.signalNames.length; i++) {
res.signals[i] = {
names: ctx.signalNames[i],
triggerComponents: []
};
ctx.signalNames[i].map( (fullName) => {
const idComponet = res.componentName2Idx[ctx.signals[fullName].component];
if (ctx.signals[fullName].direction == "IN") {
res.signals[i].triggerComponents.push(idComponet);
res.components[idComponet].inputSignals++;
}
});
}
res.constraints = buildConstraints(ctx);
res.templates = ctx.templates;
res.functions = {};
for (let f in ctx.functions) {
res.functions[f] = {
params: ctx.functionParams[f],
func: ctx.functions[f]
};
}
res.nPrvInputs = ctx.totals.prvInput;
res.nPubInputs = ctx.totals.pubInput;
res.nInputs = res.nPrvInputs + res.nPubInputs;
res.nOutputs = ctx.totals.output;
res.nVars = res.nInputs + res.nOutputs + ctx.totals.one + ctx.totals.internal;
res.nConstants = ctx.totals.constant;
res.nSignals = res.nVars + res.nConstants;
return res;
}
*/
/*
Build constraints
A constraint like this
[s1 + 2*s2 + 3*s3] * [ s2 + 5*s4] - [s0 ] = 0
[ 5*s2 + 6*s3] * [ s2 + ] - [s0 + 2* s2] = 0
[s1 + s3] * [ s2 + 5*s3] - [s4 ] = 0
is converted to
[
[{"1":"1","2":"2","3":"3"} , {"2":"1","4":"5"} , {"0":"1" }],
[{ "2":"5","3":"6"} , {"2":"1" } , {"0":"1", "2":"2"}],
[{"1":"1", "3":"1"} , {"2":"1","3":"5"} , {"4":"1" }]
]
^ ^ ^
| | |
A B C
*/
/*
function buildConstraints(ctx) {
const res = [];
function fillLC(dst, src) {
if (src.t != "LC") throw new Error("Constraint is not a LINEARCOMBINATION");
for (let s in src.coefs) {
const v = src.coefs[s].toString();
const id = ctx.signalName2Idx[s];
dst[id] = v;
}
}
for (let i=0; i<ctx.constraints.length; i++) {
const A = {};
const B = {};
const C = {};
fillLC(A, ctx.constraints[i].a);
fillLC(B, ctx.constraints[i].b);
fillLC(C, ctx.lc.negate(ctx.constraints[i].c));
res.push([A,B,C]);
}
return res;
}
*/
/*
function buildSyms(ctx, strm) {
let nSyms;
addSymbolsComponent(ctx.mainComponent + ".", ctx.getComponentIdx(ctx.mainComponent));
function addSymbolsComponent(prefix, idComponet) {
for (let n in ctx.components[idComponet].names.o) {
const entrie = ctx.components[idComponet].names.o[n];
addSymbolArray(prefix+n, entrie.type, entrie.sizes, entrie.offset);
}
}
function addSymbolArray(prefix, type, sizes, offset) {
if (sizes.length==0) {
if (type == "S") {
let s=offset;
while (ctx.signals[s].e >= 0) s = ctx.signals[s].e;
let wId = ctx.signals[s].id;
if (typeof(wId) == "undefined") wId=-1;
strm.write(`${offset},${wId},${prefix}\n`);
nSyms ++;
if ((ctx.verbose)&&(nSyms%10000 == 0)) console.log("Symbols saved: "+nSyms);
} else {
addSymbolsComponent(prefix+".", offset);
}
return 1;
} else {
let acc = 0;
for (let i=0; i<sizes[0]; i++) {
acc += addSymbolArray(`${prefix}[${i}]`, type, sizes.slice(1), offset + acc );
}
return acc;
}
} }
} }
*/

View File

@@ -567,14 +567,18 @@ function execFunctionCall(ctx, ast) {
return; return;
} }
if (ast.name == "assert") { if (ast.name == "assert") {
ast.fileName = ctx.fileName;
ast.filePath = ctx.filePath;
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 (ctx.F.isZero(ev)) return ctx.throwError(ast, "Assertion failed"); if ((typeof ev.v !== "undefined")&&(ctx.F.isZero(ev.v))) return ctx.throwError(ast, "Assertion failed");
return;
} }
const fnc = ctx.functions[ast.name]; const fnc = ctx.functions[ast.name];
if (!fnc) return ctx.throwError("Function not defined"); if (!fnc) return ctx.throwError(ast, "Function not defined");
const paramValues = []; const paramValues = [];
for (let i=0; i< ast.params.length; i++) { for (let i=0; i< ast.params.length; i++) {

View File

@@ -723,7 +723,15 @@ function genVarAssignment(ctx, ast, lRef, sels, rRef) {
if (instantiated) { if (instantiated) {
if (offset.used) { if (offset.used) {
ctx.codeBuilder.copyN(left.label, ["R", offset.label], ["R", right.label], right.sizes[0]); let ot;
if (offset.type == "BIGINT") {
ot = "R";
} else if (offset.type == "INT") {
ot= "RI";
} else {
assert(false);
}
ctx.codeBuilder.copyN(left.label, [ot, offset.label], ["R", right.label], right.sizes[0]);
} else { } else {
ctx.codeBuilder.copyN(left.label, ["V", offset.value[0]], ["R", right.label], right.sizes[0]); ctx.codeBuilder.copyN(left.label, ["V", offset.value[0]], ["R", right.label], right.sizes[0]);
} }
@@ -863,6 +871,12 @@ function genFunctionCall(ctx, ast) {
ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef)); ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef));
return vRef; return vRef;
} }
if (ast.name == "assert") {
const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
const vRef = gen(ctx, ast.params[0]);
ctx.codeBuilder.checkAssert(toRefA_Fr1(ctx, ast.params[0], vRef), strErr);
return vRef;
}
const params = []; const params = [];
for (let i=0; i<ast.params.length; i++) { for (let i=0; i<ast.params.length; i++) {
const pRef = gen(ctx, ast.params[i]); const pRef = gen(ctx, ast.params[i]);

View File

@@ -1,6 +1,7 @@
const fastFile = require("fastfile"); const fastFile = require("fastfile");
const assert = require("assert"); const assert = require("assert");
const BigArray = require("./bigarray");
module.exports.buildR1cs = buildR1cs; module.exports.buildR1cs = buildR1cs;
@@ -58,7 +59,7 @@ async function buildR1cs(ctx, fileName) {
if ((ctx.verbose)&&(i%10000 == 0)) { if ((ctx.verbose)&&(i%10000 == 0)) {
if (ctx.verbose) console.log("writing constraint: ", i); if (ctx.verbose) console.log("writing constraint: ", i);
} }
await writeConstraint(ctx.constraints[i]); await writeConstraint(ctx.constraints[i], i);
} }
const constraintsSize = fd.pos - pConstraintsSize - 8; const constraintsSize = fd.pos - pConstraintsSize - 8;
@@ -70,7 +71,7 @@ async function buildR1cs(ctx, fileName) {
await fd.writeULE64(0); // Temporally set to 0 length await fd.writeULE64(0); // Temporally set to 0 length
const arr = new Array(NWires); const arr = new BigArray(NWires);
for (let i=0; i<ctx.signals.length; i++) { for (let i=0; i<ctx.signals.length; i++) {
const outIdx = ctx.signals[i].id; const outIdx = ctx.signals[i].id;
if (ctx.signals[i].e>=0) continue; // If has an alias, continue.. if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
@@ -88,13 +89,13 @@ async function buildR1cs(ctx, fileName) {
const mapSize = fd.pos - pMapSize - 8; const mapSize = fd.pos - pMapSize - 8;
// Write sizes // Write sizes
await fd.writeULE32(headerSize, pHeaderSize); await fd.writeULE64(headerSize, pHeaderSize);
await fd.writeULE32(constraintsSize, pConstraintsSize); await fd.writeULE64(constraintsSize, pConstraintsSize);
await fd.writeULE32(mapSize, pMapSize); await fd.writeULE64(mapSize, pMapSize);
await fd.close(); await fd.close();
function writeConstraint(c) { function writeConstraint(c, ctIdx) {
const n8 = ctx.F.n8; const n8 = ctx.F.n8;
const idxA = Object.keys(c.a.coefs); const idxA = Object.keys(c.a.coefs);
const idxB = Object.keys(c.b.coefs); const idxB = Object.keys(c.b.coefs);
@@ -108,6 +109,7 @@ async function buildR1cs(ctx, fileName) {
const coef = idxA[i]; const coef = idxA[i];
let lSignal = ctx.signals[coef]; let lSignal = ctx.signals[coef];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e]; while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
if (lSignal.id >= NWires) throw new Error("Signal Coef A: " + coef + " Constraint: " + ctIdx + " id: " + lSignal.id);
buffV.setUint32(o, lSignal.id, true); o+=4; buffV.setUint32(o, lSignal.id, true); o+=4;
ctx.F.toRprLE(buff, o, c.a.coefs[coef]); o+=n8; ctx.F.toRprLE(buff, o, c.a.coefs[coef]); o+=n8;
} }
@@ -117,8 +119,8 @@ async function buildR1cs(ctx, fileName) {
const coef = idxB[i]; const coef = idxB[i];
let lSignal = ctx.signals[coef]; let lSignal = ctx.signals[coef];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e]; while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
if (lSignal.id >= NWires) throw new Error("Signal Coef B: " + coef + " Constraint: " + ctIdx + " id: " + lSignal.id);
buffV.setUint32(o, lSignal.id, true); o+=4; buffV.setUint32(o, lSignal.id, true); o+=4;
ctx.F.toRprLE(buff, o, c.b.coefs[coef]); o+=n8; ctx.F.toRprLE(buff, o, c.b.coefs[coef]); o+=n8;
} }
@@ -127,6 +129,7 @@ async function buildR1cs(ctx, fileName) {
const coef = idxC[i]; const coef = idxC[i];
let lSignal = ctx.signals[coef]; let lSignal = ctx.signals[coef];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e]; while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
if (lSignal.id >= NWires) throw new Error("Signal Coef C: " + coef + " Constraint: " + ctIdx + " id: " + lSignal.id);
buffV.setUint32(o, lSignal.id, true); o+=4; buffV.setUint32(o, lSignal.id, true); o+=4;
ctx.F.toRprLE(buff, o, ctx.F.neg(c.c.coefs[coef])); o+=n8; ctx.F.toRprLE(buff, o, ctx.F.neg(c.c.coefs[coef])); o+=n8;
} }

View File

@@ -1,4 +1,3 @@
const Readable = require("stream").Readable; const Readable = require("stream").Readable;
module.exports = function streamFromArrayTxt(ma) { module.exports = function streamFromArrayTxt(ma) {
@@ -22,7 +21,7 @@ module.exports = function streamFromArrayTxt(ma) {
function getFirstIdx(ma) { function getFirstIdx(ma) {
if (!Array.isArray(ma)) return []; if (typeof ma.push !== "function" ) return [];
return [0, ...getFirstIdx(ma[0])]; return [0, ...getFirstIdx(ma[0])];
} }

View File

@@ -10,6 +10,7 @@ module.exports.fnvHash = fnvHash;
module.exports.sameSizes = sameSizes; module.exports.sameSizes = sameSizes;
module.exports.isDefined = isDefined; module.exports.isDefined = isDefined;
module.exports.accSizes2Str = accSizes2Str; module.exports.accSizes2Str = accSizes2Str;
module.exports.setUint64 = setUint64;
function ident(text) { function ident(text) {
if (typeof text === "string") { if (typeof text === "string") {
@@ -90,6 +91,14 @@ function accSizes2Str(sizes) {
return `[${sizes[0]/sizes[1]}]`+accSizes2Str(sizes.slice(1)); return `[${sizes[0]/sizes[1]}]`+accSizes2Str(sizes.slice(1));
} }
function setUint64(buffV, o, n) {
const sLSB = n >>> 0;
const sMSB = (n - sLSB) / 0x100000000;
buffV.setUint32(o, sLSB , true);
buffV.setUint32(o+4, sMSB , true);
}