From c8a85df5111002a661c0113ba9ccfcd2abce43ec Mon Sep 17 00:00:00 2001 From: cedoor Date: Mon, 24 Jan 2022 15:39:23 +0100 Subject: [PATCH] test: add tests to create proofs and verify them Former-commit-id: f45d926275bd734185edfd1fa323e399fbc505cc [formerly 6a412ac4324d0bc65fadd31ef4952beb6b41c552] [formerly 4f9ad62e0aca23775e65b8e8bb9c2eb615ec8aca [formerly c920365e83a601a73401609bedca3542779ce6c8]] [formerly e73de9b0c0a262c979c1d17882ea3c4dd31aa59e [formerly 2a175fb199795e94a2e14e7e6774d611d72cf9de] [formerly 84f49553d22b1c51f4bd15f0f5e92c6f5ff0438e [formerly 865c5bb174c0cc0c778ab0172944dc75ad8eb9aa]]] Former-commit-id: 46e1332a4a2fbbdcc34fd4dbf5b98d04da3d52df [formerly 83b1530c98aef832277c838cd7714cfbb84d83c1] [formerly 1541c9c435e024eb0012f19e655ecb01804e4a47 [formerly 55eb157e1bfa9916887fb3a331dabcc3268cf62b]] Former-commit-id: d8385e49a2f06264e525e2ce83f75746fd1b57dd [formerly dd8f63c8d306064f9f5163e9f2a6f841634e8b96] Former-commit-id: ab49c153a92a66dfee8741a94529b7dd91ac74d2 --- packages/protocols/src/nrln.ts | 23 +++-- packages/protocols/src/rln.ts | 16 ++-- packages/protocols/tests/nrln.test.ts | 99 +++++++++++----------- packages/protocols/tests/rln.test.ts | 95 ++++++++++----------- packages/protocols/tests/semaphore.test.ts | 18 ++-- 5 files changed, 124 insertions(+), 127 deletions(-) diff --git a/packages/protocols/src/nrln.ts b/packages/protocols/src/nrln.ts index 8384326..dc6ff4d 100644 --- a/packages/protocols/src/nrln.ts +++ b/packages/protocols/src/nrln.ts @@ -1,4 +1,4 @@ -import { MerkleProof } from "@zk-kit/types" +import { MerkleProof, StrBigInt } from "@zk-kit/types" import { poseidon } from "circomlibjs" import { Fq, genSignalHash } from "./utils" import ZkProtocol from "./zk-protocol" @@ -15,9 +15,9 @@ export default class NRLN extends ZkProtocol { * @returns rln witness */ public static genWitness( - identitySecret: Array, + identitySecret: bigint[], merkleProof: MerkleProof, - epoch: string | bigint, + epoch: StrBigInt, signal: string, rlnIdentifier: bigint, shouldHash = true @@ -42,15 +42,15 @@ export default class NRLN extends ZkProtocol { * @returns */ public static calculateOutput( - identitySecret: Array, + identitySecret: bigint[], epoch: bigint, x: bigint, limit: number, rlnIdentifier: bigint - ): Array { + ): bigint[] { const a0 = poseidon(identitySecret) + const coeffs: bigint[] = [] - const coeffs: Array = [] let tmpX = x coeffs.push(poseidon([identitySecret[0], epoch])) @@ -73,7 +73,7 @@ export default class NRLN extends ZkProtocol { * @param coeffs coeefitients from calculated polinomial * @returns slashing nullifier */ - public static genNullifier(coeffs: Array): bigint { + public static genNullifier(coeffs: bigint[]): bigint { return poseidon(coeffs) } @@ -83,10 +83,14 @@ export default class NRLN extends ZkProtocol { * @param ys * @returns identity secret */ - public static retrieveSecret(xs: Array, ys: Array): bigint { - if (xs.length !== ys.length) throw new Error("x and y arrays must be of same size") + public static retrieveSecret(xs: bigint[], ys: bigint[]): bigint { + if (xs.length !== ys.length) { + throw new Error("x and y arrays must be of same size") + } + const numOfPoints: number = xs.length let f0 = BigInt(0) + for (let i = 0; i < numOfPoints; i += 1) { let p = BigInt(1) for (let j = 0; j < numOfPoints; j += 1) { @@ -96,6 +100,7 @@ export default class NRLN extends ZkProtocol { } f0 = Fq.add(f0, Fq.mul(ys[i], p)) } + return f0 } diff --git a/packages/protocols/src/rln.ts b/packages/protocols/src/rln.ts index 133c184..4fb1cbb 100644 --- a/packages/protocols/src/rln.ts +++ b/packages/protocols/src/rln.ts @@ -1,4 +1,4 @@ -import { MerkleProof } from "@zk-kit/types" +import { MerkleProof, StrBigInt } from "@zk-kit/types" import { poseidon } from "circomlibjs" import { Fq, genSignalHash } from "./utils" import ZkProtocol from "./zk-protocol" @@ -17,7 +17,7 @@ export default class RLN extends ZkProtocol { public static genWitness( identitySecret: bigint, merkleProof: MerkleProof, - epoch: string | bigint, + epoch: StrBigInt, signal: string, rlnIdentifier: bigint, shouldHash = true @@ -40,15 +40,11 @@ export default class RLN extends ZkProtocol { * @param x signal hash * @returns y & slashing nullfier */ - public static calculateOutput( - identitySecret: bigint, - epoch: bigint, - rlnIdentifier: bigint, - x: bigint - ): Array { - const a1: bigint = poseidon([identitySecret, epoch]) - const y: bigint = Fq.normalize(a1 * x + identitySecret) + public static calculateOutput(identitySecret: bigint, epoch: bigint, rlnIdentifier: bigint, x: bigint): bigint[] { + const a1 = poseidon([identitySecret, epoch]) + const y = Fq.normalize(a1 * x + identitySecret) const nullifier = RLN.genNullifier(a1, rlnIdentifier) + return [y, nullifier] } diff --git a/packages/protocols/tests/nrln.test.ts b/packages/protocols/tests/nrln.test.ts index 43e0df5..bb82406 100644 --- a/packages/protocols/tests/nrln.test.ts +++ b/packages/protocols/tests/nrln.test.ts @@ -1,62 +1,60 @@ import { SecretType, ZkIdentity } from "@zk-kit/identity" -import { FullProof, MerkleProof } from "@zk-kit/types" import { poseidon } from "circomlibjs" import * as fs from "fs" import * as path from "path" import { NRLN } from "../src" import { generateMerkleProof, genExternalNullifier, genSignalHash } from "../src/utils" -const identityCommitments: Array = [] -const SPAM_TRESHOLD = 3 - -beforeAll(() => { - const leafIndex = 3 - - for (let i = 0; i < leafIndex; i += 1) { - const tmpIdentity = new ZkIdentity() - const tmpCommitment: bigint = tmpIdentity.genIdentityCommitment(SecretType.MULTIPART, SPAM_TRESHOLD) - identityCommitments.push(tmpCommitment) - } -}) - describe("NRLN", () => { + const zkeyFiles = "./packages/protocols/zkeyFiles" + const identityCommitments: bigint[] = [] + const SPAM_TRESHOLD = 3 + + beforeAll(() => { + const numberOfLeaves = 3 + + for (let i = 0; i < numberOfLeaves; i += 1) { + const identity = new ZkIdentity() + const identityCommitment = identity.genIdentityCommitment(SecretType.MULTIPART, SPAM_TRESHOLD) + + identityCommitments.push(identityCommitment) + } + }) + describe("NRLN features", () => { - it("Generate NRLN witness", () => { - const identity: ZkIdentity = new ZkIdentity() + it("Should generate NRLN witness", () => { + const identity = new ZkIdentity() + const identityCommitment = identity.genIdentityCommitment(SecretType.MULTIPART, SPAM_TRESHOLD) + const identitySecret = identity.getMultipartSecret(SPAM_TRESHOLD) - const identityCommitment: bigint = identity.genIdentityCommitment(SecretType.MULTIPART, SPAM_TRESHOLD) - const identitySecret: bigint[] = identity.getMultipartSecret(SPAM_TRESHOLD) - - const commitments: Array = Object.assign([], identityCommitments) - commitments.push(identityCommitment) + const leaves = Object.assign([], identityCommitments) + leaves.push(identityCommitment) const signal = "hey hey" - const epoch: string = genExternalNullifier("test-epoch") - const rlnIdentifier: bigint = NRLN.genIdentifier() + const epoch = genExternalNullifier("test-epoch") + const rlnIdentifier = NRLN.genIdentifier() - const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment) - const witness: FullProof = NRLN.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier) + const merkleProof = generateMerkleProof(15, BigInt(0), 2, leaves, identityCommitment) + const witness = NRLN.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier) expect(typeof witness).toBe("object") }) - it.skip("Generate NRLN proof and verify it", async () => { - /** - * Compiled RLN circuits are needed to run this test so it's being skipped in hooks - */ - const identity: ZkIdentity = new ZkIdentity() - const identityCommitment: bigint = identity.genIdentityCommitment(SecretType.MULTIPART, SPAM_TRESHOLD) - const identitySecret: bigint[] = identity.getMultipartSecret(SPAM_TRESHOLD) - const commitments: Array = Object.assign([], identityCommitments) - commitments.push(identityCommitment) + it("Should generate NRLN proof and verify it", async () => { + const identity = new ZkIdentity() + const identityCommitment = identity.genIdentityCommitment(SecretType.MULTIPART, SPAM_TRESHOLD) + const identitySecret = identity.getMultipartSecret(SPAM_TRESHOLD) + + const leaves = Object.assign([], identityCommitments) + leaves.push(identityCommitment) const signal = "hey hey" const signalHash = genSignalHash(signal) - const epoch: string = genExternalNullifier("test-epoch") - const rlnIdentifier: bigint = NRLN.genIdentifier() + const epoch = genExternalNullifier("test-epoch") + const rlnIdentifier = NRLN.genIdentifier() - const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment) - const witness: FullProof = NRLN.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier) + const merkleProof = generateMerkleProof(15, BigInt(0), 2, leaves, identityCommitment) + const witness = NRLN.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier) const [y, nullifier] = NRLN.calculateOutput( identitySecret, @@ -67,21 +65,22 @@ describe("NRLN", () => { ) const publicSignals = [y, merkleProof.root, nullifier, signalHash, epoch, rlnIdentifier] - const vkeyPath: string = path.join("./zkeyFiles", "nrln", "verification_key.json") + const vkeyPath = path.join(zkeyFiles, "nrln", "verification_key.json") const vKey = JSON.parse(fs.readFileSync(vkeyPath, "utf-8")) - const wasmFilePath: string = path.join("./zkeyFiles", "nrln", "rln.wasm") - const finalZkeyPath: string = path.join("./zkeyFiles", "nrln", "rln_final.zkey") + const wasmFilePath = path.join(zkeyFiles, "nrln", "rln.wasm") + const finalZkeyPath = path.join(zkeyFiles, "nrln", "rln_final.zkey") - const fullProof: FullProof = await NRLN.genProof(witness, wasmFilePath, finalZkeyPath) - const res: boolean = await NRLN.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) + const fullProof = await NRLN.genProof(witness, wasmFilePath, finalZkeyPath) + const response = await NRLN.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) - expect(res).toBe(true) + expect(response).toBe(true) }, 30000) - it("Should retrieve user secret after spaming", () => { - const identity: ZkIdentity = new ZkIdentity() - const identitySecret: bigint[] = identity.getMultipartSecret(SPAM_TRESHOLD) + it("Should retrieve user secret after spaming", () => { + const identity = new ZkIdentity() + + const identitySecret = identity.getMultipartSecret(SPAM_TRESHOLD) const signal1 = "hey 1" const signalHash1 = genSignalHash(signal1) @@ -92,15 +91,15 @@ describe("NRLN", () => { const signal4 = "hey 4" const signalHash4 = genSignalHash(signal4) - const epoch: string = genExternalNullifier("test-epoch") - const rlnIdentifier: bigint = NRLN.genIdentifier() + const epoch = genExternalNullifier("test-epoch") + const rlnIdentifier = NRLN.genIdentifier() const [y1] = NRLN.calculateOutput(identitySecret, BigInt(epoch), signalHash1, SPAM_TRESHOLD, rlnIdentifier) const [y2] = NRLN.calculateOutput(identitySecret, BigInt(epoch), signalHash2, SPAM_TRESHOLD, rlnIdentifier) const [y3] = NRLN.calculateOutput(identitySecret, BigInt(epoch), signalHash3, SPAM_TRESHOLD, rlnIdentifier) const [y4] = NRLN.calculateOutput(identitySecret, BigInt(epoch), signalHash4, SPAM_TRESHOLD, rlnIdentifier) - const retrievedSecret: bigint = NRLN.retrieveSecret( + const retrievedSecret = NRLN.retrieveSecret( [signalHash1, signalHash2, signalHash3, signalHash4], [y1, y2, y3, y4] ) diff --git a/packages/protocols/tests/rln.test.ts b/packages/protocols/tests/rln.test.ts index 2fccda2..1e70f13 100644 --- a/packages/protocols/tests/rln.test.ts +++ b/packages/protocols/tests/rln.test.ts @@ -1,93 +1,90 @@ -import { FullProof, MerkleProof } from "@zk-kit/types" +import { SecretType, ZkIdentity } from "@zk-kit/identity" import * as fs from "fs" import * as path from "path" -import { SecretType, ZkIdentity } from "@zk-kit/identity" import { RLN } from "../src" import { generateMerkleProof, genExternalNullifier, genSignalHash } from "../src/utils" -const identityCommitments: Array = [] - -beforeAll(() => { - const leafIndex = 3 - - for (let i = 0; i < leafIndex; i += 1) { - const tmpIdentity = new ZkIdentity() - const tmpCommitment: bigint = tmpIdentity.genIdentityCommitment(SecretType.MULTIPART) - identityCommitments.push(tmpCommitment) - } -}) - describe("RLN", () => { - describe("RLN functionalities", () => { - it("Generate rln witness", () => { - const identity: ZkIdentity = new ZkIdentity() - const identityCommitment: bigint = identity.genIdentityCommitment() - const secretHash: bigint = identity.getMultipartSecretHash() + const zkeyFiles = "./packages/protocols/zkeyFiles" + const identityCommitments: bigint[] = [] - const commitments: Array = Object.assign([], identityCommitments) - commitments.push(identityCommitment) + beforeAll(() => { + const numberOfLeaves = 3 + + for (let i = 0; i < numberOfLeaves; i += 1) { + const identity = new ZkIdentity() + const identityCommitment = identity.genIdentityCommitment(SecretType.MULTIPART) + + identityCommitments.push(identityCommitment) + } + }) + + describe("RLN functionalities", () => { + it("Should generate rln witness", () => { + const identity = new ZkIdentity() + const identityCommitment = identity.genIdentityCommitment() + const secretHash = identity.getMultipartSecretHash() + + const leaves = Object.assign([], identityCommitments) + leaves.push(identityCommitment) const signal = "hey hey" const epoch: string = genExternalNullifier("test-epoch") - const rlnIdentifier: bigint = RLN.genIdentifier() + const rlnIdentifier = RLN.genIdentifier() - const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment) - const witness: FullProof = RLN.genWitness(secretHash, merkleProof, epoch, signal, rlnIdentifier) + const merkleProof = generateMerkleProof(15, BigInt(0), 2, leaves, identityCommitment) + const witness = RLN.genWitness(secretHash, merkleProof, epoch, signal, rlnIdentifier) expect(typeof witness).toBe("object") }) - it.skip("Generate rln proof and verify it", async () => { - /** - * Compiled RLN circuits are needed to run this test so it's being skipped in hooks - */ - const identity: ZkIdentity = new ZkIdentity() - const secretHash: bigint = identity.getMultipartSecretHash() + it("Should generate rln proof and verify it", async () => { + const identity = new ZkIdentity() + const secretHash = identity.getMultipartSecretHash() + const identityCommitment = identity.genIdentityCommitment(SecretType.MULTIPART) - const identityCommitment: bigint = identity.genIdentityCommitment(SecretType.MULTIPART) - - const commitments: Array = Object.assign([], identityCommitments) - commitments.push(identityCommitment) + const leaves = Object.assign([], identityCommitments) + leaves.push(identityCommitment) const signal = "hey hey" const signalHash = genSignalHash(signal) - const epoch: string = genExternalNullifier("test-epoch") - const rlnIdentifier: bigint = RLN.genIdentifier() + const epoch = genExternalNullifier("test-epoch") + const rlnIdentifier = RLN.genIdentifier() - const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment) - const witness: FullProof = RLN.genWitness(secretHash, merkleProof, epoch, signal, rlnIdentifier) + const merkleProof = generateMerkleProof(15, BigInt(0), 2, leaves, identityCommitment) + const witness = RLN.genWitness(secretHash, merkleProof, epoch, signal, rlnIdentifier) const [y, nullifier] = RLN.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash) const publicSignals = [y, merkleProof.root, nullifier, signalHash, epoch, rlnIdentifier] - const vkeyPath: string = path.join("./zkeyFiles", "rln", "verification_key.json") + const vkeyPath = path.join(zkeyFiles, "rln", "verification_key.json") const vKey = JSON.parse(fs.readFileSync(vkeyPath, "utf-8")) - const wasmFilePath: string = path.join("./zkeyFiles", "rln", "rln.wasm") - const finalZkeyPath: string = path.join("./zkeyFiles", "rln", "rln_final.zkey") + const wasmFilePath = path.join(zkeyFiles, "rln", "rln.wasm") + const finalZkeyPath = path.join(zkeyFiles, "rln", "rln_final.zkey") - const fullProof: FullProof = await RLN.genProof(witness, wasmFilePath, finalZkeyPath) - const res: boolean = await RLN.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) + const fullProof = await RLN.genProof(witness, wasmFilePath, finalZkeyPath) + const response = await RLN.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) - expect(res).toBe(true) + expect(response).toBe(true) }, 30000) it("Should retrieve user secret after spaming", () => { - const identity: ZkIdentity = new ZkIdentity() - const secretHash: bigint = identity.getSecretHash() + 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: string = genExternalNullifier("test-epoch") - const rlnIdentifier: bigint = RLN.genIdentifier() + 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: bigint = RLN.retrieveSecret(signalHash1, signalHash2, y1, y2) + 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 e05f389..f4c525c 100644 --- a/packages/protocols/tests/semaphore.test.ts +++ b/packages/protocols/tests/semaphore.test.ts @@ -1,11 +1,12 @@ import { ZkIdentity } from "@zk-kit/identity" -import { FullProof } from "@zk-kit/types" import fs from "fs" import path from "path" import { Semaphore } from "../src" import { generateMerkleProof, genExternalNullifier, genSignalHash } from "../src/utils" describe("Semaphore", () => { + const zkeyFiles = "./packages/protocols/zkeyFiles" + describe("Generate and verify proof", () => { it("Should generate a Semaphore witness", async () => { const identity = new ZkIdentity() @@ -27,8 +28,7 @@ describe("Semaphore", () => { expect(typeof witness).toBe("object") }) - // Compiled Semaphore circuits are needed to run this test, so it's being skipped in hooks. - it.skip("Should generate semaphore full proof", async () => { + it("Should generate Semaphore full proof", async () => { const identity = new ZkIdentity() const identityCommitment = identity.genIdentityCommitment() const externalNullifier = genExternalNullifier("voting_1") @@ -45,18 +45,18 @@ describe("Semaphore", () => { signal ) - const wasmFilePath: string = path.join("./zkeyFiles", "semaphore", "semaphore.wasm") - const finalZkeyPath: string = path.join("./zkeyFiles", "semaphore", "semaphore_final.zkey") - const fullProof: FullProof = await Semaphore.genProof(witness, wasmFilePath, finalZkeyPath) + const wasmFilePath = path.join(zkeyFiles, "semaphore", "semaphore.wasm") + const finalZkeyPath = path.join(zkeyFiles, "semaphore", "semaphore_final.zkey") + const fullProof = await Semaphore.genProof(witness, wasmFilePath, finalZkeyPath) - const vkeyPath: string = path.join("./zkeyFiles", "semaphore", "verification_key.json") + const vkeyPath = path.join("./packages/protocols/zkeyFiles", "semaphore", "verification_key.json") const vKey = JSON.parse(fs.readFileSync(vkeyPath, "utf-8")) const nullifierHash = Semaphore.genNullifierHash(externalNullifier, identity.getNullifier()) const publicSignals = [merkleProof.root.toString(), nullifierHash, genSignalHash(signal), externalNullifier] - const res: boolean = await Semaphore.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) + const response = await Semaphore.verifyProof(vKey, { proof: fullProof.proof, publicSignals }) - expect(res).toBe(true) + expect(response).toBe(true) }, 30000) }) })