@reclaimprotocol/zk-symmetric-crypto
Version:
JS Wrappers for Various ZK Snark Circuits
89 lines (88 loc) • 3.09 kB
JavaScript
import { isMainThread, parentPort, Worker, workerData } from 'worker_threads';
import init, { prove } from './wasm-binding.js';
const BYTES_PER_PAGE = 65536;
const logger = console;
async function main() {
const { module, initialisationMemory } = workerData;
const wasm = await init({ 'module_or_path': module });
const growthRequired = (initialisationMemory.byteLength - wasm.memory.buffer.byteLength) / BYTES_PER_PAGE;
if (growthRequired > 0) {
wasm.memory.grow(growthRequired);
logger.debug({ growthRequired }, 'memory grown');
}
// copy initialisation memory
const memory = new Uint8Array(wasm.memory.buffer);
memory.set(initialisationMemory);
logger.debug('worker initialised w memory');
parentPort.on('message', async (msg) => {
const [type, input] = msg;
if (type === 'prove') {
try {
const result = await prove(...input.args);
sendOutputRpcBack({ id: input.id, result });
logger.debug({ id: input.id }, 'prove done');
}
catch (err) {
logger.error({ err }, 'prove error');
sendOutputRpcBack({
id: input.id,
type: 'error',
message: err.message,
stack: err.stack
});
}
return;
}
throw new Error(`Unknown message type: ${type}`);
});
parentPort.postMessage({ type: 'online' });
function sendOutputRpcBack(output) {
parentPort.postMessage(['reply', output]);
}
}
export async function initWorker(workerData) {
const __filename = import.meta.url.replace('file://', '');
const worker = new Worker(__filename, { workerData });
await new Promise((resolve, reject) => {
worker.once('message', resolve);
worker.once('error', reject);
});
const channel = {
rpc(type, input) {
input.id ||= createRpcId();
const wait = waitForRpcReply(input.id);
worker.postMessage([type, input]);
return wait;
},
close() {
return worker.terminate();
}
};
return channel;
async function waitForRpcReply(id) {
return new Promise((resolve, reject) => {
worker.on('message', listener);
worker.once('error', reject);
async function listener([type, output]) {
if (type !== 'reply' || output.id !== id) {
return;
}
worker.off('message', listener);
worker.off('error', reject);
if ('type' in output && output.type === 'error') {
const err = new Error(output.message);
err.stack = output.stack;
reject(err);
return;
}
resolve(output);
}
});
}
}
function createRpcId() {
return Math.random().toString(36).slice(2);
}
if (!isMainThread) {
main();
}