|
|
const errs = require("./errs");
const buildWasmFf = require("ffwasm").buildWasmFf;
module.exports = function buildRuntime(module, builder) {
const pSanityCheck = module.alloc(4);
function buildInit() { const f = module.addFunction("init"); f.addParam("sanityCheck", "i32"); 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) ) ) );
// Save Sanity check flag
f.addCode( c.i32_store( c.i32_const(pSanityCheck), c.getLocal("sanityCheck") ) );
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) )) );
f.addCode(ifSanityCheck(c, // 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) ) ) ); f.addCode(ifSanityCheck(c, 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 ifSanityCheck(c, ...args) { return c.if( c.i32_load(c.i32_const(pSanityCheck)), [].concat(...[...args]) ); }
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( "error", c.i32_const(errs.HASH_NOT_FOUND.code), c.i32_const(errs.HASH_NOT_FOUND.pointer), c.i32_const(0), c.i32_const(0), c.i32_const(0), c.i32_const(0) ) ), 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( "error", c.i32_const(errs.INVALID_TYPE.code), c.i32_const(errs.INVALID_TYPE.pointer), c.i32_const(0), c.i32_const(0), c.i32_const(0), c.i32_const(0) ) ), 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();
f.addCode(ifSanityCheck(c, 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( "error", c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer), c.getLocal("cIdx"), c.getLocal("component"), c.getLocal("signal"), c.i32_const(0) ) ) ));
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) ) ) ) );
f.addCode(ifSanityCheck(c, c.call("logGetSignal", c.getLocal("signal"), c.getLocal("pR") ) ));
}
function buildMultiGetSignal() { const f = module.addFunction("multiGetSignal"); f.addParam("cIdx", "i32"); f.addParam("pR", "i32"); f.addParam("component", "i32"); f.addParam("signal", "i32"); f.addParam("n", "i32"); f.addLocal("i", "i32");
const c = f.getCodeBuilder();
f.addCode( c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if(1, c.i32_eq(c.getLocal("i"), c.getLocal("n"))), c.call( "getSignal", c.getLocal("cIdx"), c.i32_add( c.getLocal("pR"), c.i32_mul( c.getLocal("i"), c.i32_const(builder.sizeFr) ) ), c.getLocal("component"), c.i32_add( c.getLocal("signal"), c.getLocal("i") ) ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); }
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();
f.addCode(ifSanityCheck(c, c.call("logSetSignal", c.getLocal("signal"), c.getLocal("pVal") ), 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( "error", c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code), c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer), c.i32_const(0), c.i32_const(0), c.i32_const(0), c.i32_const(0) ) ), 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( "error", c.i32_const(errs.MAPISINPUT_DONT_MATCH.code), c.i32_const(errs.MAPISINPUT_DONT_MATCH.pointer), c.getLocal("component"), c.getLocal("signal"), c.i32_const(0), c.i32_const(0) ) ) ] ) ); }
function buildComponentFinished() { const f = module.addFunction("componentFinished"); f.addParam("cIdx", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c, c.call("logFinishComponent", c.getLocal("cIdx")) ));
f.addCode(c.ret([])); }
function buildComponentStarted() { const f = module.addFunction("componentStarted"); f.addParam("cIdx", "i32");
const c = f.getCodeBuilder();
f.addCode(ifSanityCheck(c, c.call("logStartComponent", c.getLocal("cIdx")) ));
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();
f.addCode(ifSanityCheck(c, c.call( "Fr_eq", c.i32_const(pTmp), c.getLocal("pA"), c.getLocal("pB") ), c.if ( c.i32_eqz( c.call( "Fr_isTrue", c.i32_const(pTmp), ) ), c.call( "error", 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 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() { const f = module.addFunction("getNVars"); f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(c.i32_const(builder.header.NVars)); }
function buildGetNPublic() { const f = module.addFunction("getNPublic"); f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(c.i32_const(builder.header.NPublic)); }
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( "error", c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer), c.i32_const(0), c.i32_const(0), c.i32_const(0), c.i32_const(0) ) ) ); }
f.addCode( c.i32_add( c.i32_const(builder.pSignals),
c.i32_mul( c.getLocal("signal"), c.i32_const(builder.sizeFr) ) ) ); }
function buildGetWitnessBuffer() { const f = module.addFunction("getWitnessBuffer"); f.setReturnType("i32"); f.addLocal("i", "i32"); f.addLocal("pSrc", "i32"); f.addLocal("pDst", "i32");
const c = f.getCodeBuilder();
f.addCode( 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.NVars))),
c.setLocal( "pSrc", c.call( "getPWitness", c.getLocal("i"), ) ),
c.call( "Fr_toLongNormal", c.getLocal("pSrc") ),
c.setLocal( "pDst", c.i32_add( c.i32_const(builder.pOutput), c.i32_mul( c.getLocal("i"), c.i32_const(builder.sizeFr-8) ) ) ),
c.call( "Fr_F1m_copy", c.i32_add(c.getLocal("pSrc"), c.i32_const(8)), c.getLocal("pDst") ),
// i=i+1
c.setLocal( "i", c.i32_add( c.getLocal("i"), c.i32_const(1) ) ), c.br(0) )),
c.i32_const(builder.pOutput) );
}
const fError = module.addIimportFunction("error", "runtime"); fError.addParam("code", "i32"); fError.addParam("pStr", "i32"); fError.addParam("param1", "i32"); fError.addParam("param2", "i32"); fError.addParam("param3", "i32"); fError.addParam("param4", "i32");
const fLogSetSignal = module.addIimportFunction("logSetSignal", "runtime"); fLogSetSignal.addParam("signal", "i32"); fLogSetSignal.addParam("val", "i32");
const fLogGetSignal = module.addIimportFunction("logGetSignal", "runtime"); fLogGetSignal.addParam("signal", "i32"); fLogGetSignal.addParam("val", "i32");
const fLogFinishComponent = module.addIimportFunction("logFinishComponent", "runtime"); fLogFinishComponent.addParam("cIdx", "i32");
const fLogStartComponent = module.addIimportFunction("logStartComponent", "runtime"); fLogStartComponent.addParam("cIdx", "i32");
const fLog = module.addIimportFunction("log", "runtime"); fLog.addParam("code", "i32");
buildWasmFf(module, "Fr", builder.header.P);
builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr); builder.pOutput=module.alloc(builder.header.NVars*(builder.sizeFr-8)); builder.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4); 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(); buildMultiGetSignal();
buildComponentStarted(); buildComponentFinished();
buildCheckConstraint(); buildCheckAssert();
buildGetNVars(); buildGetNPublic(); buildGetFrLen(); buildGetPWitness(); buildGetPRawPrime(); buildGetWitnessBuffer();
// buildFrToInt();
module.exportFunction("init"); module.exportFunction("getNVars"); module.exportFunction("getNPublic"); module.exportFunction("getFrLen"); module.exportFunction("getSignalOffset32"); module.exportFunction("setSignal"); module.exportFunction("multiGetSignal"); module.exportFunction("getPWitness"); module.exportFunction("Fr_toInt"); module.exportFunction("getPRawPrime"); module.exportFunction("getWitnessBuffer");
};
|