From d68cf0e0b1408bcbd2c8166cd368eb2f4b58d83d Mon Sep 17 00:00:00 2001 From: cedoor Date: Wed, 6 Dec 2023 17:19:31 +0000 Subject: [PATCH 1/5] feat(identity): update identity with eddsa --- packages/identity/README.md | 49 +++++++-- packages/identity/package.json | 7 +- packages/identity/src/checkParameter.ts | 5 - packages/identity/src/identity.test.ts | 131 +++++++--------------- packages/identity/src/identity.ts | 138 +++++++++--------------- packages/identity/src/utils.ts | 24 ----- yarn.lock | 25 ++--- 7 files changed, 136 insertions(+), 243 deletions(-) delete mode 100644 packages/identity/src/checkParameter.ts delete mode 100644 packages/identity/src/utils.ts diff --git a/packages/identity/README.md b/packages/identity/README.md index d9593655a..ab5fb6ab6 100644 --- a/packages/identity/README.md +++ b/packages/identity/README.md @@ -70,20 +70,51 @@ yarn add @semaphore-protocol/identity ## 📜 Usage -\# **new Identity**(identityOrMessage?: _string_): _Identity_ +\# **new Identity**(privateKey?: _BigNumberish_): _Identity_ ```typescript import { Identity } from "@semaphore-protocol/identity" -// The identity can be generated randomly. -const identity1 = new Identity() +// The identity will be generated randomly. +const { privateKey, publicKey } = new Identity() -// Deterministically from a secret message. -const identity2 = new Identity("secret-message") +// Alternatively, you can pass your private key. +const identity = new Identity("your-private-key") +``` + +\# **identity.signMessage**(message: _BigNumberish_): _Signature\_ + +```typescript +import { Identity } from "@semaphore-protocol/identity" + +const message = "message" +const identity = new Identity() + +const signature = identity.signMessage(message) +``` + +\# **identity.verifySignature**(message: _BigNumberish_, signature: _Signature_): _boolean_ + +```typescript +import { Identity } from "@semaphore-protocol/identity" + +const message = "message" +const identity = new Identity() + +const signature = identity.signMessage(message) + +identity.verifySignature(message, signature) +``` + +\# **Identity.verifySignature**(message: _BigNumberish_, signature: _Signature_, publicKey: _BigNumber_ | _Point_): _boolean_ + +```typescript +import { Identity } from "@semaphore-protocol/identity" + +const message = "message" +const identity = new Identity() -// Or it can be retrieved from an existing identity. -const identity3 = new Identity(identity1.toString()) +const signature = identity.signMessage("message", signature) -// Trapdoor, nullifier and commitment are the attributes (e.g. JS getters). -const { trapdoor, nullifier, commitment } = identity1 +Identity.verifySignature(message, signature, identity.publicKey) ``` diff --git a/packages/identity/package.json b/packages/identity/package.json index 14299f7a1..afbcbe9f2 100644 --- a/packages/identity/package.json +++ b/packages/identity/package.json @@ -32,15 +32,10 @@ "devDependencies": { "@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-node-resolve": "^15.0.1", - "poseidon-lite": "^0.2.0", "rollup-plugin-cleanup": "^3.2.1", "rollup-plugin-typescript2": "^0.31.2" }, "dependencies": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/random": "^5.5.1", - "@ethersproject/strings": "^5.6.1", - "js-sha512": "^0.8.0" + "@zk-kit/eddsa-poseidon": "0.4.1" } } diff --git a/packages/identity/src/checkParameter.ts b/packages/identity/src/checkParameter.ts deleted file mode 100644 index c68474f3a..000000000 --- a/packages/identity/src/checkParameter.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default function checkParameter(value: any, name: string, type: string) { - if (typeof value !== type) { - throw new TypeError(`Parameter '${name}' is not a ${type}`) - } -} diff --git a/packages/identity/src/identity.test.ts b/packages/identity/src/identity.test.ts index 505078b1d..5cd699579 100644 --- a/packages/identity/src/identity.test.ts +++ b/packages/identity/src/identity.test.ts @@ -1,124 +1,65 @@ -import { BigNumber } from "@ethersproject/bignumber" import Identity from "./identity" describe("Identity", () => { - describe("# Identity", () => { - it("Should not create a identity if the parameter is not valid", () => { - const fun1 = () => new Identity(13 as any) - const fun2 = () => new Identity(true as any) - const fun3 = () => new Identity((() => true) as any) - - expect(fun1).toThrow("Parameter 'identityOrMessage' is not a string") - expect(fun2).toThrow("Parameter 'identityOrMessage' is not a string") - expect(fun3).toThrow("Parameter 'identityOrMessage' is not a string") - }) - - it("Should create random identities", () => { - const identity1 = new Identity() - const identity2 = new Identity() - - expect(identity1.trapdoor).not.toBe(identity2.getTrapdoor()) - expect(identity1.nullifier).not.toBe(identity2.getNullifier()) - expect(identity1.secret).not.toBe(identity2.getSecret()) - expect(identity1.commitment).not.toBe(identity2.getCommitment()) - }) - - it("Should create deterministic identities from a message", () => { - const identity1 = new Identity("message") - const identity2 = new Identity("message") - - expect(identity1.trapdoor).toBe(identity2.getTrapdoor()) - expect(identity1.nullifier).toBe(identity2.getNullifier()) - }) - - it("Should create deterministic identities from number/boolean messages", () => { - const identity1 = new Identity("true") - const identity2 = new Identity("true") - const identity3 = new Identity("7") - const identity4 = new Identity("7") - - expect(identity1.trapdoor).toBe(identity2.getTrapdoor()) - expect(identity1.nullifier).toBe(identity2.getNullifier()) - expect(identity3.trapdoor).toBe(identity4.getTrapdoor()) - expect(identity3.nullifier).toBe(identity4.getNullifier()) - }) + const privateKey = "secret" - it("Should not recreate an existing invalid identity", () => { - const fun = () => new Identity('[true, "01323"]') + describe("# Identity", () => { + it("Should create a random identity", () => { + const identity = new Identity() - expect(fun).toThrow("invalid BigNumber value") + expect(Buffer.isBuffer(identity.privateKey)).toBeTruthy() + expect(typeof identity.publicKey).toBe("string") + expect(typeof identity.secretScalar).toBe("string") + expect(identity.unpackedPublicKey).toHaveLength(2) }) - it("Should recreate an existing identity", () => { - const identity1 = new Identity("message") - - const identity2 = new Identity(identity1.toString()) + it("Should create deterministic identities from a secret (private key)", () => { + const identity = new Identity(privateKey) - expect(identity1.trapdoor).toBe(identity2.getTrapdoor()) - expect(identity1.nullifier).toBe(identity2.getNullifier()) + expect(typeof identity.privateKey).toBe("string") + expect(typeof identity.publicKey).toBe("string") + expect(typeof identity.secretScalar).toBe("string") + expect(identity.unpackedPublicKey).toHaveLength(2) + expect(typeof identity.unpackedPublicKey[0]).toBe("string") }) }) - describe("# getTrapdoor", () => { - it("Should return the identity trapdoor", () => { - const identity = new Identity("message") + describe("# signMessage", () => { + it("Should sign a message", () => { + const identity = new Identity(privateKey) - const trapdoor = identity.getTrapdoor() + const signature = identity.signMessage("message") - expect(trapdoor.toString()).toBe( - "11566083507498623434013707198824105161167204201250008419741119866456392774309" - ) + expect(signature.R8).toHaveLength(2) + expect(typeof signature.R8[0]).toBe("string") + expect(typeof signature.S).toBe("string") }) }) - describe("# getNullifier", () => { - it("Should return the identity nullifier", () => { - const identity = new Identity("message") - - const nullifier = identity.getNullifier() - - expect(nullifier.toString()).toBe( - "14070056666392584007908120012103355272369511035580155843212703537125048345255" - ) - }) - }) + describe("# verifySignature", () => { + it("Should verify a signature", () => { + const identity = new Identity(privateKey) - describe("# getSecret", () => { - it("Should return an identity secret", () => { - const { secret } = new Identity("message") + const signature = identity.signMessage("message") - expect(secret.toString()).toBe( - "17452394798940441025978193762953691632066258438336130543532009665042636950194" - ) + expect(identity.verifySignature("message", signature)).toBeTruthy() }) - }) - - describe("# getCommitment", () => { - it("Should return an identity commitment", () => { - const { commitment } = new Identity("message") - - expect(commitment.toString()).toBe( - "19361462367798001240039467285882167157718016385695743307694056771074972404368" - ) - }) - }) - describe("# toString", () => { - it("Should return a string", () => { - const identity = new Identity("message") + it("Should verify an external signature", () => { + const identity = new Identity(privateKey) - const identityString = identity.toString() + const signature = identity.signMessage("message") - expect(typeof identityString).toBe("string") + expect(Identity.verifySignature("message", signature, identity.publicKey)).toBeTruthy() + expect(Identity.verifySignature("message", signature, BigInt(identity.publicKey))).toBeTruthy() }) - it("Should return a valid identity string", () => { - const identity = new Identity("message") + it("Should verify an external signature with an unpacked public key", () => { + const identity = new Identity(privateKey) - const [trapdoor, nullifier] = JSON.parse(identity.toString()) + const signature = identity.signMessage("message") - expect(BigNumber.from(trapdoor).toBigInt()).toBe(identity.trapdoor) - expect(BigNumber.from(nullifier).toBigInt()).toBe(identity.nullifier) + expect(Identity.verifySignature("message", signature, identity.unpackedPublicKey)).toBeTruthy() }) }) }) diff --git a/packages/identity/src/identity.ts b/packages/identity/src/identity.ts index 5bd562ebb..0721e5d6d 100644 --- a/packages/identity/src/identity.ts +++ b/packages/identity/src/identity.ts @@ -1,121 +1,81 @@ -import { BigNumber } from "@ethersproject/bignumber" -import hash from "js-sha512" -import { poseidon1 } from "poseidon-lite/poseidon1" -import { poseidon2 } from "poseidon-lite/poseidon2" -import checkParameter from "./checkParameter" -import { genRandomNumber, isJsonArray } from "./utils" +import { + BigNumber, + BigNumberish, + Point, + Signature, + derivePublicKey, + deriveSecretScalar, + packPublicKey, + signMessage, + unpackPublicKey, + verifySignature +} from "@zk-kit/eddsa-poseidon" +import { randomBytes } from "crypto" export default class Identity { - private _trapdoor: bigint - private _nullifier: bigint - private _secret: bigint - private _commitment: bigint + private _privateKey: BigNumberish + private _secretScalar: string + private _unpackedPublicKey: Point + private _publicKey: string /** - * Initializes the class attributes based on the strategy passed as parameter. - * @param identityOrMessage Additional data needed to create identity for given strategy. + * Initializes the class attributes based on the parameters. + * @param privateKey The secret value used to generate an EdDSA public key. */ - constructor(identityOrMessage?: string) { - if (identityOrMessage === undefined) { - this._trapdoor = genRandomNumber() - this._nullifier = genRandomNumber() - this._secret = poseidon2([this._nullifier, this._trapdoor]) - this._commitment = poseidon1([this._secret]) + constructor(privateKey: BigNumberish = randomBytes(32)) { + this._privateKey = privateKey + this._secretScalar = deriveSecretScalar(privateKey) - return - } - - checkParameter(identityOrMessage, "identityOrMessage", "string") - - if (!isJsonArray(identityOrMessage)) { - const h = hash.sha512(identityOrMessage).padStart(128, "0") - // alt_bn128 is 253.6 bits, so we can safely use 253 bits. - this._trapdoor = BigInt(`0x${h.slice(64)}`) >> BigInt(3) - this._nullifier = BigInt(`0x${h.slice(0, 64)}`) >> BigInt(3) - this._secret = poseidon2([this._nullifier, this._trapdoor]) - this._commitment = poseidon1([this._secret]) - - return - } + this._unpackedPublicKey = derivePublicKey(privateKey) - const [trapdoor, nullifier] = JSON.parse(identityOrMessage) - - this._trapdoor = BigNumber.from(trapdoor).toBigInt() - this._nullifier = BigNumber.from(nullifier).toBigInt() - this._secret = poseidon2([this._nullifier, this._trapdoor]) - this._commitment = poseidon1([this._secret]) - } - - /** - * Returns the identity trapdoor. - * @returns The identity trapdoor. - */ - public get trapdoor(): bigint { - return this._trapdoor + this._publicKey = packPublicKey(this._unpackedPublicKey) as string } /** - * Returns the identity trapdoor. - * @returns The identity trapdoor. + * Returns the private key. + * @returns The private key. */ - public getTrapdoor(): bigint { - return this._trapdoor + public get privateKey(): BigNumberish { + return this._privateKey } /** - * Returns the identity nullifier. - * @returns The identity nullifier. + * Returns the secret scalar. + * @returns The secret scalar. */ - public get nullifier(): bigint { - return this._nullifier + public get secretScalar(): string { + return this._secretScalar } /** - * Returns the identity nullifier. - * @returns The identity nullifier. + * Returns the public key. + * @returns The public key. */ - public getNullifier(): bigint { - return this._nullifier + public get publicKey(): string { + return this._publicKey } /** - * Returns the identity secret. - * @returns The identity secret. + * Returns the unpacked public key. + * @returns The unpacked public key. */ - public get secret(): bigint { - return this._secret + public get unpackedPublicKey(): Point { + return this._unpackedPublicKey } - /** - * Returns the identity secret. - * @returns The identity secret. - */ - public getSecret(): bigint { - return this._secret + public signMessage(message: BigNumberish): Signature { + return signMessage(this.privateKey, message) } - /** - * Returns the identity commitment. - * @returns The identity commitment. - */ - public get commitment(): bigint { - return this._commitment + public verifySignature(message: BigNumberish, signature: Signature): boolean { + return verifySignature(message, signature, this._unpackedPublicKey) } - /** - * Returns the identity commitment. - * @returns The identity commitment. - */ - public getCommitment(): bigint { - return this._commitment - } + static verifySignature(message: BigNumberish, signature: Signature, publicKey: BigNumber | Point): boolean { + if (typeof publicKey === "string" || typeof publicKey === "bigint") { + publicKey = unpackPublicKey(publicKey) + } - /** - * Returns a JSON string with trapdoor and nullifier. It can be used - * to export the identity and reuse it later. - * @returns The string representation of the identity. - */ - public toString(): string { - return JSON.stringify([`0x${this._trapdoor.toString(16)}`, `0x${this._nullifier.toString(16)}`]) + return verifySignature(message, signature, publicKey) } } diff --git a/packages/identity/src/utils.ts b/packages/identity/src/utils.ts deleted file mode 100644 index 0351e8eca..000000000 --- a/packages/identity/src/utils.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { BigNumber } from "@ethersproject/bignumber" -import { randomBytes } from "@ethersproject/random" - -/** - * Generates a random big number. - * @param numberOfBytes The number of bytes of the number. - * @returns The generated random number. - */ -export function genRandomNumber(numberOfBytes = 31): bigint { - return BigNumber.from(randomBytes(numberOfBytes)).toBigInt() -} - -/** - * Checks if a string is a JSON. - * @param jsonString The JSON string. - * @returns True or false. - */ -export function isJsonArray(jsonString: string) { - try { - return Array.isArray(JSON.parse(jsonString)) - } catch (error) { - return false - } -} diff --git a/yarn.lock b/yarn.lock index 55a1ce88c..293d1111a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2626,7 +2626,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/random@npm:5.7.0, @ethersproject/random@npm:^5.5.1, @ethersproject/random@npm:^5.7.0": +"@ethersproject/random@npm:5.7.0, @ethersproject/random@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/random@npm:5.7.0" dependencies: @@ -2685,7 +2685,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/strings@npm:5.7.0, @ethersproject/strings@npm:^5.5.0, @ethersproject/strings@npm:^5.6.1, @ethersproject/strings@npm:^5.7.0": +"@ethersproject/strings@npm:5.7.0, @ethersproject/strings@npm:^5.5.0, @ethersproject/strings@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/strings@npm:5.7.0" dependencies: @@ -4588,14 +4588,9 @@ __metadata: version: 0.0.0-use.local resolution: "@semaphore-protocol/identity@workspace:packages/identity" dependencies: - "@ethersproject/bignumber": ^5.5.0 - "@ethersproject/keccak256": ^5.7.0 - "@ethersproject/random": ^5.5.1 - "@ethersproject/strings": ^5.6.1 "@rollup/plugin-commonjs": ^24.0.1 "@rollup/plugin-node-resolve": ^15.0.1 - js-sha512: ^0.8.0 - poseidon-lite: ^0.2.0 + "@zk-kit/eddsa-poseidon": 0.4.1 rollup-plugin-cleanup: ^3.2.1 rollup-plugin-typescript2: ^0.31.2 languageName: unknown @@ -5771,6 +5766,13 @@ __metadata: languageName: node linkType: hard +"@zk-kit/eddsa-poseidon@npm:0.4.1": + version: 0.4.1 + resolution: "@zk-kit/eddsa-poseidon@npm:0.4.1" + checksum: 82dcb0f45066a2899ae93c59fbe8246eaf28b3ab3078e909f4156534b1f998da0e480d3ab7f9044d12becc9546e02ea89d08305c64d60544f26aaa34ef1072f5 + languageName: node + linkType: hard + "@zk-kit/groth16@npm:0.3.0": version: 0.3.0 resolution: "@zk-kit/groth16@npm:0.3.0" @@ -13542,13 +13544,6 @@ __metadata: languageName: node linkType: hard -"js-sha512@npm:^0.8.0": - version: 0.8.0 - resolution: "js-sha512@npm:0.8.0" - checksum: 32ca371ebd14c6c5c83360fd8b036cad2211537bef546b199ac8b901917299cab4c68f7f7c26ae72f836bbce0349cb463df9a62cdb4c90e38090fdb4db89ee87 - languageName: node - linkType: hard - "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" From e9906cba84021d7779edab5cef7c0a275a88ee37 Mon Sep 17 00:00:00 2001 From: cedoor Date: Wed, 6 Dec 2023 19:58:13 +0000 Subject: [PATCH 2/5] refactor(identity): add identity commitment attribute --- packages/identity/README.md | 4 ++-- packages/identity/package.json | 3 ++- packages/identity/src/identity.test.ts | 12 +++++------ packages/identity/src/identity.ts | 30 +++++++++++--------------- yarn.lock | 1 + 5 files changed, 22 insertions(+), 28 deletions(-) diff --git a/packages/identity/README.md b/packages/identity/README.md index ab5fb6ab6..7064f48f4 100644 --- a/packages/identity/README.md +++ b/packages/identity/README.md @@ -76,7 +76,7 @@ yarn add @semaphore-protocol/identity import { Identity } from "@semaphore-protocol/identity" // The identity will be generated randomly. -const { privateKey, publicKey } = new Identity() +const { privateKey, publicKey, identityCommitment } = new Identity() // Alternatively, you can pass your private key. const identity = new Identity("your-private-key") @@ -106,7 +106,7 @@ const signature = identity.signMessage(message) identity.verifySignature(message, signature) ``` -\# **Identity.verifySignature**(message: _BigNumberish_, signature: _Signature_, publicKey: _BigNumber_ | _Point_): _boolean_ +\# **Identity.verifySignature**(message: _BigNumberish_, signature: _Signature_, publicKey: _Point_): _boolean_ ```typescript import { Identity } from "@semaphore-protocol/identity" diff --git a/packages/identity/package.json b/packages/identity/package.json index afbcbe9f2..c11b534ac 100644 --- a/packages/identity/package.json +++ b/packages/identity/package.json @@ -36,6 +36,7 @@ "rollup-plugin-typescript2": "^0.31.2" }, "dependencies": { - "@zk-kit/eddsa-poseidon": "0.4.1" + "@zk-kit/eddsa-poseidon": "0.4.1", + "poseidon-lite": "^0.2.0" } } diff --git a/packages/identity/src/identity.test.ts b/packages/identity/src/identity.test.ts index 5cd699579..f0d12a416 100644 --- a/packages/identity/src/identity.test.ts +++ b/packages/identity/src/identity.test.ts @@ -8,19 +8,18 @@ describe("Identity", () => { const identity = new Identity() expect(Buffer.isBuffer(identity.privateKey)).toBeTruthy() - expect(typeof identity.publicKey).toBe("string") expect(typeof identity.secretScalar).toBe("string") - expect(identity.unpackedPublicKey).toHaveLength(2) + expect(identity.publicKey).toHaveLength(2) + expect(typeof identity.identityCommitment).toBe("string") }) it("Should create deterministic identities from a secret (private key)", () => { const identity = new Identity(privateKey) expect(typeof identity.privateKey).toBe("string") - expect(typeof identity.publicKey).toBe("string") expect(typeof identity.secretScalar).toBe("string") - expect(identity.unpackedPublicKey).toHaveLength(2) - expect(typeof identity.unpackedPublicKey[0]).toBe("string") + expect(identity.publicKey).toHaveLength(2) + expect(typeof identity.identityCommitment).toBe("string") }) }) @@ -51,7 +50,6 @@ describe("Identity", () => { const signature = identity.signMessage("message") expect(Identity.verifySignature("message", signature, identity.publicKey)).toBeTruthy() - expect(Identity.verifySignature("message", signature, BigInt(identity.publicKey))).toBeTruthy() }) it("Should verify an external signature with an unpacked public key", () => { @@ -59,7 +57,7 @@ describe("Identity", () => { const signature = identity.signMessage("message") - expect(Identity.verifySignature("message", signature, identity.unpackedPublicKey)).toBeTruthy() + expect(Identity.verifySignature("message", signature, identity.publicKey)).toBeTruthy() }) }) }) diff --git a/packages/identity/src/identity.ts b/packages/identity/src/identity.ts index 0721e5d6d..507f50f95 100644 --- a/packages/identity/src/identity.ts +++ b/packages/identity/src/identity.ts @@ -1,22 +1,20 @@ import { - BigNumber, BigNumberish, Point, Signature, derivePublicKey, deriveSecretScalar, - packPublicKey, signMessage, - unpackPublicKey, verifySignature } from "@zk-kit/eddsa-poseidon" import { randomBytes } from "crypto" +import { poseidon2 } from "poseidon-lite/poseidon2" export default class Identity { private _privateKey: BigNumberish private _secretScalar: string - private _unpackedPublicKey: Point - private _publicKey: string + private _publicKey: Point + private _identityCommitment: string /** * Initializes the class attributes based on the parameters. @@ -26,9 +24,9 @@ export default class Identity { this._privateKey = privateKey this._secretScalar = deriveSecretScalar(privateKey) - this._unpackedPublicKey = derivePublicKey(privateKey) + this._publicKey = derivePublicKey(privateKey) - this._publicKey = packPublicKey(this._unpackedPublicKey) as string + this._identityCommitment = poseidon2(this._publicKey).toString() } /** @@ -51,16 +49,16 @@ export default class Identity { * Returns the public key. * @returns The public key. */ - public get publicKey(): string { + public get publicKey(): Point { return this._publicKey } /** - * Returns the unpacked public key. - * @returns The unpacked public key. + * Returns the identity commitment. + * @returns The identity commitment. */ - public get unpackedPublicKey(): Point { - return this._unpackedPublicKey + public get identityCommitment(): string { + return this._identityCommitment } public signMessage(message: BigNumberish): Signature { @@ -68,14 +66,10 @@ export default class Identity { } public verifySignature(message: BigNumberish, signature: Signature): boolean { - return verifySignature(message, signature, this._unpackedPublicKey) + return verifySignature(message, signature, this._publicKey) } - static verifySignature(message: BigNumberish, signature: Signature, publicKey: BigNumber | Point): boolean { - if (typeof publicKey === "string" || typeof publicKey === "bigint") { - publicKey = unpackPublicKey(publicKey) - } - + static verifySignature(message: BigNumberish, signature: Signature, publicKey: Point): boolean { return verifySignature(message, signature, publicKey) } } diff --git a/yarn.lock b/yarn.lock index 293d1111a..f986a25ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4591,6 +4591,7 @@ __metadata: "@rollup/plugin-commonjs": ^24.0.1 "@rollup/plugin-node-resolve": ^15.0.1 "@zk-kit/eddsa-poseidon": 0.4.1 + poseidon-lite: ^0.2.0 rollup-plugin-cleanup: ^3.2.1 rollup-plugin-typescript2: ^0.31.2 languageName: unknown From c46d100949d8902945cfaa1321c204bb48261ce9 Mon Sep 17 00:00:00 2001 From: cedoor Date: Tue, 12 Dec 2023 14:42:26 +0000 Subject: [PATCH 3/5] feat(group): update group with lean-imt --- packages/group/README.md | 72 ++++++++++++++++++++------- packages/group/package.json | 5 +- packages/group/src/group.test.ts | 82 +++++++++++++------------------ packages/group/src/group.ts | 70 ++++++++++---------------- packages/group/src/hash.ts | 15 ------ packages/group/src/types/index.ts | 3 ++ 6 files changed, 116 insertions(+), 131 deletions(-) delete mode 100644 packages/group/src/hash.ts diff --git a/packages/group/README.md b/packages/group/README.md index 9e3b6373e..0d3594265 100644 --- a/packages/group/README.md +++ b/packages/group/README.md @@ -49,8 +49,8 @@ -| This library is an abstraction of [`@zk-kit/incremental-merkle-tree`](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/incremental-merkle-tree). The main goal is to make it easier to create offchain groups, which are also used to generate Semaphore proofs. Semaphore groups are actually incremental Merkle trees, and the group members are tree leaves. Since the Merkle tree implementation we are using is a binary tree, the maximum number of members of a group is equal to `2^treeDepth`. | -| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| This library is an abstraction of the LeanIMT data structure (part of [`@zk-kit/imt`](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/imt)). The main goal is to make it easier to create offchain groups, which are also used to generate Semaphore proofs. Semaphore groups are actually Merkle trees, and the group members are tree leaves. | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ## 🛠 Install @@ -70,54 +70,88 @@ yarn add @semaphore-protocol/group ## 📜 Usage -\# **new Group**(groupId: _Member_, treeDepth = 20): _Group_ +\# **new Group**(members: _BigNumberish[]_ = []): _Group_ ```typescript import { Group } from "@semaphore-protocol/group" import { Identity } from "@semaphore-protocol/identity" -// Group with max 1048576 members (20^²). -const group1 = new Group(1) +const group1 = new Group() -// Group with max 65536 members (16^²). -const group2 = new Group(1, 16) - -// Group with max 16777216 members (24^²). -const group3 = new Group(1, 24) - -// Group with a list of predefined members. const identity1 = new Identity() const identity2 = new Identity() -const identity3 = new Identity() -const group3 = new Group(1, 16, [identity1.commitment, identity2.commitment, identity3.commitment]) +const group2 = new Group([identity1.commitment, identity2.commitment]) ``` -\# **addMember**(identityCommitment: _Member_) +\# **addMember**(member: _BigNumberish_) ```typescript +import { Group } from "@semaphore-protocol/group" import { Identity } from "@semaphore-protocol/identity" -const identity = new Identity() -const commitment = identity.generateCommitment() +const group = new Group() + +const { commitment } = new Identity() group.addMember(commitment) + +// "12989101133047504182892154686643420754368236204022364847543591045056549053997" +console.log(group.members[0]) +``` + +\# **updateMember**(index: _number_, member: _BigNumberish_) + +```typescript +import { Group } from "@semaphore-protocol/group" + +const group = new Group([1, 3]) + +group.updateMember(0, 2) + +console.log(group.members[0]) // "2" ``` \# **removeMember**(index: _number_) ```typescript +import { Group } from "@semaphore-protocol/group" + +const group = new Group([1, 3]) + group.removeMember(0) + +console.log(group.members[0]) // "0" ``` -\# **indexOf**(member: _Member_): _number_ +\# **indexOf**(member: _BigNumberish_): _number_ ```typescript -group.indexOf(commitment) // 0 +import { Group } from "@semaphore-protocol/group" + +const group = new Group([1]) + +const index = group.indexOf(1) + +console.log(index) // 0 ``` \# **generateMerkleProof**(index: _number_): _MerkleProof_ ```typescript +import { Group } from "@semaphore-protocol/group" + +const group = new Group([1, 3]) + const proof = group.generateMerkleProof(0) + +console.log(proof) +/* +{ + index: 0, + leaf: '1', + root: '21106761926285267690763443010820487107972411248208546226053195422384279971821', + siblings: [ '3' ] +} +*/ ``` diff --git a/packages/group/package.json b/packages/group/package.json index e7c5ebb89..8a31c7d62 100644 --- a/packages/group/package.json +++ b/packages/group/package.json @@ -37,9 +37,6 @@ "rollup-plugin-typescript2": "^0.31.2" }, "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@zk-kit/incremental-merkle-tree": "1.1.0" + "@zk-kit/imt": "^2.0.0-beta" } } diff --git a/packages/group/src/group.test.ts b/packages/group/src/group.test.ts index 0910a3ad5..15a58c744 100644 --- a/packages/group/src/group.test.ts +++ b/packages/group/src/group.test.ts @@ -1,75 +1,56 @@ import Group from "./group" -import hash from "./hash" describe("Group", () => { describe("# Group", () => { it("Should create a group", () => { - const group = new Group(1) + const group = new Group() - expect(group.id).toBe(1) - expect(group.root.toString()).toContain("103543") - expect(group.depth).toBe(20) - expect(group.zeroValue).toBe(hash(1)) - expect(group.members).toHaveLength(0) - }) - - it("Should not create a group with a wrong tree depth", () => { - const fun = () => new Group(1, 33) - - expect(fun).toThrow("The tree depth must be between 16 and 32") - }) - - it("Should create a group with a different tree depth", () => { - const group = new Group(1, 32) - - expect(group.root.toString()).toContain("460373") - expect(group.depth).toBe(32) - expect(group.zeroValue).toBe(hash(1)) - expect(group.members).toHaveLength(0) + expect(group.root).toBeUndefined() + expect(group.depth).toBe(0) + expect(group.size).toBe(0) }) it("Should create a group with a list of members", () => { - const group = new Group(2, 20, [1, 2, 3]) + const group = new Group([1, 2, 3]) - const group2 = new Group(2, 20) + const group2 = new Group() group2.addMember(1) group2.addMember(2) group2.addMember(3) - expect(group.root.toString()).toContain(group2.root.toString()) - expect(group.depth).toBe(20) - expect(group.zeroValue).toBe(hash(2)) - expect(group.members).toHaveLength(3) + expect(group.root).toContain(group2.root) + expect(group.depth).toBe(2) + expect(group.size).toBe(3) }) }) describe("# addMember", () => { it("Should add a member to a group", () => { - const group = new Group(1) + const group = new Group() - group.addMember(BigInt(3)) + group.addMember(3) - expect(group.members).toHaveLength(1) + expect(group.size).toBe(1) }) }) describe("# addMembers", () => { it("Should add many members to a group", () => { - const group = new Group(1) + const group = new Group() - group.addMembers([BigInt(1), BigInt(3)]) + group.addMembers([1, 3]) - expect(group.members).toHaveLength(2) + expect(group.size).toBe(2) }) }) describe("# indexOf", () => { it("Should return the index of a member in a group", () => { - const group = new Group(1) - group.addMembers([BigInt(1), BigInt(3)]) + const group = new Group() + group.addMembers([1, 3]) - const index = group.indexOf(BigInt(3)) + const index = group.indexOf(3) expect(index).toBe(1) }) @@ -77,36 +58,39 @@ describe("Group", () => { describe("# updateMember", () => { it("Should update a member in a group", () => { - const group = new Group(1) - group.addMembers([BigInt(1), BigInt(3)]) + const group = new Group() + group.addMembers([1, 3]) - group.updateMember(0, BigInt(1)) + group.updateMember(0, 1) - expect(group.members).toHaveLength(2) - expect(group.members[0]).toBe(BigInt(1)) + expect(group.size).toBe(2) + expect(group.members[0]).toBe("1") }) }) describe("# removeMember", () => { it("Should remove a member from a group", () => { - const group = new Group(1) - group.addMembers([BigInt(1), BigInt(3)]) + const group = new Group() + group.addMembers([1, 3]) group.removeMember(0) - expect(group.members).toHaveLength(2) - expect(group.members[0]).toBe(group.zeroValue) + expect(group.size).toBe(2) + expect(group.members[0]).toBe("0") }) }) describe("# generateMerkleProof", () => { it("Should generate a proof of membership", () => { - const group = new Group(1) - group.addMembers([BigInt(1), BigInt(3)]) + const group = new Group() + + group.addMembers([1, 3]) const proof = group.generateMerkleProof(0) - expect(proof.leaf).toBe(BigInt(1)) + console.log(proof) + + expect(proof.leaf).toBe("1") }) }) }) diff --git a/packages/group/src/group.ts b/packages/group/src/group.ts index 75534db2b..a295c19e0 100644 --- a/packages/group/src/group.ts +++ b/packages/group/src/group.ts @@ -1,42 +1,24 @@ -import { IncrementalMerkleTree, MerkleProof } from "@zk-kit/incremental-merkle-tree" +import { LeanIMT } from "@zk-kit/imt" import { poseidon2 } from "poseidon-lite/poseidon2" -import hash from "./hash" -import { BigNumberish } from "./types" +import { BigNumberish, MerkleProof } from "./types" export default class Group { - private _id: BigNumberish - - merkleTree: IncrementalMerkleTree + leanIMT: LeanIMT /** * Initializes the group with the group id and the tree depth. - * @param id Group identifier. - * @param treeDepth Tree depth. * @param members List of group members. */ - constructor(id: BigNumberish, treeDepth = 20, members: BigNumberish[] = []) { - if (treeDepth < 16 || treeDepth > 32) { - throw new Error("The tree depth must be between 16 and 32") - } - - this._id = id - this.merkleTree = new IncrementalMerkleTree(poseidon2, treeDepth, hash(id), 2, members.map(BigInt)) - } - - /** - * Returns the id of the group. - * @returns Group id. - */ - get id(): BigNumberish { - return this._id + constructor(members: BigNumberish[] = []) { + this.leanIMT = new LeanIMT((a, b) => poseidon2([a, b]), members.map(BigInt)) } /** * Returns the root hash of the tree. * @returns Root hash. */ - get root(): BigNumberish { - return this.merkleTree.root + get root(): string | undefined { + return this.leanIMT.root?.toString() } /** @@ -44,23 +26,23 @@ export default class Group { * @returns Tree depth. */ get depth(): number { - return this.merkleTree.depth + return this.leanIMT.depth } /** - * Returns the zero value of the tree. - * @returns Tree zero value. + * Returns the size of the tree (i.e. number of leaves). + * @returns Tree depth. */ - get zeroValue(): BigNumberish { - return this.merkleTree.zeroes[0] + get size(): number { + return this.leanIMT.size } /** * Returns the members (i.e. identity commitments) of the group. * @returns List of members. */ - get members(): BigNumberish[] { - return this.merkleTree.leaves + get members(): string[] { + return this.leanIMT.leaves.map(String) } /** @@ -69,7 +51,7 @@ export default class Group { * @returns Index of the member. */ indexOf(member: BigNumberish): number { - return this.merkleTree.indexOf(member) + return this.leanIMT.indexOf(BigInt(member)) } /** @@ -77,18 +59,15 @@ export default class Group { * @param member New member. */ addMember(member: BigNumberish) { - this.merkleTree.insert(BigInt(member)) + this.leanIMT.insert(BigInt(member)) } /** * Adds new members to the group. * @param members New members. - * @deprecated Use the new class parameter to add a list of members. */ addMembers(members: BigNumberish[]) { - for (const member of members) { - this.addMember(member) - } + this.leanIMT.insertMany(members.map(BigInt)) } /** @@ -97,7 +76,7 @@ export default class Group { * @param member New member value. */ updateMember(index: number, member: BigNumberish) { - this.merkleTree.update(index, member) + this.leanIMT.update(index, BigInt(member)) } /** @@ -105,7 +84,7 @@ export default class Group { * @param index Index of the member to be removed. */ removeMember(index: number) { - this.merkleTree.delete(index) + this.leanIMT.update(index, BigInt(0)) } /** @@ -114,10 +93,13 @@ export default class Group { * @returns Proof object. */ generateMerkleProof(index: number): MerkleProof { - const merkleProof = this.merkleTree.createProof(index) + const { leaf, root, siblings } = this.leanIMT.generateProof(index) - merkleProof.siblings = merkleProof.siblings.map((s) => s[0]) - - return merkleProof + return { + index, + leaf: leaf.toString(), + root: root.toString(), + siblings: siblings.map(String) + } } } diff --git a/packages/group/src/hash.ts b/packages/group/src/hash.ts deleted file mode 100644 index c950f7825..000000000 --- a/packages/group/src/hash.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { BigNumber } from "@ethersproject/bignumber" -import { BytesLike, Hexable, zeroPad } from "@ethersproject/bytes" -import { keccak256 } from "@ethersproject/keccak256" - -/** - * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus. - * @param message The message to be hashed. - * @returns The message digest. - */ -export default function hash(message: BytesLike | Hexable | number | bigint): bigint { - message = BigNumber.from(message).toTwos(256).toHexString() - message = zeroPad(message, 32) - - return BigInt(keccak256(message)) >> BigInt(8) -} diff --git a/packages/group/src/types/index.ts b/packages/group/src/types/index.ts index cf1d4d67f..ab547f2ab 100644 --- a/packages/group/src/types/index.ts +++ b/packages/group/src/types/index.ts @@ -1 +1,4 @@ +import { LeanIMTMerkleProof } from "@zk-kit/imt" + export type BigNumberish = string | number | bigint +export type MerkleProof = LeanIMTMerkleProof From b40b61ae56d4bc9d70d668b771b889c0a7c7dda7 Mon Sep 17 00:00:00 2001 From: cedoor Date: Tue, 12 Dec 2023 14:42:56 +0000 Subject: [PATCH 4/5] refactor(identity): update commitment variable name --- packages/identity/README.md | 6 +++--- packages/identity/src/identity.test.ts | 4 ++-- packages/identity/src/identity.ts | 8 ++++---- yarn.lock | 12 +----------- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/packages/identity/README.md b/packages/identity/README.md index 7064f48f4..2c6e3ab6f 100644 --- a/packages/identity/README.md +++ b/packages/identity/README.md @@ -49,8 +49,8 @@ -| This library provides a class that can be used to create identities compatible with the Semaphore [circuits](https://github.com/semaphore-protocol/semaphore/tree/main/circuits). Each identity contains two secret values: _trapdoor_ and _nullifier_, and one public value: _commitment_. The Poseidon hash of the secret values is the identity secret, and its hash is the identity commitment. | -| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| This library provides a class that can be used to create identities compatible with the Semaphore [circuits](https://github.com/semaphore-protocol/semaphore/tree/main/circuits). Each identity contains an EdDSA private key, its public key, and the identity commitment, which is the Poseidon hash of the public key. | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ## 🛠 Install @@ -76,7 +76,7 @@ yarn add @semaphore-protocol/identity import { Identity } from "@semaphore-protocol/identity" // The identity will be generated randomly. -const { privateKey, publicKey, identityCommitment } = new Identity() +const { privateKey, publicKey, commitment } = new Identity() // Alternatively, you can pass your private key. const identity = new Identity("your-private-key") diff --git a/packages/identity/src/identity.test.ts b/packages/identity/src/identity.test.ts index f0d12a416..2d6be45c6 100644 --- a/packages/identity/src/identity.test.ts +++ b/packages/identity/src/identity.test.ts @@ -10,7 +10,7 @@ describe("Identity", () => { expect(Buffer.isBuffer(identity.privateKey)).toBeTruthy() expect(typeof identity.secretScalar).toBe("string") expect(identity.publicKey).toHaveLength(2) - expect(typeof identity.identityCommitment).toBe("string") + expect(typeof identity.commitment).toBe("string") }) it("Should create deterministic identities from a secret (private key)", () => { @@ -19,7 +19,7 @@ describe("Identity", () => { expect(typeof identity.privateKey).toBe("string") expect(typeof identity.secretScalar).toBe("string") expect(identity.publicKey).toHaveLength(2) - expect(typeof identity.identityCommitment).toBe("string") + expect(typeof identity.commitment).toBe("string") }) }) diff --git a/packages/identity/src/identity.ts b/packages/identity/src/identity.ts index 507f50f95..3f64bb07b 100644 --- a/packages/identity/src/identity.ts +++ b/packages/identity/src/identity.ts @@ -14,7 +14,7 @@ export default class Identity { private _privateKey: BigNumberish private _secretScalar: string private _publicKey: Point - private _identityCommitment: string + private _commitment: string /** * Initializes the class attributes based on the parameters. @@ -26,7 +26,7 @@ export default class Identity { this._publicKey = derivePublicKey(privateKey) - this._identityCommitment = poseidon2(this._publicKey).toString() + this._commitment = poseidon2(this._publicKey).toString() } /** @@ -57,8 +57,8 @@ export default class Identity { * Returns the identity commitment. * @returns The identity commitment. */ - public get identityCommitment(): string { - return this._identityCommitment + public get commitment(): string { + return this._commitment } public signMessage(message: BigNumberish): Signature { diff --git a/yarn.lock b/yarn.lock index f986a25ba..79f2d8e12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4543,12 +4543,9 @@ __metadata: version: 0.0.0-use.local resolution: "@semaphore-protocol/group@workspace:packages/group" dependencies: - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/keccak256": ^5.7.0 "@rollup/plugin-commonjs": ^24.0.1 "@rollup/plugin-node-resolve": ^15.0.1 - "@zk-kit/incremental-merkle-tree": 1.1.0 + "@zk-kit/imt": ^2.0.0-beta poseidon-lite: ^0.2.0 rollup-plugin-cleanup: ^3.2.1 rollup-plugin-typescript2: ^0.31.2 @@ -5805,13 +5802,6 @@ __metadata: languageName: node linkType: hard -"@zk-kit/incremental-merkle-tree@npm:1.1.0": - version: 1.1.0 - resolution: "@zk-kit/incremental-merkle-tree@npm:1.1.0" - checksum: 5f2d6dd2a4898aa75f72d5b3811ab965c369f0a51561250313849fb9a6a1163064c4887da3bea298d25e80a4bc79b3c6997edf6492a6a8fc157512bc3fcb5e23 - languageName: node - linkType: hard - "JSONStream@npm:^1.0.4": version: 1.3.5 resolution: "JSONStream@npm:1.3.5" From c3b685b15522e437c53a4222af9752a756f24fac Mon Sep 17 00:00:00 2001 From: cedoor Date: Tue, 12 Dec 2023 18:07:57 +0000 Subject: [PATCH 5/5] feat(proof): update proof package with new circuit --- package.json | 3 +- packages/circuits/circuits.json | 1 + packages/group/src/group.ts | 4 +- packages/proof/package.json | 5 +- packages/proof/src/calculateNullifierHash.ts | 16 - packages/proof/src/generate-proof.ts | 75 ++ packages/proof/src/generateProof.ts | 69 -- .../proof/src/get-snark-artifacts.browser.ts | 9 + .../proof/src/get-snark-artifacts.node.ts | 22 + packages/proof/src/index.test.ts | 93 +-- packages/proof/src/index.ts | 8 +- .../proof/src/{packProof.ts => pack-proof.ts} | 0 packages/proof/src/types/index.ts | 10 +- .../src/{unpackProof.ts => unpack-proof.ts} | 0 packages/proof/src/verification-keys.json | 104 +++ packages/proof/src/verificationKeys.json | 712 ------------------ packages/proof/src/verify-proof.ts | 28 + packages/proof/src/verifyProof.ts | 31 - scripts/download-snark-artifacts.ts | 30 - yarn.lock | 32 +- 20 files changed, 300 insertions(+), 952 deletions(-) delete mode 100644 packages/proof/src/calculateNullifierHash.ts create mode 100644 packages/proof/src/generate-proof.ts delete mode 100644 packages/proof/src/generateProof.ts create mode 100644 packages/proof/src/get-snark-artifacts.browser.ts create mode 100644 packages/proof/src/get-snark-artifacts.node.ts rename packages/proof/src/{packProof.ts => pack-proof.ts} (100%) rename packages/proof/src/{unpackProof.ts => unpack-proof.ts} (100%) create mode 100644 packages/proof/src/verification-keys.json delete mode 100644 packages/proof/src/verificationKeys.json create mode 100644 packages/proof/src/verify-proof.ts delete mode 100644 packages/proof/src/verifyProof.ts delete mode 100644 scripts/download-snark-artifacts.ts diff --git a/package.json b/package.json index 1a80d8820..6bf38058b 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "scripts": { "build:libraries": "yarn workspaces foreach -t --no-private run build", "compile:contracts": "yarn workspace contracts compile", - "download:snark-artifacts": "rimraf snark-artifacts && ts-node scripts/download-snark-artifacts.ts", "remove:template-files": "ts-node scripts/remove-template-files.ts", "test": "yarn test:libraries && yarn test:contracts && yarn test:circuits", "test:libraries": "jest --coverage", @@ -24,7 +23,7 @@ "version:release": "changelogithub", "commit": "cz", "precommit": "lint-staged", - "postinstall": "yarn download:snark-artifacts && husky install" + "postinstall": "husky install" }, "keywords": [ "ethereum", diff --git a/packages/circuits/circuits.json b/packages/circuits/circuits.json index bf4a378f7..e4f3ab025 100644 --- a/packages/circuits/circuits.json +++ b/packages/circuits/circuits.json @@ -2,6 +2,7 @@ "semaphore": { "file": "semaphore", "template": "Semaphore", + "pubs": ["message", "scope"], "params": [10] } } diff --git a/packages/group/src/group.ts b/packages/group/src/group.ts index a295c19e0..595b3ec7c 100644 --- a/packages/group/src/group.ts +++ b/packages/group/src/group.ts @@ -92,8 +92,8 @@ export default class Group { * @param index Index of the proof's member. * @returns Proof object. */ - generateMerkleProof(index: number): MerkleProof { - const { leaf, root, siblings } = this.leanIMT.generateProof(index) + generateMerkleProof(_index: number): MerkleProof { + const { index, leaf, root, siblings } = this.leanIMT.generateProof(_index) return { index, diff --git a/packages/proof/package.json b/packages/proof/package.json index 1f1af6676..bc3089389 100644 --- a/packages/proof/package.json +++ b/packages/proof/package.json @@ -33,6 +33,8 @@ "@rollup/plugin-commonjs": "^24.1.0", "@rollup/plugin-json": "^5.0.1", "@rollup/plugin-node-resolve": "^15.0.2", + "@types/download": "^8.0.5", + "@types/tmp": "^0.2.6", "poseidon-lite": "^0.2.0", "rimraf": "^5.0.5", "rollup": "^4.0.2", @@ -49,6 +51,7 @@ "@ethersproject/keccak256": "^5.7.0", "@ethersproject/strings": "^5.5.0", "@zk-kit/groth16": "0.3.0", - "@zk-kit/incremental-merkle-tree": "0.4.3" + "download": "^8.0.0", + "tmp": "^0.2.1" } } diff --git a/packages/proof/src/calculateNullifierHash.ts b/packages/proof/src/calculateNullifierHash.ts deleted file mode 100644 index 8cca53343..000000000 --- a/packages/proof/src/calculateNullifierHash.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { BytesLike, Hexable } from "@ethersproject/bytes" -import { poseidon2 } from "poseidon-lite" -import hash from "./hash" - -/** - * Given the identity nullifier and the external nullifier, it calculates nullifier hash. - * @param identityNullifier The identity nullifier. - * @param externalNullifier The external nullifier. - * @returns The nullifier hash. - */ -export default function calculateNullifierHash( - identityNullifier: number | bigint | string, - externalNullifier: BytesLike | Hexable | number | bigint -): bigint { - return poseidon2([hash(externalNullifier), identityNullifier]) -} diff --git a/packages/proof/src/generate-proof.ts b/packages/proof/src/generate-proof.ts new file mode 100644 index 000000000..30fd32f93 --- /dev/null +++ b/packages/proof/src/generate-proof.ts @@ -0,0 +1,75 @@ +import { BigNumber } from "@ethersproject/bignumber" +import { BytesLike, Hexable } from "@ethersproject/bytes" +import { Group } from "@semaphore-protocol/group" +import type { Identity } from "@semaphore-protocol/identity" +import { prove } from "@zk-kit/groth16" +import type { NumericString } from "snarkjs" +import getSnarkArtifacts from "./get-snark-artifacts.node" +import hash from "./hash" +import packProof from "./pack-proof" +import { SemaphoreProof, SnarkArtifacts } from "./types" + +/** + * Generates a Semaphore proof. + * @param identity The Semaphore identity. + * @param group The Semaphore group or its Merkle proof. + * @param scope The external nullifier. + * @param message The Semaphore signal. + * @param treeDepth The depth of the tree with which the circuit was compiled. + * @param snarkArtifacts The SNARK artifacts. + * @returns The Semaphore proof ready to be verified. + */ +export default async function generateProof( + identity: Identity, + group: Group, + scope: BytesLike | Hexable | number | bigint, + message: BytesLike | Hexable | number | bigint, + treeDepth?: number, + snarkArtifacts?: SnarkArtifacts +): Promise { + const leafIndex = group.indexOf(identity.commitment) + const merkeProof = group.generateMerkleProof(leafIndex) + const merkleProofLength = merkeProof.siblings.length + + treeDepth ??= merkleProofLength + + // If the Snark artifacts are not defined they will be automatically downloaded. + /* istanbul ignore next */ + if (!snarkArtifacts) { + snarkArtifacts = await getSnarkArtifacts(treeDepth) + } + + // The index must be converted to a list of indices, 1 for each tree level. + // The missing siblings can be set to 0, as they won't be used in the circuit. + const treeIndices = [] + const treeSiblings = merkeProof.siblings + + for (let i = 0; i < treeDepth; i += 1) { + treeIndices.push((merkeProof.index >> i) & 1) + + if (treeSiblings[i] === undefined) { + treeSiblings[i] = "0" + } + } + + const { proof, publicSignals } = await prove( + { + privateKey: identity.secretScalar, + treeDepth: merkleProofLength, + treeIndices, + treeSiblings, + scope: hash(scope), + message: hash(message) + }, + snarkArtifacts.wasmFilePath, + snarkArtifacts.zkeyFilePath + ) + + return { + treeRoot: publicSignals[0], + nullifier: publicSignals[1], + scope: BigNumber.from(scope).toString() as NumericString, + message: BigNumber.from(message).toString() as NumericString, + proof: packProof(proof) + } +} diff --git a/packages/proof/src/generateProof.ts b/packages/proof/src/generateProof.ts deleted file mode 100644 index 1407ce1ca..000000000 --- a/packages/proof/src/generateProof.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { BigNumber } from "@ethersproject/bignumber" -import { BytesLike, Hexable } from "@ethersproject/bytes" -import { Group } from "@semaphore-protocol/group" -import type { Identity } from "@semaphore-protocol/identity" -import { prove } from "@zk-kit/groth16" -import { MerkleProof } from "@zk-kit/incremental-merkle-tree" -import type { NumericString } from "snarkjs" -import hash from "./hash" -import packProof from "./packProof" -import { SemaphoreProof, SnarkArtifacts } from "./types" - -/** - * Generates a Semaphore proof. - * @param identity The Semaphore identity. - * @param groupOrMerkleProof The Semaphore group or its Merkle proof. - * @param externalNullifier The external nullifier. - * @param signal The Semaphore signal. - * @param snarkArtifacts The SNARK artifacts. - * @returns The Semaphore proof ready to be verified. - */ -export default async function generateProof( - { trapdoor, nullifier, commitment }: Identity, - groupOrMerkleProof: Group | MerkleProof, - externalNullifier: BytesLike | Hexable | number | bigint, - signal: BytesLike | Hexable | number | bigint, - snarkArtifacts?: SnarkArtifacts -): Promise { - let merkleProof: MerkleProof - - if ("depth" in groupOrMerkleProof) { - const index = groupOrMerkleProof.indexOf(commitment) - - if (index === -1) { - throw new Error("The identity is not part of the group") - } - - merkleProof = groupOrMerkleProof.generateMerkleProof(index) - } else { - merkleProof = groupOrMerkleProof - } - - if (!snarkArtifacts) { - snarkArtifacts = { - wasmFilePath: `https://www.trusted-setup-pse.org/semaphore/${merkleProof.siblings.length}/semaphore.wasm`, - zkeyFilePath: `https://www.trusted-setup-pse.org/semaphore/${merkleProof.siblings.length}/semaphore.zkey` - } - } - - const { proof, publicSignals } = await prove( - { - identityTrapdoor: trapdoor, - identityNullifier: nullifier, - treePathIndices: merkleProof.pathIndices, - treeSiblings: merkleProof.siblings, - externalNullifier: hash(externalNullifier), - signalHash: hash(signal) - }, - snarkArtifacts.wasmFilePath, - snarkArtifacts.zkeyFilePath - ) - - return { - merkleTreeRoot: publicSignals[0], - nullifierHash: publicSignals[1], - signal: BigNumber.from(signal).toString() as NumericString, - externalNullifier: BigNumber.from(externalNullifier).toString() as NumericString, - proof: packProof(proof) - } -} diff --git a/packages/proof/src/get-snark-artifacts.browser.ts b/packages/proof/src/get-snark-artifacts.browser.ts new file mode 100644 index 000000000..f85a5492c --- /dev/null +++ b/packages/proof/src/get-snark-artifacts.browser.ts @@ -0,0 +1,9 @@ +/* istanbul ignore file */ +import { SnarkArtifacts } from "./types" + +export default async function getSnarkArtifacts(treeDepth: number): Promise { + return { + wasmFilePath: `https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.wasm`, + zkeyFilePath: `https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.zkey` + } +} diff --git a/packages/proof/src/get-snark-artifacts.node.ts b/packages/proof/src/get-snark-artifacts.node.ts new file mode 100644 index 000000000..70fd4226f --- /dev/null +++ b/packages/proof/src/get-snark-artifacts.node.ts @@ -0,0 +1,22 @@ +/* istanbul ignore file */ +import download from "download" +import fs from "fs" +import tmp from "tmp" +import { SnarkArtifacts } from "./types" + +export default async function getSnarkArtifacts(treeDepth: number): Promise { + const tmpDir = "semaphore-proof" + const tmpPath = `${tmp.tmpdir}/${tmpDir}` + + if (!fs.existsSync(tmpPath)) { + tmp.dirSync({ name: tmpDir }) + + await download(`https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.wasm`, tmpPath) + await download(`https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.zkey`, tmpPath) + } + + return { + wasmFilePath: `${tmpPath}/semaphore.wasm`, + zkeyFilePath: `${tmpPath}/semaphore.zkey` + } +} diff --git a/packages/proof/src/index.test.ts b/packages/proof/src/index.test.ts index 420a45bec..a1153eb9b 100644 --- a/packages/proof/src/index.test.ts +++ b/packages/proof/src/index.test.ts @@ -2,24 +2,20 @@ import { formatBytes32String } from "@ethersproject/strings" import { Group } from "@semaphore-protocol/group" import { Identity } from "@semaphore-protocol/identity" import { getCurveFromName } from "ffjavascript" -import calculateNullifierHash from "./calculateNullifierHash" -import generateProof from "./generateProof" +import generateProof from "./generate-proof" import hash from "./hash" -import packProof from "./packProof" +import packProof from "./pack-proof" import { SemaphoreProof } from "./types" -import unpackProof from "./unpackProof" -import verifyProof from "./verifyProof" +import unpackProof from "./unpack-proof" +import verifyProof from "./verify-proof" describe("Proof", () => { - const treeDepth = Number(process.env.TREE_DEPTH) || 20 + const treeDepth = 10 - const externalNullifier = formatBytes32String("Topic") - const signal = formatBytes32String("Hello world") + const scope = formatBytes32String("Scope") + const message = formatBytes32String("Hello world") - const wasmFilePath = `./snark-artifacts/${treeDepth}/semaphore.wasm` - const zkeyFilePath = `./snark-artifacts/${treeDepth}/semaphore.zkey` - - const identity = new Identity() + const identity = new Identity(42) let fullProof: SemaphoreProof let curve: any @@ -34,77 +30,42 @@ describe("Proof", () => { describe("# generateProof", () => { it("Should not generate Semaphore proofs if the identity is not part of the group", async () => { - const group = new Group(treeDepth, 20, [BigInt(1), BigInt(2)]) - - const fun = () => - generateProof(identity, group, externalNullifier, signal, { - wasmFilePath, - zkeyFilePath - }) - - await expect(fun).rejects.toThrow("The identity is not part of the group") - }) - - it("Should not generate a Semaphore proof with default snark artifacts with Node.js", async () => { - const group = new Group(treeDepth, 20, [BigInt(1), BigInt(2), identity.commitment]) + const group = new Group([BigInt(1), BigInt(2)]) - const fun = () => generateProof(identity, group, externalNullifier, signal) + const fun = () => generateProof(identity, group, scope, message, treeDepth) - await expect(fun).rejects.toThrow("ENOENT: no such file or directory") + await expect(fun).rejects.toThrow("does not exist") }) - it("Should generate a Semaphore proof passing a group as parameter", async () => { - const group = new Group(treeDepth, 20, [BigInt(1), BigInt(2), identity.commitment]) - - fullProof = await generateProof(identity, group, externalNullifier, signal, { - wasmFilePath, - zkeyFilePath - }) - - expect(typeof fullProof).toBe("object") - expect(fullProof.merkleTreeRoot).toBe(group.root.toString()) - }, 20000) - - it("Should generate a Semaphore proof passing a Merkle proof as parameter", async () => { - const group = new Group(treeDepth, 20, [BigInt(1), BigInt(2), identity.commitment]) + it("Should generate a Semaphore proof", async () => { + const group = new Group([BigInt(1), BigInt(2), identity.commitment]) - fullProof = await generateProof(identity, group.generateMerkleProof(2), externalNullifier, signal, { - wasmFilePath, - zkeyFilePath - }) + fullProof = await generateProof(identity, group, scope, message, treeDepth) expect(typeof fullProof).toBe("object") - expect(fullProof.merkleTreeRoot).toBe(group.root.toString()) - }, 20000) + expect(fullProof.treeRoot).toBe(group.root) + }) }) describe("# verifyProof", () => { - it("Should not verify a proof if the tree depth is wrong", () => { - const fun = () => verifyProof(fullProof, 3) - - expect(fun).toThrow("The tree depth must be a number between 16 and 32") - }) - it("Should verify a Semaphore proof", async () => { - const response = await verifyProof(fullProof, treeDepth) + const response = await verifyProof(fullProof) expect(response).toBe(true) }) }) describe("# hash", () => { - it("Should hash the signal value correctly", async () => { - const signalHash = hash(signal) + it("Should hash the message correctly", async () => { + const messageHash = hash(message) - expect(signalHash).toBe("8665846418922331996225934941481656421248110469944536651334918563951783029") + expect(messageHash).toBe("8665846418922331996225934941481656421248110469944536651334918563951783029") }) - it("Should hash the external nullifier value correctly", async () => { - const externalNullifierHash = hash(externalNullifier) + it("Should hash the scope correctly", async () => { + const scopeHash = hash(scope) - expect(externalNullifierHash).toBe( - "244178201824278269437519042830883072613014992408751798420801126401127326826" - ) + expect(scopeHash).toBe("170164770795872309789133717676167925425155944778337387941930839678899666300") }) it("Should hash a number", async () => { @@ -128,14 +89,6 @@ describe("Proof", () => { }) }) - describe("# calculateNullifierHash", () => { - it("Should calculate the nullifier hash correctly", async () => { - const nullifierHash = calculateNullifierHash(identity.nullifier, externalNullifier) - - expect(fullProof.nullifierHash).toBe(nullifierHash.toString()) - }) - }) - describe("# packProof/unpackProof", () => { it("Should return a packed proof", async () => { const originalProof = unpackProof(fullProof.proof) diff --git a/packages/proof/src/index.ts b/packages/proof/src/index.ts index 72d4e1389..829102cfd 100644 --- a/packages/proof/src/index.ts +++ b/packages/proof/src/index.ts @@ -1,7 +1,5 @@ -import calculateNullifierHash from "./calculateNullifierHash" -import generateProof from "./generateProof" -import verifyProof from "./verifyProof" +import generateProof from "./generate-proof" +import verifyProof from "./verify-proof" -export { MerkleProof } from "@zk-kit/incremental-merkle-tree" export * from "./types" -export { generateProof, verifyProof, calculateNullifierHash } +export { generateProof, verifyProof } diff --git a/packages/proof/src/packProof.ts b/packages/proof/src/pack-proof.ts similarity index 100% rename from packages/proof/src/packProof.ts rename to packages/proof/src/pack-proof.ts diff --git a/packages/proof/src/types/index.ts b/packages/proof/src/types/index.ts index aa320d9ad..d9382e6eb 100644 --- a/packages/proof/src/types/index.ts +++ b/packages/proof/src/types/index.ts @@ -1,4 +1,4 @@ -import type { NumericString } from "snarkjs" +import type { NumericString } from "@zk-kit/groth16" export type SnarkArtifacts = { wasmFilePath: string @@ -6,10 +6,10 @@ export type SnarkArtifacts = { } export type SemaphoreProof = { - merkleTreeRoot: NumericString - signal: NumericString - nullifierHash: NumericString - externalNullifier: NumericString + treeRoot: NumericString + message: NumericString + nullifier: NumericString + scope: NumericString proof: PackedProof } diff --git a/packages/proof/src/unpackProof.ts b/packages/proof/src/unpack-proof.ts similarity index 100% rename from packages/proof/src/unpackProof.ts rename to packages/proof/src/unpack-proof.ts diff --git a/packages/proof/src/verification-keys.json b/packages/proof/src/verification-keys.json new file mode 100644 index 000000000..696c2b008 --- /dev/null +++ b/packages/proof/src/verification-keys.json @@ -0,0 +1,104 @@ +{ + "protocol": "groth16", + "curve": "bn128", + "nPublic": 4, + "vk_alpha_1": [ + "20491192805390485299153009773594534940189261866228447918068658471970481763042", + "9383485363053290200918347156157836566562967994039712273449902621266178545958", + "1" + ], + "vk_beta_2": [ + [ + "6375614351688725206403948262868962793625744043794305715222011528459656738731", + "4252822878758300859123897981450591353533073413197771768651442665752259397132" + ], + [ + "10505242626370262277552901082094356697409835680220590971873171140371331206856", + "21847035105528745403288232691147584728191162732299865338377159692350059136679" + ], + ["1", "0"] + ], + "vk_gamma_2": [ + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634" + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531" + ], + ["1", "0"] + ], + "vk_delta_2": [ + [ + [ + "1203033843370190352679536156318647846963070791761882784581562957032940878631", + "8079358190325697178560398569841376952804277857152452363880610878513176978414" + ], + [ + "1709663807054049176405784021595122468175326469739885095843389206914547034049", + "5323102298870768887773635223311040590195621468735208775728981925050238645973" + ], + ["1", "0"] + ] + ], + "vk_alphabeta_12": [ + [ + [ + "2029413683389138792403550203267699914886160938906632433982220835551125967885", + "21072700047562757817161031222997517981543347628379360635925549008442030252106" + ], + [ + "5940354580057074848093997050200682056184807770593307860589430076672439820312", + "12156638873931618554171829126792193045421052652279363021382169897324752428276" + ], + [ + "7898200236362823042373859371574133993780991612861777490112507062703164551277", + "7074218545237549455313236346927434013100842096812539264420499035217050630853" + ] + ], + [ + [ + "7077479683546002997211712695946002074877511277312570035766170199895071832130", + "10093483419865920389913245021038182291233451549023025229112148274109565435465" + ], + [ + "4595479056700221319381530156280926371456704509942304414423590385166031118820", + "19831328484489333784475432780421641293929726139240675179672856274388269393268" + ], + [ + "11934129596455521040620786944827826205713621633706285934057045369193958244500", + "8037395052364110730298837004334506829870972346962140206007064471173334027475" + ] + ] + ], + "IC": [ + [ + [ + "7810627885438804854799393101615420860004300484567847086674409667961806655819", + "17752894058911463947056561254031971003439956976683150238952280384884265610345", + "1" + ], + [ + "1859027844886249956101358092211425783821368393550326618436626137559481879491", + "21054817398797605484546956719908640544118839476669181800056403255004730797738", + "1" + ], + [ + "15796976765804300435452771769828280808531244272386620395606681167033336150695", + "903968937841233929826399002238948203245370749106069849010375461873649600286", + "1" + ], + [ + "9939447176137952809861441974771884976492003509733419789700227062163769465749", + "10252048733134373819769164658668132695840284406808712977431939424744406823235", + "1" + ], + [ + "7393464059707248328549959352154443030400062088967711800345697753542770722400", + "7750652018971809526357985723000957185438256496025176410178561237545956517939", + "1" + ] + ] + ] +} diff --git a/packages/proof/src/verificationKeys.json b/packages/proof/src/verificationKeys.json deleted file mode 100644 index 9de3064fe..000000000 --- a/packages/proof/src/verificationKeys.json +++ /dev/null @@ -1,712 +0,0 @@ -{ - "protocol": "groth16", - "curve": "bn128", - "nPublic": 4, - "vk_alpha_1": [ - "20491192805390485299153009773594534940189261866228447918068658471970481763042", - "9383485363053290200918347156157836566562967994039712273449902621266178545958", - "1" - ], - "vk_beta_2": [ - [ - "6375614351688725206403948262868962793625744043794305715222011528459656738731", - "4252822878758300859123897981450591353533073413197771768651442665752259397132" - ], - [ - "10505242626370262277552901082094356697409835680220590971873171140371331206856", - "21847035105528745403288232691147584728191162732299865338377159692350059136679" - ], - ["1", "0"] - ], - "vk_gamma_2": [ - [ - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - "11559732032986387107991004021392285783925812861821192530917403151452391805634" - ], - [ - "8495653923123431417604973247489272438418190587263600148770280649306958101930", - "4082367875863433681332203403145435568316851327593401208105741076214120093531" - ], - ["1", "0"] - ], - "vk_delta_2": [ - [ - [ - "16243966861079634958125511652590761846958471358623040426599000904006426210032", - "13406811599156507528361773763681356312643537981039994686313383243831956396116" - ], - [ - "15688083679237922164673518758181461582601853873216319711156397437601833996222", - "11781596534582143578120404722739278517564025497573071755253972265891888117374" - ], - ["1", "0"] - ], - [ - [ - "13589689305661231568162336263197960570915890299814486885851912452076929115480", - "15629200772768268814959330350023920183087521275477047626405113853190187031523" - ], - [ - "16004221700357242255845535848024178544616388017965468694776181247983831995562", - "11464919285924930973853174493551975632739604254498590354200272115844983493029" - ], - ["1", "0"] - ], - [ - [ - "19717684456458906358368865507225121991585492363133107109865920739019288468011", - "9218320951536642499143228327011901814587826948504871816273184688188019956292" - ], - [ - "18221695645112467945186983098720611586049108689347006136423489099202471884089", - "16717590750910963405756115910371408378114896008824240863060392362901176601412" - ], - ["1", "0"] - ], - [ - [ - "15953239752392927777442331623182226063776310198012173504208557434319753428770", - "3995128789564535587814512245259203300137618476815456454931286633947953135662" - ], - [ - "2523786679709693946058523307330825034772478122295850507521258983130425334580", - "20957319343912866335583737646657534123362052690050674068142580221965936605075" - ], - ["1", "0"] - ], - [ - [ - "1382518990777992893805140303684642328066746531257780279226677247567004248173", - "18976133691706015337908381757202123182841901611067930614519324084182946094218" - ], - [ - "21806956747910197517744499423107239699428979652113081469385876768212706694581", - "6627710380771660558660627878547223719795356903257079198333641681330388499309" - ], - ["1", "0"] - ], - [ - [ - "9032545080831535702239063467087720597970266046938395860207839433937324718536", - "3811592683283527904145155808200366192489850711742363953668998371801696238057" - ], - [ - "12429982191499850873612518410809641163252887523090441166572590809691267943605", - "16308433125974933290258540904373317426123214107276055539769464205982500660715" - ], - ["1", "0"] - ], - [ - [ - "17626503110323089701269363177710295379967225765713250625279671011873619640598", - "9485639152672984144988597737758037391807993615552051606205480347442429414340" - ], - [ - "18953587685067712486092665232725058638563458484886448540567142557894080640927", - "12391874700409435648975069978280047983726144854114915177376036190441913967689" - ], - ["1", "0"] - ], - [ - [ - "11408965575174993375815840422438995549652812400401163392501956884932167624437", - "9830856103389248449121962275587399130605902703453384856543071762984116567573" - ], - [ - "19969543376625663966419118899515353499678204573709836615846115182224340858492", - "11814906841949499037550820576929552248172160643991870665022770052632331265834" - ], - ["1", "0"] - ], - [ - [ - "10090041889587324002759549286390619541526396451963494627957072069124011137562", - "15035335306919942325459417688135340085377315274625768597233474641923619728582" - ], - [ - "10507786999799841055999967456762679569286329319056926475375760604262707147294", - "21342049717074059749518233491526445388158772701642182532370641230478027030319" - ], - ["1", "0"] - ], - [ - [ - "43456740675249348549891878341522275183186932745162972528932808393415299552", - "15718373132479769904443326381037437528372212185108294117696143473979328398658" - ], - [ - "4289247401578837038775845192875793775418122783738936298355403103074020081838", - "11236864934894600819960883124570686936554376109344998527334431594565774237827" - ], - ["1", "0"] - ], - [ - [ - "4023016874169005249382064394379671330447496454371261692205411970999350949293", - "1723458149089715907994189658689343304709709060535625667210252753337752162173" - ], - [ - "17710652158212212080502343565075513548898593397103675832636832371532093744857", - "7651670126664625790835334090273463062538865895183205964669372719235003083565" - ], - ["1", "0"] - ], - [ - [ - "13132169670125192016391258838554965176628317453468870968867717287446623320643", - "745924679191739894055143748466112994378439645681039136007774787076115375124" - ], - [ - "20909608709868730010029182074820840312550443752829480953667886902663547957991", - "2126777833939378028304266129616145667925849332481755567268747182629795296580" - ], - ["1", "0"] - ], - [ - [ - "16835654219229187428071649241190746119082269636345872682107941472241044260584", - "4553625243522856553165922942982108474187282402890756796515747778282922584601" - ], - [ - "873742823867191038535544062852920538566418819521732785500614249239215175476", - "3272293478534046729728233267765357195255129499603632413158978822084188871854" - ], - ["1", "0"] - ], - [ - [ - "7601443214415704135008588588192028557655441716696726549510699770097979655628", - "7252337675475138150830402909353772156046809729627064992143762325769537840623" - ], - [ - "18500126298578278987997086114400065402270866280547473913420536595663876273004", - "436607343827794507835462908831699962173244647704538949914686722631806931932" - ], - ["1", "0"] - ], - [ - [ - "15028154694713144242204861571552635520290993855826554325002991692907421516918", - "10202326166286888893675634318107715186834588694714750762952081034135561546271" - ], - [ - "12766289885372833812620582632847872978085960777075662988932200910695848591357", - "18486039841380105976272577521609866666900576498507352937328726490052296469859" - ], - ["1", "0"] - ], - [ - [ - "13682963731073238132274278610660469286329368216526659590944079211949686450402", - "14930624777162656776068112402283260602512252179767747308433194885322661150422" - ], - [ - "21315724107376627085778492378001676935454590984229146391746301404292016287653", - "18705481657148807016785305378773304476425591636333098330324049960258682574070" - ], - ["1", "0"] - ], - [ - [ - "18994803742708336446369128568423705404354655742604689352630273180469431952708", - "12315240965742683516581565369496371929586281338862761742109651525191835544242" - ], - [ - "12707009780301102830224094192984906206920666691015255692741008594808694787917", - "18019403342409608922812569436317484250134945386869657285229378095251425778096" - ], - ["1", "0"] - ] - ], - "vk_alphabeta_12": [ - [ - [ - "2029413683389138792403550203267699914886160938906632433982220835551125967885", - "21072700047562757817161031222997517981543347628379360635925549008442030252106" - ], - [ - "5940354580057074848093997050200682056184807770593307860589430076672439820312", - "12156638873931618554171829126792193045421052652279363021382169897324752428276" - ], - [ - "7898200236362823042373859371574133993780991612861777490112507062703164551277", - "7074218545237549455313236346927434013100842096812539264420499035217050630853" - ] - ], - [ - [ - "7077479683546002997211712695946002074877511277312570035766170199895071832130", - "10093483419865920389913245021038182291233451549023025229112148274109565435465" - ], - [ - "4595479056700221319381530156280926371456704509942304414423590385166031118820", - "19831328484489333784475432780421641293929726139240675179672856274388269393268" - ], - [ - "11934129596455521040620786944827826205713621633706285934057045369193958244500", - "8037395052364110730298837004334506829870972346962140206007064471173334027475" - ] - ] - ], - "IC": [ - [ - [ - "1964404930528116823793003656764176108669615750422202377358993070935069307720", - "2137714996673694828207437580381836490878070731768805974506391024595988817424", - "1" - ], - [ - "19568893707760843340848992184233194433177372925415116053368211122719346671126", - "11639469568629189918046964192305250472192697612201524135560178632824282818614", - "1" - ], - [ - "5317268879687484957437879782519918549127939892210247573193613900261494313825", - "528174394975085006443543773707702838726735933116136102590448357278717993744", - "1" - ], - [ - "14865918005176722116473730206622066845866539143554731094374354951675249722731", - "3197770568483953664363740385883457803041685902965668289308665954510373380344", - "1" - ], - [ - "6863358721495494421022713667808247652425178970453300712435830652679038918987", - "15025816433373311798308762709072064417001390853103872064614174594927359131281", - "1" - ] - ], - [ - [ - "17789438292552571310739605737896030466581277887660997531707911256058650850910", - "4112657509505371631825493224748310061184972897405589115208158208294581472016", - "1" - ], - [ - "3322052920119834475842380240689494113984887785733316517680891208549118967155", - "381029395779795399840019487059126246243641886087320875571067736504031557148", - "1" - ], - [ - "8777645223617381095463415690983421308854368583891690388850387317049320450400", - "11923582117369144413749726090967341613266070909169947059497952692052020331958", - "1" - ], - [ - "15493263571528401950994933073246603557158047091963487223668240334879173885581", - "6315532173951617115856055775098532808695228294437279844344466163873167020700", - "1" - ], - [ - "3481637421055377106140197938175958155334313900824697193932986771017625492245", - "20088416136090515091300914661950097694450984520235647990572441134215240947932", - "1" - ] - ], - [ - [ - "4691595252082380256698158158199364410440273386659834000993210659508747323919", - "9205801980459323513061837717352821162780471027241700646145937351740096374660", - "1" - ], - [ - "16150531426263112884093068164597994126623437929929609532055221646496813246000", - "20245743178241899668170758952526381872637304119026868520579207157118516761827", - "1" - ], - [ - "6063536446992770713985314309889717594240410784717230886576072989709763902848", - "18258781411255795973918859665416013869184055573057512603788635470145328981347", - "1" - ], - [ - "10109932964756104512054045207253535333686585863745296080906925765480296575285", - "4174640428253153601540284363759502713687021920150940723252842152556151210349", - "1" - ], - [ - "18049428534741480832385046397049175120355008065781483226058177421025493210952", - "591730261265040164434889324846001338201068482543108348317417391345612814922", - "1" - ] - ], - [ - [ - "9877211178693075145402462781884120278654771727348087433632224794894486095150", - "19972682062587174829535281061580296764150591339640180868104711395548066529340", - "1" - ], - [ - "6324578424031095537345184040149690238371517387586958921377481904541316423724", - "15513931720576048544404512239839508014664224085062729779520992909505663748296", - "1" - ], - [ - "11371337652479737143800707796204655130812036287859296372695832558127430723628", - "11757275188600040111649009832378343123994225623498773406233261322165903848967", - "1" - ], - [ - "13282496583564708104981015168203451877588903263486398132954741568835583461335", - "1746144324840370907926720490289700342734912534857331743685374514401176014195", - "1" - ], - [ - "7993952462467372951144011615584426050192046712674662254138390197508963352374", - "5156942148925224345709309361345680948125600198010285179548841917923439945819", - "1" - ] - ], - [ - [ - "19918517214839406678907482305035208173510172567546071380302965459737278553528", - "7151186077716310064777520690144511885696297127165278362082219441732663131220", - "1" - ], - [ - "690581125971423619528508316402701520070153774868732534279095503611995849608", - "21271996888576045810415843612869789314680408477068973024786458305950370465558", - "1" - ], - [ - "16461282535702132833442937829027913110152135149151199860671943445720775371319", - "2814052162479976678403678512565563275428791320557060777323643795017729081887", - "1" - ], - [ - "4319780315499060392574138782191013129592543766464046592208884866569377437627", - "13920930439395002698339449999482247728129484070642079851312682993555105218086", - "1" - ], - [ - "3554830803181375418665292545416227334138838284686406179598687755626325482686", - "5951609174746846070367113593675211691311013364421437923470787371738135276998", - "1" - ] - ], - [ - [ - "9494885690931955877467315318223108618392113101843890678090902614660136056680", - "11783514256715757384821021009301806722951917744219075907912683963173706887379", - "1" - ], - [ - "7562082660623781416745328104576133910743071878837764423695105915778139873834", - "17954307004260053757579194018551114133664721761483240877658498973152950708099", - "1" - ], - [ - "19338184851116432029108109461622579541195083625346674255186169347975445785058", - "38361206266360048012365562393026952048730052530888439195454086987795985927", - "1" - ], - [ - "21178537742782571863590222710872928190886000600239072595684369348717288330049", - "9786438258541172244884631831247223050494423968411444302812755467521949734320", - "1" - ], - [ - "11330504221972341797183339350494223413034293674225690456356444509688810101433", - "1490009915387901405464437253469086864085891770312035292355706249426866485365", - "1" - ] - ], - [ - [ - "21791720972262589799021600767292883644106575897307484548888696814333235336885", - "11092962469758788187888592619035811117815082357439060720677582048880121542623", - "1" - ], - [ - "9418924955930663972575130074928583215922927562059194231976193350658171304436", - "16113558481826020406162261319744796072664750077095575593106901121115073101408", - "1" - ], - [ - "20054934960262983176880675919444457578562219675808407582143519621873973120773", - "14877415271301547911435683263206245199959943680225555496786470669330176961657", - "1" - ], - [ - "4215199263810110748751715719957184804379752373072771007598572158043965517488", - "5225943468606602818132879686778547605180105897615251160509064537462109826521", - "1" - ], - [ - "6250242626034734280813142093008675407723196706248829741247204621913994561803", - "1472231555266678689888727724824566171966416459791722465278225775922487343641", - "1" - ] - ], - [ - [ - "3047486363455933831148688762823238723024952519326207356549121929667745957778", - "20241836359289449005887237560564358543646542598344362915541027571505243817211", - "1" - ], - [ - "5965631918800530319167124148627450454569264331058008407732200168631989208657", - "20463557477532480934514091877628554948892025887087712764683631108388998871350", - "1" - ], - [ - "16605042322692983282732511249912403956057999815658038166796858627082222971215", - "12219061498275616585164456833410962809536084885494309093787669879221959361956", - "1" - ], - [ - "1548998572074037722622224303222294716243074837074272552644853986075252666508", - "10393312002885367652301897874262367916506364670364584602554176742602334134772", - "1" - ], - [ - "16180907689593358346406392015123900260925622357393826746385511046141256905390", - "12267326749885120640972074479210537480053065569337817484467225562817467244765", - "1" - ] - ], - [ - [ - "19590996174696909242575628014943555633938195923520472786993379268302478708283", - "2673753072556442230312995111304911178679525806396134504594492458566941824354", - "1" - ], - [ - "13411253172375451489380472831999887223592471057462692619008484995624281735092", - "17181767455563581254432161119660408482332423481128600038352147258951772423229", - "1" - ], - [ - "19138864631164378176055647711995352935065134904103255748190268290992108588628", - "14282526277736365863821375748687709839392307698935143595732632710176778519757", - "1" - ], - [ - "20183773658676161990469276414858234178608794783112866811307579993999118293429", - "5223464433544489066271184294750886227362580875255044558831927430970236355539", - "1" - ], - [ - "12333466991139269670298178539679773509487545471126920233507132846828588847444", - "3787586478923104354547687861486563468235879611952775292288436085429794222238", - "1" - ] - ], - [ - [ - "18580370382199518848261939652153768394883698461842792002922164533882262019935", - "20516185953882700254387267244708111605796661864845495645678049276372075842359", - "1" - ], - [ - "20041291712709610738573661974551517833120775539593003477018637287434210072702", - "6326630253906616820412999166182553773360987412889775567442543181359104720511", - "1" - ], - [ - "13268971611130152315428629919012388924225656285593904211561391821918930327614", - "9247437189452353488017802041158840512956111558640958728149597697508914590433", - "1" - ], - [ - "6267384495557139339708615182113725421733376438932580472141549274050146739549", - "1832264154031452148715318442722960696977572389206897240030908464579133134237", - "1" - ], - [ - "16650684165487873559901140599157559153018449083939294496255590830891994564285", - "14140282729498011406186082176268025578697081678243955538935501306868500498994", - "1" - ] - ], - [ - [ - "4247947150009812467217672970806328247513830308400387953244764907353849211641", - "14500381439127180474801393438175928191199696177607750163263715436006533630877", - "1" - ], - [ - "21213779524495874664157797605662894019112036728653622806607467354233012380232", - "1429370857470083395421401524518861545167550347090873730934256398864585069083", - "1" - ], - [ - "12465277751642747637430517396067173985821959773399832969105187923427872239200", - "4377704428607835904642653580543541241155601291484645500691968624389522190030", - "1" - ], - [ - "11283027832501128633761619552392013253304972822086786857121687098087331014745", - "21463394238922953607096052056881931791797740737164052798044623278557203313720", - "1" - ], - [ - "19687293493101130967741578773742597470558958652351513582962108464055656171331", - "4445165696525061401582979300506082669540223774145877762689724631935313716632", - "1" - ] - ], - [ - [ - "3388767735894417381503201756905214431625081913405504580464345986403824999889", - "21014112837214011009096825602791072748195337199912773858499588477762724153070", - "1" - ], - [ - "10521317016331497094903116740581271122844131442882845700567581775404872949272", - "13201921794561774338466680421903602920184688290946713194187958007088351657367", - "1" - ], - [ - "16170260722059932609965743383032703380650557609693540121262881902248073364496", - "6004983491336500911294872035126141746032033211872472427212274143945425740617", - "1" - ], - [ - "10275615677574391293596971122111363003313434841806630200532546038183081960924", - "5955568702561336410725734958627459212680756023420452791680213386065159525989", - "1" - ], - [ - "19059081014385850734732058652137664919364805650872154944590269874395511868415", - "19202365837673729366500417038229950532560250566916189579621883380623278182155", - "1" - ] - ], - [ - [ - "7856986171681248404396064225772749784181602218562773063185003409958949630985", - "11707218736744382138692483591389641607570557654489363179025201039696228471230", - "1" - ], - [ - "2902255937308264958973169948617099471543255757887963647238093192858290079050", - "4092153880227661899721872164083575597602963673456107552146583620177664115673", - "1" - ], - [ - "18380478859138320895837407377103009470968863533040661874531861881638854174636", - "14502773952184441371657781525836310753176308880224816843041318743809785835984", - "1" - ], - [ - "2781117248053224106149213822307598926495461873135153638774638501111353469325", - "3500056595279027698683405880585654897391289317486204483344715855049598477604", - "1" - ], - [ - "8880120765926282932795149634761705738498809569874317407549203808931092257005", - "19080036326648068547894941015038877788526324720587349784852594495705578761000", - "1" - ] - ], - [ - [ - "18427701611614193839908361166447988195308352665132182219164437649866377475111", - "5299493942596042045861137432338955179078182570752746487573709678936617478454", - "1" - ], - [ - "4188155714164125069834512529839479682516489319499446390214266838952761728656", - "2720966082507704094346897998659841489771837229143573083003847010258396944787", - "1" - ], - [ - "13256461570028177373135283778770729308216900804505379897951455548375840027026", - "10722074030307391322177899534114921764931623271723882054692012663305322382747", - "1" - ], - [ - "9824147497244652955949696442395586567974424828238608972020527958186701134273", - "15755269950882650791869946186461432242513999576056199368058858215068920022191", - "1" - ], - [ - "21172488506061181949536573476893375313339715931330476837156243346077173297265", - "13892434487977776248366965108031841947713544939953824768291380177301871559945", - "1" - ] - ], - [ - [ - "1452272927738590248356371174422184656932731110936062990115610832462181634644", - "3608050114233210789542189629343107890943266759827387991788718454179833288695", - "1" - ], - [ - "14798240452388909327945424685903532333765637883272751382037716636327236955001", - "10773894897711848209682368488916121016695006898681985691467605219098835500201", - "1" - ], - [ - "17204267933132009093604099819536245144503489322639121825381131096467570698650", - "7704298975420304156332734115679983371345754866278811368869074990486717531131", - "1" - ], - [ - "8060465662017324080560848316478407038163145149983639907596180500095598669247", - "20475082166427284188002500222093571716651248980245637602667562336751029856573", - "1" - ], - [ - "7457566682692308112726332096733260585025339741083447785327706250123165087868", - "11904519443874922292602150685069370036383697877657723976244907400392778002614", - "1" - ] - ], - [ - [ - "12628427235010608529869146871556870477182704310235373946877240509680742038961", - "15093298104438768585559335868663959710321348106117735180051519837845319121254", - "1" - ], - [ - "6593907467779318957599440584793099005109789224774644007604434924706249001015", - "18549596630007199540674697114946251030815675677713256327810772799104711621483", - "1" - ], - [ - "6271101737045248834759003849256661059806617144229427987717476992610974162336", - "355748132218964841305454070022507122319085542484477110563322753565651576458", - "1" - ], - [ - "2116139772133141967317791473319540620104888687412078412336248003979594158546", - "4004400204967325849492155713520296687406035356901102254880522534085890616486", - "1" - ], - [ - "4206647028595764233995379982714022410660284578620723510907006350595207905228", - "19380634286337609988098517090003334645113675227742745065381519159322795845003", - "1" - ] - ], - [ - [ - "2592407181901686208061988776764501828311271519595797153264758207470081204331", - "11847594161160074962679125411562687287595382335410213641115001866587988494499", - "1" - ], - [ - "3346927026869562921166545684451290646273836362895645367665514203662899621366", - "15758185693543979820528128025093553492246135914029575732836221618882836493143", - "1" - ], - [ - "20528686657810499188368147206002308531447185877994439397529705707372170337045", - "18025396678079701612906003769476076600196287001844168390936182972248852818155", - "1" - ], - [ - "9799815250059685769827017947834627563597884023490186073806184882963949644596", - "4998495094322372762314630336611134866447406022687118703953312157819349892603", - "1" - ], - [ - "16176535527670849161173306151058200762642157343823553073439957507563856439772", - "21877331533292960470552563236986670222564955589137303622102707801351340670855", - "1" - ] - ] - ] -} diff --git a/packages/proof/src/verify-proof.ts b/packages/proof/src/verify-proof.ts new file mode 100644 index 000000000..d24f91bc3 --- /dev/null +++ b/packages/proof/src/verify-proof.ts @@ -0,0 +1,28 @@ +import { verify } from "@zk-kit/groth16" +import hash from "./hash" +import { SemaphoreProof } from "./types" +import unpackProof from "./unpack-proof" +import verificationKeys from "./verification-keys.json" + +/** + * Verifies a Semaphore proof. + * @param fullProof The SnarkJS Semaphore proof. + * @returns True if the proof is valid, false otherwise. + */ +export default function verifyProof({ treeRoot, nullifier, scope, message, proof }: SemaphoreProof): Promise { + // TODO: support all tree depths after trusted-setup. + // if (treeDepth < 1 || treeDepth > 32) { + // throw new TypeError("The tree depth must be a number between 1 and 32") + // } + + const verificationKey = { + ...verificationKeys, + vk_delta_2: verificationKeys.vk_delta_2[0], + IC: verificationKeys.IC[0] + } + + return verify(verificationKey, { + publicSignals: [treeRoot, nullifier, hash(message), hash(scope)], + proof: unpackProof(proof) + }) +} diff --git a/packages/proof/src/verifyProof.ts b/packages/proof/src/verifyProof.ts deleted file mode 100644 index dc4cd3540..000000000 --- a/packages/proof/src/verifyProof.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { verify } from "@zk-kit/groth16" -import hash from "./hash" -import { SemaphoreProof } from "./types" -import unpackProof from "./unpackProof" -import verificationKeys from "./verificationKeys.json" - -/** - * Verifies a Semaphore proof. - * @param fullProof The SnarkJS Semaphore proof. - * @param treeDepth The Merkle tree depth. - * @returns True if the proof is valid, false otherwise. - */ -export default function verifyProof( - { merkleTreeRoot, nullifierHash, externalNullifier, signal, proof }: SemaphoreProof, - treeDepth: number -): Promise { - if (treeDepth < 16 || treeDepth > 32) { - throw new TypeError("The tree depth must be a number between 16 and 32") - } - - const verificationKey = { - ...verificationKeys, - vk_delta_2: verificationKeys.vk_delta_2[treeDepth - 16], - IC: verificationKeys.IC[treeDepth - 16] - } - - return verify(verificationKey, { - publicSignals: [merkleTreeRoot, nullifierHash, hash(signal), hash(externalNullifier)], - proof: unpackProof(proof) - }) -} diff --git a/scripts/download-snark-artifacts.ts b/scripts/download-snark-artifacts.ts deleted file mode 100644 index 5e0bee63e..000000000 --- a/scripts/download-snark-artifacts.ts +++ /dev/null @@ -1,30 +0,0 @@ -import dotenv from "dotenv" -import download from "download" - -dotenv.config() - -async function main() { - const snarkArtifactsPath = "./snark-artifacts" - - if (process.env.ALL_SNARK_ARTIFACTS === "true") { - const url = `https://www.trusted-setup-pse.org/semaphore/semaphore.zip` - - await download(url, snarkArtifactsPath, { - extract: true - }) - } else { - const treeDepth = process.env.TREE_DEPTH || 20 - const url = `https://www.trusted-setup-pse.org/semaphore/${treeDepth}` - - await download(`${url}/semaphore.wasm`, `${snarkArtifactsPath}/${treeDepth}`) - await download(`${url}/semaphore.zkey`, `${snarkArtifactsPath}/${treeDepth}`) - await download(`${url}/semaphore.json`, `${snarkArtifactsPath}/${treeDepth}`) - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/yarn.lock b/yarn.lock index 79f2d8e12..0ce5c2ced 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4605,13 +4605,16 @@ __metadata: "@rollup/plugin-commonjs": ^24.1.0 "@rollup/plugin-json": ^5.0.1 "@rollup/plugin-node-resolve": ^15.0.2 + "@types/download": ^8.0.5 + "@types/tmp": ^0.2.6 "@zk-kit/groth16": 0.3.0 - "@zk-kit/incremental-merkle-tree": 0.4.3 + download: ^8.0.0 poseidon-lite: ^0.2.0 rimraf: ^5.0.5 rollup: ^4.0.2 rollup-plugin-cleanup: ^3.2.1 rollup-plugin-typescript2: ^0.31.2 + tmp: ^0.2.1 peerDependencies: "@semaphore-protocol/group": 3.15.1 "@semaphore-protocol/identity": 3.15.1 @@ -5126,6 +5129,17 @@ __metadata: languageName: node linkType: hard +"@types/download@npm:^8.0.5": + version: 8.0.5 + resolution: "@types/download@npm:8.0.5" + dependencies: + "@types/decompress": "*" + "@types/got": ^9 + "@types/node": "*" + checksum: 10e807e9e4a6dc21918ff3ec302c41db529ba5488c7b296cd6ee7d5cefc872b35f0078d6f47671eb5dd40661d5128eab552c1882982c69fb4825b8a4943f30c9 + languageName: node + linkType: hard + "@types/estree@npm:*, @types/estree@npm:^1.0.0": version: 1.0.0 resolution: "@types/estree@npm:1.0.0" @@ -5575,6 +5589,13 @@ __metadata: languageName: node linkType: hard +"@types/tmp@npm:^0.2.6": + version: 0.2.6 + resolution: "@types/tmp@npm:0.2.6" + checksum: 0b24bb6040cc289440a609e10ec99a704978c890a5828ff151576489090b2257ce2e2570b0f320ace9c8099c3642ea6221fbdf6d8f2e22b7cd1f4fbf6e989e3e + languageName: node + linkType: hard + "@types/tough-cookie@npm:*": version: 4.0.2 resolution: "@types/tough-cookie@npm:4.0.2" @@ -5795,13 +5816,6 @@ __metadata: languageName: node linkType: hard -"@zk-kit/incremental-merkle-tree@npm:0.4.3": - version: 0.4.3 - resolution: "@zk-kit/incremental-merkle-tree@npm:0.4.3" - checksum: 582ef97bd2b1b9638ce7c8a941200a5cf0ab86975f767de233905e8af0ff72d31b44f2497595f0ff585e45c7491481cf4e027ee6486a136cd64498d4b16b3e29 - languageName: node - linkType: hard - "JSONStream@npm:^1.0.4": version: 1.3.5 resolution: "JSONStream@npm:1.3.5" @@ -19309,7 +19323,7 @@ __metadata: languageName: node linkType: hard -"tmp@npm:^0.2.0": +"tmp@npm:^0.2.0, tmp@npm:^0.2.1": version: 0.2.1 resolution: "tmp@npm:0.2.1" dependencies: