From 59089bb5fcc8ba23ee3785c3a8d7e1367c1440e5 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 25 Oct 2023 14:13:10 -0400 Subject: [PATCH 1/7] remove hardcoded snarkjs --- circuits/ts/index.ts | 70 +++------------------------------------- circuits/ts/snarkjs.d.ts | 25 ++++++++++++++ cli/ts/genProofs.ts | 6 ++-- 3 files changed, 33 insertions(+), 68 deletions(-) create mode 100644 circuits/ts/snarkjs.d.ts diff --git a/circuits/ts/index.ts b/circuits/ts/index.ts index 8b60c53583..a52a887731 100644 --- a/circuits/ts/index.ts +++ b/circuits/ts/index.ts @@ -2,15 +2,10 @@ import * as fs from 'fs' import * as path from 'path' import * as shelljs from 'shelljs' import * as tmp from 'tmp' +import { zKey, groth16 } from 'snarkjs' import { stringifyBigInts } from 'maci-crypto' -const snarkjsPath = path.join( - __dirname, - '..', - './node_modules/snarkjs/cli.js', -) - const genProof = ( inputs: string[], rapidsnarkExePath: string, @@ -71,69 +66,14 @@ const genProof = ( return { proof, publicInputs } } -const verifyProof = ( - publicInputs: any, - proof: any, - vk: any, -) => { - // Create tmp directory - const tmpObj = tmp.dirSync() - const tmpDirPath = tmpObj.name - - const publicJsonPath = path.join(tmpDirPath, 'public.json') - const proofJsonPath = path.join(tmpDirPath, 'proof.json') - const vkJsonPath = path.join(tmpDirPath, 'vk.json') - - fs.writeFileSync( - publicJsonPath, - JSON.stringify(stringifyBigInts(publicInputs)), - ) - - fs.writeFileSync( - proofJsonPath, - JSON.stringify(stringifyBigInts(proof)), - ) - - fs.writeFileSync( - vkJsonPath, - JSON.stringify(stringifyBigInts(vk)), - ) - - const verifyCmd = `node ${snarkjsPath} g16v ${vkJsonPath} ${publicJsonPath} ${proofJsonPath}` - const output = shelljs.exec(verifyCmd, { silent: true }) - const isValid = output.stdout && output.stdout.indexOf('OK!') > -1 - - //// Generate calldata - //const calldataCmd = `node ${snarkjsPath} zkesc ${publicJsonPath} ${proofJsonPath}` - //console.log(shelljs.exec(calldataCmd).stdout) - - fs.unlinkSync(proofJsonPath) - fs.unlinkSync(publicJsonPath) - fs.unlinkSync(vkJsonPath) - tmpObj.removeCallback() - +const verifyProof = async (publicInputs: any, proof: any, vk: any) => { + const isValid = await groth16.verify(vk, publicInputs, proof) return isValid } const extractVk = (zkeyPath: string) => { - // Create tmp directory - const tmpObj = tmp.dirSync() - const tmpDirPath = tmpObj.name - const vkJsonPath = path.join(tmpDirPath, 'vk.json') - - const exportCmd = `node ${snarkjsPath} zkev ${zkeyPath} ${vkJsonPath}` - shelljs.exec(exportCmd) - - const vk = JSON.parse(fs.readFileSync(vkJsonPath).toString()) - - fs.unlinkSync(vkJsonPath) - tmpObj.removeCallback() - + const vk = zKey.exportJson(zkeyPath) return vk } -export { - genProof, - verifyProof, - extractVk, -} +export { genProof, verifyProof, extractVk } diff --git a/circuits/ts/snarkjs.d.ts b/circuits/ts/snarkjs.d.ts new file mode 100644 index 0000000000..a1cd9ed62e --- /dev/null +++ b/circuits/ts/snarkjs.d.ts @@ -0,0 +1,25 @@ +declare module 'snarkjs' { + export type NumericString = `${number}` | string + export type PublicSignals = NumericString[] + + export interface Groth16Proof { + pi_a: NumericString[] + pi_b: NumericString[][] + pi_c: NumericString[] + protocol: string + curve: string + } + + export namespace zKey { + function exportJson(zkeyFileName: any): Promise + } + + export namespace groth16 { + function verify( + _vk_verifier: any, + _publicSignals: PublicSignals, + _proof: Groth16Proof, + logger?: any, + ): Promise + } +} diff --git a/cli/ts/genProofs.ts b/cli/ts/genProofs.ts index 2e0afc43e5..cad355411d 100644 --- a/cli/ts/genProofs.ts +++ b/cli/ts/genProofs.ts @@ -394,7 +394,7 @@ const genProofs = async (args: any) => { } // Verify the proof - const isValid = verifyProof( + const isValid = await verifyProof( r.publicInputs, r.proof, processVk, @@ -440,7 +440,7 @@ const genProofs = async (args: any) => { subsidyCircuitInputs = poll.subsidyPerBatch() const r = genProof(subsidyCircuitInputs, rapidsnarkExe, args.subsidy_witnessgen, args.subsidy_zkey) - const isValid = verifyProof(r.publicInputs, r.proof, subsidyVk) + const isValid = await verifyProof(r.publicInputs, r.proof, subsidyVk) if (!isValid) { console.error('Error: generated an invalid subsidy calc proof') return 1 @@ -501,7 +501,7 @@ const genProofs = async (args: any) => { ) // Verify the proof - const isValid = verifyProof( + const isValid = await verifyProof( r.publicInputs, r.proof, tallyVk, From 2d57f120e2f5eaa519861245b20f46947e541b97 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 25 Oct 2023 14:50:23 -0400 Subject: [PATCH 2/7] add missing await --- circuits/ts/index.ts | 4 ++-- cli/ts/checkVerifyingKey.ts | 4 ++-- cli/ts/genProofs.ts | 6 +++--- cli/ts/setVerifyingKeys.ts | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/circuits/ts/index.ts b/circuits/ts/index.ts index a52a887731..5f765f1691 100644 --- a/circuits/ts/index.ts +++ b/circuits/ts/index.ts @@ -71,8 +71,8 @@ const verifyProof = async (publicInputs: any, proof: any, vk: any) => { return isValid } -const extractVk = (zkeyPath: string) => { - const vk = zKey.exportJson(zkeyPath) +const extractVk = async (zkeyPath: string) => { + const vk = await zKey.exportJson(zkeyPath) return vk } diff --git a/cli/ts/checkVerifyingKey.ts b/cli/ts/checkVerifyingKey.ts index e391a5e3c5..59f937b395 100644 --- a/cli/ts/checkVerifyingKey.ts +++ b/cli/ts/checkVerifyingKey.ts @@ -126,8 +126,8 @@ const checkVerifyingKey = async (args: any) => { const pmZkeyFile = path.resolve(args.process_messages_zkey) const tvZkeyFile = path.resolve(args.tally_votes_zkey) - const processVk: VerifyingKey = VerifyingKey.fromObj(extractVk(pmZkeyFile)) - const tallyVk: VerifyingKey = VerifyingKey.fromObj(extractVk(tvZkeyFile)) + const processVk: VerifyingKey = VerifyingKey.fromObj(await extractVk(pmZkeyFile)) + const tallyVk: VerifyingKey = VerifyingKey.fromObj(await extractVk(tvZkeyFile)) const signer = await getDefaultSigner() if (!await contractExists(signer.provider, maciAddress)) { diff --git a/cli/ts/genProofs.ts b/cli/ts/genProofs.ts index cad355411d..be349ca354 100644 --- a/cli/ts/genProofs.ts +++ b/cli/ts/genProofs.ts @@ -232,12 +232,12 @@ const genProofs = async (args: any) => { return 1 } - subsidyVk = extractVk(args.subsidy_zkey) + subsidyVk = await extractVk(args.subsidy_zkey) } // Extract the verifying keys - const processVk = extractVk(args.process_zkey) - const tallyVk = extractVk(args.tally_zkey) + const processVk = await extractVk(args.process_zkey) + const tallyVk = await extractVk(args.tally_zkey) // The coordinator's MACI private key let serializedPrivkey diff --git a/cli/ts/setVerifyingKeys.ts b/cli/ts/setVerifyingKeys.ts index c8e635fe97..b589e80e7f 100644 --- a/cli/ts/setVerifyingKeys.ts +++ b/cli/ts/setVerifyingKeys.ts @@ -131,8 +131,8 @@ const setVerifyingKeys = async (args: any) => { return 1 } - const processVk: VerifyingKey = VerifyingKey.fromObj(extractVk(pmZkeyFile)) - const tallyVk: VerifyingKey = VerifyingKey.fromObj(extractVk(tvZkeyFile)) + const processVk: VerifyingKey = VerifyingKey.fromObj(await extractVk(pmZkeyFile)) + const tallyVk: VerifyingKey = VerifyingKey.fromObj(await extractVk(tvZkeyFile)) let ssZkeyFile: string @@ -144,7 +144,7 @@ const setVerifyingKeys = async (args: any) => { return 1 } - subsidyVk = VerifyingKey.fromObj(extractVk(ssZkeyFile)) + subsidyVk = VerifyingKey.fromObj(await extractVk(ssZkeyFile)) } // Simple validation From 8bc5ee0e9d5d0dfe12efc7329c20a1127c2797d6 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 25 Oct 2023 15:36:11 -0400 Subject: [PATCH 3/7] fix wrong file format error --- circuits/ts/index.ts | 2 +- circuits/ts/snarkjs.d.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/circuits/ts/index.ts b/circuits/ts/index.ts index 5f765f1691..99aa70697f 100644 --- a/circuits/ts/index.ts +++ b/circuits/ts/index.ts @@ -72,7 +72,7 @@ const verifyProof = async (publicInputs: any, proof: any, vk: any) => { } const extractVk = async (zkeyPath: string) => { - const vk = await zKey.exportJson(zkeyPath) + const vk = await zKey.exportVerificationKey(zkeyPath) return vk } diff --git a/circuits/ts/snarkjs.d.ts b/circuits/ts/snarkjs.d.ts index a1cd9ed62e..d1b68764a4 100644 --- a/circuits/ts/snarkjs.d.ts +++ b/circuits/ts/snarkjs.d.ts @@ -11,7 +11,10 @@ declare module 'snarkjs' { } export namespace zKey { - function exportJson(zkeyFileName: any): Promise + function exportVerificationKey( + zkeyName: any, + logger?: any, + ): Promise } export namespace groth16 { From a11bd3203bdc16265bc96754fa7ff1f60a3de02e Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 26 Oct 2023 11:37:41 -0400 Subject: [PATCH 4/7] fix code formatting --- circuits/ts/snarkjs.d.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/circuits/ts/snarkjs.d.ts b/circuits/ts/snarkjs.d.ts index d1b68764a4..58717255ca 100644 --- a/circuits/ts/snarkjs.d.ts +++ b/circuits/ts/snarkjs.d.ts @@ -3,11 +3,11 @@ declare module 'snarkjs' { export type PublicSignals = NumericString[] export interface Groth16Proof { - pi_a: NumericString[] - pi_b: NumericString[][] - pi_c: NumericString[] - protocol: string - curve: string + pi_a: NumericString[]; + pi_b: NumericString[][]; + pi_c: NumericString[]; + protocol: string; + curve: string; } export namespace zKey { From 488da5fbae991a58f1c2612d470d9ffd16ff93c0 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 26 Oct 2023 12:20:40 -0400 Subject: [PATCH 5/7] allow tests to take longer to run --- integrationTests/integrations.yml | 2 +- integrationTests/ts/__tests__/suites.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationTests/integrations.yml b/integrationTests/integrations.yml index 0031f948bf..89de60ff41 100644 --- a/integrationTests/integrations.yml +++ b/integrationTests/integrations.yml @@ -17,7 +17,7 @@ invalidVote: voteCreditBalance: 1 constants: poll: - duration: 120 + duration: 300 intStateTreeDepth: 1 messageTreeDepth: 2 messageBatchDepth: 1 diff --git a/integrationTests/ts/__tests__/suites.ts b/integrationTests/ts/__tests__/suites.ts index d70d56cfc5..ce28130c50 100644 --- a/integrationTests/ts/__tests__/suites.ts +++ b/integrationTests/ts/__tests__/suites.ts @@ -221,7 +221,7 @@ const executeSuite = async (data: any, expect: any) => { } } - const timeTravelCommand = `node build/index.js timeTravel -s ${config.constants.maci.votingDuration}` + const timeTravelCommand = `node build/index.js timeTravel -s ${config.constants.poll.duration}` execute(timeTravelCommand) const mergeMessagesCommand = `node build/index.js mergeMessages -x ${maciAddress} -o ${pollId}` From 2895dfe20379e2fdb1838087a87ff0d3f869d44a Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 26 Oct 2023 12:22:29 -0400 Subject: [PATCH 6/7] fix script stalling by removing threads at the end of curve calls --- circuits/ts/index.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/circuits/ts/index.ts b/circuits/ts/index.ts index 99aa70697f..640eba5978 100644 --- a/circuits/ts/index.ts +++ b/circuits/ts/index.ts @@ -6,6 +6,23 @@ import { zKey, groth16 } from 'snarkjs' import { stringifyBigInts } from 'maci-crypto' +/* + * https://github.com/iden3/snarkjs/issues/152 + * Need to cleanup the threads to avoid stalling + */ +const cleanThreads = async () => { + if (!globalThis) { + return Promise.resolve(true) + } + + const curves = ['curve_bn128', 'curve_bls12381'] + const promises = Promise.all(curves.map(curve => { + return globalThis[curve]?.terminate? globalThis[curve]?.terminate() : null + }).filter(Boolean)) + + return promises +} + const genProof = ( inputs: string[], rapidsnarkExePath: string, @@ -68,11 +85,13 @@ const genProof = ( const verifyProof = async (publicInputs: any, proof: any, vk: any) => { const isValid = await groth16.verify(vk, publicInputs, proof) + await cleanThreads() return isValid } const extractVk = async (zkeyPath: string) => { const vk = await zKey.exportVerificationKey(zkeyPath) + await cleanThreads() return vk } From 5573e97a1a0a7977c2ebfb03a409118db7d06bbd Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 1 Nov 2023 01:39:00 -0400 Subject: [PATCH 7/7] extend poll duration to allow integration test enough time to vote --- integrationTests/integrations.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrationTests/integrations.yml b/integrationTests/integrations.yml index a30cbd29e2..89de60ff41 100644 --- a/integrationTests/integrations.yml +++ b/integrationTests/integrations.yml @@ -17,7 +17,7 @@ invalidVote: voteCreditBalance: 1 constants: poll: - duration: 250 + duration: 300 intStateTreeDepth: 1 messageTreeDepth: 2 messageBatchDepth: 1