UNPKG

@nori-zk/proof-conversion

Version:

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

61 lines 3.48 kB
import { Field, Poseidon, Provable, ZkProgram } from 'o1js'; import { FrC } from '../../towers/index.js'; import { VK } from '../vk_from_env.js'; import { G1Affine } from '../../ec/index.js'; import { bn254 } from '../../ec/g1.js'; import { getDistribution } from '../config.js'; // Factory function to create zkp15 with correct public input array size export function createZkp15(inputCount) { const distribution = getDistribution(inputCount); const zkp15InputCount = distribution.zkp15.length; const zkp15 = ZkProgram({ name: `zkp15_${inputCount}inputs`, publicInput: Field, publicOutput: Field, methods: { compute: { privateInputs: [G1Affine, G1Affine, Provable.Array(FrC.provable, inputCount)], async method(input, PI, acc, full_pis) { const pi_hash = Poseidon.hashPacked(G1Affine, PI); const pis_hash = Poseidon.hashPacked(Provable.Array(FrC.provable, inputCount), full_pis); const acc_hash = Poseidon.hashPacked(G1Affine, acc); input.assertEquals(Poseidon.hashPacked(Provable.Array(Field, 3), [ pi_hash, pis_hash, acc_hash, ])); let accBn = new bn254({ x: acc.x, y: acc.y }); // Handle inputs based on distribution strategy // Index directly into full_pis to ensure accumulation uses the same // values that are hashed into pis_hash (prevents unconstrained witness attack) // In provable code both branches of Provable.if are always evaluated, so we // cannot guard scale() with a plain if. Instead we replace a zero scalar with // a dummy non-zero value (1) so scale() never sees zero, then use Provable.if // to keep accBn unchanged when the original scalar was zero. for (let i = 0; i < zkp15InputCount; i++) { const originalIndex = distribution.zkp15[i]; // original index in pis array const icIndex = originalIndex + 1; // ic1, ic2, etc. const icPoint = VK.getIcPoint(icIndex); if (!icPoint) { throw new Error(`Missing IC point ic${icIndex} for zkp15 input ${i}`); } const isZero = full_pis[originalIndex].equals(0n); const safeScalar = Provable.if(isZero, FrC.provable, FrC.from(1n), full_pis[originalIndex]); const scaled = icPoint.scale(safeScalar); const accBnWithScaled = accBn.add(scaled); accBn = Provable.if(isZero, bn254.provable, accBn, accBnWithScaled); } // Verify that the accumulated result equals PI accBn.x.assertCanonical().assertEquals(PI.x); accBn.y.assertCanonical().assertEquals(PI.y); return { publicOutput: pis_hash }; }, }, }, }); return { zkp15, ZKP15Proof: ZkProgram.Proof(zkp15) }; } // Default export for backwards compatibility (can be removed later) const { zkp15, ZKP15Proof } = createZkp15(5); // Default to 5 inputs for Risc0 export { ZKP15Proof, zkp15 }; //# sourceMappingURL=zkp15.js.map