@semaphore-protocol/proof 3.15.2 → 4.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ import { BytesLike, Hexable } from "@ethersproject/bytes";
2
+ import type { Group, MerkleProof } from "@semaphore-protocol/group";
3
+ import type { Identity } from "@semaphore-protocol/identity";
4
+ import { SemaphoreProof, SnarkArtifacts } from "./types";
5
+ /**
6
+ * Generates a Semaphore proof.
7
+ * @param identity The Semaphore identity.
8
+ * @param groupOrMerkleProof The Semaphore group or its Merkle proof.
9
+ * @param scope The external nullifier.
10
+ * @param message The Semaphore signal.
11
+ * @param merkleTreeDepth The depth of the tree with which the circuit was compiled.
12
+ * @param snarkArtifacts The SNARK artifacts.
13
+ * @returns The Semaphore proof ready to be verified.
14
+ */
15
+ export default function generateProof(identity: Identity, groupOrMerkleProof: Group | MerkleProof, message: BytesLike | Hexable | number | bigint, scope: BytesLike | Hexable | number | bigint, merkleTreeDepth?: number, snarkArtifacts?: SnarkArtifacts): Promise<SemaphoreProof>;
@@ -0,0 +1,2 @@
1
+ import { SnarkArtifacts } from "./types";
2
+ export default function getSnarkArtifacts(treeDepth: number): Promise<SnarkArtifacts>;
@@ -0,0 +1,2 @@
1
+ import { SnarkArtifacts } from "./types";
2
+ export default function getSnarkArtifacts(treeDepth: number): Promise<SnarkArtifacts>;
@@ -1,6 +1,7 @@
1
- import calculateNullifierHash from "./calculateNullifierHash";
2
- import generateProof from "./generateProof";
3
- import verifyProof from "./verifyProof";
4
- export { MerkleProof } from "@zk-kit/incremental-merkle-tree";
1
+ import generateProof from "./generate-proof";
2
+ import getSnarkArtifacts from "./get-snark-artifacts.node";
3
+ import packPoints from "./pack-points";
4
+ import unpackPoints from "./unpack-points";
5
+ import verifyProof from "./verify-proof";
5
6
  export * from "./types";
6
- export { generateProof, verifyProof, calculateNullifierHash };
7
+ export { generateProof, getSnarkArtifacts, packPoints, unpackPoints, verifyProof };
@@ -0,0 +1,8 @@
1
+ import { Groth16Proof } from "snarkjs";
2
+ import { PackedPoints } from "./types";
3
+ /**
4
+ * Packs the Groth16 proof points into a format compatible with Semaphore.
5
+ * @param proof The proof points generated with SnarkJS.
6
+ * @returns The proof points compatible with Semaphore.
7
+ */
8
+ export default function packPoints(proof: Groth16Proof): PackedPoints;
@@ -1,16 +1,18 @@
1
1
  import type { NumericString } from "snarkjs";
2
+ export type BigNumberish = string | number | bigint;
2
3
  export type SnarkArtifacts = {
3
4
  wasmFilePath: string;
4
5
  zkeyFilePath: string;
5
6
  };
6
7
  export type SemaphoreProof = {
8
+ merkleTreeDepth: number;
7
9
  merkleTreeRoot: NumericString;
8
- signal: NumericString;
9
- nullifierHash: NumericString;
10
- externalNullifier: NumericString;
11
- proof: PackedProof;
10
+ message: NumericString;
11
+ nullifier: NumericString;
12
+ scope: NumericString;
13
+ points: PackedPoints;
12
14
  };
13
- export type PackedProof = [
15
+ export type PackedPoints = [
14
16
  NumericString,
15
17
  NumericString,
16
18
  NumericString,
@@ -0,0 +1,8 @@
1
+ import { Groth16Proof } from "snarkjs";
2
+ import { PackedPoints } from "./types";
3
+ /**
4
+ * Unpacks the Groth16 proof points into their original form.
5
+ * @param proof The proof points compatible with Semaphore.
6
+ * @returns The proof points compatible with SnarkJS.
7
+ */
8
+ export default function unpackPoints(proof: PackedPoints): Groth16Proof;
@@ -0,0 +1,8 @@
1
+ import { SemaphoreProof } from "./types";
2
+ /**
3
+ * Verifies a Semaphore proof.
4
+ * @param fullProof The SnarkJS Semaphore proof.
5
+ * @param treeDepth The depth of the tree.
6
+ * @returns True if the proof is valid, false otherwise.
7
+ */
8
+ export default function verifyProof({ merkleTreeDepth, merkleTreeRoot, nullifier, message, scope, points }: SemaphoreProof): Promise<boolean>;
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@semaphore-protocol/proof",
3
- "version": "3.15.2",
3
+ "version": "4.0.0-alpha.1",
4
4
  "description": "A library to generate and verify Semaphore proofs.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.node.js",
7
7
  "exports": {
8
- "import": "./dist/index.node.mjs",
9
- "require": "./dist/index.node.js",
8
+ "node": {
9
+ "import": "./dist/index.node.mjs",
10
+ "require": "./dist/index.node.js"
11
+ },
12
+ "browser": "./dist/index.browser.mjs",
13
+ "default": "./dist/index.browser.mjs",
10
14
  "types": "./dist/types/index.d.ts"
11
15
  },
12
16
  "types": "dist/types/index.d.ts",
@@ -22,17 +26,20 @@
22
26
  "url": "https://github.com/semaphore-protocol/semaphore.git/issues"
23
27
  },
24
28
  "scripts": {
25
- "build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
26
- "build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
29
+ "build": "rimraf dist && yarn build:browser && yarn build:node",
30
+ "build:browser": "rollup -c rollup.browser.config.ts --configPlugin typescript",
31
+ "build:node": "rollup -c rollup.node.config.ts --configPlugin typescript",
27
32
  "prepublishOnly": "yarn build"
28
33
  },
29
34
  "publishConfig": {
30
35
  "access": "public"
31
36
  },
32
37
  "devDependencies": {
33
- "@rollup/plugin-commonjs": "^24.1.0",
38
+ "@ethersproject/strings": "^5.7.0",
39
+ "@rollup/plugin-alias": "^5.1.0",
34
40
  "@rollup/plugin-json": "^5.0.1",
35
- "@rollup/plugin-node-resolve": "^15.0.2",
41
+ "@types/download": "^8.0.5",
42
+ "@types/tmp": "^0.2.6",
36
43
  "poseidon-lite": "^0.2.0",
37
44
  "rimraf": "^5.0.5",
38
45
  "rollup": "^4.0.2",
@@ -40,15 +47,16 @@
40
47
  "rollup-plugin-typescript2": "^0.31.2"
41
48
  },
42
49
  "peerDependencies": {
43
- "@semaphore-protocol/group": "3.15.2",
44
- "@semaphore-protocol/identity": "3.15.2"
50
+ "@semaphore-protocol/group": "4.0.0-alpha.1",
51
+ "@semaphore-protocol/identity": "4.0.0-alpha.1"
45
52
  },
46
53
  "dependencies": {
47
- "@ethersproject/bignumber": "^5.5.0",
48
- "@ethersproject/bytes": "^5.7.0",
49
- "@ethersproject/keccak256": "^5.7.0",
50
- "@ethersproject/strings": "^5.5.0",
51
- "@zk-kit/groth16": "0.3.0",
52
- "@zk-kit/incremental-merkle-tree": "0.4.3"
54
+ "@ethersproject/bignumber": "5.7.0",
55
+ "@ethersproject/bytes": "5.7.0",
56
+ "@ethersproject/keccak256": "5.7.0",
57
+ "@types/snarkjs": "0.7.8",
58
+ "download": "8.0.0",
59
+ "snarkjs": "0.7.3",
60
+ "tmp": "0.2.1"
53
61
  }
54
62
  }
@@ -0,0 +1,88 @@
1
+ import { BigNumber } from "@ethersproject/bignumber"
2
+ import { BytesLike, Hexable } from "@ethersproject/bytes"
3
+ import type { Group, MerkleProof } from "@semaphore-protocol/group"
4
+ import type { Identity } from "@semaphore-protocol/identity"
5
+ import { NumericString, groth16 } from "snarkjs"
6
+ import getSnarkArtifacts from "./get-snark-artifacts.node"
7
+ import hash from "./hash"
8
+ import packPoints from "./pack-points"
9
+ import { SemaphoreProof, SnarkArtifacts } from "./types"
10
+
11
+ /**
12
+ * Generates a Semaphore proof.
13
+ * @param identity The Semaphore identity.
14
+ * @param groupOrMerkleProof The Semaphore group or its Merkle proof.
15
+ * @param scope The external nullifier.
16
+ * @param message The Semaphore signal.
17
+ * @param merkleTreeDepth The depth of the tree with which the circuit was compiled.
18
+ * @param snarkArtifacts The SNARK artifacts.
19
+ * @returns The Semaphore proof ready to be verified.
20
+ */
21
+ export default async function generateProof(
22
+ identity: Identity,
23
+ groupOrMerkleProof: Group | MerkleProof,
24
+ message: BytesLike | Hexable | number | bigint,
25
+ scope: BytesLike | Hexable | number | bigint,
26
+ merkleTreeDepth?: number,
27
+ snarkArtifacts?: SnarkArtifacts
28
+ ): Promise<SemaphoreProof> {
29
+ let merkleProof
30
+
31
+ if ("siblings" in groupOrMerkleProof) {
32
+ merkleProof = groupOrMerkleProof
33
+ } else {
34
+ const leafIndex = groupOrMerkleProof.indexOf(identity.commitment)
35
+ merkleProof = groupOrMerkleProof.generateMerkleProof(leafIndex)
36
+ }
37
+
38
+ const merkleProofLength = merkleProof.siblings.length
39
+
40
+ if (merkleTreeDepth !== undefined) {
41
+ if (merkleTreeDepth < 1 || merkleTreeDepth > 12) {
42
+ throw new TypeError("The tree depth must be a number between 1 and 12")
43
+ }
44
+ } else {
45
+ merkleTreeDepth = merkleProofLength
46
+ }
47
+
48
+ // If the Snark artifacts are not defined they will be automatically downloaded.
49
+ /* istanbul ignore next */
50
+ if (!snarkArtifacts) {
51
+ snarkArtifacts = await getSnarkArtifacts(merkleTreeDepth)
52
+ }
53
+
54
+ // The index must be converted to a list of indices, 1 for each tree level.
55
+ // The missing siblings can be set to 0, as they won't be used in the circuit.
56
+ const merkleProofIndices = []
57
+ const merkleProofSiblings = merkleProof.siblings
58
+
59
+ for (let i = 0; i < merkleTreeDepth; i += 1) {
60
+ merkleProofIndices.push((merkleProof.index >> i) & 1)
61
+
62
+ if (merkleProofSiblings[i] === undefined) {
63
+ merkleProofSiblings[i] = "0"
64
+ }
65
+ }
66
+
67
+ const { proof, publicSignals } = await groth16.fullProve(
68
+ {
69
+ secret: identity.secretScalar,
70
+ merkleProofLength,
71
+ merkleProofIndices,
72
+ merkleProofSiblings,
73
+ scope: hash(scope),
74
+ message: hash(message)
75
+ },
76
+ snarkArtifacts.wasmFilePath,
77
+ snarkArtifacts.zkeyFilePath
78
+ )
79
+
80
+ return {
81
+ merkleTreeDepth,
82
+ merkleTreeRoot: publicSignals[0],
83
+ nullifier: publicSignals[1],
84
+ message: BigNumber.from(message).toString() as NumericString,
85
+ scope: BigNumber.from(scope).toString() as NumericString,
86
+ points: packPoints(proof)
87
+ }
88
+ }
@@ -0,0 +1,9 @@
1
+ /* istanbul ignore file */
2
+ import { SnarkArtifacts } from "./types"
3
+
4
+ export default async function getSnarkArtifacts(treeDepth: number): Promise<SnarkArtifacts> {
5
+ return {
6
+ wasmFilePath: `https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.wasm`,
7
+ zkeyFilePath: `https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.zkey`
8
+ }
9
+ }
@@ -0,0 +1,20 @@
1
+ /* istanbul ignore file */
2
+ import download from "download"
3
+ import fs from "fs"
4
+ import tmp from "tmp"
5
+ import { SnarkArtifacts } from "./types"
6
+
7
+ export default async function getSnarkArtifacts(treeDepth: number): Promise<SnarkArtifacts> {
8
+ const tmpDir = "semaphore-proof"
9
+ const tmpPath = `${tmp.tmpdir}/${tmpDir}-${treeDepth}`
10
+
11
+ if (!fs.existsSync(tmpPath) || fs.readdirSync(tmpPath).length !== 2) {
12
+ await download(`https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.wasm`, tmpPath)
13
+ await download(`https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.zkey`, tmpPath)
14
+ }
15
+
16
+ return {
17
+ wasmFilePath: `${tmpPath}/semaphore.wasm`,
18
+ zkeyFilePath: `${tmpPath}/semaphore.zkey`
19
+ }
20
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
1
- import calculateNullifierHash from "./calculateNullifierHash"
2
- import generateProof from "./generateProof"
3
- import verifyProof from "./verifyProof"
1
+ import generateProof from "./generate-proof"
2
+ import getSnarkArtifacts from "./get-snark-artifacts.node"
3
+ import packPoints from "./pack-points"
4
+ import unpackPoints from "./unpack-points"
5
+ import verifyProof from "./verify-proof"
4
6
 
5
- export { MerkleProof } from "@zk-kit/incremental-merkle-tree"
6
7
  export * from "./types"
7
- export { generateProof, verifyProof, calculateNullifierHash }
8
+ export { generateProof, getSnarkArtifacts, packPoints, unpackPoints, verifyProof }
@@ -0,0 +1,20 @@
1
+ import { Groth16Proof } from "snarkjs"
2
+ import { PackedPoints } from "./types"
3
+
4
+ /**
5
+ * Packs the Groth16 proof points into a format compatible with Semaphore.
6
+ * @param proof The proof points generated with SnarkJS.
7
+ * @returns The proof points compatible with Semaphore.
8
+ */
9
+ export default function packPoints(proof: Groth16Proof): PackedPoints {
10
+ return [
11
+ proof.pi_a[0],
12
+ proof.pi_a[1],
13
+ proof.pi_b[0][1],
14
+ proof.pi_b[0][0],
15
+ proof.pi_b[1][1],
16
+ proof.pi_b[1][0],
17
+ proof.pi_c[0],
18
+ proof.pi_c[1]
19
+ ]
20
+ }
@@ -1,19 +1,22 @@
1
1
  import type { NumericString } from "snarkjs"
2
2
 
3
+ export type BigNumberish = string | number | bigint
4
+
3
5
  export type SnarkArtifacts = {
4
6
  wasmFilePath: string
5
7
  zkeyFilePath: string
6
8
  }
7
9
 
8
10
  export type SemaphoreProof = {
11
+ merkleTreeDepth: number
9
12
  merkleTreeRoot: NumericString
10
- signal: NumericString
11
- nullifierHash: NumericString
12
- externalNullifier: NumericString
13
- proof: PackedProof
13
+ message: NumericString
14
+ nullifier: NumericString
15
+ scope: NumericString
16
+ points: PackedPoints
14
17
  }
15
18
 
16
- export type PackedProof = [
19
+ export type PackedPoints = [
17
20
  NumericString,
18
21
  NumericString,
19
22
  NumericString,
@@ -0,0 +1,20 @@
1
+ import { Groth16Proof } from "snarkjs"
2
+ import { PackedPoints } from "./types"
3
+
4
+ /**
5
+ * Unpacks the Groth16 proof points into their original form.
6
+ * @param proof The proof points compatible with Semaphore.
7
+ * @returns The proof points compatible with SnarkJS.
8
+ */
9
+ export default function unpackPoints(proof: PackedPoints): Groth16Proof {
10
+ return {
11
+ pi_a: [proof[0], proof[1]],
12
+ pi_b: [
13
+ [proof[3], proof[2]],
14
+ [proof[5], proof[4]]
15
+ ],
16
+ pi_c: [proof[6], proof[7]],
17
+ protocol: "groth16",
18
+ curve: "bn128"
19
+ }
20
+ }