UNPKG

@reclaimprotocol/zk-symmetric-crypto

Version:
80 lines (79 loc) 3.35 kB
import { CONFIG } from "../config.js"; import { serialiseValuesToBits } from "../utils.js"; import { initWorker } from "./node-worker.js"; import { loadCircuitIfRequired, loadExpander, loadProverCircuitIfRequired, makeWorkerPool } from "./utils.js"; import { prove, verify } from './wasm-binding.js'; let wasmInit; export function makeExpanderZkOperator({ algorithm, fetcher, options: { maxWorkers = 0 } = {} }) { const { index: id, keySizeBytes } = CONFIG[algorithm]; const workerPool = maxWorkers ? makeWorkerPool(maxWorkers, _initWorker) : undefined; let proverLoader; let circuitLoader; return { generateWitness(input) { const { noncesAndCounters: [{ nonce, counter }] } = input; const witness = new Uint8Array([ // let's just call this the version flag 1, ...serialiseValuesToBits(algorithm, counter, nonce, input.in, input.out, input.key) ]); return witness; }, async groth16Prove(witness, logger) { const version = readFromWitness(1)[0]; if (version !== 1) { throw new Error(`Unsupported witness version: ${version}`); } // * 8 because we're reading bits const pubBits = readFromWitness(-keySizeBytes * 8); const privBits = witness; await loadProverAsRequired(logger); if (!workerPool) { const bytes = prove(id, privBits, pubBits); return { proof: bytes }; } const worker = await workerPool.getNext(); const { result: proof } = await (worker.rpc('prove', { args: [id, privBits, pubBits] })); return { proof }; function readFromWitness(length) { const result = witness.slice(0, length); witness = witness.slice(length); return result; } }, async groth16Verify(publicSignals, proof, logger) { if (!(proof instanceof Uint8Array)) { throw new Error('Expected proof to be binary'); } await loadCircuitAsRequired(logger); const { noncesAndCounters: [{ nonce, counter }], in: inData, out: outData } = publicSignals; const pubSignals = new Uint8Array(serialiseValuesToBits(algorithm, counter, nonce, inData, outData)); return verify(id, pubSignals, proof); }, release() { return workerPool?.release(); } }; async function loadProverAsRequired(logger) { wasmInit ||= loadExpander(fetcher, logger); await wasmInit; proverLoader ||= loadProverCircuitIfRequired(algorithm, fetcher, logger); circuitLoader ||= loadCircuitIfRequired(algorithm, fetcher, logger); await Promise.all([proverLoader, circuitLoader]); } async function loadCircuitAsRequired(logger) { wasmInit ||= loadExpander(fetcher, logger); await wasmInit; circuitLoader ||= loadCircuitIfRequired(algorithm, fetcher, logger); await circuitLoader; } } async function _initWorker() { const { wasm, module } = await wasmInit; return initWorker({ module, initialisationMemory: new Uint8Array(wasm.memory.buffer), }); }