diff --git a/package-lock.json b/package-lock.json index bd4285d..35c7487 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "ejs": "3.1.10", - "snarkjs": "0.7.3" + "snarkjs": "0.7.5" }, "devDependencies": { "@nomicfoundation/hardhat-ethers": "3.0.5", @@ -788,12 +788,12 @@ "integrity": "sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==" }, "node_modules/@iden3/binfileutils": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.11.tgz", - "integrity": "sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.12.tgz", + "integrity": "sha512-naAmzuDufRIcoNfQ1d99d7hGHufLA3wZSibtr4dMe6ZeiOPV1KwOZWTJ1YVz4HbaWlpDuzVU72dS4ATQS4PXBQ==", "dependencies": { "fastfile": "0.0.20", - "ffjavascript": "^0.2.48" + "ffjavascript": "^0.3.0" } }, "node_modules/@istanbuljs/load-nyc-config": { @@ -2268,26 +2268,16 @@ } }, "node_modules/circom_runtime": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.24.tgz", - "integrity": "sha512-H7/7I2J/cBmRnZm9docOCGhfxzS61BEm4TMCWcrZGsWNBQhePNfQq88Oj2XpUfzmBTCd8pRvRb3Mvazt3TMrJw==", + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.28.tgz", + "integrity": "sha512-ACagpQ7zBRLKDl5xRZ4KpmYIcZDUjOiNRuxvXLqhnnlLSVY1Dbvh73TI853nqoR0oEbihtWmMSjgc5f+pXf/jQ==", "dependencies": { - "ffjavascript": "0.2.60" + "ffjavascript": "0.3.1" }, "bin": { "calcwit": "calcwit.js" } }, - "node_modules/circom_runtime/node_modules/ffjavascript": { - "version": "0.2.60", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.60.tgz", - "integrity": "sha512-T/9bnEL5xAZRDbQoEMf+pM9nrhK+C3JyZNmqiWub26EQorW7Jt+jR54gpqDhceA4Nj0YctPQwYnl8xa52/A26A==", - "dependencies": { - "wasmbuilder": "0.0.16", - "wasmcurves": "0.2.2", - "web-worker": "^1.2.0" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2815,9 +2805,9 @@ "integrity": "sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==" }, "node_modules/ffjavascript": { - "version": "0.2.63", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.63.tgz", - "integrity": "sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.1.tgz", + "integrity": "sha512-4PbK1WYodQtuF47D4pRI5KUg3Q392vuP5WjE1THSnceHdXwU3ijaoS0OqxTzLknCtz4Z2TtABzkBdBdMn3B/Aw==", "dependencies": { "wasmbuilder": "0.0.16", "wasmcurves": "0.2.2", @@ -4807,24 +4797,24 @@ } }, "node_modules/r1csfile": { - "version": "0.0.47", - "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.47.tgz", - "integrity": "sha512-oI4mAwuh1WwuFg95eJDNDDL8hCaZkwnPuNZrQdLBWvDoRU7EG+L/MOHL7SwPW2Y+ZuYcTLpj3rBkgllBQZN/JA==", + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.48.tgz", + "integrity": "sha512-kHRkKUJNaor31l05f2+RFzvcH5XSa7OfEfd/l4hzjte6NL6fjRkSMfZ4BjySW9wmfdwPOtq3mXurzPvPGEf5Tw==", "dependencies": { "@iden3/bigarray": "0.0.2", - "@iden3/binfileutils": "0.0.11", + "@iden3/binfileutils": "0.0.12", "fastfile": "0.0.20", - "ffjavascript": "0.2.60" + "ffjavascript": "0.3.0" } }, "node_modules/r1csfile/node_modules/ffjavascript": { - "version": "0.2.60", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.60.tgz", - "integrity": "sha512-T/9bnEL5xAZRDbQoEMf+pM9nrhK+C3JyZNmqiWub26EQorW7Jt+jR54gpqDhceA4Nj0YctPQwYnl8xa52/A26A==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.0.tgz", + "integrity": "sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ==", "dependencies": { "wasmbuilder": "0.0.16", "wasmcurves": "0.2.2", - "web-worker": "^1.2.0" + "web-worker": "1.2.0" } }, "node_modules/randombytes": { @@ -5073,20 +5063,20 @@ "dev": true }, "node_modules/snarkjs": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.7.3.tgz", - "integrity": "sha512-cDLpWqdqEJSCQNc+cXYX1XTKdUZBtYEisuOsgmXf/HUsN5WmGN+FO7HfCS+cMQT1Nzbm1a9gAEpKH6KRtDtS1Q==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.7.5.tgz", + "integrity": "sha512-h+3c4rXZKLhLuHk4LHydZCk/h5GcNvk5GjVKRRkHmfb6Ntf8gHOA9zea3g656iclRuhqQ3iKDWFgiD9ypLrKiA==", "dependencies": { - "@iden3/binfileutils": "0.0.11", + "@iden3/binfileutils": "0.0.12", "bfj": "^7.0.2", "blake2b-wasm": "^2.4.0", - "circom_runtime": "0.1.24", + "circom_runtime": "0.1.28", "ejs": "^3.1.6", "fastfile": "0.0.20", - "ffjavascript": "0.2.63", + "ffjavascript": "0.3.1", "js-sha3": "^0.8.0", "logplease": "^1.2.15", - "r1csfile": "0.0.47" + "r1csfile": "0.0.48" }, "bin": { "snarkjs": "build/cli.cjs" diff --git a/package.json b/package.json index 5686b05..b0202b8 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ }, "dependencies": { "ejs": "3.1.10", - "snarkjs": "0.7.3" + "snarkjs": "0.7.5" }, "devDependencies": { "@nomicfoundation/hardhat-ethers": "3.0.5", diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..180b121 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1 @@ +export const BN128_CURVE_NAME = "bn128"; diff --git a/src/core/CircuitZKit.ts b/src/core/CircuitZKit.ts index ee59c81..4eb01d6 100644 --- a/src/core/CircuitZKit.ts +++ b/src/core/CircuitZKit.ts @@ -7,6 +7,8 @@ import { ArtifactsFileType, CircuitZKitConfig, VerifierLanguageType } from "../t import { Signals } from "../types/proof-utils"; import { CalldataByProtocol, IProtocolImplementer, ProofStructByProtocol, ProvingSystemType } from "../types/protocols"; +import { getBn128Curve } from "../utils"; + /** * `CircuitZKit` represents a single circuit and provides a high-level API to work with it. */ @@ -45,9 +47,15 @@ export class CircuitZKit { const wtnsFile = path.join(tmpDir, `${this.getCircuitName()}.wtns`); const wasmFile = this.mustGetArtifactsFilePath("wasm"); + const curve = await getBn128Curve(); + await snarkjs.wtns.calculate(inputs, wasmFile, wtnsFile); - return (await snarkjs.wtns.exportJson(wtnsFile)) as bigint[]; + const wtnsJson = await snarkjs.wtns.exportJson(wtnsFile); + + curve.terminate(); + + return wtnsJson as bigint[]; } /** diff --git a/src/core/protocols/Groth16Implementer.ts b/src/core/protocols/Groth16Implementer.ts index f2ee3bd..3da0969 100644 --- a/src/core/protocols/Groth16Implementer.ts +++ b/src/core/protocols/Groth16Implementer.ts @@ -6,20 +6,38 @@ import { AbstractProtocolImplementer } from "./AbstractImplementer"; import { Signals } from "../../types/proof-utils"; import { Groth16ProofStruct, ProvingSystemType, Groth16Calldata } from "../../types/protocols"; +import { getBn128Curve } from "../../utils"; + export class Groth16Implementer extends AbstractProtocolImplementer<"groth16"> { public async generateProof(inputs: Signals, zKeyFilePath: string, wasmFilePath: string): Promise { - return (await snarkjs.groth16.fullProve(inputs, wasmFilePath, zKeyFilePath)) as Groth16ProofStruct; + const curve = await getBn128Curve(); + + const fullProof = await snarkjs.groth16.fullProve(inputs, wasmFilePath, zKeyFilePath); + + curve.terminate(); + + return fullProof as Groth16ProofStruct; } public async verifyProof(proof: Groth16ProofStruct, vKeyFilePath: string): Promise { const verifier = JSON.parse(fs.readFileSync(vKeyFilePath).toString()); - return await snarkjs.groth16.verify(verifier, proof.publicSignals, proof.proof); + const curve = await getBn128Curve(); + + const proofVerification = await snarkjs.groth16.verify(verifier, proof.publicSignals, proof.proof); + + curve.terminate(); + + return proofVerification; } public async generateCalldata(proof: Groth16ProofStruct): Promise { + const curve = await getBn128Curve(); + const calldata = await snarkjs.groth16.exportSolidityCallData(proof.proof, proof.publicSignals); + curve.terminate(); + return JSON.parse(`[${calldata}]`) as Groth16Calldata; } diff --git a/src/core/protocols/PlonkImplementer.ts b/src/core/protocols/PlonkImplementer.ts index 91adc0c..bff9344 100644 --- a/src/core/protocols/PlonkImplementer.ts +++ b/src/core/protocols/PlonkImplementer.ts @@ -6,21 +6,39 @@ import { AbstractProtocolImplementer } from "./AbstractImplementer"; import { Signals } from "../../types/proof-utils"; import { PlonkCalldata, PlonkProofStruct, ProvingSystemType } from "../../types/protocols"; +import { getBn128Curve } from "../../utils"; + export class PlonkImplementer extends AbstractProtocolImplementer<"plonk"> { public async generateProof(inputs: Signals, zKeyFilePath: string, wasmFilePath: string): Promise { - return (await snarkjs.plonk.fullProve(inputs, wasmFilePath, zKeyFilePath)) as PlonkProofStruct; + const curve = await getBn128Curve(); + + const fullProof = await snarkjs.plonk.fullProve(inputs, wasmFilePath, zKeyFilePath); + + curve.terminate(); + + return fullProof as PlonkProofStruct; } public async verifyProof(proof: PlonkProofStruct, vKeyFilePath: string): Promise { + const curve = await getBn128Curve(); + const verifier = JSON.parse(fs.readFileSync(vKeyFilePath).toString()); - return await snarkjs.plonk.verify(verifier, proof.publicSignals, proof.proof); + const proofVerification = await snarkjs.plonk.verify(verifier, proof.publicSignals, proof.proof); + + curve.terminate(); + + return proofVerification; } public async generateCalldata(proof: PlonkProofStruct): Promise { + const curve = await getBn128Curve(); + const calldata = await snarkjs.plonk.exportSolidityCallData(proof.proof, proof.publicSignals); const proofArrEndIndex: number = calldata.indexOf("]") + 1; + curve.terminate(); + return JSON.parse( `[${calldata.slice(0, proofArrEndIndex)},${calldata.slice(proofArrEndIndex, calldata.length)}]`, ) as PlonkCalldata; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..7ea7841 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,6 @@ +import * as snarkjs from "snarkjs"; +import { BN128_CURVE_NAME } from "./constants"; + +export async function getBn128Curve() { + return (snarkjs as any).curves.getCurveFromName(BN128_CURVE_NAME); +}