From 4b631994ca269f9dbbdf2e6723de50e700c9c038 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Thu, 13 Aug 2020 18:56:30 +0200 Subject: [PATCH] c to cpp --- cli.js | 3 + package-lock.json | 24 ++-- package.json | 4 +- ports/c/builder.js | 298 +++++++++++++++++++++++++++------------------ ports/c/tester.js | 8 +- src/compiler.js | 2 +- src/utils.js | 9 ++ 7 files changed, 205 insertions(+), 143 deletions(-) diff --git a/cli.js b/cli.js index a78e33f..4140623 100755 --- a/cli.js +++ b/cli.js @@ -87,6 +87,8 @@ async function run() { 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 @@ async function run() { 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; diff --git a/package-lock.json b/package-lock.json index 69ad616..e2b40e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -203,22 +203,12 @@ "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 @@ "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", diff --git a/package.json b/package.json index 423fdeb..3ff095c 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,9 @@ }, "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", diff --git a/ports/c/builder.js b/ports/c/builder.js index 58b10b0..10165d0 100644 --- a/ports/c/builder.js +++ b/ports/c/builder.js @@ -352,6 +352,13 @@ class BuilderC { 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 @@ class BuilderC { _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 @@ class BuilderC { ); } - _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; j0?",":" "}{${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; i0) 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; i0 ? "," : " ") + "{" + 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 @@ class BuilderC { &&(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 = ""; - const arr = Scalar.toArray(a, 0x100000000); - for (let i=0; i0) S = S + ","; + let p = offset; + const arr = Scalar.toArray(a, 0x100000000); + for (let i=0; i=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 @@ class BuilderC { } } + } _buildFunctions(code) { + const listedFunctions = []; for (let i=0; i0 ? " ," : " "; + 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; i0 ? " ," : " "; - 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; i0 ? ", " : " "; - line += toHex(this.mapIsInput[i]); - if (((i+1) % 64)==0) { - code.push(" "+line); - line = ""; - } - } - 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; + buffV.setUint32(4*i, this.mapIsInput[i], true); } + + 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; i0 ? "," : " "; - 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) { - code.push( - "// Circuit Variable", - "Circom_Circuit _circuit = {" , - " NSignals,", - " NComponents,", - " NInputs,", - " NOutputs,", - " NVars,", - " _wit2sig,", - " _components,", - " _mapIsInput,", - " _constants,", - " __P__", - "};" - ); + 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(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 @@ class BuilderC { await writeCode(c[i]); } } else if (typeof c === "string") { - await fd.write(encoder.encode(c + "\n")); + await fdCode.write(encoder.encode(c + "\n")); } } } diff --git a/ports/c/tester.js b/ports/c/tester.js index 079aece..5a8fa0e 100644 --- a/ports/c/tester.js +++ b/ports/c/tester.js @@ -31,6 +31,7 @@ async function c_tester(circomFile, _options) { 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 @@ async function c_tester(circomFile, _options) { 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 @@ async function c_tester(circomFile, _options) { ` ${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)}` + diff --git a/src/compiler.js b/src/compiler.js index 5e70f91..b1a8a00 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -134,7 +134,7 @@ async function compile(srcFile, options) { 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(); } diff --git a/src/utils.js b/src/utils.js index f61a6c2..4f16c10 100644 --- a/src/utils.js +++ b/src/utils.js @@ -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") { @@ -90,6 +91,14 @@ function accSizes2Str(sizes) { 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); +} + +