Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions compiler/integration-tests/circuits/recursion/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
global HONK_PROOF_SIZE: u32 = 456;
global HONK_IDENTIFIER: u32 = 1;

fn main(
verification_key: [Field; 114],
proof: [Field; 93],
public_inputs: [Field; 1],
key_hash: Field
verification_key: [Field; 128],
proof: [Field; HONK_PROOF_SIZE],
public_inputs: [Field; 1]
) {
std::verify_proof(verification_key, proof, public_inputs, key_hash)
std::verify_proof_with_type(
verification_key,
proof,
public_inputs,
0x0,
HONK_IDENTIFIER,
);
}
4 changes: 2 additions & 2 deletions compiler/integration-tests/scripts/codegen-verifiers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ $NARGO_BACKEND_PATH write_solidity_verifier -k $KEYS/vk -o $contracts_dir/assert
# Codegen verifier contract for recursion
recursion_dir=$repo_root/compiler/integration-tests/circuits/recursion
nargo --program-dir $recursion_dir compile
$NARGO_BACKEND_PATH OLD_API write_vk -b $recursion_dir/target/recursion.json -o $KEYS/recursion
$NARGO_BACKEND_PATH OLD_API contract -k $KEYS/recursion -o $contracts_dir/recursion.sol
$NARGO_BACKEND_PATH write_vk --scheme ultra_honk --oracle_hash keccak -b $recursion_dir/target/recursion.json -o $KEYS
$NARGO_BACKEND_PATH write_solidity_verifier --scheme ultra_honk -k $KEYS/vk -o $contracts_dir/recursion.sol

rm -rf $KEYS
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { expect } from 'chai';
import { ethers } from 'hardhat';

import { readFileSync } from 'node:fs';
import { resolve, join } from 'path';
import toml from 'toml';

import { Noir } from '@noir-lang/noir_js';
import { UltraPlonkBackend } from '@aztec/bb.js';
import { Field, InputMap } from '@noir-lang/noirc_abi';

import { Barretenberg, RawBuffer, UltraHonkBackend } from '@aztec/bb.js';
import { compile, createFileManager } from '@noir-lang/noir_wasm';

// TODO(https://github.com/AztecProtocol/aztec-packages/issues/6672): Reinstate this test.
it.skip(`smart contract can verify a recursive proof`, async () => {
it(`smart contract can verify a recursive proof`, async () => {
const basePath = resolve(join(__dirname, '../../../../'));
const fm = createFileManager(basePath);
const innerCompilationResult = await compile(
Expand All @@ -35,47 +29,40 @@ it.skip(`smart contract can verify a recursive proof`, async () => {

// Intermediate proof

const inner_backend = new UltraPlonkBackend(innerProgram.bytecode, {}, { recursive: true });
const innerBackend = new UltraHonkBackend(innerProgram.bytecode, {}, { recursive: true });
const inner = new Noir(innerProgram);

const inner_prover_toml = readFileSync(
const innerProverToml = readFileSync(
join(basePath, `./test_programs/execution_success/assert_statement/Prover.toml`),
).toString();

const inner_inputs = toml.parse(inner_prover_toml);

const { witness: main_witness } = await inner.execute(inner_inputs);
const intermediate_proof = await inner_backend.generateProof(main_witness);

expect(await inner_backend.verifyProof(intermediate_proof)).to.be.true;
const innerInputs = toml.parse(innerProverToml);

const { proofAsFields, vkAsFields, vkHash } = await inner_backend.generateRecursiveProofArtifacts(
intermediate_proof,
1, // 1 public input
);
// Generate intermediate proof
const { witness: main_witness } = await inner.execute(innerInputs);
const { proof: intermediateProof, publicInputs: intermediatePublicInputs } =
await innerBackend.generateProofForRecursiveAggregation(main_witness);

// Final proof
// Get verification key for inner circuit as fields
const innerCircuitVerificationKey = await innerBackend.getVerificationKey();
const barretenbergAPI = await Barretenberg.new({ threads: 1 });
const vkAsFields = await barretenbergAPI.acirVkAsFieldsUltraHonk(new RawBuffer(innerCircuitVerificationKey));

const recursion = new Noir(recursionProgram);
// Generate proof of the recursive circuit
const recursiveCircuitNoir = new Noir(recursionProgram);
const recursiveBackend = new UltraHonkBackend(recursionProgram.bytecode, { threads: 1 });

const recursion_inputs: InputMap = {
verification_key: vkAsFields,
proof: proofAsFields,
public_inputs: [inner_inputs.y as Field],
key_hash: vkHash,
const recursiveInputs = {
proof: intermediateProof,
public_inputs: intermediatePublicInputs,
verification_key: vkAsFields.map((field) => field.toString()),
};
const { witness: recursiveWitness } = await recursiveCircuitNoir.execute(recursiveInputs);
const { proof: recursiveProof, publicInputs: recursivePublicInputs } =
await recursiveBackend.generateProof(recursiveWitness);

const { witness: recursionWitness } = await recursion.execute(recursion_inputs);

const recursion_backend = new UltraPlonkBackend(recursionProgram.bytecode, {}, { recursive: false });
const recursion_proof = await recursion_backend.generateProof(recursionWitness);
expect(await recursion_backend.verifyProof(recursion_proof)).to.be.true;

// Smart contract verification

const contract = await ethers.deployContract('contracts/recursion.sol:UltraVerifier', []);

const result = await contract.verify.staticCall(recursion_proof.proof, recursion_proof.publicInputs);
// Verify recursive proof
const verified = await recursiveBackend.verifyProof({ proof: recursiveProof, publicInputs: recursivePublicInputs });

expect(result).to.be.true;
expect(verified).to.be.true;
});