diff --git a/wasm/tester.js b/wasm/tester.js new file mode 100644 index 0000000..1c0b55d --- /dev/null +++ b/wasm/tester.js @@ -0,0 +1,198 @@ +const chai = require("chai"); +const assert = chai.assert; + +const fs = require("fs"); +var tmp = require("tmp-promise"); +const path = require("path"); + +const util = require("util"); +const exec = util.promisify(require("child_process").exec); + +const loadR1cs = require("r1csfile").load; +const ZqField = require("ffjavascript").ZqField; + +module.exports = wasm_tester; + +async function wasm_tester(circomInput, _options) { + + assert(await compiler_above_version("2.0.0"),"Wrong compiler version. Must be at least 2.0.0"); + + tmp.setGracefulCleanup(); + + const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true }); + + //console.log(dir.path); + + const baseName = path.basename(circomInput, ".circom"); + const options = Object.assign({}, _options); + + options.wasm = true; + + options.sym = true; + options.json = options.json || false; // costraints in json format + options.r1cs = true; + options.output = dir.path; + + await compile(circomInput, options); + + const utils = require("./utils"); + const WitnessCalculator = require("./witness_calculator"); + + const wasm = await fs.promises.readFile(path.join(dir.path, baseName+"_js/"+ baseName + ".wasm")); + + const wc = await WitnessCalculator(wasm); + + return new WasmTester(dir, baseName, wc); +} + +async function compile (fileName, options) { + var flags = "--wasm "; + if (options.sym) flags += "--sym "; + if (options.r1cs) flags += "--r1cs "; + if (options.json) flags += "--json "; + if (options.output) flags += "--output " + options.output + " "; + console.log(circom + flags + fileName); + + await exec("circom " + flags + fileName); +} + +class WasmTester { + + constructor(dir, baseName, witnessCalculator) { + this.dir=dir; + this.baseName = baseName; + this.witnessCalculator = witnessCalculator; + } + + async release() { + await this.dir.cleanup(); + } + + async calculateWitness(input, sanityCheck) { + return await this.witnessCalculator.calculateWitness(input, sanityCheck); + } + + async loadSymbols() { + if (this.symbols) return; + this.symbols = {}; + const symsStr = await fs.promises.readFile( + path.join(this.dir.path, this.baseName + ".sym"), + "utf8" + ); + const lines = symsStr.split("\n"); + for (let i=0; i ${v}`); + } + return lines.join("\n"); + } + + async checkConstraints(witness) { + const self = this; + if (!self.constraints) await self.loadConstraints(); + for (let i=0; i v2[i]) return true; + if (v1[i] < v2[i]) return false; + } + return true; +} + +async function compiler_above_version(v) { + let output = await exec('circom --version').toString(); + let compiler_version = version_to_list(output.slice(output.search(/\d/),-1)); + vlist = version_to_list(v); + return check_versions ( compiler_version, vlist ); +} + diff --git a/wasm/utils.js b/wasm/utils.js new file mode 100755 index 0000000..8c2f261 --- /dev/null +++ b/wasm/utils.js @@ -0,0 +1,53 @@ +const fnv = require("fnv-plus"); + +module.exports.fnvHash = fnvHash; +module.exports.toArray32 = toArray32; +module.exports.fromArray32 = fromArray32; +module.exports.flatArray = flatArray; + +function toArray32(s,size) { + const res = []; //new Uint32Array(size); //has no unshift + let rem = BigInt(s); + const radix = BigInt(0x100000000); + while (rem) { + res.unshift( Number(rem % radix)); + rem = rem / radix; + } + if (size) { + var i = size - res.length; + while (i>0) { + res.unshift(0); + i--; + } + } + return res; +} + +function fromArray32(arr) { //returns a BigInt + var res = BigInt(0); + const radix = BigInt(0x100000000); + for (let i = 0; i { + const h = utils.fnvHash(k); + const hMSB = parseInt(h.slice(0,8), 16); + const hLSB = parseInt(h.slice(8,16), 16); + const fArr = utils.flatArray(input[k]); + for (let i=0; i