UNPKG

@nori-zk/proof-conversion

Version:

Verifying zkVM proofs inside o1js circuits, to generate Mina compatible proof

146 lines 6.62 kB
import rootDir from '../../../utils/root_dir.js'; import { range } from '../../../utils/range.js'; import { getMlo } from '../../../plonk/get_mlo.js'; import { resolve } from 'path'; import { getRandomString } from '../../../utils/random.js'; import { computeAuxWitness } from '../../../pairing-utils/index.js'; import { readFileSync, rmSync, writeFileSync } from 'fs'; import { createDirectories, createDirectory, } from '../../../utils/cache.js'; const proofVkCacheStructure = { proofs: range(6).map((i) => `layer${i}`), vks: range(6).map((i) => `layer${i}`), }; const nodeCacheStructure = range(4).map((i) => `node${i}`); // SP1ProofWithPublicValues Sp1PlonkInputTransformed export class Sp1PlonkComputationalPlan { constructor() { this.name = 'Sp1PlonkConverter'; this.stages = [ { name: 'CreateFileSystemCache', type: 'main-thread', execute: (state) => { createDirectory(state.cacheDir); createDirectory(state.workingDir); createDirectories(state.workingDir, proofVkCacheStructure); createDirectories(state.workingDir, nodeCacheStructure); }, }, { name: 'GenerateWitness', type: 'main-thread', execute: (state) => { const mlo = getMlo(state.input.encodedProof, state.input.programVK, state.input.hexPi, state.input.pi2, state.input.pi3, state.input.pi4).toJSON(); const witness = computeAuxWitness(JSON.parse(mlo)); state.witnessPath = resolve(state.workingDir, 'aux_wtns.json'); // Write the mlo and witness to the cache dir writeFileSync(resolve(state.workingDir, 'mlo.json'), mlo); writeFileSync(state.witnessPath, JSON.stringify(witness)); return; }, }, // If u wanna see stdout then you can change the capture boolean key in the plonk plan to emit { name: 'CompileRecursion', type: 'serial-cmd', processCmd: (state) => { return { cmd: 'node', args: [ '--max-old-space-size=6000', resolve(rootDir, 'build', 'src', 'compile_recursion_vks.js'), state.workingDir, state.cacheDir, ], capture: true, printableArgs: [0, 1, 2], }; }, }, { name: 'ComputeZPK', type: 'parallel-cmd', processCmds: (state) => { return range(24).map((i) => { return { cmd: 'node', args: [ '--max-old-space-size=6000', resolve(rootDir, 'build', 'src', 'plonk', 'recursion', 'prove_zkps.js'), `zkp${i}`, state.input.encodedProof, state.input.programVK, state.input.hexPi, state.input.pi2, state.input.pi3, state.input.pi4, state.witnessPath, state.workingDir, state.cacheDir, ], capture: true, printableArgs: [0, 1, 2], }; }); }, numaOptimized: true, }, ...range(1, 6).map((i) => { const stage = { name: `CompressLayer${i}`, type: 'parallel-cmd', processCmds: (state) => { const upperLimit = Math.pow(2, 5 - i) - 1; return range(upperLimit + 1).map((ZKP_J) => { return { cmd: 'node', args: [ '--max-old-space-size=6000', resolve(rootDir, 'build', 'src', 'node_resolver.js'), '24', `${i}`, `${ZKP_J}`, state.workingDir, state.cacheDir, ], capture: true, printableArgs: [0, 1, 2, 3, 4], }; }); }, numaOptimized: true, }; return stage; }), ]; } async init(state, input) { // SP1 v6: encoded_proof = [exit_code(32B)][vk_root(32B)][proof_nonce(32B)][gnark_proof(864B)] // Skip the 96-byte SP1 prefix (192 hex chars) to get the raw gnark PLONK proof. // public_inputs[2..4] carry those same values as Fr field elements. const inputTransformed = { hexPi: `0x${Buffer.from(input.public_values.buffer.data).toString('hex')}`, programVK: input.proof.Plonk.public_inputs[0], encodedProof: `0x${input.proof.Plonk.encoded_proof.slice(192)}`, pi2: input.proof.Plonk.public_inputs[2], pi3: input.proof.Plonk.public_inputs[3], pi4: input.proof.Plonk.public_inputs[4], }; state.input = inputTransformed; state.workingDirName = getRandomString(20); const pwd = process.cwd(); state.workingDir = resolve(pwd, '.conversion-cache', state.workingDirName); state.cacheDir = resolve(pwd, '.conversion-cache', 'sp1_plonk_cache'); } async then(state) { const output = { vkData: JSON.parse(readFileSync(resolve(state.workingDir, 'vks', 'nodeVk.json'), 'utf8')), proofData: JSON.parse(readFileSync(resolve(state.workingDir, 'proofs', 'layer5', 'p0.json'), 'utf8')), }; return output; } async finally(state) { rmSync(state.workingDir, { recursive: true, force: true }); } } //# sourceMappingURL=plonk.js.map