diff --git a/src/abi.ts b/src/abi.ts new file mode 100644 index 0000000..2eb5dd7 --- /dev/null +++ b/src/abi.ts @@ -0,0 +1,8 @@ +import { Abi } from "@noir-lang/noirc_abi"; + +export function filterPublic(abi: Abi): Abi { + return { + ...abi, + parameters: abi.parameters.filter((parameter) => parameter.visibility === "public"), + }; +} diff --git a/src/index.ts b/src/index.ts index 8100b43..e2d2578 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { readInputMap, readProof, readWitnessMap, initCircuit } from "./utils.js"; +import { readAllInputs, readProof, readWitnessMap, initCircuit } from "./utils.js"; import assert from "assert"; import { Action, argv } from "./cli.js"; @@ -14,7 +14,7 @@ if (argv.action == Action.Verify) { let isCorrect = await noir.verifyProof(proofData); assert(isCorrect, "Proof verification failed"); } else if (argv.action == Action.Prove) { - let inputMap = await readInputMap(argv.package); + let inputMap = await readAllInputs(argv.package); await noir.generateProof(inputMap); } diff --git a/src/recursive.ts b/src/recursive.ts index 65f1ae8..42dd49f 100644 --- a/src/recursive.ts +++ b/src/recursive.ts @@ -1,17 +1,20 @@ -import { initCircuit, readInputMap } from "./utils.js"; -import { Field, type InputMap } from "@noir-lang/noirc_abi"; +import { encodePublicInputs, initCircuit, readCircuit } from "./utils.js"; +import { type InputMap } from "@noir-lang/noirc_abi"; import assert from "assert"; import { prepareIntermediateProofArtifacts, prepareIntermediateProofArtifactsUsingNargo } from "./recursive_utils.js"; -const packageName = "keccak_big"; +const packageName = "keccak"; +const keccakCircuit = await readCircuit(packageName); const { vkAsFields, proofAsFields, vkHash } = await prepareIntermediateProofArtifactsUsingNargo(packageName); +const publicInputs = await encodePublicInputs(packageName, keccakCircuit.abi); + // // RECURSIVE PROOF const recursive = await initCircuit("recursive"); const recursionInputs: InputMap = { verification_key: vkAsFields, proof: proofAsFields, - public_inputs: [(await readInputMap(packageName)).x as Field], + public_inputs: publicInputs, key_hash: vkHash, }; const { witness: recursiveWitness } = await recursive.noir.execute(recursionInputs); diff --git a/src/recursive_tree.ts b/src/recursive_tree.ts index 67c2da3..e25fb8d 100644 --- a/src/recursive_tree.ts +++ b/src/recursive_tree.ts @@ -1,4 +1,4 @@ -import { initCircuit, readInputMap } from "./utils.js"; +import { initCircuit, readAllInputs } from "./utils.js"; import { InputMap } from "@noir-lang/noir_js"; import { Field } from "@noir-lang/noirc_abi"; import assert from "assert"; @@ -10,8 +10,8 @@ const rhsProof = await prepareIntermediateProofArtifacts(packageName); // RECURSIVE PROOF const recursive2x = await initCircuit("recursive_2x"); -const lhsPublicInputs = [(await readInputMap(packageName)).x as Field]; -const rhsPublicInputs = [(await readInputMap(packageName)).x as Field]; +const lhsPublicInputs = [(await readAllInputs(packageName)).x as Field]; +const rhsPublicInputs = [(await readAllInputs(packageName)).x as Field]; const lhsRecursionInputs: InputMap = { verification_key: lhsProof.vkAsFields, proof: lhsProof.proofAsFields, diff --git a/src/recursive_utils.ts b/src/recursive_utils.ts index 6d1749d..2e257ec 100644 --- a/src/recursive_utils.ts +++ b/src/recursive_utils.ts @@ -1,5 +1,12 @@ import assert from "assert"; -import { initCircuit, readInputMap, readProofHex, readWitnessMap } from "./utils.js"; +import { + encodePublicInputs, + initCircuit, + readAllInputs, + readProofHex, + readPublicInputs, + readWitnessMap, +} from "./utils.js"; import { readFile, writeFile } from "fs/promises"; import { Hex, concatHex } from "viem"; import { CompiledCircuit } from "@noir-lang/noir_js"; @@ -15,7 +22,7 @@ export interface IntermediateProofArtifacts { export async function prepareIntermediateProofArtifacts(packageName: string): Promise { const { bb, noir } = await initCircuit(packageName); - const inputs = await readInputMap(packageName); + const inputs = await readAllInputs(packageName); let { witness } = await noir.execute(inputs); console.time(`${packageName}.bb.generateIntermediateProof`); @@ -28,7 +35,7 @@ export async function prepareIntermediateProofArtifacts(packageName: string): Pr console.timeEnd(`${packageName}.bb.verifyIntermediateProof`); console.time(`${packageName}.bb.generateIntermediateProofArtifacts`); - const numPublicInputs = 1; + const numPublicInputs = 32 + 32 + 1; const intermediateProofArtifacts = await bb.generateRecursiveProofArtifacts(proof, numPublicInputs); console.timeEnd(`${packageName}.bb.generateIntermediateProofArtifacts`); @@ -44,17 +51,17 @@ async function getProofAsFields( ): Promise { const proofHex = await readProofHex(packageName); - const inputs = await readWitnessMap(packageName, circuit.abi); - const inputsHex = concatHex(Array.from(inputs.values()) as Hex[]); + const publicInputs = await encodePublicInputs(packageName, circuit.abi); + const publicInputsHex = concatHex(publicInputs); - const proofWithInputsHex = concatHex([inputsHex, proofHex]); + const proofWithInputsHex = concatHex([publicInputsHex, proofHex]); await writeFile(bb.proofWithInputsPath, proofWithInputsHex.substring(2), "hex"); await bb.proofAsFields(); const proofAsFieldsWithInputs = JSON.parse(await readFile(bb.proofAsFieldsPath, "utf8")); - return proofAsFieldsWithInputs.slice(inputs.size); + return proofAsFieldsWithInputs.slice(publicInputs.length); } export async function prepareIntermediateProofArtifactsUsingNargo( diff --git a/src/utils.ts b/src/utils.ts index 698ad15..33035f3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,6 +5,7 @@ import os from "os"; import { Abi, abiEncode, type InputMap } from "@noir-lang/noirc_abi"; import { BarretenbergBackend } from "@noir-lang/backend_barretenberg"; +import { filterPublic } from "./abi.js"; interface CircuitData { noir: Noir; @@ -45,16 +46,23 @@ export async function readProofHex(packageName: string): Promise { } export async function readWitnessMap(packageName: string, abi: Abi): Promise { - const inputMap = await readInputMap(packageName); + const inputMap = await readAllInputs(packageName); const witnessMap = abiEncode(abi, inputMap, inputMap["return"]); return witnessMap; } -export async function readInputMap(packageName: string): Promise { +export async function readAllInputs(packageName: string): Promise { const PROVER_MAP_PATH = `./circuits/${packageName}/Prover.toml`; const verifierData = await fs.readFile(PROVER_MAP_PATH, "utf-8"); - const inputMap = toml.parse(verifierData); - return inputMap; + const allInputs = toml.parse(verifierData); + return allInputs; +} + +export async function readPublicInputs(packageName: string): Promise { + const VERIFIER_MAP_PATH = `./circuits/${packageName}/Verifier.toml`; + const verifierData = await fs.readFile(VERIFIER_MAP_PATH, "utf-8"); + const publicInputs = toml.parse(verifierData); + return publicInputs; } export function encodeHexString(value: string): Uint8Array { @@ -82,3 +90,11 @@ export async function withProfiling(name: string, fn: () => Promise): Prom console.timeEnd(name); return result; } + +export async function encodePublicInputs(packageName: string, abi: Abi): Promise { + const publicInputs = await readPublicInputs(packageName); + const publicInputsAbi = filterPublic(abi); + const publicInputsEncodedMap = abiEncode(publicInputsAbi, publicInputs, publicInputs["return"]); + const publicInputsEncoded = Array.from(publicInputsEncodedMap.values()); + return publicInputsEncoded as Hex[]; +}