c to cpp
@@ -87,6 +87,8 @@ options.sanityCheck = argv.sanitycheck;
if (argv.csource) { options.cSourceFile = await fastFile.createOverride(cSourceName); + const noExt = cSourceName.substr(0, cSourceName.lastIndexOf(".")) || cSourceName; + options.dataFile = await fastFile.createOverride(noExt+".dat"); } if (argv.wasm) { options.wasmFile = await fastFile.createOverride(wasmName);@@ -117,6 +119,7 @@
await compiler(fullFileName, options); if (options.cSourceFile) await options.cSourceFile.close(); + if (options.dataFile) await options.dataFile.close(); if (options.wasmFile) await options.wasmFile.close(); if (options.watFile) await options.watFile.close(); let symDone = false;
@@ -203,22 +203,12 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" }, "circom_runtime": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.0.6.tgz", - "integrity": "sha512-o0T5MuWzxnxinWG3+CygS/kZouoP+z5ZrufUwqKJy3gsVFJhkbqMpfKmcBGjhExB3uatA7cKyOiRAOLOz5+t5w==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.2.tgz", + "integrity": "sha512-qh1GsfxXLGAhLBcIQWrFHO/zu6kuXQQL1xC3+P8KRETvynTbBVSb1ul3dCiXyetm7lVNNdhb1/UoOCEZ6yu1RQ==", "requires": { - "ffjavascript": "0.1.0", + "ffjavascript": "0.2.4", "fnv-plus": "^1.3.1" - }, - "dependencies": { - "ffjavascript": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz", - "integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==", - "requires": { - "big-integer": "^1.6.48" - } - } } }, "cjson": {@@ -581,9 +571,9 @@ "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.12.tgz",
"integrity": "sha512-0EZo2y5eW8X0oiDDRvcnufjVxlM96CQL5hvmRQtbRABWlCkH73IHwkzl0qOSdxtchaMr+0TSB7GVqaVEixRr1Q==" }, "ffiasm": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/ffiasm/-/ffiasm-0.0.2.tgz", - "integrity": "sha512-o/CL7F4IodB7eRHCOQL1SrqN2DIPHrQbEwjPY7NIyeBRdnB3G0xo6b6Mj44SKiWFnvpQMb3n4N7acjD3vv4NVQ==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ffiasm/-/ffiasm-0.1.0.tgz", + "integrity": "sha512-fQI7b6oye7Yw3t28ku9XuhPSwwzKMeqB0pkIaGPrKl9s/ipV90o8J4Ge0s5F0UsH5Mu2wfr3hFQ2sGF+vQk5Sg==", "requires": { "big-integer": "^1.6.48", "ejs": "^3.0.1",
@@ -30,9 +30,9 @@ "url": "https://github.com/iden3/circom.git"
}, "dependencies": { "chai": "^4.2.0", - "circom_runtime": "0.0.6", + "circom_runtime": "0.1.2", "fastfile": "0.0.12", - "ffiasm": "0.0.2", + "ffiasm": "0.1.0", "ffjavascript": "0.2.4", "ffwasm": "0.0.7", "fnv-plus": "^1.3.1",
@@ -352,6 +352,13 @@ this.functions = [];
this.components = new BigArray(); this.usedConstants = {}; this.verbose = verbose; + + + this.sizePointers = {}; + this.hashMapPointers = {}; + this.cetPointers = {}; + this.functionIdx = {}; + this.nCets = 0; } setHeader(header) {@@ -413,8 +420,8 @@ // Body functions
_buildHeader(code) { code.push( - "#include \"circom.h\"", - "#include \"calcwit.h\"", + "#include \"circom.hpp\"", + "#include \"calcwit.hpp\"", `#define NSignals ${this.header.NSignals}`, `#define NComponents ${this.header.NComponents}`, `#define NOutputs ${this.header.NOutputs}`,@@ -425,70 +432,92 @@ ""
); } - _buildHashMaps(code) { + async _buildHashMaps(fdData) { - code.push("// Hash Maps "); + 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]; - let c = `Circom_HashEntry ${hmName}[256] = {`; for (let i=0; i<256; i++) { - c += i>0 ? "," : ""; - if (hm[i]) { - c += `{0x${hm[i][0]}LL, ${hm[i][1]}} /* ${hm[i][2]} */`; - } else { - c += "{0,0}"; - } + 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); } - c += "};"; - code.push(c); + + await fdData.write(buff); } } - _buildComponentEntriesTables(code) { - code.push("// Component Entry tables"); + 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; - code.push(`Circom_ComponentEntry ${cetName}[${cet.length}] = {`); + 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++) { - const ty = cet[j].type == "S" ? "_typeSignal" : "_typeComponent"; - code.push(` ${j>0?",":" "}{${cet[j].offset},${cet[j].sizeName}, ${ty}}`); + 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 ++; } - code.push("};"); + + await fdData.write(buff); + } } - _buildSizes(code) { - code.push("// Sizes"); + async _buildSizes(fdData) { for (let sName in this.sizes) { const accSizes = this.sizes[sName]; - let c = `Circom_Size ${sName}[${accSizes.length}] = {`; + 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++) { - if (i>0) c += ","; - c += accSizes[i]; + buffV.setUint32(i*4, accSizes[i], true); } - c += "};"; - code.push(c); + await fdData.write(buff); } } - _buildConstants(code) { + + async _buildConstants(fdData) { const self = this; - code.push("// Constants"); - code.push(`FrElement _constants[${self.constants.length}] = {`); + 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++) { - if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildConstants ${i}/${this.constants.length}`); - code.push((i>0 ? "," : " ") + "{" + number2Code(self.constants[i]) + "}"); + Fr2Bytes(buffV, o, self.constants[i]); + o += frSize; } - code.push("};"); + await fdData.write(buff); - function number2Code(n) { + + function Fr2Bytes(buffV, offset, n) { const minShort = self.F.neg(self.F.e("80000000")); const maxShort = self.F.e("7FFFFFFF", 16);@@ -496,51 +525,49 @@ if ( (self.F.geq(n, minShort))
&&(self.F.leq(n, maxShort))) { if (self.F.geq(n, self.F.zero)) { - return addShortMontgomeryPositive(n); + return shortMontgomeryPositive(n); } else { - return addShortMontgomeryNegative(n); + return shortMontgomeryNegative(n); } } - return addLongMontgomery(n); + return longMontgomery(n); - function addShortMontgomeryPositive(a) { - return `${a.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`; + function shortMontgomeryPositive(a) { + buffV.setUint32(offset, Scalar.toNumber(a) , true ); + buffV.setUint32(offset + 4, 0x40000000 , true ); + long(buffV, offset + 8, toMontgomery(a)); } - function addShortMontgomeryNegative(a) { + function shortMontgomeryNegative(a) { const b = -Scalar.toNumber(self.F.neg(a)); - return `${b.toString()}, 0x40000000, { ${getLongString(toMontgomery(a))} }`; + buffV.setUint32(offset, b , true ); + buffV.setUint32(offset + 4, 0x40000000 , true ); + long(buffV, offset + 8, toMontgomery(a)); } - function addLongMontgomery(a) { - return `0, 0xC0000000, { ${getLongString(toMontgomery(a))} }`; + function longMontgomery(a) { + buffV.setUint32(offset, 0 , true ); + buffV.setUint32(offset + 4, 0xC0000000 , true ); + long(buffV, offset + 8, toMontgomery(a)); } - function getLongString(a) { - let S = ""; + function long(buffV, offset, a) { + + let p = offset; const arr = Scalar.toArray(a, 0x100000000); - for (let i=0; i<self.F.n64*2; i+=2) { - const idx = arr.length-2-i; - - if (i>0) S = S + ","; + for (let i=0; i<self.F.n64*2; i++) { + const idx = arr.length-1-i; if ( idx >=0) { - let msb = arr[idx].toString(16); - while (msb.length<8) msb = "0" + msb; - - let lsb = arr[idx+1].toString(16); - while (lsb.length<8) lsb = "0" + lsb; - - S += "0x" + msb + lsb + "LL"; + buffV.setUint32(p, arr[idx], true); } else { - S += "0LL"; + buffV.setUint32(p, 0, true); } + p+= 4; } - - return S; } function toMontgomery(a) {@@ -548,101 +575,132 @@ 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("};"); } - _buildComponents(code) { - code.push("// Components"); - code.push(`Circom_Component _components[${this.components.length}] = {`); + + 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]; - const sep = i>0 ? " ," : " "; - code.push(`${sep}{${c.hashMapName}, ${c.entryTableName}, ${c.functionName}, ${c.nInSignals}, ${c.newThread}}`); + + 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); } - code.push("};"); } - _buildMapIsInput(code) { - code.push("// mapIsInput"); - code.push(`u32 _mapIsInput[${this.mapIsInput.length}] = {`); - let line = ""; + 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}`); - line += i>0 ? ", " : " "; - line += toHex(this.mapIsInput[i]); - if (((i+1) % 64)==0) { - code.push(" "+line); - line = ""; - } + + buffV.setUint32(4*i, this.mapIsInput[i], true); } - if (line != "") code.push(" "+line); - code.push("};"); - function toHex(number) { - if (number < 0) number = 0xFFFFFFFF + number + 1; - let S=number.toString(16).toUpperCase(); - while (S.length<8) S = "0" + S; - return "0x"+S; - } + await fdData.write(buff); } - _buildWit2Sig(code) { - code.push("// Witness to Signal Table"); - code.push(`int _wit2sig[${this.wit2sig.length}] = {`); - let line = ""; + 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}`); - line += i>0 ? "," : " "; - line += this.wit2sig[i]; - if (((i+1) % 64) == 0) { - code.push(" "+line); - line = ""; - } + + buffV.setUint32(4*i, this.wit2sig[i], true); } - if (line != "") code.push(" "+line); - code.push("};"); + + await fdData.write(buff); } - _buildCircuitVar(code) { + 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); - code.push( - "// Circuit Variable", - "Circom_Circuit _circuit = {" , - " NSignals,", - " NComponents,", - " NInputs,", - " NOutputs,", - " NVars,", - " _wit2sig,", - " _components,", - " _mapIsInput,", - " _constants,", - " __P__", - "};" - ); + 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(fd) { + 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); - this._buildSizes(code); - this._buildConstants(code); - this._buildHashMaps(code); - this._buildComponentEntriesTables(code); + await this._buildSizes(fdData); + await this._buildConstants(fdData); + await this._buildHashMaps(fdData); + await this._buildComponentEntriesTables(fdData); this._buildFunctions(code); - this._buildComponents(code); - this._buildMapIsInput(code); - this._buildWit2Sig(code); - this._buildCircuitVar(code); + await this._buildComponents(fdData); + await this._buildMapIsInput(fdData); + await this._buildWit2Sig(fdData); + await this._buildCircuitVar(fdData); await writeCode(code); async function writeCode(c) {@@ -651,7 +709,7 @@ for (let i=0; i<c.length; i++) {
await writeCode(c[i]); } } else if (typeof c === "string") { - await fd.write(encoder.encode(c + "\n")); + await fdCode.write(encoder.encode(c + "\n")); } } }
@@ -31,6 +31,7 @@ const baseName = path.basename(circomFile, ".circom");
const options = Object.assign({}, _options); options.cSourceFile = await fastFile.createOverride(path.join(dir.path, baseName + ".cpp")); + options.dataFile = await fastFile.createOverride(path.join(dir.path, baseName + ".dat")); options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym")); options.r1csFileName = path.join(dir.path, baseName + ".r1cs");@@ -38,14 +39,15 @@ options.p = options.p || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
await compiler(circomFile, options); await options.cSourceFile.close(); + await options.dataFile.close(); const source = await buildZqField(options.p, "Fr"); // console.log(dir.path); await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8"); - await fs.promises.writeFile(path.join(dir.path, "fr.h"), source.h, "utf8"); - await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "fr.hpp"), source.hpp, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "fr.cpp"), source.cpp, "utf8"); let pThread = "";@@ -66,7 +68,7 @@ await exec("g++" + ` ${pThread}` +
` ${path.join(cdir, "main.cpp")}` + ` ${path.join(cdir, "calcwit.cpp")}` + ` ${path.join(cdir, "utils.cpp")}` + - ` ${path.join(dir.path, "fr.c")}` + + ` ${path.join(dir.path, "fr.cpp")}` + ` ${path.join(dir.path, "fr.o")}` + ` ${path.join(dir.path, baseName + ".cpp")} ` + ` -o ${path.join(dir.path, baseName)}` +
@@ -134,7 +134,7 @@ if (ctx.verbose) console.log("Generating c...");
measures.generateC = -performance.now(); ctx.builder = new BuilderC(options.prime, ctx.verbose); build(ctx); - await ctx.builder.build(options.cSourceFile); + await ctx.builder.build(options.cSourceFile, options.dataFile); measures.generateC += performance.now(); }
@@ -10,6 +10,7 @@ module.exports.fnvHash = fnvHash;
module.exports.sameSizes = sameSizes; module.exports.isDefined = isDefined; module.exports.accSizes2Str = accSizes2Str; +module.exports.setUint64 = setUint64; function ident(text) { if (typeof text === "string") {@@ -89,6 +90,14 @@ function accSizes2Str(sizes) {
if (sizes.length == 2) return ""; return `[${sizes[0]/sizes[1]}]`+accSizes2Str(sizes.slice(1)); } + +function setUint64(buffV, o, n) { + const sLSB = n >>> 0; + const sMSB = (n - sLSB) / 0x100000000; + buffV.setUint32(o, sLSB , true); + buffV.setUint32(o+4, sMSB , true); +} +