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");
|
|
|
|
};
|