@semaphore-protocol/proof 4.0.0-alpha.6 → 4.0.0-alpha.8

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.
package/README.md CHANGED
@@ -73,8 +73,8 @@ yarn add @semaphore-protocol/identity @semaphore-protocol/group @semaphore-proto
73
73
  \# **generateProof**(
74
74
  identity: _Identity_,
75
75
  group: _Group_,
76
- message: _BytesLike | Hexable | number | bigint_,
77
- scope: _BytesLike | Hexable | number | bigint_,
76
+ message: _BigNumberish_ | _Uint8Array_ | string,
77
+ scope: _BigNumberish_ | _Uint8Array_ | string,
78
78
  merkleTreeDepth: _number_,
79
79
  snarkArtifacts?: _SnarkArtifacts_
80
80
  ): Promise\<_SemaphoreProof_>
@@ -83,23 +83,23 @@ snarkArtifacts?: _SnarkArtifacts_
83
83
  import { Identity } from "@semaphore-protocol/identity"
84
84
  import { Group } from "@semaphore-protocol/group"
85
85
  import { generateProof } from "@semaphore-protocol/proof"
86
- import { utils } from "ethers"
87
86
 
88
- const identity = new Identity()
89
- const group = new Group()
87
+ const identity1 = new Identity()
88
+ const identity2 = new Identity()
89
+ const identity3 = new Identity()
90
90
 
91
- const scope = utils.formatBytes32String("Topic")
92
- const message = utils.formatBytes32String("Hello world")
91
+ const group = new Group([identity1.commitment, identity2.commitment, identity3.commitment])
93
92
 
94
- group.addMembers([...identityCommitments, identity.generateCommitment()])
93
+ const message = "Hello world"
94
+ const scope = "Semaphore"
95
95
 
96
- const proof1 = await generateProof(identity, group, message, scope)
96
+ const proof1 = await generateProof(identity1, group, message, scope)
97
97
 
98
98
  // You can also specify the maximum tree depth supported by the proof.
99
- const proof2 = await generateProof(identity, group, message, scope, 20)
99
+ const proof2 = await generateProof(identity2, group, message, scope, 20)
100
100
 
101
101
  // You can also specify the default zkey/wasm files.
102
- const proof3 = await generateProof(identity, group, message, scope, 20, {
102
+ const proof3 = await generateProof(identity3, group, message, scope, 20, {
103
103
  wasmFilePath: "./semaphore.wasm",
104
104
  zkeyFilePath: "./semaphore.zkey"
105
105
  })
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/proof
3
- * @version 4.0.0-alpha.6
3
+ * @version 4.0.0-alpha.8
4
4
  * @file A library to generate and verify Semaphore proofs.
5
5
  * @copyright Ethereum Foundation 2024
6
6
  * @license MIT
7
7
  * @see [Github]{@link https://github.com/semaphore-protocol/semaphore/tree/main/packages/proof}
8
8
  */
9
- import { BigNumber } from '@ethersproject/bignumber';
10
9
  import { groth16 } from 'snarkjs';
11
- import { zeroPad } from '@ethersproject/bytes';
12
- import { keccak256 } from '@ethersproject/keccak256';
10
+ import { keccak256 } from 'ethers/crypto';
11
+ import { toBeHex, toBigInt as toBigInt$1 } from 'ethers/utils';
12
+ import { encodeBytes32String } from 'ethers/abi';
13
13
 
14
14
  /******************************************************************************
15
15
  Copyright (c) Microsoft Corporation.
@@ -99,9 +99,7 @@ function getSnarkArtifacts(treeDepth) {
99
99
  * @returns The message digest.
100
100
  */
101
101
  function hash(message) {
102
- message = BigNumber.from(message).toTwos(256).toHexString();
103
- message = zeroPad(message, 32);
104
- return (BigInt(keccak256(message)) >> BigInt(8)).toString();
102
+ return (BigInt(keccak256(toBeHex(message, 32))) >> BigInt(8)).toString();
105
103
  }
106
104
 
107
105
  /**
@@ -122,12 +120,24 @@ function packPoints(proof) {
122
120
  ];
123
121
  }
124
122
 
123
+ function toBigInt(value) {
124
+ try {
125
+ return toBigInt$1(value);
126
+ }
127
+ catch (error) {
128
+ if (typeof value === "string") {
129
+ return toBigInt$1(encodeBytes32String(value));
130
+ }
131
+ throw TypeError(error.message);
132
+ }
133
+ }
134
+
125
135
  /**
126
136
  * Generates a Semaphore proof.
127
137
  * @param identity The Semaphore identity.
128
138
  * @param groupOrMerkleProof The Semaphore group or its Merkle proof.
129
- * @param scope The external nullifier.
130
- * @param message The Semaphore signal.
139
+ * @param scope The Semaphore scope.
140
+ * @param message The Semaphore message.
131
141
  * @param merkleTreeDepth The depth of the tree with which the circuit was compiled.
132
142
  * @param snarkArtifacts The SNARK artifacts.
133
143
  * @returns The Semaphore proof ready to be verified.
@@ -138,6 +148,8 @@ function generateProof(identity, groupOrMerkleProof, message, scope, merkleTreeD
138
148
  return __generator(this, function (_b) {
139
149
  switch (_b.label) {
140
150
  case 0:
151
+ message = toBigInt(message);
152
+ scope = toBigInt(scope);
141
153
  if ("siblings" in groupOrMerkleProof) {
142
154
  merkleProof = groupOrMerkleProof;
143
155
  }
@@ -182,8 +194,8 @@ function generateProof(identity, groupOrMerkleProof, message, scope, merkleTreeD
182
194
  merkleTreeDepth: merkleTreeDepth,
183
195
  merkleTreeRoot: publicSignals[0],
184
196
  nullifier: publicSignals[1],
185
- message: BigNumber.from(message).toString(),
186
- scope: BigNumber.from(scope).toString(),
197
+ message: message.toString(),
198
+ scope: scope.toString(),
187
199
  points: packPoints(proof)
188
200
  }];
189
201
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/proof
3
- * @version 4.0.0-alpha.6
3
+ * @version 4.0.0-alpha.8
4
4
  * @file A library to generate and verify Semaphore proofs.
5
5
  * @copyright Ethereum Foundation 2024
6
6
  * @license MIT
@@ -8,13 +8,16 @@
8
8
  */
9
9
  'use strict';
10
10
 
11
- var bignumber = require('@ethersproject/bignumber');
12
11
  var snarkjs = require('snarkjs');
13
- var download = require('download');
14
- var fs = require('fs');
15
- var tmp = require('tmp');
16
- var bytes = require('@ethersproject/bytes');
17
- var keccak256 = require('@ethersproject/keccak256');
12
+ var node_fs = require('node:fs');
13
+ var promises$1 = require('node:fs/promises');
14
+ var os = require('node:os');
15
+ var node_path = require('node:path');
16
+ var node_stream = require('node:stream');
17
+ var promises = require('node:stream/promises');
18
+ var crypto = require('ethers/crypto');
19
+ var utils = require('ethers/utils');
20
+ var abi = require('ethers/abi');
18
21
 
19
22
  /******************************************************************************
20
23
  Copyright (c) Microsoft Corporation.
@@ -87,6 +90,30 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
87
90
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
88
91
  };
89
92
 
93
+ function download(url, outputPath) {
94
+ return __awaiter(this, void 0, void 0, function () {
95
+ var response, dir, fileStream;
96
+ return __generator(this, function (_a) {
97
+ switch (_a.label) {
98
+ case 0: return [4 /*yield*/, fetch(url)];
99
+ case 1:
100
+ response = _a.sent();
101
+ if (!response.ok) {
102
+ throw new Error("Failed to fetch ".concat(url, ": ").concat(response.statusText));
103
+ }
104
+ dir = node_path.dirname(outputPath);
105
+ return [4 /*yield*/, promises$1.mkdir(dir, { recursive: true })];
106
+ case 2:
107
+ _a.sent();
108
+ fileStream = node_fs.createWriteStream(outputPath);
109
+ return [4 /*yield*/, promises.finished(node_stream.Readable.fromWeb(response.body).pipe(fileStream))];
110
+ case 3:
111
+ _a.sent();
112
+ return [2 /*return*/];
113
+ }
114
+ });
115
+ });
116
+ }
90
117
  function getSnarkArtifacts(treeDepth) {
91
118
  return __awaiter(this, void 0, void 0, function () {
92
119
  var tmpDir, tmpPath;
@@ -94,12 +121,12 @@ function getSnarkArtifacts(treeDepth) {
94
121
  switch (_a.label) {
95
122
  case 0:
96
123
  tmpDir = "semaphore-proof";
97
- tmpPath = "".concat(tmp.tmpdir, "/").concat(tmpDir, "-").concat(treeDepth);
98
- if (!(!fs.existsSync(tmpPath) || fs.readdirSync(tmpPath).length !== 2)) return [3 /*break*/, 3];
99
- return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.wasm"), tmpPath)];
124
+ tmpPath = "".concat(os.tmpdir(), "/").concat(tmpDir, "-").concat(treeDepth);
125
+ if (!(!node_fs.existsSync(tmpPath) || node_fs.readdirSync(tmpPath).length !== 2)) return [3 /*break*/, 3];
126
+ return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.wasm"), "".concat(tmpPath, "/semaphore.wasm"))];
100
127
  case 1:
101
128
  _a.sent();
102
- return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.zkey"), tmpPath)];
129
+ return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.zkey"), "".concat(tmpPath, "/semaphore.zkey"))];
103
130
  case 2:
104
131
  _a.sent();
105
132
  _a.label = 3;
@@ -118,9 +145,7 @@ function getSnarkArtifacts(treeDepth) {
118
145
  * @returns The message digest.
119
146
  */
120
147
  function hash(message) {
121
- message = bignumber.BigNumber.from(message).toTwos(256).toHexString();
122
- message = bytes.zeroPad(message, 32);
123
- return (BigInt(keccak256.keccak256(message)) >> BigInt(8)).toString();
148
+ return (BigInt(crypto.keccak256(utils.toBeHex(message, 32))) >> BigInt(8)).toString();
124
149
  }
125
150
 
126
151
  /**
@@ -141,12 +166,24 @@ function packPoints(proof) {
141
166
  ];
142
167
  }
143
168
 
169
+ function toBigInt(value) {
170
+ try {
171
+ return utils.toBigInt(value);
172
+ }
173
+ catch (error) {
174
+ if (typeof value === "string") {
175
+ return utils.toBigInt(abi.encodeBytes32String(value));
176
+ }
177
+ throw TypeError(error.message);
178
+ }
179
+ }
180
+
144
181
  /**
145
182
  * Generates a Semaphore proof.
146
183
  * @param identity The Semaphore identity.
147
184
  * @param groupOrMerkleProof The Semaphore group or its Merkle proof.
148
- * @param scope The external nullifier.
149
- * @param message The Semaphore signal.
185
+ * @param scope The Semaphore scope.
186
+ * @param message The Semaphore message.
150
187
  * @param merkleTreeDepth The depth of the tree with which the circuit was compiled.
151
188
  * @param snarkArtifacts The SNARK artifacts.
152
189
  * @returns The Semaphore proof ready to be verified.
@@ -157,6 +194,8 @@ function generateProof(identity, groupOrMerkleProof, message, scope, merkleTreeD
157
194
  return __generator(this, function (_b) {
158
195
  switch (_b.label) {
159
196
  case 0:
197
+ message = toBigInt(message);
198
+ scope = toBigInt(scope);
160
199
  if ("siblings" in groupOrMerkleProof) {
161
200
  merkleProof = groupOrMerkleProof;
162
201
  }
@@ -201,8 +240,8 @@ function generateProof(identity, groupOrMerkleProof, message, scope, merkleTreeD
201
240
  merkleTreeDepth: merkleTreeDepth,
202
241
  merkleTreeRoot: publicSignals[0],
203
242
  nullifier: publicSignals[1],
204
- message: bignumber.BigNumber.from(message).toString(),
205
- scope: bignumber.BigNumber.from(scope).toString(),
243
+ message: message.toString(),
244
+ scope: scope.toString(),
206
245
  points: packPoints(proof)
207
246
  }];
208
247
  }
@@ -1,18 +1,21 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/proof
3
- * @version 4.0.0-alpha.6
3
+ * @version 4.0.0-alpha.8
4
4
  * @file A library to generate and verify Semaphore proofs.
5
5
  * @copyright Ethereum Foundation 2024
6
6
  * @license MIT
7
7
  * @see [Github]{@link https://github.com/semaphore-protocol/semaphore/tree/main/packages/proof}
8
8
  */
9
- import { BigNumber } from '@ethersproject/bignumber';
10
9
  import { groth16 } from 'snarkjs';
11
- import download from 'download';
12
- import fs from 'fs';
13
- import tmp from 'tmp';
14
- import { zeroPad } from '@ethersproject/bytes';
15
- import { keccak256 } from '@ethersproject/keccak256';
10
+ import { existsSync, readdirSync, createWriteStream } from 'node:fs';
11
+ import { mkdir } from 'node:fs/promises';
12
+ import os from 'node:os';
13
+ import { dirname } from 'node:path';
14
+ import { Readable } from 'node:stream';
15
+ import { finished } from 'node:stream/promises';
16
+ import { keccak256 } from 'ethers/crypto';
17
+ import { toBeHex, toBigInt as toBigInt$1 } from 'ethers/utils';
18
+ import { encodeBytes32String } from 'ethers/abi';
16
19
 
17
20
  /******************************************************************************
18
21
  Copyright (c) Microsoft Corporation.
@@ -85,6 +88,30 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
85
88
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
86
89
  };
87
90
 
91
+ function download(url, outputPath) {
92
+ return __awaiter(this, void 0, void 0, function () {
93
+ var response, dir, fileStream;
94
+ return __generator(this, function (_a) {
95
+ switch (_a.label) {
96
+ case 0: return [4 /*yield*/, fetch(url)];
97
+ case 1:
98
+ response = _a.sent();
99
+ if (!response.ok) {
100
+ throw new Error("Failed to fetch ".concat(url, ": ").concat(response.statusText));
101
+ }
102
+ dir = dirname(outputPath);
103
+ return [4 /*yield*/, mkdir(dir, { recursive: true })];
104
+ case 2:
105
+ _a.sent();
106
+ fileStream = createWriteStream(outputPath);
107
+ return [4 /*yield*/, finished(Readable.fromWeb(response.body).pipe(fileStream))];
108
+ case 3:
109
+ _a.sent();
110
+ return [2 /*return*/];
111
+ }
112
+ });
113
+ });
114
+ }
88
115
  function getSnarkArtifacts(treeDepth) {
89
116
  return __awaiter(this, void 0, void 0, function () {
90
117
  var tmpDir, tmpPath;
@@ -92,12 +119,12 @@ function getSnarkArtifacts(treeDepth) {
92
119
  switch (_a.label) {
93
120
  case 0:
94
121
  tmpDir = "semaphore-proof";
95
- tmpPath = "".concat(tmp.tmpdir, "/").concat(tmpDir, "-").concat(treeDepth);
96
- if (!(!fs.existsSync(tmpPath) || fs.readdirSync(tmpPath).length !== 2)) return [3 /*break*/, 3];
97
- return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.wasm"), tmpPath)];
122
+ tmpPath = "".concat(os.tmpdir(), "/").concat(tmpDir, "-").concat(treeDepth);
123
+ if (!(!existsSync(tmpPath) || readdirSync(tmpPath).length !== 2)) return [3 /*break*/, 3];
124
+ return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.wasm"), "".concat(tmpPath, "/semaphore.wasm"))];
98
125
  case 1:
99
126
  _a.sent();
100
- return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.zkey"), tmpPath)];
127
+ return [4 /*yield*/, download("https://semaphore.cedoor.dev/artifacts/".concat(treeDepth, "/semaphore.zkey"), "".concat(tmpPath, "/semaphore.zkey"))];
101
128
  case 2:
102
129
  _a.sent();
103
130
  _a.label = 3;
@@ -116,9 +143,7 @@ function getSnarkArtifacts(treeDepth) {
116
143
  * @returns The message digest.
117
144
  */
118
145
  function hash(message) {
119
- message = BigNumber.from(message).toTwos(256).toHexString();
120
- message = zeroPad(message, 32);
121
- return (BigInt(keccak256(message)) >> BigInt(8)).toString();
146
+ return (BigInt(keccak256(toBeHex(message, 32))) >> BigInt(8)).toString();
122
147
  }
123
148
 
124
149
  /**
@@ -139,12 +164,24 @@ function packPoints(proof) {
139
164
  ];
140
165
  }
141
166
 
167
+ function toBigInt(value) {
168
+ try {
169
+ return toBigInt$1(value);
170
+ }
171
+ catch (error) {
172
+ if (typeof value === "string") {
173
+ return toBigInt$1(encodeBytes32String(value));
174
+ }
175
+ throw TypeError(error.message);
176
+ }
177
+ }
178
+
142
179
  /**
143
180
  * Generates a Semaphore proof.
144
181
  * @param identity The Semaphore identity.
145
182
  * @param groupOrMerkleProof The Semaphore group or its Merkle proof.
146
- * @param scope The external nullifier.
147
- * @param message The Semaphore signal.
183
+ * @param scope The Semaphore scope.
184
+ * @param message The Semaphore message.
148
185
  * @param merkleTreeDepth The depth of the tree with which the circuit was compiled.
149
186
  * @param snarkArtifacts The SNARK artifacts.
150
187
  * @returns The Semaphore proof ready to be verified.
@@ -155,6 +192,8 @@ function generateProof(identity, groupOrMerkleProof, message, scope, merkleTreeD
155
192
  return __generator(this, function (_b) {
156
193
  switch (_b.label) {
157
194
  case 0:
195
+ message = toBigInt(message);
196
+ scope = toBigInt(scope);
158
197
  if ("siblings" in groupOrMerkleProof) {
159
198
  merkleProof = groupOrMerkleProof;
160
199
  }
@@ -199,8 +238,8 @@ function generateProof(identity, groupOrMerkleProof, message, scope, merkleTreeD
199
238
  merkleTreeDepth: merkleTreeDepth,
200
239
  merkleTreeRoot: publicSignals[0],
201
240
  nullifier: publicSignals[1],
202
- message: BigNumber.from(message).toString(),
203
- scope: BigNumber.from(scope).toString(),
241
+ message: message.toString(),
242
+ scope: scope.toString(),
204
243
  points: packPoints(proof)
205
244
  }];
206
245
  }
@@ -1,15 +1,14 @@
1
- import { BytesLike, Hexable } from "@ethersproject/bytes";
2
1
  import type { Group, MerkleProof } from "@semaphore-protocol/group";
3
2
  import type { Identity } from "@semaphore-protocol/identity";
4
- import { SemaphoreProof, SnarkArtifacts } from "./types";
3
+ import { BigNumberish, SemaphoreProof, SnarkArtifacts } from "./types";
5
4
  /**
6
5
  * Generates a Semaphore proof.
7
6
  * @param identity The Semaphore identity.
8
7
  * @param groupOrMerkleProof The Semaphore group or its Merkle proof.
9
- * @param scope The external nullifier.
10
- * @param message The Semaphore signal.
8
+ * @param scope The Semaphore scope.
9
+ * @param message The Semaphore message.
11
10
  * @param merkleTreeDepth The depth of the tree with which the circuit was compiled.
12
11
  * @param snarkArtifacts The SNARK artifacts.
13
12
  * @returns The Semaphore proof ready to be verified.
14
13
  */
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>;
14
+ export default function generateProof(identity: Identity, groupOrMerkleProof: Group | MerkleProof, message: BigNumberish | Uint8Array | string, scope: BigNumberish | Uint8Array | string, merkleTreeDepth?: number, snarkArtifacts?: SnarkArtifacts): Promise<SemaphoreProof>;
@@ -1,8 +1,8 @@
1
- import { BytesLike, Hexable } from "@ethersproject/bytes";
2
1
  import { NumericString } from "snarkjs";
2
+ import { BigNumberish } from "./types";
3
3
  /**
4
4
  * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
5
5
  * @param message The message to be hashed.
6
6
  * @returns The message digest.
7
7
  */
8
- export default function hash(message: BytesLike | Hexable | number | bigint): NumericString;
8
+ export default function hash(message: BigNumberish): NumericString;
@@ -0,0 +1,2 @@
1
+ import { BigNumberish } from "./types";
2
+ export default function toBigInt(value: BigNumberish | Uint8Array | string): bigint;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semaphore-protocol/proof",
3
- "version": "4.0.0-alpha.6",
3
+ "version": "4.0.0-alpha.8",
4
4
  "description": "A library to generate and verify Semaphore proofs.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -38,7 +38,6 @@
38
38
  "access": "public"
39
39
  },
40
40
  "devDependencies": {
41
- "@ethersproject/strings": "^5.7.0",
42
41
  "@rollup/plugin-alias": "^5.1.0",
43
42
  "@rollup/plugin-json": "^6.1.0",
44
43
  "@types/download": "^8.0.5",
@@ -50,16 +49,12 @@
50
49
  "rollup-plugin-typescript2": "^0.36.0"
51
50
  },
52
51
  "peerDependencies": {
53
- "@semaphore-protocol/group": "4.0.0-alpha.6",
54
- "@semaphore-protocol/identity": "4.0.0-alpha.6"
52
+ "@semaphore-protocol/group": "4.0.0-alpha.8",
53
+ "@semaphore-protocol/identity": "4.0.0-alpha.8"
55
54
  },
56
55
  "dependencies": {
57
- "@ethersproject/bignumber": "5.7.0",
58
- "@ethersproject/bytes": "5.7.0",
59
- "@ethersproject/keccak256": "5.7.0",
60
56
  "@types/snarkjs": "0.7.8",
61
- "download": "8.0.0",
62
- "snarkjs": "0.7.3",
63
- "tmp": "0.2.1"
57
+ "ethers": "6.10.0",
58
+ "snarkjs": "0.7.3"
64
59
  }
65
60
  }
@@ -1,19 +1,18 @@
1
- import { BigNumber } from "@ethersproject/bignumber"
2
- import { BytesLike, Hexable } from "@ethersproject/bytes"
3
1
  import type { Group, MerkleProof } from "@semaphore-protocol/group"
4
2
  import type { Identity } from "@semaphore-protocol/identity"
5
3
  import { NumericString, groth16 } from "snarkjs"
6
4
  import getSnarkArtifacts from "./get-snark-artifacts.node"
7
5
  import hash from "./hash"
8
6
  import packPoints from "./pack-points"
9
- import { SemaphoreProof, SnarkArtifacts } from "./types"
7
+ import { BigNumberish, SemaphoreProof, SnarkArtifacts } from "./types"
8
+ import toBigInt from "./to-bigint"
10
9
 
11
10
  /**
12
11
  * Generates a Semaphore proof.
13
12
  * @param identity The Semaphore identity.
14
13
  * @param groupOrMerkleProof The Semaphore group or its Merkle proof.
15
- * @param scope The external nullifier.
16
- * @param message The Semaphore signal.
14
+ * @param scope The Semaphore scope.
15
+ * @param message The Semaphore message.
17
16
  * @param merkleTreeDepth The depth of the tree with which the circuit was compiled.
18
17
  * @param snarkArtifacts The SNARK artifacts.
19
18
  * @returns The Semaphore proof ready to be verified.
@@ -21,11 +20,14 @@ import { SemaphoreProof, SnarkArtifacts } from "./types"
21
20
  export default async function generateProof(
22
21
  identity: Identity,
23
22
  groupOrMerkleProof: Group | MerkleProof,
24
- message: BytesLike | Hexable | number | bigint,
25
- scope: BytesLike | Hexable | number | bigint,
23
+ message: BigNumberish | Uint8Array | string,
24
+ scope: BigNumberish | Uint8Array | string,
26
25
  merkleTreeDepth?: number,
27
26
  snarkArtifacts?: SnarkArtifacts
28
27
  ): Promise<SemaphoreProof> {
28
+ message = toBigInt(message)
29
+ scope = toBigInt(scope)
30
+
29
31
  let merkleProof
30
32
 
31
33
  if ("siblings" in groupOrMerkleProof) {
@@ -46,7 +48,6 @@ export default async function generateProof(
46
48
  }
47
49
 
48
50
  // If the Snark artifacts are not defined they will be automatically downloaded.
49
- /* istanbul ignore next */
50
51
  if (!snarkArtifacts) {
51
52
  snarkArtifacts = await getSnarkArtifacts(merkleTreeDepth)
52
53
  }
@@ -81,8 +82,8 @@ export default async function generateProof(
81
82
  merkleTreeDepth,
82
83
  merkleTreeRoot: publicSignals[0],
83
84
  nullifier: publicSignals[1],
84
- message: BigNumber.from(message).toString() as NumericString,
85
- scope: BigNumber.from(scope).toString() as NumericString,
85
+ message: message.toString() as NumericString,
86
+ scope: scope.toString() as NumericString,
86
87
  points: packPoints(proof)
87
88
  }
88
89
  }
@@ -1,16 +1,40 @@
1
1
  /* istanbul ignore file */
2
- import download from "download"
3
- import fs from "fs"
4
- import tmp from "tmp"
2
+ import { createWriteStream, existsSync, readdirSync } from "node:fs"
3
+ import { mkdir } from "node:fs/promises"
4
+ import os from "node:os"
5
+ import { dirname } from "node:path"
6
+ import { Readable } from "node:stream"
7
+ import { finished } from "node:stream/promises"
5
8
  import { SnarkArtifacts } from "./types"
6
9
 
10
+ async function download(url: string, outputPath: string) {
11
+ const response = await fetch(url)
12
+
13
+ if (!response.ok) {
14
+ throw new Error(`Failed to fetch ${url}: ${response.statusText}`)
15
+ }
16
+
17
+ // Ensure the directory exists.
18
+ const dir = dirname(outputPath)
19
+ await mkdir(dir, { recursive: true })
20
+
21
+ const fileStream = createWriteStream(outputPath)
22
+ await finished(Readable.fromWeb(response.body as any).pipe(fileStream))
23
+ }
24
+
7
25
  export default async function getSnarkArtifacts(treeDepth: number): Promise<SnarkArtifacts> {
8
26
  const tmpDir = "semaphore-proof"
9
- const tmpPath = `${tmp.tmpdir}/${tmpDir}-${treeDepth}`
27
+ const tmpPath = `${os.tmpdir()}/${tmpDir}-${treeDepth}`
10
28
 
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)
29
+ if (!existsSync(tmpPath) || readdirSync(tmpPath).length !== 2) {
30
+ await download(
31
+ `https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.wasm`,
32
+ `${tmpPath}/semaphore.wasm`
33
+ )
34
+ await download(
35
+ `https://semaphore.cedoor.dev/artifacts/${treeDepth}/semaphore.zkey`,
36
+ `${tmpPath}/semaphore.zkey`
37
+ )
14
38
  }
15
39
 
16
40
  return {
package/src/hash.ts CHANGED
@@ -1,16 +1,13 @@
1
- import { BigNumber } from "@ethersproject/bignumber"
2
- import { BytesLike, Hexable, zeroPad } from "@ethersproject/bytes"
3
- import { keccak256 } from "@ethersproject/keccak256"
1
+ import { keccak256 } from "ethers/crypto"
2
+ import { toBeHex } from "ethers/utils"
4
3
  import { NumericString } from "snarkjs"
4
+ import { BigNumberish } from "./types"
5
5
 
6
6
  /**
7
7
  * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
8
8
  * @param message The message to be hashed.
9
9
  * @returns The message digest.
10
10
  */
11
- export default function hash(message: BytesLike | Hexable | number | bigint): NumericString {
12
- message = BigNumber.from(message).toTwos(256).toHexString()
13
- message = zeroPad(message, 32)
14
-
15
- return (BigInt(keccak256(message)) >> BigInt(8)).toString() as NumericString
11
+ export default function hash(message: BigNumberish): NumericString {
12
+ return (BigInt(keccak256(toBeHex(message, 32))) >> BigInt(8)).toString()
16
13
  }
@@ -0,0 +1,15 @@
1
+ import { encodeBytes32String } from "ethers/abi"
2
+ import { toBigInt as _toBigInt } from "ethers/utils"
3
+ import { BigNumberish } from "./types"
4
+
5
+ export default function toBigInt(value: BigNumberish | Uint8Array | string): bigint {
6
+ try {
7
+ return _toBigInt(value)
8
+ } catch (error: any) {
9
+ if (typeof value === "string") {
10
+ return _toBigInt(encodeBytes32String(value))
11
+ }
12
+
13
+ throw TypeError(error.message)
14
+ }
15
+ }