Skip to content

Commit e2fce0f

Browse files
critesjoshclaude
andcommitted
Upgrade recursive verification to Aztec v3.0.0-devnet.20251212
- Update all @aztec/* dependencies to 3.0.0-devnet.20251212 - Use bb_proof_verification::verify_honk_proof for proof verification - Store vk_hash in PublicImmutable storage during initialization - Read vk_hash from storage in increment function (per PR #18) - Update proof size to 508 fields, VK size remains 115 fields - Use PublicMutable for counters instead of EasyPrivateUint - Update storage access pattern: self.storage.x - Update enqueue pattern: self.enqueue_self.func() - Use #[only_self] for public functions callable only by contract - Fix registerContract API: use positional params (instance, artifact) - Fix bb.js API: use deflattenFields for proof conversion - Update README, CLAUDE.md, and EXPLAINER.md documentation Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 27088d3 commit e2fce0f

File tree

13 files changed

+434
-411
lines changed

13 files changed

+434
-411
lines changed

.github/workflows/recursive-verification-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
runs-on: ubuntu-latest
1919
env:
2020
AZTEC_ENV: sandbox
21-
AZTEC_VERSION: 3.0.0-devnet.4
21+
AZTEC_VERSION: 3.0.0-devnet.20251212
2222

2323
steps:
2424
- name: Checkout repository

CLAUDE.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ aztec-examples/
5252
bash -i <(curl -s https://install.aztec.network)
5353

5454
# Set specific version (examples may require different versions)
55-
aztec-up 3.0.0-devnet.4 # For recursive_verification
55+
aztec-up 3.0.0-devnet.20251212 # For recursive_verification
5656
aztec-up 2.0.2 # For starter-token
5757
```
5858

@@ -199,9 +199,10 @@ Key considerations:
199199
The recursive verification example demonstrates:
200200

201201
- **Off-chain proof generation**: Noir circuits compiled and executed with Barretenberg
202-
- **On-chain verification**: Using `std::verify_proof_with_type` in Aztec contracts
203-
- **UltraHonk proving system**: Generates proofs with 457 field elements, verification keys with 115 fields
204-
- **Private state management**: Using `EasyPrivateUint` for private counters
202+
- **On-chain verification**: Using `bb_proof_verification::verify_honk_proof` in Aztec contracts
203+
- **UltraHonk proving system**: Generates proofs with 508 field elements, verification keys with 115 fields
204+
- **VK Hash Storage**: Verification key hash stored in `PublicImmutable` storage, readable from private context
205+
- **Public state management**: Using `PublicMutable` for per-user counters
205206

206207
### Token Pattern (starter-token)
207208

@@ -245,7 +246,7 @@ easy_private_state = { git = "https://github.com/AztecProtocol/aztec-packages/",
245246

246247
**Version Compatibility**: Different examples may use different Aztec versions:
247248

248-
- `recursive_verification`: v3.0.0-devnet.4
249+
- `recursive_verification`: v3.0.0-devnet.20251212
249250

250251
### JavaScript/TypeScript Dependencies
251252

recursive_verification/CLAUDE.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
This is an Aztec-Noir project that demonstrates proof verification in Aztec contracts. It uses Aztec version 3.0.0-devnet.4 to verify Noir proofs within smart contracts on the Aztec network.
7+
This is an Aztec-Noir project that demonstrates proof verification in Aztec contracts. It uses Aztec version 3.0.0-devnet.20251212 to verify Noir proofs within smart contracts on the Aztec network.
88

99
The project consists of:
1010

@@ -67,11 +67,12 @@ bun recursion
6767
### Contract (`contract/`)
6868

6969
- **`src/main.nr`**: Aztec smart contract with:
70-
- `initialize()`: Sets up counter with initial value for an owner
71-
- `increment()`: Verifies a Noir proof and increments the counter
70+
- `constructor()`: Sets up counter with initial value for an owner and stores the VK hash
71+
- `increment()`: Verifies a Noir proof (reads VK hash from storage) and increments the counter
7272
- `get_counter()`: Reads current counter value for an owner
73-
- Uses Honk proof verification (457 field elements for proof, 115 for verification key)
74-
- Stores private counters using `EasyPrivateUint` from Aztec-nr libraries
73+
- Uses `bb_proof_verification::verify_honk_proof` for proof verification (508 field elements for proof, 115 for verification key)
74+
- Stores VK hash in `PublicImmutable` storage (readable from private context)
75+
- Stores public counters per user using `PublicMutable` from Aztec-nr libraries
7576

7677
### Scripts (`scripts/`)
7778

recursive_verification/EXPLAINER.md

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ flowchart TB
3232
subgraph "3. Proof Generation"
3333
BYTECODE -->|Barretenberg| PROVER[UltraHonk Prover]
3434
INPUTS[Inputs: x=1, y=2] --> PROVER
35-
PROVER -->|Generates| PROOF_DATA[Proof Data<br/>- Proof: 457 fields<br/>- VK: 115 fields<br/>- Public inputs]
35+
PROVER -->|Generates| PROOF_DATA[Proof Data<br/>- Proof: 508 fields<br/>- VK: 115 fields<br/>- Public inputs]
3636
PROOF_DATA -->|Saved to| JSON[data.json]
3737
end
3838
3939
subgraph "4. Smart Contract"
4040
CONTRACT[ValueNotEqual Contract<br/>contract/src/main.nr]
41-
CONTRACT -->|Contains| VERIFY[verify_proof_with_type]
42-
CONTRACT -->|Manages| STATE[Private Counter State]
41+
CONTRACT -->|Contains| VERIFY[verify_honk_proof]
42+
CONTRACT -->|Manages| STATE[Public Counter State]
4343
end
4444
4545
subgraph "5. On-chain Verification"
@@ -135,14 +135,14 @@ fn main(x: Field, y: pub Field) {
135135
The contract has three main functions:
136136

137137
```rust
138-
// 1. Initialize with a starting counter value
139-
fn initialize(headstart: u64, owner: AztecAddress)
138+
// 1. Initialize with a starting counter value and VK hash
139+
fn constructor(headstart: Field, owner: AztecAddress, vk_hash: Field)
140140

141-
// 2. Verify proof and increment counter
141+
// 2. Verify proof (VK hash read from storage) and increment counter
142142
fn increment(
143143
owner: AztecAddress,
144144
verification_key: [Field; 115],
145-
proof: [Field; 457],
145+
proof: [Field; 508],
146146
public_inputs: [Field; 1]
147147
)
148148

@@ -157,7 +157,7 @@ fn get_counter(owner: AztecAddress) -> Field
157157
**Size breakdown**:
158158

159159
- **Verification Key**: 115 field elements (~3.7KB)
160-
- **Proof**: 457 field elements (~14.6KB)
160+
- **Proof**: 508 field elements (~16.3KB)
161161
- **Public Inputs**: 1 field element (the value of y)
162162

163163
## 📝 Step-by-Step Code Breakdown
@@ -195,58 +195,60 @@ const vkAsFields = await barretenbergAPI.acirVkAsFieldsUltraHonk(vk);
195195
### Step 2: Contract Verification (`contract/src/main.nr`)
196196

197197
```rust
198-
#[private]
198+
#[external("private")]
199199
fn increment(
200200
owner: AztecAddress,
201201
verification_key: [Field; HONK_VK_SIZE], // 115 elements
202-
proof: [Field; HONK_PROOF_SIZE], // 457 elements
202+
proof: [Field; HONK_PROOF_SIZE], // 508 elements
203203
public_inputs: [Field; 1], // Just 'y' value
204204
) {
205+
// Read VK hash from storage (stored during contract initialization)
206+
let vk_hash = self.storage.vk_hash.read();
207+
205208
// This is the magic line - on-chain proof verification!
206-
std::verify_proof_with_type(
209+
verify_honk_proof(
207210
verification_key,
208211
proof,
209212
public_inputs,
210-
0x0, // Key hash (0 for self-verification)
211-
HONK_IDENTIFIER // Proof system type (1 = UltraHonk)
213+
vk_hash // VK hash for verification
212214
);
213215

214-
// If proof is valid, increment the counter
215-
let counters = storage.counters;
216-
counters.at(owner).add(1, owner);
216+
// If proof is valid, enqueue public function to increment the counter
217+
self.enqueue_self._increment_public(owner);
217218
}
218219
```
219220

220221
### Step 3: Deployment & Interaction (`scripts/run_recursion.ts`)
221222

222223
```typescript
223-
// 1. Connect to Aztec network
224-
const pxe = await createPXEClient("http://localhost:8080");
225-
226-
// 2. Deploy the contract with initial counter = 10
227-
const contract = await Contract.deploy(
228-
wallets.owner,
229-
ValueNotEqualContractArtifact,
230-
[10, wallets.owner.getAddress()], // Constructor args
231-
"initialize"
224+
// 1. Connect to Aztec network and setup wallet
225+
const aztecNode = await createAztecNodeClient("http://localhost:8080");
226+
const testWallet = await TestWallet.create(aztecNode, config);
227+
228+
// 2. Deploy the contract with initial counter = 10 and VK hash
229+
const contract = await ValueNotEqualContract.deploy(
230+
testWallet,
231+
10, // Initial counter value
232+
accounts[0].item, // Owner address
233+
data.vkHash // VK hash stored in contract
232234
)
233-
.send()
235+
.send(sendOpts)
234236
.deployed();
235237

236-
// 3. Submit proof for verification
238+
// 3. Submit proof for verification (VK hash read from storage)
237239
const tx = await contract.methods
238240
.increment(
239-
wallets.owner.getAddress(),
240-
data.vkAsFields, // Verification key
241-
data.proofAsFields, // The proof
242-
data.publicInputs // Public input (y=2)
241+
accounts[0].item,
242+
data.vkAsFields, // Verification key
243+
data.proofAsFields, // The proof
244+
data.publicInputs // Public input (y=2)
243245
)
244-
.send()
246+
.send(sendOpts)
245247
.wait();
246248

247249
// 4. Check the counter increased
248250
const counter = await contract.methods
249-
.get_counter(wallets.owner.getAddress())
250-
.simulate();
251+
.get_counter(accounts[0].item)
252+
.simulate({ from: accounts[0].item });
251253
// Counter is now 11 (10 + 1)
252254
```

recursive_verification/README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ This project implements:
1111
- **Proof Generation**: Scripts to generate UltraHonk proofs using Barretenberg
1212
- **On-chain Verification**: Deployment and interaction scripts for proof verification on Aztec
1313

14-
**Aztec Version**: `3.0.0-devnet.4`
14+
**Aztec Version**: `3.0.0-devnet.20251212`
1515

1616
## Prerequisites
1717

1818
- [Bun](https://bun.sh/) runtime (v1.0 or higher)
19-
- [Aztec CLI](https://docs.aztec.network/getting_started/quickstart) (version 3.0.0-devnet.4)
19+
- [Aztec CLI](https://docs.aztec.network/getting_started/quickstart) (version 3.0.0-devnet.20251212)
2020
- Linux/macOS (Windows users can use WSL2)
2121
- 8GB+ RAM recommended for proof generation
2222

@@ -61,7 +61,7 @@ bash -i <(curl -s https://install.aztec.network)
6161
### Set Aztec to the correct version:
6262

6363
```bash
64-
aztec-up 3.0.0-devnet.4
64+
aztec-up 3.0.0-devnet.20251212
6565
```
6666

6767
This ensures compatibility with the contract dependencies.
@@ -108,7 +108,7 @@ This runs `scripts/generate_data.ts` which:
108108

109109
- Executes the circuit with inputs x=1, y=2
110110
- Generates an UltraHonk proof using Barretenberg
111-
- Saves proof data to `data.json` (457 field elements for proof, 115 for VK)
111+
- Saves proof data to `data.json` (508 field elements for proof, 115 for VK)
112112

113113
## Deploy and Verify On-Chain
114114

@@ -153,7 +153,7 @@ For a fresh setup, run these commands in order:
153153
bun install
154154

155155
# 2. Setup Aztec
156-
aztec-up 3.0.0-devnet.4
156+
aztec-up 3.0.0-devnet.20251212
157157

158158
# 3. Compile circuit
159159
cd circuit && aztec-nargo compile && cd ..
@@ -254,8 +254,9 @@ bun data
254254

255255
1. **Circuit**: The Noir circuit in `circuit/src/main.nr` creates a zero-knowledge proof that two values are not equal
256256
2. **Proof Generation**: Barretenberg generates an UltraHonk proof from the circuit execution
257-
3. **Contract**: The Aztec contract uses `std::verify_proof_with_type` to verify the proof on-chain
258-
4. **Privacy**: The contract uses private state (`EasyPrivateUint`) to maintain counters secretly
257+
3. **Contract**: The Aztec contract uses `bb_proof_verification::verify_honk_proof` to verify the proof on-chain
258+
4. **VK Hash Storage**: The verification key hash is stored in contract storage during initialization and read during proof verification
259+
5. **Counter Management**: The contract maintains public counters per user using `PublicMutable` storage
259260

260261
## Additional Scripts
261262

recursive_verification/bun.lockb

1.94 KB
Binary file not shown.

recursive_verification/contract/Nargo.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,5 @@ type = "contract"
44
authors = ["Satyam Bansal"]
55

66
[dependencies]
7-
aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.4", directory = "noir-projects/aztec-nr/aztec" }
8-
value_note = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.4", directory = "noir-projects/aztec-nr/value-note" }
9-
easy_private_state = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.4", directory = "noir-projects/aztec-nr/easy-private-state" }
10-
bb_proof_verification = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.4", directory = "barretenberg/noir/bb_proof_verification" }
7+
aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.20251212", directory = "noir-projects/aztec-nr/aztec" }
8+
bb_proof_verification = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.20251212", directory = "barretenberg/noir/bb_proof_verification" }

recursive_verification/contract/src/main.nr

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,29 @@ use aztec::macros::aztec;
22

33
#[aztec]
44
pub contract ValueNotEqual {
5+
// Sizes for bb_proof_verification
56
global HONK_VK_SIZE: u32 = 115;
6-
global HONK_PROOF_SIZE: u32 = 492 + 16;
7+
global HONK_PROOF_SIZE: u32 = 508;
78

89
use aztec::{
9-
macros::{functions::{external, initializer, internal}, storage::storage},
10+
macros::{functions::{external, initializer, internal, only_self, view}, storage::storage},
1011
oracle::debug_log::debug_log_format,
1112
protocol_types::{address::AztecAddress, traits::ToField},
12-
state_vars::{Map, PublicImmutable},
13+
state_vars::{Map, PublicImmutable, PublicMutable},
1314
};
14-
use bb_proof_verification::verify_ultrahonkzk_proof;
15-
use easy_private_state::EasyPrivateUint;
15+
use bb_proof_verification::verify_honk_proof;
1616

1717
#[storage]
1818
struct Storage<Context> {
19-
counters: Map<AztecAddress, EasyPrivateUint<Context>, Context>,
19+
counters: Map<AztecAddress, PublicMutable<Field, Context>, Context>,
2020
vk_hash: PublicImmutable<Field, Context>,
2121
}
2222

2323
#[initializer]
24-
#[external("private")]
25-
fn initialize(headstart: u64, owner: AztecAddress, vk_hash: Field) {
26-
let counters = storage.counters;
27-
counters.at(owner).add(headstart, owner);
28-
29-
ValueNotEqual::at(context.this_address())._set_vk_hash(vk_hash).enqueue(&mut context);
30-
}
31-
32-
#[internal]
3324
#[external("public")]
34-
fn _set_vk_hash(vk_hash: Field) {
35-
storage.vk_hash.initialize(vk_hash);
25+
fn constructor(headstart: Field, owner: AztecAddress, vk_hash: Field) {
26+
self.storage.counters.at(owner).write(headstart);
27+
self.storage.vk_hash.initialize(vk_hash);
3628
}
3729

3830
#[external("private")]
@@ -43,20 +35,21 @@ pub contract ValueNotEqual {
4335
public_inputs: [Field; 1],
4436
) {
4537
debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]);
46-
let vk_hash = storage.vk_hash.read();
47-
verify_ultrahonkzk_proof(verification_key, proof, public_inputs, vk_hash);
48-
ValueNotEqual::at(context.this_address()).emit_in_public(12345).enqueue(&mut context);
49-
let counters = storage.counters;
50-
counters.at(owner).add(1, owner);
38+
let vk_hash = self.storage.vk_hash.read();
39+
verify_honk_proof(verification_key, proof, public_inputs, vk_hash);
40+
self.enqueue_self._increment_public(owner);
5141
}
5242

43+
#[only_self]
5344
#[external("public")]
54-
fn emit_in_public(n: Field) {
55-
context.push_note_hash(n);
45+
fn _increment_public(owner: AztecAddress) {
46+
let current = self.storage.counters.at(owner).read();
47+
self.storage.counters.at(owner).write(current + 1);
5648
}
5749

58-
#[external("utility")]
59-
unconstrained fn get_counter(owner: AztecAddress) -> Field {
60-
storage.counters.at(owner).get_value()
50+
#[view]
51+
#[external("public")]
52+
fn get_counter(owner: AztecAddress) -> Field {
53+
self.storage.counters.at(owner).read()
6154
}
6255
}

0 commit comments

Comments
 (0)