From 1efa58e2eee9e274a5e20d56731524beb4e6d83c Mon Sep 17 00:00:00 2001 From: cedoor Date: Mon, 21 Feb 2022 18:26:10 +0100 Subject: [PATCH 1/2] fix: remove public signal checks Also, the old zk-protocols common class has been removed and the proof methods are now specific for each protocol. Former-commit-id: 5a3d58e887812ce723669dbb2f7386b90a6fdbad [formerly 645adb793f1d23506283e595c9af1ef5d076e417] [formerly ea00f95097fd448bb42069cafdf567a9865b5cfa [formerly 2ee146a57bfa1781379f5cf0538c849854d65320]] [formerly c46fd9ff9280c5b341a99d762b973c7abd9b5484 [formerly 6505b3db20597900a17e828dc29306d60760e303] [formerly f705a82231905640d3e6f55fbd149217b6749efb [formerly dfa386ad651aacb4bacd034604aef0107e2f0b8f]]] Former-commit-id: a41369fa90510f4a87caa5e3dc738cc7709ec2ae [formerly fcc74a56fd11578302e5f2a39ac94652e5993369] [formerly f0c11204a7a316338a39ae08f23deb4889efb3ab [formerly 6090f264221d6b97d7233ea8743580c2e5e2b899]] Former-commit-id: 52703d2f0bb29f109cce8df5e02ecfd9206e0884 [formerly 07e444e60751dee51f7a15f3553a59c851cc29f8] Former-commit-id: 13b8ff6f9b40574b105e57dd2b0855e5cc93b825 --- packages/protocols/src/rln.ts | 56 +++++++++++------ packages/protocols/src/semaphore.ts | 71 ++++++++++++++++------ packages/protocols/src/types/index.ts | 20 +++++- packages/protocols/src/zk-protocol.ts | 39 ------------ packages/protocols/tests/rln.test.ts | 41 ++++++------- packages/protocols/tests/semaphore.test.ts | 1 - 6 files changed, 126 insertions(+), 102 deletions(-) delete mode 100644 packages/protocols/src/zk-protocol.ts diff --git a/packages/protocols/src/rln.ts b/packages/protocols/src/rln.ts index 1639660..1cbde55 100644 --- a/packages/protocols/src/rln.ts +++ b/packages/protocols/src/rln.ts @@ -1,16 +1,10 @@ import { MerkleProof } from "@zk-kit/incremental-merkle-tree" import { poseidon } from "circomlibjs" import { groth16 } from "snarkjs" -import { FullProof, RLNPublicSignals, StrBigInt } from "./types" +import { RLNFullProof, StrBigInt } from "./types" import { Fq, genSignalHash } from "./utils" -import ZkProtocol from "./zk-protocol" - -export default class RLN extends ZkProtocol { - /** - * The number of public signals that should be returned by snarkjs when generating a proof. - */ - private static PUBLIC_SIGNALS_COUNT: number = 6 +export default class RLN { /** * Generates a SnarkJS full proof with Groth16. * @param witness The parameters for creating the proof. @@ -18,21 +12,43 @@ export default class RLN extends ZkProtocol { * @param finalZkeyPath The ZKey file path. * @returns The full SnarkJS proof. */ - public static async genProof(witness: any, wasmFilePath: string, finalZkeyPath: string): Promise { - const { proof, publicSignalsArray } = await groth16.fullProve(witness, wasmFilePath, finalZkeyPath, null) + /* istanbul ignore next */ + public static async genProof(witness: any, wasmFilePath: string, finalZkeyPath: string): Promise { + const { proof, publicSignals } = await groth16.fullProve(witness, wasmFilePath, finalZkeyPath, null) - if (publicSignalsArray.length !== RLN.PUBLIC_SIGNALS_COUNT) throw new Error("Error while generating proof") - - const publicSignals: RLNPublicSignals = { - yShare: publicSignalsArray[0], - merkleRoot: publicSignalsArray[1], - internalNullifier: publicSignalsArray[2], - signalHash: publicSignalsArray[3], - epoch: publicSignalsArray[4], - rlnIdentifier: publicSignalsArray[5] + return { + proof, + publicSignals: { + yShare: publicSignals[0], + merkleRoot: publicSignals[1], + internalNullifier: publicSignals[2], + signalHash: publicSignals[3], + epoch: publicSignals[4], + rlnIdentifier: publicSignals[5] + } } + } - return { proof, publicSignals } + /** + * Verifies a zero-knowledge SnarkJS proof. + * @param verificationKey The zero-knowledge verification key. + * @param fullProof The SnarkJS full proof. + * @returns True if the proof is valid, false otherwise. + */ + /* istanbul ignore next */ + public static verifyProof(verificationKey: string, { proof, publicSignals }: RLNFullProof): Promise { + return groth16.verify( + verificationKey, + [ + publicSignals.yShare, + publicSignals.merkleRoot, + publicSignals.internalNullifier, + publicSignals.signalHash, + publicSignals.epoch, + publicSignals.rlnIdentifier + ], + proof + ) } /** diff --git a/packages/protocols/src/semaphore.ts b/packages/protocols/src/semaphore.ts index 5e9738d..7a09dba 100644 --- a/packages/protocols/src/semaphore.ts +++ b/packages/protocols/src/semaphore.ts @@ -1,16 +1,10 @@ import { MerkleProof } from "@zk-kit/incremental-merkle-tree" import { poseidon } from "circomlibjs" import { groth16 } from "snarkjs" -import { FullProof, StrBigInt, SemaphoreWitness, SemaphorePublicSignals } from "./types" +import { SemaphoreFullProof, SemaphoreSolidityProof, SemaphoreWitness, StrBigInt } from "./types" import { genSignalHash } from "./utils" -import ZkProtocol from "./zk-protocol" - -export default class Semaphore extends ZkProtocol { - /** - * The number of public signals that should be returned by snarkjs when generating a proof. - */ - private static PUBLIC_SIGNALS_COUNT: number = 6 +export default class Semaphore { /** * Generates a SnarkJS full proof with Groth16. * @param witness The parameters for creating the proof. @@ -18,19 +12,39 @@ export default class Semaphore extends ZkProtocol { * @param finalZkeyPath The ZKey file path. * @returns The full SnarkJS proof. */ - public static async genProof(witness: any, wasmFilePath: string, finalZkeyPath: string): Promise { - const { proof, publicSignalsArray } = await groth16.fullProve(witness, wasmFilePath, finalZkeyPath, null) + /* istanbul ignore next */ + public static async genProof(witness: any, wasmFilePath: string, finalZkeyPath: string): Promise { + const { proof, publicSignals } = await groth16.fullProve(witness, wasmFilePath, finalZkeyPath, null) - if (publicSignalsArray.length !== Semaphore.PUBLIC_SIGNALS_COUNT) throw new Error("Error while generating proof") - - const publicSignals: SemaphorePublicSignals = { - merkleRoot: publicSignalsArray[0], - nullifierHash: publicSignalsArray[1], - signalHash: publicSignalsArray[2], - externalNullifier: publicSignalsArray[3] + return { + proof, + publicSignals: { + merkleRoot: publicSignals[0], + nullifierHash: publicSignals[1], + signalHash: publicSignals[2], + externalNullifier: publicSignals[3] + } } + } - return { proof, publicSignals } + /** + * Verifies a zero-knowledge SnarkJS proof. + * @param verificationKey The zero-knowledge verification key. + * @param fullProof The SnarkJS full proof. + * @returns True if the proof is valid, false otherwise. + */ + /* istanbul ignore next */ + public static verifyProof(verificationKey: string, { proof, publicSignals }: SemaphoreFullProof): Promise { + return groth16.verify( + verificationKey, + [ + publicSignals.merkleRoot, + publicSignals.nullifierHash, + publicSignals.signalHash, + publicSignals.externalNullifier + ], + proof + ) } /** @@ -70,4 +84,25 @@ export default class Semaphore extends ZkProtocol { public static genNullifierHash(externalNullifier: StrBigInt, identityNullifier: StrBigInt): bigint { return poseidon([BigInt(externalNullifier), BigInt(identityNullifier)]) } + + /** + * Converts a full proof in a proof compatible with the Verifier.sol method inputs. + * @param fullProof The proof generated with SnarkJS. + * @returns The Solidity compatible proof. + */ + /* istanbul ignore next */ + public static packToSolidityProof(fullProof: SemaphoreFullProof): SemaphoreSolidityProof { + const { proof } = fullProof + + return [ + proof.pi_a[0], + proof.pi_a[1], + proof.pi_b[0][1], + proof.pi_b[0][0], + proof.pi_b[1][1], + proof.pi_b[1][0], + proof.pi_c[0], + proof.pi_c[1] + ] + } } diff --git a/packages/protocols/src/types/index.ts b/packages/protocols/src/types/index.ts index df8d759..734111f 100644 --- a/packages/protocols/src/types/index.ts +++ b/packages/protocols/src/types/index.ts @@ -8,9 +8,14 @@ export type Proof = { curve: string } -export type FullProof = { +export type RLNFullProof = { proof: Proof - publicSignals: RLNPublicSignals | SemaphorePublicSignals + publicSignals: RLNPublicSignals +} + +export type SemaphoreFullProof = { + proof: Proof + publicSignals: SemaphorePublicSignals } export type RLNPublicSignals = { @@ -29,7 +34,16 @@ export type SemaphorePublicSignals = { externalNullifier: StrBigInt } -export type SolidityProof = StrBigInt[] +export type SemaphoreSolidityProof = [ + StrBigInt, + StrBigInt, + StrBigInt, + StrBigInt, + StrBigInt, + StrBigInt, + StrBigInt, + StrBigInt +] export type SemaphoreWitness = { identityNullifier: StrBigInt diff --git a/packages/protocols/src/zk-protocol.ts b/packages/protocols/src/zk-protocol.ts deleted file mode 100644 index 89db91b..0000000 --- a/packages/protocols/src/zk-protocol.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* istanbul ignore file */ -import { groth16 } from "snarkjs" -import { FullProof, SolidityProof, StrBigInt } from "./types" - -export default class ZkProtocol { - /** - * Verifies a zero-knowledge SnarkJS proof. - * @param verificationKey The zero-knowledge verification key. - * @param fullProof The SnarkJS full proof. - * @returns True if the proof is valid, false otherwise. - */ - public static verifyProof(verificationKey: string, fullProof: FullProof): Promise { - const { proof, publicSignals } = fullProof - - const publicSignalsArray: StrBigInt[] = Object.values(publicSignals) - - return groth16.verify(verificationKey, publicSignalsArray, proof) - } - - /** - * Converts a full proof in a proof compatible with the Verifier.sol method inputs. - * @param fullProof The proof generated with SnarkJS. - * @returns The Solidity compatible proof. - */ - public static packToSolidityProof(fullProof: FullProof): SolidityProof { - const { proof } = fullProof - - return [ - proof.pi_a[0], - proof.pi_a[1], - proof.pi_b[0][1], - proof.pi_b[0][0], - proof.pi_b[1][1], - proof.pi_b[1][0], - proof.pi_c[0], - proof.pi_c[1] - ] - } -} diff --git a/packages/protocols/tests/rln.test.ts b/packages/protocols/tests/rln.test.ts index 125412a..e96ec1d 100644 --- a/packages/protocols/tests/rln.test.ts +++ b/packages/protocols/tests/rln.test.ts @@ -58,6 +58,26 @@ describe("RLN", () => { expect(fun).toThrow("Can't generate a proof for a zero leaf") }) + it("Should retrieve user secret after spaming", () => { + const identity = new ZkIdentity() + const secretHash = identity.getSecretHash() + + const signal1 = "hey hey" + const signalHash1 = genSignalHash(signal1) + const signal2 = "hey hey again" + const signalHash2 = genSignalHash(signal2) + + const epoch = genExternalNullifier("test-epoch") + const rlnIdentifier = RLN.genIdentifier() + + const [y1] = RLN.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash1) + const [y2] = RLN.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash2) + + const retrievedSecret = RLN.retrieveSecret(signalHash1, signalHash2, y1, y2) + + expect(retrievedSecret).toEqual(secretHash) + }) + // eslint-disable-next-line jest/no-disabled-tests it.skip("Should generate rln proof and verify it", async () => { const identity = new ZkIdentity() @@ -96,27 +116,6 @@ describe("RLN", () => { const response = await RLN.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) expect(response).toBe(true) - expect(fullProof.publicSignals).toEqual(publicSignals) }, 30000) - - it("Should retrieve user secret after spaming", () => { - const identity = new ZkIdentity() - const secretHash = identity.getSecretHash() - - const signal1 = "hey hey" - const signalHash1 = genSignalHash(signal1) - const signal2 = "hey hey again" - const signalHash2 = genSignalHash(signal2) - - const epoch = genExternalNullifier("test-epoch") - const rlnIdentifier = RLN.genIdentifier() - - const [y1] = RLN.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash1) - const [y2] = RLN.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash2) - - const retrievedSecret = RLN.retrieveSecret(signalHash1, signalHash2, y1, y2) - - expect(retrievedSecret).toEqual(secretHash) - }) }) }) diff --git a/packages/protocols/tests/semaphore.test.ts b/packages/protocols/tests/semaphore.test.ts index 9718254..2b9f93e 100644 --- a/packages/protocols/tests/semaphore.test.ts +++ b/packages/protocols/tests/semaphore.test.ts @@ -76,7 +76,6 @@ describe("Semaphore", () => { const response = await Semaphore.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) expect(response).toBe(true) - expect(fullProof.publicSignals).toEqual(publicSignals) }, 30000) }) }) From 03c6529b536725c00d5caaa460acfd0ec41f4a79 Mon Sep 17 00:00:00 2001 From: cedoor Date: Mon, 21 Feb 2022 18:34:06 +0100 Subject: [PATCH 2/2] fix: export all types Former-commit-id: 98925289cafe6401d676ac687eb419207c16f079 [formerly 2ebdb66d8a7efe5283739f1164a6126eebc620ed] [formerly dbe8049d3409c07e17eb864a220781713589aa7e [formerly 3f693694e41a054ea7298469a453e531fb833565]] [formerly 46bfee05316c1d116fd1bdd5d7fa5eac311421b0 [formerly adfba9bd403588ae80fbce576bd99357fc0f8465] [formerly 6a74aa0ef7f456095ae4a9eb527c2334fe7d09c5 [formerly 8c9e48837444b298680f45574fc378d14c514e7c]]] Former-commit-id: 0b71c979853e71884b84735822e8aedc12de0cf2 [formerly f8891a828d04dd53a339ceba7daf931ad5966cf2] [formerly c4a4036f4f21d4d445d55d6dc0b34742a538aa10 [formerly e7439bdbb9923b171096cacdc8b34be0bb939f3f]] Former-commit-id: e1b7067b2af3360400b344635c590db09cd5b31f [formerly ad6cda09651ec465cd53eb67b35ba422c0556293] Former-commit-id: eda484cb577a23f383d6222a37c7ce45a8c37dee --- packages/protocols/src/index.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/protocols/src/index.ts b/packages/protocols/src/index.ts index 0203f9f..a57ee5a 100644 --- a/packages/protocols/src/index.ts +++ b/packages/protocols/src/index.ts @@ -1,17 +1,7 @@ import { MerkleProof } from "@zk-kit/incremental-merkle-tree" import RLN from "./rln" import Semaphore from "./semaphore" -import { FullProof, SolidityProof } from "./types" import { generateMerkleProof, generateMerkleTree, genExternalNullifier, genSignalHash } from "./utils" -export { - Semaphore, - RLN, - generateMerkleProof, - generateMerkleTree, - genExternalNullifier, - genSignalHash, - MerkleProof, - FullProof, - SolidityProof -} +export { Semaphore, RLN, generateMerkleProof, generateMerkleTree, genExternalNullifier, genSignalHash, MerkleProof } +export * from "./types"