From d96509bfd8a781cd0b9de304ea09c8d338801e0b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 26 Jan 2024 10:30:57 +0100 Subject: [PATCH 1/6] Sort packages by circuit size --- Nargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nargo.toml b/Nargo.toml index 588241f..d8b9c73 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -1,8 +1,8 @@ [workspace] members = [ "circuits/poseidon", + "circuits/rlp", "circuits/keccak", "circuits/keccak_2x", - "circuits/rlp" ] default-member = "circuits/keccak" \ No newline at end of file From 98665eaaa9a1c71893a9729e45e3e854a062ef7c Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 26 Jan 2024 14:10:58 +0100 Subject: [PATCH 2/6] Add recursive_poseidon circuit --- Nargo.toml | 1 + circuits/recursive_poseidon/Nargo.toml | 3 +++ circuits/recursive_poseidon/src/main.nr | 15 +++++++++++++++ 3 files changed, 19 insertions(+) create mode 100644 circuits/recursive_poseidon/Nargo.toml create mode 100644 circuits/recursive_poseidon/src/main.nr diff --git a/Nargo.toml b/Nargo.toml index d8b9c73..f594662 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -4,5 +4,6 @@ members = [ "circuits/rlp", "circuits/keccak", "circuits/keccak_2x", + "circuits/recursive_poseidon" ] default-member = "circuits/keccak" \ No newline at end of file diff --git a/circuits/recursive_poseidon/Nargo.toml b/circuits/recursive_poseidon/Nargo.toml new file mode 100644 index 0000000..95a4320 --- /dev/null +++ b/circuits/recursive_poseidon/Nargo.toml @@ -0,0 +1,3 @@ +[package] +name = "recursive_poseidon" +type = "bin" diff --git a/circuits/recursive_poseidon/src/main.nr b/circuits/recursive_poseidon/src/main.nr new file mode 100644 index 0000000..6dce514 --- /dev/null +++ b/circuits/recursive_poseidon/src/main.nr @@ -0,0 +1,15 @@ +use dep::std; + +fn main( + verification_key: [Field; 114], + proof: [Field; 93], + public_inputs: [Field; 1], + key_hash: Field +) { + std::verify_proof( + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), + key_hash + ); +} From f887d190ed845681bb1f39e3aafcdeb19b033e4f Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 26 Jan 2024 14:12:42 +0100 Subject: [PATCH 3/6] Slight refactor --- src/index.ts | 26 +++++--------------------- src/utils.ts | 50 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/index.ts b/src/index.ts index f1706ee..b455dd6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,28 +1,12 @@ -import { - readInputMap, - readProof, - readWitnessMap, - readCircuit, -} from "./utils.js"; +import { readInputMap, readProof, readWitnessMap, initCircuit } from "./utils.js"; import assert from "assert"; -import os from "os"; -import { BarretenbergBackend } from "@noir-lang/backend_barretenberg"; -import { Noir } from "@noir-lang/noir_js"; import { Action, argv } from "./cli.js"; -const PROOF_PATH = `./proofs/${argv.package}.proof`; -const VERIFIER_MAP_PATH = `./circuits/${argv.package}/Verifier.toml`; -const PROVER_MAP_PATH = `./circuits/${argv.package}/Prover.toml`; - -const circuit = await readCircuit(argv.package); -const backend = new BarretenbergBackend(circuit, { - threads: os.cpus().length, -}); -const noir = new Noir(circuit, backend); +const { noir, circuit } = await initCircuit(argv.package); if (argv.action == Action.Verify) { - let proof = await readProof(PROOF_PATH); - let witnessMap = await readWitnessMap(VERIFIER_MAP_PATH, circuit.abi); + let proof = await readProof(argv.package); + let witnessMap = await readWitnessMap(argv.package, circuit.abi); const proofData = { proof, publicInputs: Array.from(witnessMap.values()), @@ -30,7 +14,7 @@ if (argv.action == Action.Verify) { let isCorrect = await noir.verifyFinalProof(proofData); assert(isCorrect, "Proof vefification failed"); } else if (argv.action == Action.Prove) { - let inputMap = await readInputMap(PROVER_MAP_PATH); + let inputMap = await readInputMap(argv.package); await noir.generateFinalProof(inputMap); } diff --git a/src/utils.ts b/src/utils.ts index b5d99c0..efe5a55 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,33 +1,52 @@ -import { CompiledCircuit, WitnessMap } from "@noir-lang/noir_js"; +import { CompiledCircuit, Noir, WitnessMap } from "@noir-lang/noir_js"; import { promises as fs } from "fs"; import toml from "toml"; +import os from "os"; import { Abi, abiEncode, type InputMap } from "@noir-lang/noirc_abi"; +import { BarretenbergBackend } from "@noir-lang/backend_barretenberg"; -export async function readCircuit( - packageName: string, -): Promise { +interface CircuitData { + noir: Noir; + bb: BarretenbergBackend; + circuit: CompiledCircuit; +} + +export async function initCircuit(packageName: string): Promise { + const circuit = await readCircuit(packageName); + const bb = new BarretenbergBackend(circuit, { + threads: os.cpus().length, + }); + const noir = new Noir(circuit, bb); + + return { + noir, + circuit, + bb, + }; +} + +export async function readCircuit(packageName: string): Promise { const CIRCUIT_PATH = `./target/${packageName}.json`; const data = await fs.readFile(CIRCUIT_PATH, "utf8"); return JSON.parse(data); } -export async function readProof(path: string): Promise { - const proofHex = await fs.readFile(path, "utf-8"); +export async function readProof(packageName: string): Promise { + const PROOF_PATH = `./proofs/${packageName}.proof`; + const proofHex = await fs.readFile(PROOF_PATH, "utf-8"); return encodeHexString("0x" + proofHex); } -export async function readWitnessMap( - path: string, - abi: Abi, -): Promise { - const inputMap = await readInputMap(path); +export async function readWitnessMap(packageName: string, abi: Abi): Promise { + const inputMap = await readInputMap(packageName); const witnessMap = abiEncode(abi, inputMap, inputMap["return"]); return witnessMap; } -export async function readInputMap(path: string): Promise { - const verifierData = await fs.readFile(path, "utf-8"); +export async function readInputMap(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; } @@ -45,10 +64,7 @@ export function encodeHexString(value: string): Uint8Array { export type Hex = `0x${string}`; -export function isHex( - value: unknown, - { strict = true }: { strict?: boolean } = {}, -): value is Hex { +export function isHex(value: unknown, { strict = true }: { strict?: boolean } = {}): value is Hex { if (!value) return false; if (typeof value !== "string") return false; return strict ? /^0x[0-9a-fA-F]*$/.test(value) : value.startsWith("0x"); From c322adf551fc42ba416667070133923f4ed9c2ca Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 26 Jan 2024 14:12:59 +0100 Subject: [PATCH 4/6] Prettier width --- .prettierrc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..963354f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "printWidth": 120 +} From 403f717f0dad46831ac112d23e6a9acafdc132bd Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 26 Jan 2024 14:13:18 +0100 Subject: [PATCH 5/6] Temp script --- package.json | 1 + src/temp.ts | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/temp.ts diff --git a/package.json b/package.json index 606f335..139bafa 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "yargs": "^17.7.2" }, "scripts": { + "temp": "tsx src/temp.ts", "build": "tsc", "start": "node dist/index.js" }, diff --git a/src/temp.ts b/src/temp.ts new file mode 100644 index 0000000..9961bd4 --- /dev/null +++ b/src/temp.ts @@ -0,0 +1,67 @@ +import { initCircuit, readInputMap, readProof, readWitnessMap } from "./utils.js"; +import { InputMap } from "@noir-lang/noir_js"; +import { Field } from "@noir-lang/noirc_abi"; +import assert from "assert"; + +const packageName = "poseidon"; +console.time("initCircuit for poseidon"); +const poseidon = await initCircuit(packageName); +console.timeEnd("initCircuit for poseidon"); + +console.time("readInputMap for poseidon"); +const poseidonInputs = await readInputMap(packageName); +console.timeEnd("readInputMap for poseidon"); + +console.time("poseidon.noir.execute"); +let { witness: poseidonWitness } = await poseidon.noir.execute(poseidonInputs); +console.timeEnd("poseidon.noir.execute"); + +console.time("poseidon.bb.generateIntermediateProof"); +const poseidonProof = await poseidon.bb.generateIntermediateProof(poseidonWitness); +console.timeEnd("poseidon.bb.generateIntermediateProof"); + +console.time("poseidon.bb.verifyIntermediateProof"); +const poseidonProofVerification = await poseidon.bb.verifyIntermediateProof(poseidonProof); +console.timeEnd("poseidon.bb.verifyIntermediateProof"); + +assert(poseidonProofVerification, "Poseidon proof verification failed"); + +console.time("generateIntermediateProofArtifacts"); +const numPublicInputs = 1; +const { proofAsFields, vkAsFields, vkHash } = await poseidon.bb.generateIntermediateProofArtifacts( + poseidonProof, + numPublicInputs, +); +console.timeEnd("generateIntermediateProofArtifacts"); + +console.time("poseidon.noir.destroy"); +await poseidon.noir.destroy(); +console.timeEnd("poseidon.noir.destroy"); + +// RECURSIVE PROOF +console.time("initCircuit for recursive_poseidon"); +const recursivePoseidon = await initCircuit("recursive_poseidon"); +console.timeEnd("initCircuit for recursive_poseidon"); + +console.time("recursivePoseidon.noir.execute"); +const recursionInputs: InputMap = { + verification_key: vkAsFields, + proof: proofAsFields, + public_inputs: [(await readInputMap(packageName)).x as Field], + key_hash: vkHash, +}; +const { witness: recursivePoseidonWitness } = await recursivePoseidon.noir.execute(recursionInputs); +console.timeEnd("recursivePoseidon.noir.execute"); + +console.time("recursivePoseidon.bb.generateFinalProof"); +const recursivePoseidonProof = await recursivePoseidon.bb.generateFinalProof(recursivePoseidonWitness); +console.timeEnd("recursivePoseidon.bb.generateFinalProof"); + +console.time("recursivePoseidon.bb.verifyFinalProof"); +const recursivePoseidonProofVerification = await recursivePoseidon.bb.verifyFinalProof(recursivePoseidonProof); +console.timeEnd("recursivePoseidon.bb.verifyFinalProof"); +assert(recursivePoseidonProofVerification, "Recursive Poseidon proof verification failed"); + +console.time("recursivePoseidon.noir.destroy"); +await recursivePoseidon.noir.destroy(); +console.timeEnd("recursivePoseidon.noir.destroy"); From 61af41edc02c635a4b2dbc27c8de1da81bcb6d50 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 26 Jan 2024 14:41:26 +0100 Subject: [PATCH 6/6] Remove timing for fast functions --- src/temp.ts | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/temp.ts b/src/temp.ts index 9961bd4..c8f9334 100644 --- a/src/temp.ts +++ b/src/temp.ts @@ -1,20 +1,14 @@ -import { initCircuit, readInputMap, readProof, readWitnessMap } from "./utils.js"; +import { initCircuit, readInputMap } from "./utils.js"; import { InputMap } from "@noir-lang/noir_js"; import { Field } from "@noir-lang/noirc_abi"; import assert from "assert"; const packageName = "poseidon"; -console.time("initCircuit for poseidon"); const poseidon = await initCircuit(packageName); -console.timeEnd("initCircuit for poseidon"); -console.time("readInputMap for poseidon"); const poseidonInputs = await readInputMap(packageName); -console.timeEnd("readInputMap for poseidon"); -console.time("poseidon.noir.execute"); let { witness: poseidonWitness } = await poseidon.noir.execute(poseidonInputs); -console.timeEnd("poseidon.noir.execute"); console.time("poseidon.bb.generateIntermediateProof"); const poseidonProof = await poseidon.bb.generateIntermediateProof(poseidonWitness); @@ -22,9 +16,8 @@ console.timeEnd("poseidon.bb.generateIntermediateProof"); console.time("poseidon.bb.verifyIntermediateProof"); const poseidonProofVerification = await poseidon.bb.verifyIntermediateProof(poseidonProof); -console.timeEnd("poseidon.bb.verifyIntermediateProof"); - assert(poseidonProofVerification, "Poseidon proof verification failed"); +console.timeEnd("poseidon.bb.verifyIntermediateProof"); console.time("generateIntermediateProofArtifacts"); const numPublicInputs = 1; @@ -34,16 +27,10 @@ const { proofAsFields, vkAsFields, vkHash } = await poseidon.bb.generateIntermed ); console.timeEnd("generateIntermediateProofArtifacts"); -console.time("poseidon.noir.destroy"); await poseidon.noir.destroy(); -console.timeEnd("poseidon.noir.destroy"); // RECURSIVE PROOF -console.time("initCircuit for recursive_poseidon"); const recursivePoseidon = await initCircuit("recursive_poseidon"); -console.timeEnd("initCircuit for recursive_poseidon"); - -console.time("recursivePoseidon.noir.execute"); const recursionInputs: InputMap = { verification_key: vkAsFields, proof: proofAsFields, @@ -51,7 +38,6 @@ const recursionInputs: InputMap = { key_hash: vkHash, }; const { witness: recursivePoseidonWitness } = await recursivePoseidon.noir.execute(recursionInputs); -console.timeEnd("recursivePoseidon.noir.execute"); console.time("recursivePoseidon.bb.generateFinalProof"); const recursivePoseidonProof = await recursivePoseidon.bb.generateFinalProof(recursivePoseidonWitness); @@ -59,9 +45,7 @@ console.timeEnd("recursivePoseidon.bb.generateFinalProof"); console.time("recursivePoseidon.bb.verifyFinalProof"); const recursivePoseidonProofVerification = await recursivePoseidon.bb.verifyFinalProof(recursivePoseidonProof); -console.timeEnd("recursivePoseidon.bb.verifyFinalProof"); assert(recursivePoseidonProofVerification, "Recursive Poseidon proof verification failed"); +console.timeEnd("recursivePoseidon.bb.verifyFinalProof"); -console.time("recursivePoseidon.noir.destroy"); await recursivePoseidon.noir.destroy(); -console.timeEnd("recursivePoseidon.noir.destroy");