/
proving-manager.ts
91 lines (73 loc) · 2.79 KB
/
proving-manager.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Copyright 2022-2023 Webb Technologies Inc.
// SPDX-License-Identifier: Apache-2.0
import type { NoteProtocol } from '@webb-tools/wasm-utils';
import { CircomProvingManagerThread } from '@webb-tools/sdk-core/proving/circom/proving-manager-thread.js';
import { ProofInterface, ProvingManagerSetupInput } from '../types.js';
import { workerInputMapper, WorkerProofInterface, workerProofTranslator, WorkerProvingManagerSetupInput } from '../worker-utils.js';
// Circom uses snarkjs to generate and verify proofs. It requires a witness calculator.
export class CircomProvingManager {
constructor (
private circuitWasm: Uint8Array,
private treeDepth: number,
private readonly worker: Worker | null | undefined // Optional WebWorker
) {
}
/**
* @param input - input to prove
**/
public async prove<T extends NoteProtocol> (protocol: T, input: ProvingManagerSetupInput<T>): Promise<ProofInterface<T>> {
const worker = this.worker;
const workerThreadInput = workerInputMapper(protocol, input);
const workerProof = worker
? await this.proveWithWorker([protocol, workerThreadInput], worker)
: await this.proveWithoutWorker(protocol, workerThreadInput);
return workerProofTranslator(protocol, workerProof);
}
private proveWithoutWorker<T extends NoteProtocol> (protocol: T, input: WorkerProvingManagerSetupInput<T>): Promise<WorkerProofInterface<T>> {
// If the worker CTX is direct-call
const pm = new CircomProvingManagerThread(this.circuitWasm, this.treeDepth, 'direct-call');
return pm.prove(protocol, input);
}
public setupWorker () {
return new Promise((resolve, reject) => {
const worker = this.worker;
if (worker) {
worker.postMessage({
setup: {
circuitWasm: this.circuitWasm,
treeDepth: this.treeDepth
}
});
const handler = (event: MessageEvent<any>) => {
const eventName = event.data.name;
if (eventName === 'setup') {
worker.removeEventListener('message', handler);
resolve(undefined);
}
};
worker.addEventListener('message', handler);
} else {
reject(new Error('No worker attached to the proving manager'));
}
});
}
private async proveWithWorker<T extends NoteProtocol> (
input: [T, WorkerProvingManagerSetupInput<T>],
worker: Worker
): Promise<WorkerProofInterface<T>> {
await this.setupWorker();
return new Promise<WorkerProofInterface<T>>((resolve, reject) => {
try {
worker.addEventListener('message', (e) => {
const payload = e.data.data as WorkerProofInterface<T>;
resolve(payload);
});
worker.postMessage({
proof: input
});
} catch (e) {
reject(e);
}
});
}
}