@solarity/zkit 0.1.1 → 0.2.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.
@@ -1,89 +1,71 @@
1
- import { randomBytes } from "crypto";
2
1
  import ejs from "ejs";
3
2
  import fs from "fs";
4
3
  import path from "path";
5
4
  import * as snarkjs from "snarkjs";
6
5
 
7
- import { defaultCompileOptions, CompileOptions } from "../config/config";
8
- import { ManagerZKit } from "./ManagerZKit";
9
- import { Calldata, DirType, FileType, Inputs, ProofStruct } from "../types/types";
10
- import { readDirRecursively } from "../utils/utils";
11
-
12
- const { CircomRunner, bindings } = require("@distributedlab/circom2");
6
+ import {
7
+ ArtifactsFileType,
8
+ Calldata,
9
+ CircuitZKitConfig,
10
+ Inputs,
11
+ ProofStruct,
12
+ VerifierTemplateType,
13
+ } from "../types/circuit-zkit";
13
14
 
14
15
  /**
15
16
  * `CircuitZKit` represents a single circuit and provides a high-level API to work with it.
16
- *
17
- * @dev This class is not meant to be used directly. Use the `CircomZKit` to create its instance.
18
17
  */
19
18
  export class CircuitZKit {
20
- /**
21
- * Creates a new instance of `CircuitZKit`.
22
- *
23
- * @param {string} _circuit - The path to the circuit.
24
- * @param {ManagerZKit} _manager - The manager that maintains the global state.
25
- */
26
- constructor(
27
- private readonly _circuit: string,
28
- private readonly _manager: ManagerZKit,
29
- ) {}
19
+ constructor(private readonly _config: CircuitZKitConfig) {}
30
20
 
31
21
  /**
32
- * Compiles the circuit and generates the artifacts.
22
+ * Returns the Solidity verifier template for the specified proving system.
33
23
  *
34
- * @dev If compilation fails, the latest valid artifacts will be preserved.
35
- * @dev Doesn't show the compilation error if `quiet` is set to `true`.
36
- *
37
- * @param {Partial<CompileOptions>} [options=defaultCompileOptions] - Compilation options.
24
+ * @param {VerifierTemplateType} templateType - The template type.
25
+ * @returns {string} The Solidity verifier template.
38
26
  */
39
- public async compile(options: Partial<CompileOptions> = defaultCompileOptions): Promise<void> {
40
- const tempDir = this._manager.getTempDir();
41
-
42
- try {
43
- const artifactDir = this._getDir("artifact");
44
-
45
- fs.mkdirSync(tempDir, { recursive: true });
46
-
47
- const overriddenOptions: CompileOptions = { ...defaultCompileOptions, ...options };
48
-
49
- await this._compile(overriddenOptions, tempDir);
50
-
51
- await this._generateZKey(overriddenOptions, tempDir);
52
- await this._generateVKey(tempDir);
53
-
54
- this._moveFromTempDirToOutDir(tempDir, artifactDir);
55
- } finally {
56
- fs.rmSync(tempDir, { recursive: true, force: true });
27
+ public static getTemplate(templateType: VerifierTemplateType): string {
28
+ switch (templateType) {
29
+ case "groth16":
30
+ return fs.readFileSync(path.join(__dirname, "templates", "verifier_groth16.sol.ejs"), "utf8");
31
+ default:
32
+ throw new Error(`Ambiguous template type: ${templateType}.`);
57
33
  }
58
34
  }
59
35
 
60
36
  /**
61
- * Creates a verifier contract.
37
+ * Creates a Solidity verifier contract.
62
38
  */
63
39
  public async createVerifier(): Promise<void> {
64
- const tempDir = this._manager.getTempDir();
65
-
66
- try {
67
- const verifierDir = this._getDir("verifier");
40
+ const vKeyFilePath: string = this.mustGetArtifactsFilePath("vkey");
41
+ const verifierFilePath = path.join(this._config.verifierDirPath, `${this.getVerifierName()}.sol`);
68
42
 
69
- fs.mkdirSync(tempDir, { recursive: true });
43
+ const verifierTemplate: string = CircuitZKit.getTemplate(this.getTemplateType());
70
44
 
71
- const vKeyFile = this._mustGetFile("vkey");
72
- const verifierFile = this._getFile("sol", tempDir);
45
+ if (!fs.existsSync(this._config.verifierDirPath)) {
46
+ fs.mkdirSync(this._config.verifierDirPath, { recursive: true });
47
+ }
73
48
 
74
- const groth16Template = this._manager.getTemplate("groth16");
49
+ const templateParams = JSON.parse(fs.readFileSync(vKeyFilePath, "utf-8"));
50
+ templateParams["verifier_id"] = this.getVerifierName();
75
51
 
76
- const templateParams = JSON.parse(fs.readFileSync(vKeyFile, "utf-8"));
77
- templateParams["verifier_id"] = this.getVerifierId();
52
+ const verifierCode = ejs.render(verifierTemplate, templateParams);
78
53
 
79
- const verifierCode = ejs.render(groth16Template, templateParams);
54
+ fs.writeFileSync(verifierFilePath, verifierCode, "utf-8");
55
+ }
80
56
 
81
- fs.writeFileSync(verifierFile, verifierCode, "utf-8");
57
+ /**
58
+ * Creates a witness for the given inputs.
59
+ *
60
+ * @dev The `inputs` should be in the same order as the circuit expects them.
61
+ *
62
+ * @param {Inputs} inputs - The inputs for the circuit.
63
+ */
64
+ public async createWitness(inputs: Inputs): Promise<void> {
65
+ const wasmFile = this.mustGetArtifactsFilePath("wasm");
66
+ const wtnsFile = this.getArtifactsFilePath("wtns");
82
67
 
83
- this._moveFromTempDirToOutDir(tempDir, verifierDir);
84
- } finally {
85
- fs.rmSync(tempDir, { recursive: true, force: true });
86
- }
68
+ await snarkjs.wtns.calculate(inputs, wasmFile, wtnsFile);
87
69
  }
88
70
 
89
71
  /**
@@ -96,8 +78,8 @@ export class CircuitZKit {
96
78
  * @todo Add support for other proving systems.
97
79
  */
98
80
  public async generateProof(inputs: Inputs): Promise<ProofStruct> {
99
- const zKeyFile = this._mustGetFile("zkey");
100
- const wasmFile = this._mustGetFile("wasm");
81
+ const zKeyFile = this.mustGetArtifactsFilePath("zkey");
82
+ const wasmFile = this.mustGetArtifactsFilePath("wasm");
101
83
 
102
84
  return (await snarkjs.groth16.fullProve(inputs, wasmFile, zKeyFile)) as ProofStruct;
103
85
  }
@@ -112,7 +94,7 @@ export class CircuitZKit {
112
94
  * @returns {Promise<boolean>} Whether the proof is valid.
113
95
  */
114
96
  public async verifyProof(proof: ProofStruct): Promise<boolean> {
115
- const vKeyFile = this._mustGetFile("vkey");
97
+ const vKeyFile = this.mustGetArtifactsFilePath("vkey");
116
98
 
117
99
  const verifier = JSON.parse(fs.readFileSync(vKeyFile).toString());
118
100
 
@@ -133,264 +115,87 @@ export class CircuitZKit {
133
115
  }
134
116
 
135
117
  /**
136
- * Returns the circuit ID. The circuit ID is the name of the circuit file without the extension.
118
+ * Returns the circuit name. The circuit name is the name of the circuit file without the extension.
137
119
  *
138
- * @returns {string} The circuit ID.
120
+ * @returns {string} The circuit name.
139
121
  */
140
- public getCircuitId(): string {
141
- return path.parse(this._circuit).name;
122
+ public getCircuitName(): string {
123
+ return this._config.circuitName;
142
124
  }
143
125
 
144
126
  /**
145
- * Returns the verifier ID. The verifier ID is the name of the circuit file without the extension, suffixed with "Verifier".
127
+ * Returns the verifier name. The verifier name is the name of the circuit file without the extension, suffixed with "Verifier".
146
128
  *
147
- * @returns {string} The verifier ID.
129
+ * @returns {string} The verifier name.
148
130
  */
149
- public getVerifierId(): string {
150
- return `${path.parse(this._circuit).name}Verifier`;
131
+ public getVerifierName(): string {
132
+ return `${this._config.circuitName}Verifier`;
151
133
  }
152
134
 
153
135
  /**
154
- * Generates zero-knowledge key for the circuit.
136
+ * Returns the type of verifier template that was stored in the config
155
137
  *
156
- * @param {CompileOptions} options - Compilation options.
157
- * @param {string} outDir - The directory to save the generated key.
158
- * @todo This method may cause issues https://github.com/iden3/snarkjs/issues/494
138
+ * @returns {VerifierTemplateType} The verifier template type.
159
139
  */
160
- private async _generateZKey(options: CompileOptions, outDir: string): Promise<void> {
161
- const r1csFile = this._getFile("r1cs", outDir);
162
- const zKeyFile = this._getFile("zkey", outDir);
163
-
164
- const constraints = await this._getConstraints(outDir);
165
- const ptauFile = await this._manager.fetchPtauFile(constraints);
166
-
167
- if (options.setup == "groth16") {
168
- await snarkjs.zKey.newZKey(r1csFile, ptauFile, zKeyFile);
169
-
170
- const zKeyFileNext = `${zKeyFile}.next.zkey`;
171
-
172
- for (let i = 0; i < options.contributions; ++i) {
173
- await snarkjs.zKey.contribute(
174
- zKeyFile,
175
- zKeyFileNext,
176
- `${zKeyFile}_contribution_${i}`,
177
- randomBytes(32).toString("hex"),
178
- );
179
-
180
- fs.rmSync(zKeyFile);
181
- fs.renameSync(zKeyFileNext, zKeyFile);
182
- }
183
- }
184
- }
185
-
186
- /**
187
- * Generates verification key for the circuit.
188
- *
189
- * @param {string} outDir - The directory to save the generated key.
190
- */
191
- private async _generateVKey(outDir: string): Promise<void> {
192
- const zKeyFile = this._getFile("zkey", outDir);
193
- const vKeyFile = this._getFile("vkey", outDir);
194
-
195
- const vKeyData = await snarkjs.zKey.exportVerificationKey(zKeyFile);
196
-
197
- fs.writeFileSync(vKeyFile, JSON.stringify(vKeyData));
198
- }
199
-
200
- /**
201
- * Returns the arguments to compile the circuit.
202
- *
203
- * @param {CompileOptions} options - Compilation options.
204
- * @param {string} outDir - The directory to save the compiled artifacts.
205
- * @returns {string[]} The arguments to compile the circuit.
206
- */
207
- private _getCompileArgs(options: CompileOptions, outDir: string): string[] {
208
- let args = [this._circuit, "--r1cs", "--wasm"];
209
-
210
- options.sym && args.push("--sym");
211
- options.json && args.push("--json");
212
- options.c && args.push("--c");
213
-
214
- args.push("-o", outDir);
215
-
216
- return args;
140
+ public getTemplateType(): VerifierTemplateType {
141
+ return this._config.templateType ?? "groth16";
217
142
  }
218
143
 
219
144
  /**
220
- * Compiles the circuit.
145
+ * Returns the path to the file of the given type inside artifacts directory. Throws an error if the file doesn't exist.
221
146
  *
222
- * @param {CompileOptions} options - Compilation options.
223
- * @param {string} outDir - The directory to save the compiled artifacts.
224
- */
225
- private async _compile(options: CompileOptions, outDir: string): Promise<void> {
226
- const args = this._getCompileArgs(options, outDir);
227
-
228
- try {
229
- await this._getCircomRunner(args, options.quiet).execute(this._manager.getCompiler());
230
- } catch (err) {
231
- if (options.quiet) {
232
- throw new Error(
233
- 'Compilation failed with an unknown error. Consider passing "quiet=false" flag to see the compilation error.',
234
- { cause: err },
235
- );
236
- }
237
-
238
- throw new Error("Compilation failed.", { cause: err });
239
- }
240
- }
241
-
242
- /**
243
- * Returns the number of constraints in the circuit. This value is used to fetch the correct `ptau` file.
244
- *
245
- * @param {string} outDir - The directory where the compiled artifacts are saved.
246
- * @returns {Promise<number>} The number of constraints in the circuit.
147
+ * @param {ArtifactsFileType} fileType - The type of the file.
148
+ * @returns {string} The path to the file.
247
149
  */
248
- async _getConstraints(outDir: string): Promise<number> {
249
- const r1csFile = this._getFile("r1cs", outDir);
250
-
251
- const r1csDescriptor = fs.openSync(r1csFile, "r");
252
-
253
- const readBytes = (position: number, length: number): bigint => {
254
- const buffer = Buffer.alloc(length);
255
-
256
- fs.readSync(r1csDescriptor, buffer, { length, position });
150
+ public mustGetArtifactsFilePath(fileType: ArtifactsFileType): string {
151
+ const file = this.getArtifactsFilePath(fileType);
257
152
 
258
- return BigInt(`0x${buffer.reverse().toString("hex")}`);
259
- };
260
-
261
- /// @dev https://github.com/iden3/r1csfile/blob/d82959da1f88fbd06db0407051fde94afbf8824a/doc/r1cs_bin_format.md#format-of-the-file
262
- const numberOfSections = readBytes(8, 4);
263
- let sectionStart = 12;
264
-
265
- for (let i = 0; i < numberOfSections; ++i) {
266
- const sectionType = Number(readBytes(sectionStart, 4));
267
- const sectionSize = Number(readBytes(sectionStart + 4, 8));
268
-
269
- /// @dev Reading header section
270
- if (sectionType == 1) {
271
- const totalConstraintsOffset = 4 + 8 + 4 + 32 + 4 + 4 + 4 + 4 + 8;
272
-
273
- return Number(readBytes(sectionStart + totalConstraintsOffset, 4));
274
- }
275
-
276
- sectionStart += 4 + 8 + sectionSize;
153
+ if (!fs.existsSync(file)) {
154
+ throw new Error(`Expected the file "${file}" to exist`);
277
155
  }
278
156
 
279
- throw new Error("Header section is not found.");
157
+ return file;
280
158
  }
281
159
 
282
160
  /**
283
- * Returns the path to the file of the given type.
161
+ * Returns the path to the file of the given type inside artifacts directory.
284
162
  *
285
- * @param {FileType} fileType - The type of the file.
286
- * @param {string | undefined} temp - The temporary directory to use.
163
+ * @param {ArtifactsFileType} fileType - The type of the file.
287
164
  * @returns {string} The path to the file.
288
165
  */
289
- private _getFile(fileType: FileType, temp?: string): string {
290
- const circuitId = this.getCircuitId();
166
+ public getArtifactsFilePath(fileType: ArtifactsFileType): string {
167
+ const circuitName = this.getCircuitName();
168
+
169
+ let fileName: string;
170
+ let fileDir: string = this._config.circuitArtifactsPath;
291
171
 
292
172
  switch (fileType) {
293
173
  case "r1cs":
294
- return path.join(temp ?? this._getDir("artifact"), `${circuitId}.r1cs`);
174
+ fileName = `${circuitName}.r1cs`;
175
+ break;
295
176
  case "zkey":
296
- return path.join(temp ?? this._getDir("artifact"), `${circuitId}.zkey`);
177
+ fileName = `${circuitName}.zkey`;
178
+ break;
297
179
  case "vkey":
298
- return path.join(temp ?? this._getDir("artifact"), `${circuitId}.vkey.json`);
180
+ fileName = `${circuitName}.vkey.json`;
181
+ break;
299
182
  case "sym":
300
- return path.join(temp ?? this._getDir("artifact"), `${circuitId}.sym`);
183
+ fileName = `${circuitName}.sym`;
184
+ break;
301
185
  case "json":
302
- return path.join(temp ?? this._getDir("artifact"), `${circuitId}.json`);
186
+ fileName = `${circuitName}_constraints.json`;
187
+ break;
188
+ case "wtns":
189
+ fileName = `${circuitName}.wtns`;
190
+ break;
303
191
  case "wasm":
304
- return path.join(temp ?? this._getDir("artifact"), `${circuitId}_js`, `${circuitId}.wasm`);
305
- case "sol":
306
- return path.join(temp ?? this._getDir("verifier"), `${circuitId}Verifier.sol`);
192
+ fileName = `${circuitName}.wasm`;
193
+ fileDir = path.join(fileDir, `${circuitName}_js`);
194
+ break;
307
195
  default:
308
196
  throw new Error(`Ambiguous file type: ${fileType}.`);
309
197
  }
310
- }
311
-
312
- /**
313
- * Returns the path to the directory of the given type.
314
- *
315
- * @param {DirType} dirType - The type of the directory.
316
- * @returns {string} The path to the directory.
317
- */
318
- private _getDir(dirType: DirType): string {
319
- const circuitRelativePath = path.relative(this._manager.getCircuitsDir(), this._circuit);
320
-
321
- switch (dirType) {
322
- case "circuit":
323
- return path.join(this._manager.getCircuitsDir(), circuitRelativePath, "..");
324
- case "artifact":
325
- return path.join(this._manager.getArtifactsDir(), circuitRelativePath);
326
- case "verifier":
327
- return path.join(this._manager.getVerifiersDir(), circuitRelativePath, "..");
328
- default:
329
- throw new Error(`Ambiguous dir type: ${dirType}.`);
330
- }
331
- }
332
-
333
- /**
334
- * Returns the path to the file of the given type. Throws an error if the file doesn't exist.
335
- *
336
- * @param {FileType} fileType - The type of the file.
337
- * @param {string | undefined} temp - The temporary directory to use.
338
- * @returns {string} The path to the file.
339
- */
340
- private _mustGetFile(fileType: FileType, temp?: string): string {
341
- const file = this._getFile(fileType, temp);
342
-
343
- if (!fs.existsSync(file)) {
344
- throw new Error(`Expected the file "${file}" to exist`);
345
- }
346
-
347
- return file;
348
- }
349
198
 
350
- /**
351
- * Moves the files from the temporary directory to the output directory.
352
- *
353
- * @param {string} tempDir - The temporary directory.
354
- * @param {string} outDir - The output directory.
355
- */
356
- private _moveFromTempDirToOutDir(tempDir: string, outDir: string): void {
357
- fs.mkdirSync(outDir, { recursive: true });
358
-
359
- readDirRecursively(tempDir, (dir: string, file: string) => {
360
- const correspondingOutDir = path.join(outDir, path.relative(tempDir, dir));
361
- const correspondingOutFile = path.join(outDir, path.relative(tempDir, file));
362
-
363
- if (!fs.existsSync(correspondingOutDir)) {
364
- fs.mkdirSync(correspondingOutDir);
365
- }
366
-
367
- if (fs.existsSync(correspondingOutFile)) {
368
- fs.rmSync(correspondingOutFile);
369
- }
370
-
371
- fs.copyFileSync(file, correspondingOutFile);
372
- });
373
- }
374
-
375
- /**
376
- * Returns a new instance of `CircomRunner`. The `CircomRunner` is used to compile the circuit.
377
- *
378
- * @param {string[]} args - The arguments to run the `circom` compiler.
379
- * @param {boolean} quiet - Whether to suppress the compilation error.
380
- * @returns {typeof CircomRunner} The `CircomRunner` instance.
381
- */
382
- private _getCircomRunner(args: string[], quiet: boolean): typeof CircomRunner {
383
- return new CircomRunner({
384
- args,
385
- preopens: { "/": "/" },
386
- bindings: {
387
- ...bindings,
388
- exit(code: number) {
389
- throw new Error(`Compilation error. Exit code: ${code}.`);
390
- },
391
- fs,
392
- },
393
- quiet,
394
- });
199
+ return path.join(fileDir, fileName);
395
200
  }
396
201
  }
package/src/index.ts CHANGED
@@ -1,7 +1,2 @@
1
- export * from "./core/CircomZKit";
2
1
  export * from "./core/CircuitZKit";
3
- export * from "./core/ManagerZKit";
4
-
5
- export { NumericString, PublicSignals, Groth16Proof, Calldata, ProofStruct, Inputs, CircuitInfo } from "./types/types";
6
-
7
- export { CompileOptions, ManagerZKitConfig, defaultCompileOptions, defaultManagerOptions } from "./config/config";
2
+ export * from "./types/circuit-zkit";
@@ -28,16 +28,12 @@ export type InputLike = NumberLike | ArrayLike;
28
28
 
29
29
  export type Inputs = Record<string, InputLike>;
30
30
 
31
- export type CircuitInfo = {
32
- path: string;
33
- id: string | null;
34
- };
35
-
36
- export type FileType = "r1cs" | "zkey" | "vkey" | "sym" | "json" | "wasm" | "sol";
37
- export type DirType = "circuit" | "artifact" | "verifier";
38
- export type TemplateType = "groth16";
39
-
40
- export type PtauInfo = {
41
- file: string;
42
- url: string | null;
31
+ export type ArtifactsFileType = "r1cs" | "zkey" | "vkey" | "sym" | "json" | "wasm" | "wtns";
32
+ export type VerifierTemplateType = "groth16";
33
+
34
+ export type CircuitZKitConfig = {
35
+ circuitName: string;
36
+ circuitArtifactsPath: string;
37
+ verifierDirPath: string;
38
+ templateType?: VerifierTemplateType;
43
39
  };
@@ -1,43 +0,0 @@
1
- import { TemplateType } from "../types/types";
2
-
3
- const { Context } = require("@distributedlab/circom2");
4
-
5
- export type ManagerZKitConfig = {
6
- circuitsDir: string;
7
- artifactsDir: string;
8
- verifiersDir: string;
9
- ptauDir: string;
10
- allowDownload: boolean;
11
- };
12
-
13
- export const defaultManagerOptions: Partial<ManagerZKitConfig> = {
14
- circuitsDir: "circuits",
15
- artifactsDir: "zkit-artifacts",
16
- verifiersDir: "contracts/verifiers",
17
- allowDownload: true,
18
- };
19
-
20
- export type CompileOptions = {
21
- sym: boolean;
22
- json: boolean;
23
- c: boolean;
24
- quiet: boolean;
25
- setup: TemplateType;
26
- contributions: number;
27
- };
28
-
29
- export const defaultCompileOptions: CompileOptions = {
30
- sym: false,
31
- json: false,
32
- c: false,
33
- quiet: false,
34
- setup: "groth16",
35
- contributions: 5,
36
- };
37
-
38
- export type ManagerZKitPrivateConfig = ManagerZKitConfig & {
39
- compiler: typeof Context;
40
- templates: {
41
- groth16: string;
42
- };
43
- };
@@ -1,110 +0,0 @@
1
- import os from "os";
2
- import path from "path";
3
-
4
- import { CircuitZKit } from "./CircuitZKit";
5
- import { ManagerZKit } from "./ManagerZKit";
6
- import { CircuitInfo } from "../types/types";
7
- import { readDirRecursively } from "../utils/utils";
8
- import { defaultManagerOptions, ManagerZKitConfig } from "../config/config";
9
-
10
- /**
11
- * `CircomZKit` acts as a factory for `CircuitZKit` instances.
12
- */
13
- export class CircomZKit {
14
- private readonly _manager: ManagerZKit;
15
-
16
- /**
17
- * Creates a new `CircomZKit` instance.
18
- *
19
- * @param {Partial<ManagerZKitConfig>} [options=defaultManagerOptions] - The configuration options to use.
20
- */
21
- constructor(options: Partial<ManagerZKitConfig> = defaultManagerOptions) {
22
- this._manager = new ManagerZKit({ ...defaultManagerOptions, ...options });
23
- }
24
-
25
- /**
26
- * Returns a `CircuitZKit` instance for the specified circuit.
27
- *
28
- * @dev If the circuit id is not unique, the path to the circuit file must be provided.
29
- *
30
- * @param {string} circuit - The path to the circuit file or the circuit id (filename without extension).
31
- * @returns {CircomZKit} The `CircuitZKit` instance.
32
- */
33
- public getCircuit(circuit: string): CircuitZKit {
34
- const circuits = this._getAllCircuits();
35
-
36
- const candidates = circuits.filter((file) => {
37
- if (circuit.endsWith(".circom")) {
38
- return file == path.normalize(circuit);
39
- }
40
-
41
- return path.basename(file) == `${circuit}.circom`;
42
- });
43
-
44
- if (candidates.length == 0) {
45
- throw Error(`No circuits with name \"${circuit}\" found`);
46
- }
47
-
48
- if (candidates.length > 1) {
49
- throw Error(
50
- `Found multiple entries for the circuit "${circuit}".
51
-
52
- \rConsider replacing \"${circuit}\" with one of the valid paths:
53
- \r${candidates.map((candidate) => `"${candidate}"`).join(os.EOL)}`,
54
- );
55
- }
56
-
57
- return new CircuitZKit(path.join(this._manager.getCircuitsDir(), candidates[0]), this._manager);
58
- }
59
-
60
- /**
61
- * Returns an array of all circuits available in the circuits directory.
62
- *
63
- * @dev If a circuit id is not unique, the id will be set to `null`.
64
- *
65
- * @returns {CircuitInfo[]} An array of circuit information objects.
66
- */
67
- public getCircuits(): CircuitInfo[] {
68
- const circuits = this._getAllCircuits();
69
-
70
- let circuitsCount = {} as Record<string, number>;
71
-
72
- for (const circuit of circuits) {
73
- const circuitId = path.parse(circuit).name;
74
-
75
- circuitsCount[circuitId] = (circuitsCount[circuitId] || 0) + 1;
76
- }
77
-
78
- let result = [] as CircuitInfo[];
79
-
80
- for (const circuit of circuits) {
81
- const circuitId = path.parse(circuit).name;
82
-
83
- result.push({
84
- path: circuit,
85
- id: circuitsCount[circuitId] > 1 ? null : circuitId,
86
- });
87
- }
88
-
89
- return result;
90
- }
91
-
92
- /**
93
- * Returns an array of all circuits paths available in the circuits directory.
94
- *
95
- * @returns {string[]} An array of circuit paths.
96
- */
97
- private _getAllCircuits(): string[] {
98
- const circuitsDir = this._manager.getCircuitsDir();
99
-
100
- let circuits = [] as string[];
101
-
102
- readDirRecursively(circuitsDir, (_dir: string, file: string) => {
103
- if (path.extname(file) == ".circom") {
104
- circuits.push(path.relative(circuitsDir, file));
105
- }
106
- });
107
-
108
- return circuits;
109
- }
110
- }