@nori-zk/proof-conversion
Version:
Verifying zkVM proofs inside o1js circuits, to generate Mina compatible proof
163 lines • 7.23 kB
JavaScript
import { resolve } from 'path';
import { computeAuxWitness } from '../../../pairing-utils/index.js';
import { makeAlphaBeta } from '../../../pairing-utils/index.js';
import { createDirectories, createDirectory, } from '../../../utils/cache.js';
import { getRandomString } from '../../../utils/random.js';
import { range } from '../../../utils/range.js';
import rootDir from '../../../utils/root_dir.js';
import { readFileSync, rmSync, writeFileSync } from 'fs';
import { Groth16Verifier } from '../../../groth/verifier.js';
import { Proof } from '../../../groth/proof.js';
const proofVkCacheStructure = {
proofs: range(5).map((i) => `layer${i}`),
vks: range(5).map((i) => `layer${i}`),
};
const nodeCacheStructure = range(4).map((i) => `node${i}`);
export class Groth16ComputationalPlan {
constructor() {
this.name = 'Groth16Converter';
this.stages = [
{
// Create the cache and working directories
// Create the proofs and vks directories
// Create the node directories
name: 'CreateFileSystemCache',
type: 'main-thread',
execute: (state) => {
createDirectory(state.cacheDir);
createDirectory(state.workingDir);
createDirectories(state.workingDir, proofVkCacheStructure);
createDirectories(state.workingDir, nodeCacheStructure);
},
},
{
name: 'makeAlphaBeta',
type: 'main-thread',
execute: (state) => {
const raw_vk = state.input.raw_vk;
const input = {
alpha: {
x: raw_vk.alpha.x,
y: raw_vk.alpha.y,
},
beta: {
x_c0: raw_vk.beta.x_c0,
x_c1: raw_vk.beta.x_c1,
y_c0: raw_vk.beta.y_c0,
y_c1: raw_vk.beta.y_c1,
},
};
const risc0_vk = makeAlphaBeta(raw_vk, input);
writeFileSync(resolve(state.workingDir, 'risc_zero_vk.json'), JSON.stringify(risc0_vk));
writeFileSync(resolve(state.workingDir, 'risc_zero_proof.json'), JSON.stringify(state.input.risc0_proof));
state.vkPath = resolve(state.workingDir, 'risc_zero_vk.json');
state.proofPath = resolve(state.workingDir, 'risc_zero_proof.json');
},
},
{
name: 'GenerateWitness',
type: 'main-thread',
execute: (state) => {
// args = [vk_path, proof_path, mlo_write_path]
const vk_path = state.vkPath;
const proof_path = state.proofPath;
const groth16 = new Groth16Verifier(vk_path);
const proof = Proof.parse(groth16.vk, proof_path);
const mlo = groth16.multiMillerLoop(proof).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;
},
},
{
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: 'ComputeZKP',
type: 'parallel-cmd',
processCmds: (state) => {
process.env.GROTH16_VK_PATH = state.vkPath;
return range(16).map((i) => {
return {
cmd: 'node',
args: [
'--max-old-space-size=6000',
resolve(rootDir, 'build', 'src', 'groth', 'recursion', 'prove_zkps.js'),
`zkp${i}`,
state.proofPath,
state.witnessPath,
state.workingDir,
state.cacheDir,
],
capture: true,
printableArgs: [0, 1, 2],
};
});
},
numaOptimized: true,
},
...range(1, 5).map((i) => {
const stage = {
name: `CompressLayer${i}`,
type: 'parallel-cmd',
processCmds: (state) => {
const upperLimit = Math.pow(2, 4 - 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'),
'16',
`${i}`,
`${ZKP_J}`,
state.workingDir,
state.cacheDir,
],
capture: true,
printableArgs: [0, 1, 2, 3, 4],
};
});
},
numaOptimized: true,
};
return stage;
}),
];
}
async init(state, input) {
state.input = input;
state.workingDirName = getRandomString(20);
const pwd = process.cwd();
state.workingDir = resolve(pwd, '.conversion-cache', state.workingDirName);
state.cacheDir = resolve(pwd, '.conversion-cache', 'groth16_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', 'layer4', 'p0.json'), 'utf8')),
};
return output;
}
async finally(state) {
rmSync(state.workingDir, { recursive: true, force: true });
}
}
//# sourceMappingURL=index.js.map