const assert = require("assert"); const ModuleBuilder = require("wasmbuilder").ModuleBuilder; const ModuleBuilderWat = require("wasmbuilder").ModuleBuilderWat; const buildRuntime = require("./build_runtime"); const Scalar = require("ffjavascript").Scalar; const F1Field = require("ffjavascript").F1Field; const errs = require("./errs"); function hexToBytesR(hex) { for (var bytes = [], c = hex.length-2; c >=0; c -= 2) bytes.push(parseInt(hex.substr(c, 2), 16)); return bytes; } function intToBytes32(v) { return [ v &0xFF, (v>>8) & 0xFF, (v>>16) & 0xFF, (v>>24) & 0xFF ]; } class CodeBuilderWasm { constructor(fnBuilder) { this.fnBuilder = fnBuilder; this.ops = []; } addComment(comment) { this.ops.push({op: "COMMENT", comment}); } addBlock(block) { this.ops.push({op: "BLOCK", block}); } calcOffset(dLabel, offsets) { this.ops.push({op: "CALCOFFSETS", dLabel, offsets}); } assign(dLabel, src, sOffset) { this.ops.push({op: "ASSIGN", dLabel, src, sOffset}); } getSubComponentOffset(dLabel, component, hash, hashLabel) { this.ops.push({op: "GETSUBCOMPONENTOFFSET", dLabel, component, hash, hashLabel}); } getSubComponentSizes(dLabel, component, hash, hashLabel) { this.ops.push({op: "GETSUBCOMPONENTSIZES", dLabel, component, hash, hashLabel}); } getSignalOffset(dLabel, component, hash, hashLabel) { this.ops.push({op: "GETSIGNALOFFSET", dLabel, component, hash, hashLabel}); } getSignalSizes(dLabel, component, hash, hashLabel) { this.ops.push({op: "GETSIGNALSIZES", dLabel, component, hash, hashLabel}); } setSignal(component, signal, value) { this.ops.push({op: "SETSIGNAL", component, signal, value}); } getSignal(dLabel, component, signal) { this.ops.push({op: "GETSIGNAL", dLabel, component, signal}); } copyN(dLabel, offset, src, n) { this.ops.push({op: "COPYN", dLabel, offset, src, n}); } copyNRet(src, n) { this.ops.push({op: "COPYNRET", src, n}); } fieldOp(dLabel, fOp, params) { this.ops.push({op: "FOP", dLabel, fOp, params}); } ret() { this.ops.push({op: "RET"}); } addLoop(condLabel, body) { this.ops.push({op: "LOOP", condLabel, body}); } addIf(condLabel, thenCode, elseCode) { this.ops.push({op: "IF", condLabel, thenCode, elseCode}); } fnCall(fnName, retLabel, params) { this.ops.push({op: "FNCALL", fnName, retLabel, params}); } checkConstraint(a, b, strErr) { this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr}); } concat(cb) { this.ops.push(...cb.ops); } log(val) { this.ops.push({op: "LOG", val}); } hasCode() { for (let i=0; i { if ((o[0][0] == "V") && (o[1][0]== "V")) { rN += o[0][1]*o[1][1]; return; } let f=[]; if (o[0][0] == "V") { f = c.i32_const(o[0][1]); } else if (o[0][0] == "RI") { f = c.i32_load(this.fnBuilder._getPtr(c, o[0][1])); } else if (o[0][0] == "R") { f = c.call("Fr_toInt", this.fnBuilder._getPtr(c, o[0][1])); } else { assert(false); } if (o[1][0] == "V") { if (o[1][1]==0) return; if (o[1][1]>1) { f = c.i32_mul(f, c.i32_const(o[1][1])); } } else if (o[1][0] == "RS") { f = c.i32_mul( f, c.i32_load( c.i32_add( c.i32_load(this.fnBuilder._getPtr(c, o[1][1])), c.i32_const(o[1][2]*4) ) ) ); } else { assert(false); } if (S!=null) { S = c.i32_add( S, f); } else { S = f; } }); if (rN>0) { if (S!=null) { S = c.i32_add( S, c.i32_const(rN)); } else { S = c.i32_const(rN); } } return S; } build(c) { const code = []; this.ops.forEach( (o) => { if (o.op == "COMMENT") { code.push( c.comment(o.comment) ); // DO nothing } else if (o.op == "BLOCK") { code.push( o.block.build(c) ); } else if (o.op == "CALCOFFSETS") { code.push( c.i32_store( this.fnBuilder._getPtr(c, o.dLabel), this._buildOffset(c, o.offsets) ) ); } else if (o.op == "ASSIGN") { code.push( c.i32_store( this.fnBuilder._getPtr(c, o.dLabel), c.i32_add( this.fnBuilder._deRefFr(c, o.src), c.i32_mul( this.fnBuilder._deRefInt(c, o.sOffset), c.i32_const(this.fnBuilder.builder.sizeFr) ) ) ) ); } else if (o.op == "GETSUBCOMPONENTOFFSET") { code.push( c.call( "getSubComponentOffset", this.fnBuilder._getPtr(c, o.dLabel), this.fnBuilder._deRefInt(c, o.component), c.i64_const("0x" + o.hash) ) ); } else if (o.op == "GETSUBCOMPONENTSIZES") { code.push( c.call( "getSubComponentSizes", this.fnBuilder._getPtr(c, o.dLabel), this.fnBuilder._deRefInt(c, o.component), c.i64_const("0x" + o.hash) ) ); } else if (o.op == "GETSIGNALOFFSET") { code.push( c.call( "getSignalOffset", this.fnBuilder._getPtr(c, o.dLabel), this.fnBuilder._deRefInt(c, o.component), c.i64_const("0x" + o.hash) ) ); } else if (o.op == "GETSIGNALSIZES") { code.push( c.call( "getSignalSizes", this.fnBuilder._getPtr(c, o.dLabel), this.fnBuilder._deRefInt(c, o.component), c.i64_const("0x" + o.hash) ) ); } else if (o.op == "SETSIGNAL") { code.push( c.call( "setSignal", c.getLocal("cIdx"), this.fnBuilder._deRefInt(c, o.component), this.fnBuilder._deRefInt(c, o.signal), this.fnBuilder._deRefFr(c, o.value) ) ); } else if (o.op == "GETSIGNAL") { code.push( c.call( "getSignal", c.getLocal("cIdx"), this.fnBuilder._getPtr(c, o.dLabel), this.fnBuilder._deRefInt(c, o.component), this.fnBuilder._deRefInt(c, o.signal) ) ); } else if (o.op == "COPYN") { code.push( c.call( "Fr_copyn", c.i32_add( this.fnBuilder._getPtr(c, o.dLabel), c.i32_mul( this.fnBuilder._deRefInt(c, o.offset), c.i32_const(this.fnBuilder.builder.sizeFr) ) ), this.fnBuilder._deRefFr(c, o.src), c.i32_const(o.n) ) ); } else if (o.op == "COPYNRET") { code.push( c.call( "Fr_copyn", c.getLocal("pRet"), this.fnBuilder._deRefFr(c, o.src), c.i32_const(o.n) ) ); } else if (o.op == "RET") { code.push(this.fnBuilder._freeStack(c)); code.push(c.ret([])); } else if (o.op == "FOP") { let params = []; for (let i=0; i { code.push( c.call( "Fr_copy", this._getPtr(c, o.dLabel, o.offset), this._getPtrConstant(c, o.idConstant) ) ); }); this.initializedSignalOffset.forEach( (o) => { code.push( c.call( "getSignalOffset", this._getPtr(c, o.dLabel, o.offset), this._deRefInt(c, o.component), c.i64_const("0x" + o.hash) ) ); }); this.initializedSignalSizes.forEach( (o) => { code.push( c.call( "getSignalSizes", this._getPtr(c, o.dLabel, o.offset), this._deRefInt(c, o.component), c.i64_const("0x" + o.hash) ) ); }); return code; } _buildFooter(c) { return this._freeStack(c); } newCodeBuilder() { return new CodeBuilderWasm(this); } setBody(body) { this.body = body; } build(module) { const f = module.addFunction(this.name, this.instanceDef); if (this.type=="COMPONENT") { f.addParam("cIdx", "i32"); } else if (this.type=="FUNCTION") { f.addParam("pRet", "i32"); for (let i=0;i=0) { bytes.push(...intToBytes32(arr[idx])); } else { bytes.push(...intToBytes32(0)); } } return bytes; } function toMontgomery(a) { return self.F.mul(a, self.F.R); } } } _buildFunctions(module) { for (let i=0; i