const utils = require("../../src/utils");
|
|
const assert = require("assert");
|
|
const Scalar = require("ffjavascript").Scalar;
|
|
const F1Field = require("ffjavascript").F1Field;
|
|
const BigArray = require("../../src/bigarray");
|
|
|
|
function ref2src(c) {
|
|
if ((c[0] == "R")||(c[0] == "RI")) {
|
|
return c[1];
|
|
} else if (c[0] == "V") {
|
|
return c[1].toString();
|
|
} else if (c[0] == "C") {
|
|
return `(ctx->circuit->constants + ${c[1]})`;
|
|
} else if (c[0] == "CC") {
|
|
return "__cIdx";
|
|
} else {
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
class CodeBuilderC {
|
|
constructor() {
|
|
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});
|
|
}
|
|
|
|
log(val) {
|
|
this.ops.push({op: "LOG", val});
|
|
}
|
|
|
|
concat(cb) {
|
|
this.ops.push(...cb.ops);
|
|
}
|
|
|
|
hasCode() {
|
|
for (let i=0; i<this.ops.length; i++) {
|
|
if (this.ops[i].op != "COMMENT") return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
_buildOffset(offsets) {
|
|
let rN=0;
|
|
let S = "";
|
|
offsets.forEach((o) => {
|
|
if ((o[0][0] == "V") && (o[1][0]== "V")) {
|
|
rN += o[0][1]*o[1][1];
|
|
return;
|
|
}
|
|
let f="";
|
|
if (o[0][0] == "V") {
|
|
if (o[0][1]==0) return;
|
|
f += o[0][1];
|
|
} else if (o[0][0] == "RI") {
|
|
if (o[0][1]==0) return;
|
|
f += o[0][1];
|
|
} else if (o[0][0] == "R") {
|
|
f += `Fr_toInt(${o[0][1]})`;
|
|
} else {
|
|
assert(false);
|
|
}
|
|
if (o[1][0] == "V") {
|
|
if (o[1][1]==0) return;
|
|
if (o[1][1]>1) {
|
|
f += "*" + o[1][1];
|
|
}
|
|
} else if (o[1][0] == "RS") {
|
|
f += `*${o[1][1]}[${o[1][2]}]`;
|
|
} else {
|
|
assert(false);
|
|
}
|
|
if (S!="") S+= " + ";
|
|
S += f;
|
|
});
|
|
if (rN>0) {
|
|
S = `${rN} + ${S}`;
|
|
}
|
|
return S;
|
|
}
|
|
|
|
build(code) {
|
|
this.ops.forEach( (o) => {
|
|
if (o.op == "COMMENT") {
|
|
code.push(`/* ${o.comment} */`);
|
|
} else if (o.op == "BLOCK") {
|
|
const codeBlock=[];
|
|
o.block.build(codeBlock);
|
|
code.push(utils.ident(codeBlock));
|
|
} else if (o.op == "CALCOFFSETS") {
|
|
code.push(`${o.dLabel} = ${this._buildOffset(o.offsets)};`);
|
|
} else if (o.op == "ASSIGN") {
|
|
const oS = ref2src(o.sOffset);
|
|
if (oS != "0") {
|
|
code.push(`${o.dLabel} = ${ref2src(o.src)} + ${oS};`);
|
|
} else {
|
|
code.push(`${o.dLabel} = ${ref2src(o.src)};`);
|
|
}
|
|
} else if (o.op == "GETSUBCOMPONENTOFFSET") {
|
|
code.push(`${o.dLabel} = ctx->getSubComponentOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
|
} else if (o.op == "GETSUBCOMPONENTSIZES") {
|
|
code.push(`${o.dLabel} = ctx->getSubComponentSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
|
} else if (o.op == "GETSIGNALOFFSET") {
|
|
code.push(`${o.dLabel} = ctx->getSignalOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
|
} else if (o.op == "GETSIGNALSIZES") {
|
|
code.push(`${o.dLabel} = ctx->getSignalSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
|
} else if (o.op == "SETSIGNAL") {
|
|
code.push(`ctx->setSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${ref2src(o.value)});`);
|
|
} else if (o.op == "GETSIGNAL") {
|
|
code.push(`ctx->getSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${o.dLabel});`);
|
|
} else if (o.op == "COPYN") {
|
|
const oS = ref2src(o.offset);
|
|
const dLabel = (oS != "0") ? (o.dLabel + "+" + oS) : o.dLabel;
|
|
code.push(`Fr_copyn(${dLabel}, ${ref2src(o.src)}, ${o.n});`);
|
|
} else if (o.op == "COPYNRET") {
|
|
code.push(`Fr_copyn(__retValue, ${ref2src(o.src)}, ${o.n});`);
|
|
} else if (o.op == "RET") {
|
|
code.push("goto returnFunc;");
|
|
} else if (o.op == "FOP") {
|
|
let paramsS = "";
|
|
for (let i=0; i<o.params.length; i++) {
|
|
if (i>0) paramsS += ", ";
|
|
paramsS += ref2src(o.params[i]);
|
|
}
|
|
code.push(`Fr_${o.fOp}(${o.dLabel}, ${paramsS});`);
|
|
} else if (o.op == "LOOP") {
|
|
code.push(`while (Fr_isTrue(${o.condLabel})) {`);
|
|
const body = [];
|
|
o.body.build(body);
|
|
code.push(utils.ident(body));
|
|
code.push("}");
|
|
} else if (o.op == "IF") {
|
|
code.push(`if (Fr_isTrue(${o.condLabel})) {`);
|
|
const thenCode = [];
|
|
o.thenCode.build(thenCode);
|
|
code.push(utils.ident(thenCode));
|
|
if (o.elseCode) {
|
|
code.push("} else {");
|
|
const elseCode = [];
|
|
o.elseCode.build(elseCode);
|
|
code.push(utils.ident(elseCode));
|
|
}
|
|
code.push("}");
|
|
} else if (o.op == "FNCALL") {
|
|
code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`);
|
|
} else if (o.op == "CHECKCONSTRAINT") {
|
|
code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`);
|
|
} else if (o.op == "LOG") {
|
|
code.push(`ctx->log(${ref2src(o.val)});`);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
class FunctionBuilderC {
|
|
|
|
constructor(name, instanceDef, type) {
|
|
this.name = name;
|
|
this.instanceDef = instanceDef;
|
|
this.type = type; // "COMPONENT" or "FUNCTIOM"
|
|
this.definedFrElements = [];
|
|
this.definedIntElements = [];
|
|
this.definedSizeElements = [];
|
|
this.definedPFrElements = [];
|
|
this.initializedElements = [];
|
|
this.initializedSignalOffset = [];
|
|
this.initializedSignalSizes = [];
|
|
|
|
}
|
|
|
|
defineFrElements(dLabel, size) {
|
|
this.definedFrElements.push({dLabel, size});
|
|
}
|
|
|
|
defineIntElement(dLabel) {
|
|
this.definedIntElements.push({dLabel});
|
|
}
|
|
|
|
defineSizesElement(dLabel) {
|
|
this.definedSizeElements.push({dLabel});
|
|
}
|
|
|
|
definePFrElement(dLabel) {
|
|
this.definedPFrElements.push({dLabel});
|
|
}
|
|
|
|
initializeFrElement(dLabel, offset, idConstant) {
|
|
this.initializedElements.push({dLabel, offset, idConstant});
|
|
}
|
|
|
|
initializeSignalOffset(dLabel, component, hash, hashLabel) {
|
|
this.initializedSignalOffset.push({dLabel, component, hash, hashLabel});
|
|
}
|
|
|
|
initializeSignalSizes(dLabel, component, hash, hashLabel) {
|
|
this.initializedSignalSizes.push({dLabel, component, hash, hashLabel});
|
|
}
|
|
|
|
setParams(params) {
|
|
this.params = params;
|
|
}
|
|
|
|
_buildHeader(code) {
|
|
this.definedFrElements.forEach( (o) => {
|
|
code.push(`FrElement ${o.dLabel}[${o.size}];`);
|
|
});
|
|
this.definedIntElements.forEach( (o) => {
|
|
code.push(`int ${o.dLabel};`);
|
|
});
|
|
this.definedSizeElements.forEach( (o) => {
|
|
code.push(`Circom_Sizes ${o.dLabel};`);
|
|
});
|
|
this.definedPFrElements.forEach( (o) => {
|
|
code.push(`PFrElement ${o.dLabel};`);
|
|
});
|
|
this.initializedElements.forEach( (o) => {
|
|
code.push(`Fr_copy(&(${o.dLabel}[${o.offset}]), ctx->circuit->constants +${o.idConstant});`);
|
|
});
|
|
this.initializedSignalOffset.forEach( (o) => {
|
|
code.push(`${o.dLabel} = ctx->getSignalOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
|
});
|
|
this.initializedSignalSizes.forEach( (o) => {
|
|
code.push(`${o.dLabel} = ctx->getSignalSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
|
|
});
|
|
}
|
|
|
|
_buildFooter(code) {
|
|
}
|
|
|
|
newCodeBuilder() {
|
|
return new CodeBuilderC();
|
|
}
|
|
|
|
setBody(body) {
|
|
this.body = body;
|
|
}
|
|
|
|
build(code) {
|
|
code.push(
|
|
"/*",
|
|
this.instanceDef,
|
|
"*/"
|
|
);
|
|
|
|
if (this.type=="COMPONENT") {
|
|
code.push(`void ${this.name}(Circom_CalcWit *ctx, int __cIdx) {`);
|
|
} else if (this.type=="FUNCTION") {
|
|
let sParams = "";
|
|
for (let i=0;i<this.params.length;i++ ) sParams += `, PFrElement ${this.params[i]}`;
|
|
code.push(`void ${this.name}(Circom_CalcWit *ctx, PFrElement __retValue ${sParams}) {`);
|
|
} else {
|
|
assert(false);
|
|
}
|
|
|
|
const fnCode = [];
|
|
this._buildHeader(fnCode);
|
|
this.body.build(fnCode);
|
|
if (this.type=="COMPONENT") {
|
|
fnCode.push("ctx->finished(__cIdx);");
|
|
} else if (this.type=="FUNCTION") {
|
|
fnCode.push("returnFunc: ;");
|
|
} else {
|
|
assert(false);
|
|
}
|
|
this._buildFooter(fnCode);
|
|
|
|
code.push(utils.ident(fnCode));
|
|
code.push("}");
|
|
}
|
|
|
|
}
|
|
|
|
class BuilderC {
|
|
constructor(p, verbose) {
|
|
this.F = new F1Field(p);
|
|
|
|
this.hashMaps={};
|
|
this.componentEntriesTables=new BigArray();
|
|
this.sizes ={};
|
|
this.constants = [];
|
|
this.functions = [];
|
|
this.components = new BigArray();
|
|
this.usedConstants = {};
|
|
this.verbose = verbose;
|
|
|
|
|
|
this.sizePointers = {};
|
|
this.hashMapPointers = {};
|
|
this.cetPointers = {};
|
|
this.functionIdx = {};
|
|
this.nCets = 0;
|
|
}
|
|
|
|
setHeader(header) {
|
|
this.header=header;
|
|
}
|
|
|
|
// ht is an array of 256 element that can be undefined or [Hash, Idx, KeyName] elements.
|
|
addHashMap(name, hm) {
|
|
this.hashMaps[name] = hm;
|
|
}
|
|
|
|
addComponentEntriesTable(name, cet) {
|
|
this.componentEntriesTables.push({
|
|
name: name,
|
|
cet: cet
|
|
});
|
|
}
|
|
|
|
addSizes(name, accSizes) {
|
|
this.sizes[name] = accSizes;
|
|
}
|
|
|
|
addConstant(c) {
|
|
c = this.F.e(c);
|
|
const cS = c.toString();
|
|
if (typeof this.usedConstants[cS] != "undefined") return this.usedConstants[cS];
|
|
this.constants.push(c);
|
|
this.usedConstants[cS] = this.constants.length - 1;
|
|
return this.constants.length - 1;
|
|
}
|
|
|
|
addFunction(fnBuilder) {
|
|
this.functions.push(fnBuilder);
|
|
}
|
|
|
|
addComponent(component) {
|
|
this.components.push(component);
|
|
}
|
|
|
|
setMapIsInput(map) {
|
|
this.mapIsInput = map;
|
|
}
|
|
|
|
setWit2Sig(wit2sig) {
|
|
this.wit2sig = wit2sig;
|
|
}
|
|
|
|
|
|
newComponentFunctionBuilder(name, instanceDef) {
|
|
return new FunctionBuilderC(name, instanceDef, "COMPONENT");
|
|
}
|
|
|
|
newFunctionBuilder(name, instanceDef) {
|
|
return new FunctionBuilderC(name, instanceDef, "FUNCTION");
|
|
}
|
|
|
|
|
|
// Body functions
|
|
|
|
_buildHeader(code) {
|
|
code.push(
|
|
"#include \"circom.hpp\"",
|
|
"#include \"calcwit.hpp\"",
|
|
`#define NSignals ${this.header.NSignals}`,
|
|
`#define NComponents ${this.header.NComponents}`,
|
|
`#define NOutputs ${this.header.NOutputs}`,
|
|
`#define NInputs ${this.header.NInputs}`,
|
|
`#define NVars ${this.header.NVars}`,
|
|
`#define __P__ "${this.header.P.toString()}"`,
|
|
""
|
|
);
|
|
}
|
|
|
|
async _buildHashMaps(fdData) {
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.pHashMaps = fdData.pos;
|
|
|
|
const buff = new Uint8Array(256*12);
|
|
const buffV = new DataView(buff.buffer);
|
|
for (let hmName in this.hashMaps ) {
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.hashMapPointers[hmName] = fdData.pos;
|
|
const hm = this.hashMaps[hmName];
|
|
|
|
for (let i=0; i<256; i++) {
|
|
buffV.setUint32(i*12, hm[i] ? parseInt( hm[i][0].slice(8), 16 ) : 0, true);
|
|
buffV.setUint32(i*12+4, hm[i] ? parseInt( hm[i][0].slice(0,8), 16 ) : 0, true);
|
|
buffV.setUint32(i*12+8, hm[i] ? hm[i][1] : 0, true);
|
|
}
|
|
|
|
await fdData.write(buff);
|
|
}
|
|
|
|
}
|
|
|
|
async _buildComponentEntriesTables(fdData) {
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.pCets = fdData.pos;
|
|
for (let i=0; i< this.componentEntriesTables.length; i++) {
|
|
if ((this.verbose)&&(i%100000 ==0)) console.log(`_buildComponentEntriesTables ${i}/${this.componentEntriesTables.length}`);
|
|
const cetName = this.componentEntriesTables[i].name;
|
|
const cet = this.componentEntriesTables[i].cet;
|
|
|
|
this.cetPointers[cetName] = fdData.pos;
|
|
const buff = new Uint8Array(16*cet.length);
|
|
const buffV = new DataView(buff.buffer);
|
|
|
|
for (let j=0; j<cet.length; j++) {
|
|
utils.setUint64(buffV, 16*j+0, this.sizePointers[ cet[j].sizeName]);
|
|
buffV.setUint32(16*j+8, cet[j].offset, true);
|
|
buffV.setUint32(16*j+12, cet[j].type == "S" ? 0 : 1, true); // Size type 0-> Signal, 1->Component
|
|
this.nCets ++;
|
|
}
|
|
|
|
await fdData.write(buff);
|
|
|
|
}
|
|
}
|
|
|
|
async _buildSizes(fdData) {
|
|
for (let sName in this.sizes) {
|
|
const accSizes = this.sizes[sName];
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.sizePointers[sName] = fdData.pos;
|
|
|
|
const buff = new Uint8Array(4*accSizes.length);
|
|
const buffV = new DataView(buff.buffer);
|
|
for (let i=0; i<accSizes.length; i++) {
|
|
buffV.setUint32(i*4, accSizes[i], true);
|
|
}
|
|
await fdData.write(buff);
|
|
}
|
|
}
|
|
|
|
|
|
async _buildConstants(fdData) {
|
|
const self = this;
|
|
|
|
const frSize = (8 + self.F.n64*8);
|
|
const buff = new Uint8Array(self.constants.length* frSize);
|
|
const buffV = new DataView(buff.buffer);
|
|
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.pConstants = fdData.pos;
|
|
|
|
let o = 0;
|
|
for (let i=0; i<self.constants.length; i++) {
|
|
Fr2Bytes(buffV, o, self.constants[i]);
|
|
o += frSize;
|
|
}
|
|
await fdData.write(buff);
|
|
|
|
|
|
function Fr2Bytes(buffV, offset, n) {
|
|
const minShort = self.F.neg(self.F.e("80000000"));
|
|
const maxShort = self.F.e("7FFFFFFF", 16);
|
|
|
|
if ( (self.F.geq(n, minShort))
|
|
&&(self.F.leq(n, maxShort)))
|
|
{
|
|
if (self.F.geq(n, self.F.zero)) {
|
|
return shortMontgomeryPositive(n);
|
|
} else {
|
|
return shortMontgomeryNegative(n);
|
|
}
|
|
}
|
|
|
|
return longMontgomery(n);
|
|
|
|
|
|
function shortMontgomeryPositive(a) {
|
|
buffV.setUint32(offset, Scalar.toNumber(a) , true );
|
|
buffV.setUint32(offset + 4, 0x40000000 , true );
|
|
long(buffV, offset + 8, toMontgomery(a));
|
|
}
|
|
|
|
|
|
function shortMontgomeryNegative(a) {
|
|
const b = -Scalar.toNumber(self.F.neg(a));
|
|
buffV.setUint32(offset, b , true );
|
|
buffV.setUint32(offset + 4, 0x40000000 , true );
|
|
long(buffV, offset + 8, toMontgomery(a));
|
|
}
|
|
|
|
function longMontgomery(a) {
|
|
buffV.setUint32(offset, 0 , true );
|
|
buffV.setUint32(offset + 4, 0xC0000000 , true );
|
|
long(buffV, offset + 8, toMontgomery(a));
|
|
}
|
|
|
|
function long(buffV, offset, a) {
|
|
|
|
let p = offset;
|
|
const arr = Scalar.toArray(a, 0x100000000);
|
|
for (let i=0; i<self.F.n64*2; i++) {
|
|
const idx = arr.length-1-i;
|
|
|
|
if ( idx >=0) {
|
|
buffV.setUint32(p, arr[idx], true);
|
|
} else {
|
|
buffV.setUint32(p, 0, true);
|
|
}
|
|
p+= 4;
|
|
}
|
|
}
|
|
|
|
function toMontgomery(a) {
|
|
return self.F.mul(a, self.F.R);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_buildFunctions(code) {
|
|
const listedFunctions = [];
|
|
for (let i=0; i<this.functions.length; i++) {
|
|
const cfb = this.functions[i];
|
|
cfb.build(code);
|
|
if (this.functions[i].type == "COMPONENT") {
|
|
this.functionIdx[this.functions[i].name] = listedFunctions.length;
|
|
listedFunctions.push(i);
|
|
}
|
|
}
|
|
|
|
code.push("// Function Table");
|
|
code.push(`Circom_ComponentFunction _functionTable[${listedFunctions.length}] = {`);
|
|
for (let i=0; i<listedFunctions.length; i++) {
|
|
const sep = i>0 ? " ," : " ";
|
|
code.push(`${sep}${this.functions[listedFunctions[i]].name}`);
|
|
}
|
|
code.push("};");
|
|
}
|
|
|
|
|
|
async _buildComponents(fdData) {
|
|
|
|
const buff = new Uint8Array(32);
|
|
const buffV = new DataView(buff.buffer);
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.pComponents = fdData.pos;
|
|
|
|
for (let i=0; i<this.components.length; i++) {
|
|
if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildComponents ${i}/${this.components.length}`);
|
|
const c = this.components[i];
|
|
|
|
utils.setUint64(buffV, 0, this.hashMapPointers[c.hashMapName], true);
|
|
utils.setUint64(buffV, 8, this.cetPointers[c.entryTableName], true);
|
|
utils.setUint64(buffV, 16, this.functionIdx[c.functionName], true);
|
|
buffV.setUint32(24, c.nInSignals, true);
|
|
buffV.setUint32(28, c.newThread ? 1 : 0, true);
|
|
|
|
await fdData.write(buff);
|
|
}
|
|
}
|
|
|
|
async _buildMapIsInput(fdData) {
|
|
|
|
const buff = new Uint8Array(this.mapIsInput.length * 4);
|
|
const buffV = new DataView(buff.buffer);
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.pMapIsInput = fdData.pos;
|
|
|
|
for (let i=0; i<this.mapIsInput.length; i++) {
|
|
if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildMapIsInput ${i}/${this.mapIsInput.length}`);
|
|
|
|
buffV.setUint32(4*i, this.mapIsInput[i], true);
|
|
}
|
|
|
|
await fdData.write(buff);
|
|
}
|
|
|
|
async _buildWit2Sig(fdData) {
|
|
|
|
const buff = new Uint8Array(this.wit2sig.length * 4);
|
|
const buffV = new DataView(buff.buffer);
|
|
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
this.pWit2Sig = fdData.pos;
|
|
|
|
for (let i=0; i<this.wit2sig.length; i++) {
|
|
if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildWit2Sig ${i}/${this.wit2sig.length}`);
|
|
|
|
buffV.setUint32(4*i, this.wit2sig[i], true);
|
|
}
|
|
|
|
await fdData.write(buff);
|
|
}
|
|
|
|
async _buildCircuitVar(fdData) {
|
|
|
|
const pP = fdData.pos;
|
|
|
|
const strBuff = new TextEncoder("utf-8").encode(this.header.P.toString());
|
|
await fdData.write(strBuff);
|
|
|
|
const buff = new Uint8Array(72);
|
|
const buffV = new DataView(buff.buffer);
|
|
|
|
utils.setUint64(buffV, 0, this.pWit2Sig, true);
|
|
utils.setUint64(buffV, 8, this.pComponents, true);
|
|
utils.setUint64(buffV, 16, this.pMapIsInput, true);
|
|
utils.setUint64(buffV, 24, this.pConstants, true);
|
|
utils.setUint64(buffV, 32, pP, true);
|
|
utils.setUint64(buffV, 40, this.pCets, true);
|
|
|
|
buffV.setUint32(48, this.header.NSignals, true);
|
|
buffV.setUint32(52, this.header.NComponents, true);
|
|
buffV.setUint32(56, this.header.NOutputs, true);
|
|
buffV.setUint32(60, this.header.NInputs, true);
|
|
buffV.setUint32(64, this.header.NVars, true);
|
|
buffV.setUint32(68, this.nCets, true);
|
|
|
|
fdData.pos = 0;
|
|
|
|
await fdData.write(buff);
|
|
}
|
|
|
|
|
|
async build(fdCode, fdData) {
|
|
const encoder = new TextEncoder("utf-8");
|
|
fdData.pos = 72;
|
|
while (fdData.pos % 8) fdData.pos++;
|
|
|
|
const code=new BigArray();
|
|
this._buildHeader(code);
|
|
await this._buildSizes(fdData);
|
|
await this._buildConstants(fdData);
|
|
await this._buildHashMaps(fdData);
|
|
await this._buildComponentEntriesTables(fdData);
|
|
this._buildFunctions(code);
|
|
await this._buildComponents(fdData);
|
|
await this._buildMapIsInput(fdData);
|
|
await this._buildWit2Sig(fdData);
|
|
await this._buildCircuitVar(fdData);
|
|
await writeCode(code);
|
|
|
|
async function writeCode(c) {
|
|
if (c.push) {
|
|
for (let i=0; i<c.length; i++) {
|
|
await writeCode(c[i]);
|
|
}
|
|
} else if (typeof c === "string") {
|
|
await fdCode.write(encoder.encode(c + "\n"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
module.exports = BuilderC;
|