Begining of wasm

This commit is contained in:
Jordi Baylina
2020-03-09 21:16:56 +01:00
parent 6c1a3e7687
commit 8f63d18ff4
70 changed files with 4135 additions and 1353 deletions

748
ports/wasm/build_runtime.js Normal file
View File

@@ -0,0 +1,748 @@
const errs = require("./errs");
const buildWasmFf = require("fflib").buildWasmFf;
module.exports = function buildRuntime(module, builder) {
function buildInit() {
const f = module.addFunction("init");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
// Set the stack to current memory
f.addCode(
c.i32_store(
c.i32_const(4),
c.i32_shl(
c.i32_and(
c.current_memory(),
c.i32_const(0xFFFFFFF8)
),
c.i32_const(16)
)
)
);
f.addCode(
// i=0
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
// if (i==NComponents) break
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
// inputSignalsToTrigger[i] = components[i].nInputSignals
c.i32_store(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("i"),
c.i32_const(4)
)
),
c.i32_load(
c.i32_add(
c.i32_load(c.i32_const(builder.ppComponents)),
c.i32_mul(
c.getLocal("i"),
c.i32_const(builder.sizeofComponent) // Sizeof component
)
),
builder.offsetComponentNInputSignals
)
),
// i=i+1
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
);
if (builder.sanityCheck) {
f.addCode(
// i=0
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
// if (i==NSignals) break
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NSignals))),
// signalsAssigned[i] = false
c.i32_store(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("i"),
c.i32_const(4)
)
),
c.i32_const(0)
),
// i=i+1
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
);
}
f.addCode(
c.call(
"Fr_copy",
c.i32_const(builder.pSignals),
c.i32_add(
c.i32_load(c.i32_const(builder.ppConstants)),
c.i32_const(builder.addConstant(1) * builder.sizeFr)
)
)
);
if (builder.sanityCheck) {
f.addCode(
c.i32_store(
c.i32_const(builder.pSignalsAssigned),
c.i32_const(1)
)
);
}
f.addCode(
// i=0
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
// if (i==NComponents) break
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
// if (inputSignalsToTrigger[i] == 0) triggerComponent(i)
c.if(
c.i32_eqz(
c.i32_load(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("i"),
c.i32_const(4)
)
)
)
),
c.call(
"triggerComponent",
c.getLocal("i")
)
),
// i=i+1
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
);
}
function buildTriggerComponent() {
const f = module.addFunction("triggerComponent");
f.addParam("component", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.call_indirect(
c.getLocal("component"), // Idx in table
c.getLocal("component") // Parameter
)
);
}
function buildHash2ComponentEntry() {
const f = module.addFunction("hash2ComponentEntry");
f.addParam("component", "i32");
f.addParam("hash", "i64");
f.setReturnType("i32");
f.addLocal("pComponent", "i32");
f.addLocal("pHashTable", "i32");
f.addLocal("hIdx", "i32");
f.addLocal("h", "i64");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"pComponent",
c.i32_add(
c.i32_load(c.i32_const(builder.ppComponents)), // pComponents
c.i32_mul(
c.getLocal("component"),
c.i32_const(20) // sizeof(Component)
)
)
),
c.setLocal(
"pHashTable",
c.i32_load(c.getLocal("pComponent"))
),
c.setLocal(
"hIdx",
c.i32_and(
c.i32_wrap_i64(c.getLocal("hash")),
c.i32_const(0xFF)
)
),
c.block(c.loop(
c.setLocal(
"h",
c.i64_load(
c.i32_add(
c.getLocal("pHashTable"),
c.i32_mul(
c.getLocal("hIdx"),
c.i32_const(12)
)
)
)
),
c.br_if(1, c.i64_eq(c.getLocal("h"), c.getLocal("hash"))),
c.if(
c.i64_eqz(c.getLocal("h")),
c.call(
"err",
c.i32_const(errs.HASH_NOT_FOUND.code),
c.i32_const(errs.HASH_NOT_FOUND.pointer)
)
),
c.setLocal(
"hIdx",
c.i32_and(
c.i32_add(
c.getLocal("hIdx"),
c.i32_const(1)
),
c.i32_const(0xFF)
)
),
c.br(0)
)),
c.i32_add( // pComponentEntry
c.i32_load( // pComponentEntryTable
c.i32_add(
c.getLocal("pComponent"),
c.i32_const(4)
)
),
c.i32_mul(
c.i32_load( // idx to the componentEntry
c.i32_add(
c.getLocal("pHashTable"),
c.i32_mul(
c.getLocal("hIdx"),
c.i32_const(12)
)
),
8
),
c.i32_const(12)
)
)
);
}
function buildGetFromComponentEntry(fnName, offset, type) {
const f = module.addFunction(fnName);
f.addParam("pR", "i32");
f.addParam("component", "i32");
f.addParam("hash", "i64");
f.addLocal("pComponentEntry", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"pComponentEntry",
c.call(
"hash2ComponentEntry",
c.getLocal("component"),
c.getLocal("hash")
)
),
c.if( // If type is not signal
c.i32_ne(
c.i32_load(
c.getLocal("pComponentEntry"),
8 // type offset
),
c.i32_const(type)
),
c.call(
"err",
c.i32_const(errs.INVALID_TYPE.code),
c.i32_const(errs.INVALID_TYPE.pointer)
)
),
c.i32_store(
c.getLocal("pR"),
c.i32_load(
c.getLocal("pComponentEntry"),
offset
)
)
);
const f2 = module.addFunction(fnName + "32");
f2.addParam("pR", "i32");
f2.addParam("component", "i32");
f2.addParam("hashMSB", "i32");
f2.addParam("hashLSB", "i32");
const c2 = f2.getCodeBuilder();
f2.addCode(
c2.call(
fnName,
c2.getLocal("pR"),
c2.getLocal("component"),
c2.i64_or(
c2.i64_shl(
c2.i64_extend_i32_u(c2.getLocal("hashMSB")),
c2.i64_const(32)
),
c2.i64_extend_i32_u(c2.getLocal("hashLSB"))
)
)
);
}
function buildGetSignal() {
const f = module.addFunction("getSignal");
f.addParam("cIdx", "i32");
f.addParam("pR", "i32");
f.addParam("component", "i32");
f.addParam("signal", "i32");
const c = f.getCodeBuilder();
if (builder.sanityCheck) {
f.addCode(
c.if(
c.i32_eqz(
c.i32_load(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
)
),
c.call(
"err",
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer)
)
)
);
}
f.addCode(
c.call(
"Fr_copy",
c.getLocal("pR"),
c.i32_add(
c.i32_const(builder.pSignals),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(builder.sizeFr)
)
)
)
);
}
function buildSetSignal() {
const f = module.addFunction("setSignal");
f.addParam("cIdx", "i32");
f.addParam("component", "i32");
f.addParam("signal", "i32");
f.addParam("pVal", "i32");
f.addLocal("signalsToTrigger", "i32");
const c = f.getCodeBuilder();
if (builder.sanityCheck) {
f.addCode(
c.if(
c.i32_load(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
),
c.call(
"err",
c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code),
c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer)
)
),
c.i32_store(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
c.i32_const(1)
),
);
}
f.addCode(
c.call(
"Fr_copy",
c.i32_add(
c.i32_const(builder.pSignals),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(builder.sizeFr)
)
),
c.getLocal("pVal"),
)
);
f.addCode(
c.if( // If ( mapIsInput[s >> 5] & 1 << (s & 0x1f) )
c.i32_and(
c.i32_load(
c.i32_add(
c.i32_load(c.i32_const(builder.ppMapIsInput)),
c.i32_shl(
c.i32_shr_u(
c.getLocal("signal"),
c.i32_const(5)
),
c.i32_const(2)
)
)
),
c.i32_shl(
c.i32_const(1),
c.i32_and(
c.getLocal("signal"),
c.i32_const(0x1F)
)
)
),
[
...c.setLocal(
"signalsToTrigger",
c.i32_load(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("component"),
c.i32_const(4)
)
)
)
),
...c.if( // if (signalsToTrigger > 0)
c.i32_gt_u(
c.getLocal("signalsToTrigger"),
c.i32_const(0)
),
[
...c.setLocal( // signalsToTrigger--
"signalsToTrigger",
c.i32_sub(
c.getLocal("signalsToTrigger"),
c.i32_const(1)
)
),
...c.i32_store(
c.i32_add(
c.i32_const(builder.pInputSignalsToTrigger),
c.i32_mul(
c.getLocal("component"),
c.i32_const(4)
)
),
c.getLocal("signalsToTrigger"),
),
...c.if( // if (signalsToTrigger==0) triggerCompomnent(component)
c.i32_eqz(c.getLocal("signalsToTrigger")),
c.call(
"triggerComponent",
c.getLocal("component")
)
)
],
c.call(
"err2",
c.i32_const(errs.MAPISINPUT_DONT_MATCH.code),
c.i32_const(errs.MAPISINPUT_DONT_MATCH.pointer),
c.getLocal("component"),
c.getLocal("signal")
)
)
]
)
);
}
function buildComponentFinished() {
const f = module.addFunction("componentFinished");
f.addParam("cIdx", "i32");
const c = f.getCodeBuilder();
f.addCode(c.ret([]));
}
function buildCheckConstraint() {
const pTmp = module.alloc(builder.sizeFr);
const f = module.addFunction("checkConstraint");
f.addParam("cIdx", "i32");
f.addParam("pA", "i32");
f.addParam("pB", "i32");
f.addParam("pStr", "i32");
const c = f.getCodeBuilder();
if (builder.sanityCheck) {
f.addCode(
c.call(
"Fr_eq",
c.getLocal(c.i32_const(pTmp)),
c.getLocal("pA"),
c.getLocal("pB")
),
c.if (
c.eqz(
c.call(
"Fr_isTrue",
c.getLocal(c.i32_const(pTmp)),
)
),
c.call(
"err4",
c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.code),
c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.pointer),
c.getLocal("cIdx"),
c.getLocal("pA"),
c.getLocal("pB"),
c.getLocal("pStr"),
)
)
);
}
}
function buildGetNVars() {
const f = module.addFunction("getNVars");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(c.i32_const(builder.header.NVars));
}
function buildGetFrLen() {
const f = module.addFunction("getFrLen");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.i32_const(builder.sizeFr));
}
function buildGetPRawPrime() {
const f = module.addFunction("getPRawPrime");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.i32_const(module.modules["Fr_F1m"].pq));
}
function buildGetPWitness() {
const f = module.addFunction("getPWitness");
f.addParam("w", "i32");
f.addLocal("signal", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"signal",
c.i32_load( // wit2sig[w]
c.i32_add(
c.i32_load( c.i32_const(builder.ppWit2sig)),
c.i32_mul(
c.getLocal("w"),
c.i32_const(4)
)
)
)
)
);
if (builder.sanityCheck) {
f.addCode(
c.if(
c.i32_eqz(
c.i32_load(
c.i32_add(
c.i32_const(builder.pSignalsAssigned),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(4)
)
),
)
),
c.call(
"err",
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer)
)
)
);
}
f.addCode(
c.i32_add(
c.i32_const(builder.pSignals),
c.i32_mul(
c.getLocal("signal"),
c.i32_const(builder.sizeFr)
)
)
);
}
function buildFrToInt() {
const f = module.addFunction("Fr_toInt");
f.addParam("p", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.i32_load(c.getLocal("p"))
);
// TODO Handle long and montgomery.
}
const fErr = module.addIimportFunction("err", "runtime");
fErr.addParam("code", "i32");
fErr.addParam("pStr", "i32");
const fErr1 = module.addIimportFunction("err1", "runtime");
fErr1.addParam("code", "i32");
fErr1.addParam("pStr", "i32");
fErr1.addParam("param1", "i32");
const fErr2 = module.addIimportFunction("err2", "runtime");
fErr2.addParam("code", "i32");
fErr2.addParam("pStr", "i32");
fErr2.addParam("param1", "i32");
fErr2.addParam("param2", "i32");
const fErr3 = module.addIimportFunction("err3", "runtime");
fErr3.addParam("code", "i32");
fErr3.addParam("pStr", "i32");
fErr3.addParam("param1", "i32");
fErr3.addParam("param2", "i32");
fErr3.addParam("param3", "i32");
const fErr4 = module.addIimportFunction("err4", "runtime");
fErr4.addParam("code", "i32");
fErr4.addParam("pStr", "i32");
fErr4.addParam("param1", "i32");
fErr4.addParam("param2", "i32");
fErr4.addParam("param3", "i32");
fErr4.addParam("param4", "i32");
buildWasmFf(module, "Fr", builder.header.P);
builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr);
builder.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4);
if (builder.sanityCheck) {
builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4);
}
buildHash2ComponentEntry();
buildTriggerComponent();
buildInit();
buildGetFromComponentEntry("getSubComponentOffset", 0 /* offset */, builder.TYPE_COMPONENT);
buildGetFromComponentEntry("getSubComponentSizes", 4 /* offset */, builder.TYPE_COMPONENT);
buildGetFromComponentEntry("getSignalOffset", 0 /* offset */, builder.TYPE_SIGNAL);
buildGetFromComponentEntry("getSignalSizes", 4 /* offset */, builder.TYPE_SIGNAL);
buildGetSignal();
buildSetSignal();
buildComponentFinished();
buildCheckConstraint();
buildGetNVars();
buildGetFrLen();
buildGetPWitness();
buildGetPRawPrime();
buildFrToInt();
module.exportFunction("init");
module.exportFunction("getNVars");
module.exportFunction("getFrLen");
module.exportFunction("getSignalOffset32");
module.exportFunction("setSignal");
module.exportFunction("getPWitness");
module.exportFunction("Fr_toInt");
module.exportFunction("getPRawPrime");
};

1003
ports/wasm/builder.js Normal file

File diff suppressed because it is too large Load Diff

10
ports/wasm/errs.js Normal file
View File

@@ -0,0 +1,10 @@
module.exports = {
STACK_OUT_OF_MEM: {code: 1, str: "Stack out of memory"},
STACK_TOO_SMALL: {code: 2, str: "Stack too small"},
HASH_NOT_FOUND: {code: 3, str: "Hash not found"},
INVALID_TYPE: {code: 4, str: "Invalid type"},
ACCESSING_NOT_ASSIGNED_SIGNAL: {code: 5, str: "Accessing a not assigned signal"},
SIGNAL_ASSIGNED_TWICE: {code: 6, str: "Signal assigned twice"},
CONSTRAIN_DOES_NOT_MATCH: {code: 7, str: "Constraint doesn't match"},
MAPISINPUT_DONT_MATCH: {code: 8, str: "MapIsInput don't match"},
};

167
ports/wasm/tester.js Normal file
View File

@@ -0,0 +1,167 @@
const chai = require("chai");
const assert = chai.assert;
const fs = require("fs");
var tmp = require("tmp-promise");
const path = require("path");
const compiler = require("../../src/compiler");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const stringifyBigInts = require("../../src/utils").stringifyBigInts;
const unstringifyBigInts = require("../../src/utils").unstringifyBigInts;
const bigInt = require("big-integer");
const utils = require("../../src/utils");
const loadR1cs = require("../../src/r1csfile").loadR1cs;
const ZqField = require("fflib").ZqField;
const WitnessCalculator = require("./witness_calculator");
module.exports = wasm_tester;
async function wasm_tester(circomFile, _options) {
tmp.setGracefulCleanup();
const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
// console.log(dir.path);
const baseName = path.basename(circomFile, ".circom");
const options = Object.assign({}, _options);
options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm"));
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
const promisesArr = [];
promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill)));
await compiler(circomFile, options);
await Promise.all(promisesArr);
const wc = await WitnessCalculator.fromFile(path.join(dir.path, baseName + ".wasm"));
return new WasmTester(dir, baseName, wc);
}
class WasmTester {
constructor(dir, baseName, witnessCalculator) {
this.dir=dir;
this.baseName = baseName;
this.witnessCalculator = witnessCalculator;
}
async release() {
await this.dir.cleanup();
}
async calculateWitness(input) {
return await this.witnessCalculator.calculateWitness(input);
}
async loadSymbols() {
if (this.symbols) return;
this.symbols = {};
const symsStr = await fs.promises.readFile(
path.join(this.dir.path, this.baseName + ".sym"),
"utf8"
);
const lines = symsStr.split("\n");
for (let i=0; i<lines.length; i++) {
const arr = lines[i].split(",");
if (arr.length!=3) continue;
this.symbols[arr[2]] = {
idx: Number(arr[0]),
idxWit: Number(arr[1])
};
}
}
async loadConstraints() {
const self = this;
if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.field = new ZqField(r1cs.prime);
self.nWires = r1cs.nWires;
self.constraints = r1cs.constraints;
}
async assertOut(actualOut, expectedOut) {
const self = this;
if (!self.symbols) await self.loadSymbols();
checkObject("main", expectedOut);
function checkObject(prefix, eOut) {
if (Array.isArray(eOut)) {
for (let i=0; i<eOut.length; i++) {
checkObject(prefix + "["+i+"]", eOut[i]);
}
} else if ((typeof eOut == "object")&&(eOut.constructor.name == "Object")) {
for (let k in eOut) {
checkObject(prefix + "."+k, eOut[k]);
}
} else {
if (typeof self.symbols[prefix] == "undefined") {
assert(false, "Output variable not defined: "+ prefix);
}
const ba = bigInt(actualOut[self.symbols[prefix].idxWit]).toString();
const be = bigInt(eOut).toString();
assert.strictEqual(ba, be, prefix);
}
}
}
async getDecoratedOutput(witness) {
const self = this;
const lines = [];
if (!self.symbols) await self.loadSymbols();
for (let n in self.symbols) {
let v;
if (utils.isDefined(witness[self.symbols[n].idxWit])) {
v = witness[self.symbols[n].idxWit].toString();
} else {
v = "undefined";
}
lines.push(`${n} --> ${v}`);
}
return lines.join("\n");
}
async checkConstraints(witness) {
const self = this;
if (!self.constraints) await self.loadConstraints();
for (let i=0; i<self.constraints.length; i++) {
checkConstraint(self.constraints[i]);
}
function checkConstraint(constraint) {
const F = self.field;
const a = evalLC(constraint.a);
const b = evalLC(constraint.b);
const c = evalLC(constraint.c);
assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match");
}
function evalLC(lc) {
const F = self.field;
let v = F.zero;
for (let w in lc) {
v = F.add(
v,
F.mul( lc[w], witness[w] )
);
}
return v;
}
}
}

View File

@@ -0,0 +1,186 @@
/* globals WebAssembly */
const fs = require("fs");
const utils = require("../../src/utils");
const bigInt = require("big-integer");
module.exports.fromFile = async function(file) {
const code = await fs.promises.readFile(file);
return await module.exports.fromBuffer(code);
};
module.exports.fromBuffer = async function(code) {
const memory = new WebAssembly.Memory({initial:20000});
const wasmModule = await WebAssembly.compile(code);
const instance = await WebAssembly.instantiate(wasmModule, {
env: {
"memory": memory
},
runtime: {
err: function(code, pstr) {
console.log("ERROR", code, p2str(pstr));
},
err1: function(code, pstr, a) {
console.log("ERROR: ", code, p2str(pstr), a);
},
err2: function(code, pstr, a, b) {
console.log("ERROR: ", code, p2str(pstr), a, b);
},
err3: function(code, pstr, a, b, c) {
console.log("ERROR: ", code, p2str(pstr), a, b, c);
},
err4: function(code, pstr, a,b,c,d) {
console.log("ERROR: ", code, p2str(pstr), a, b, c, d);
},
}
});
return new WitnessCalculator(memory, instance);
function p2str(p) {
return "TODO"+p;
}
};
class WitnessCalculator {
constructor(memory, instance) {
this.memory = memory;
this.i32 = new Uint32Array(memory.buffer);
this.instance = instance;
this.n32 = (this.instance.exports.getFrLen() >> 2) - 2;
const pRawPrime = this.instance.exports.getPRawPrime();
this.prime = bigInt(0);
for (let i=this.n32-1; i>=0; i--) {
this.prime = this.prime.shiftLeft(32);
this.prime = this.prime.add(bigInt(this.i32[(pRawPrime >> 2) + i]));
}
this.mask32 = bigInt("FFFFFFFF", 16);
this.NVars = this.instance.exports.getNVars();
this.n64 = Math.floor((this.prime.bitLength() - 1) / 64)+1;
this.R = bigInt.one.shiftLeft(this.n64*64);
this.RInv = this.R.modInv(this.prime);
}
async calculateWitness(input) {
const w = [];
const old0 = this.i32[0];
this.instance.exports.init();
const pSigOffset = this.allocInt();
const pFr = this.allocFr();
for (let k in input) {
const h = utils.fnvHash(k);
const hMSB = parseInt(h.slice(0,8), 16);
const hLSB = parseInt(h.slice(8,16), 16);
this.instance.exports.getSignalOffset32(pSigOffset, 0, hMSB, hLSB);
const sigOffset = this.getInt(pSigOffset);
const fArr = utils.flatArray(input[k]);
for (let i=0; i<fArr.length; i++) {
this.setFr(pFr, fArr[i]);
this.instance.exports.setSignal(0, 0, sigOffset + i, pFr);
}
}
for (let i=0; i<this.NVars; i++) {
const pWitness = this.instance.exports.getPWitness(i);
w.push(this.getFr(pWitness));
}
this.i32[0] = old0;
return w;
}
allocInt() {
const p = this.i32[0];
this.i32[0] = p+8;
return p;
}
allocFr() {
const p = this.i32[0];
this.i32[0] = p+this.n32*4 + 8;
return p;
}
getInt(p) {
return this.i32[p>>2];
}
setInt(p, v) {
this.i32[p>>2] = v;
}
getFr(p) {
const idx = (p>>2);
if (this.i32[idx + 1] & 0x80000000) {
let res= bigInt(0);
for (let i=this.n32-1; i>=0; i--) {
res = res.shiftLeft(32);
res = res.add(bigInt(this.i32[idx+2+i]));
}
if (this.i32[idx + 1] & 0x40000000) {
return fromMontgomery(res);
} else {
return res;
}
} else {
if (this.i32[idx] & 0x80000000) {
return this.prime.add( bigInt(this.i32[idx]).minus(bigInt(0x100000000)) );
} else {
return bigInt(this.i32[idx]);
}
}
function fromMontgomery(n) {
return n.times(this.RInv).mod(this.prime);
}
}
setFr(p, v) {
const self = this;
v = bigInt(v);
if (v.lt(bigInt("80000000", 16)) ) {
return setShortPositive(v);
}
if (v.geq(self.prime.minus(bigInt("80000000", 16))) ) {
return setShortNegative(v);
}
return setLongNormal(v);
function setShortPositive(a) {
self.i32[(p >> 2)] = parseInt(a);
self.i32[(p >> 2) + 1] = 0;
}
function setShortNegative(a) {
const b = bigInt("80000000", 16 ).add(a.minus( self.prime.minus(bigInt("80000000", 16 ))));
self.i32[(p >> 2)] = parseInt(b);
self.i32[(p >> 2) + 1] = 0;
}
function setLongNormal(a) {
self.i32[(p >> 2)] = 0;
self.i32[(p >> 2) + 1] = 0x80000000;
for (let i=0; i<self.n32; i++) {
self.i32[(p >> 2) + 2 + i] = a.shiftRight(i*32).and(self.mask32);
}
}
}
}