Skip to content

Commit 58a6386

Browse files
committed
Add initial implementation for recursive verification in Aztec contracts
- Introduced .gitignore to exclude build artifacts and dependencies. - Added CLAUDE.md and EXPLAINER.md for project documentation and guidance. - Created data.json for proof data storage. - Implemented scripts for proof generation and contract interaction. - Developed the ValueNotEqual contract to verify Noir proofs. - Included tests for contract deployment, proof verification, and counter management. - Established project structure with necessary configurations and dependencies.
1 parent ccff394 commit 58a6386

File tree

18 files changed

+1717
-0
lines changed

18 files changed

+1717
-0
lines changed

recursive_verification/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
**/target/
3+
**/codegenCache.json
4+
**/artifacts/

recursive_verification/CLAUDE.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is an Aztec-Noir project that demonstrates proof verification in Aztec contracts. It uses Aztec version 2.0.3 to verify Noir proofs within smart contracts on the Aztec network.
8+
9+
The project consists of:
10+
- A Noir circuit (`hello_circuit`) that proves x ≠ y
11+
- An Aztec smart contract (`ValueNotEqual`) that verifies the proof on-chain
12+
- Scripts to generate proof data and deploy/interact with the contract
13+
14+
## Common Development Commands
15+
16+
### Environment Setup
17+
```bash
18+
# Install dependencies
19+
bun install
20+
21+
# Install/update Aztec tools
22+
aztec-up
23+
24+
# Start Aztec Sandbox (required for contract deployment)
25+
aztec start --sandbox
26+
```
27+
28+
### Circuit Development
29+
```bash
30+
# Compile the Noir circuit
31+
cd circuit && aztec-nargo compile
32+
33+
# Execute the circuit (generate witness)
34+
cd circuit && nargo execute
35+
36+
# Run circuit tests
37+
cd circuit && nargo test
38+
```
39+
40+
### Contract Development
41+
```bash
42+
# Compile contract, postprocess, and generate TypeScript bindings
43+
bun ccc
44+
# This runs: cd contract && aztec-nargo compile && aztec-postprocess-contract && aztec codegen target -o artifacts
45+
46+
# Generate proof data (vk, proof, public inputs) for contract verification
47+
bun data
48+
# This runs: bun run scripts/generate_data.ts
49+
50+
# Deploy contract and run proof verification
51+
bun recursion
52+
# This runs: bun run scripts/run_recursion.ts
53+
```
54+
55+
## Architecture
56+
57+
### Circuit (`circuit/`)
58+
- **`src/main.nr`**: Simple circuit that asserts two field values are not equal
59+
- **`target/hello_circuit.json`**: Compiled circuit bytecode and ABI
60+
- Uses UltraHonk proving system for proof generation
61+
62+
### Contract (`contract/`)
63+
- **`src/main.nr`**: Aztec smart contract with:
64+
- `initialize()`: Sets up counter with initial value for an owner
65+
- `increment()`: Verifies a Noir proof and increments the counter
66+
- `get_counter()`: Reads current counter value for an owner
67+
- Uses Honk proof verification (457 field elements for proof, 115 for verification key)
68+
- Stores private counters using `EasyPrivateUint` from Aztec-nr libraries
69+
70+
### Scripts (`scripts/`)
71+
- **`generate_data.ts`**:
72+
- Executes the circuit with inputs (x=1, y=2)
73+
- Generates UltraHonk proof using Barretenberg backend
74+
- Serializes proof, verification key, and public inputs to `data.json`
75+
76+
- **`run_recursion.ts`**:
77+
- Connects to Aztec PXE at localhost:8080
78+
- Deploys the ValueNotEqual contract
79+
- Calls `increment()` with the generated proof data
80+
- Verifies the proof on-chain and updates the counter
81+
82+
### Data Flow
83+
1. Circuit compilation produces bytecode (`hello_circuit.json`)
84+
2. `generate_data.ts` creates proof data from circuit execution
85+
3. Contract compilation produces Aztec contract artifact and TypeScript bindings
86+
4. `run_recursion.ts` deploys contract and submits proof for on-chain verification
87+
88+
## Key Dependencies
89+
- `@aztec/aztec.js`: Aztec SDK for contract deployment and interaction
90+
- `@aztec/bb.js`: Barretenberg backend for proof generation
91+
- `@aztec/noir-noir_js`: Noir.js for circuit execution
92+
- `bun`: JavaScript runtime and package manager
93+
94+
## Testing
95+
- Circuit tests: Use `nargo test` in the circuit directory
96+
- Contract verification: Run the full flow with `bun recursion` after starting the sandbox
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# Aztec-Noir Proof Verification: Complete Code Explanation
2+
3+
## 🔍 Code Complexity Analysis
4+
5+
**Project Type**: Zero-Knowledge Proof Verification System
6+
**Complexity Level**: Intermediate-Advanced
7+
**Key Technologies**: Noir (ZK DSL), Aztec (Private Smart Contracts), Barretenberg (Proving System)
8+
9+
### Core Concepts Used:
10+
11+
- Zero-knowledge proofs (ZK-SNARKs)
12+
- Private smart contract execution
13+
- Cryptographic proof generation and verification
14+
- Cross-system integration (off-chain proving → on-chain verification)
15+
16+
## 📊 Visual Architecture Diagram
17+
18+
### System Flow Visualization
19+
20+
```mermaid
21+
22+
flowchart TB
23+
subgraph "1. Circuit Definition"
24+
NC[Noir Circuit<br/>circuit/src/main.nr]
25+
NC -->|Proves x ≠ y| PROOF_LOGIC[Assertion Logic]
26+
end
27+
28+
subgraph "2. Compilation Phase"
29+
NC -->|aztec-nargo compile| BYTECODE[Circuit Bytecode<br/>hello_circuit.json]
30+
end
31+
32+
subgraph "3. Proof Generation"
33+
BYTECODE -->|Barretenberg| PROVER[UltraHonk Prover]
34+
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]
36+
PROOF_DATA -->|Saved to| JSON[data.json]
37+
end
38+
39+
subgraph "4. Smart Contract"
40+
CONTRACT[ValueNotEqual Contract<br/>contract/src/main.nr]
41+
CONTRACT -->|Contains| VERIFY[verify_proof_with_type]
42+
CONTRACT -->|Manages| STATE[Private Counter State]
43+
end
44+
45+
subgraph "5. On-chain Verification"
46+
JSON -->|Submitted to| CONTRACT
47+
VERIFY -->|Verifies| RESULT{Valid?}
48+
RESULT -->|Yes| INCREMENT[Increment Counter]
49+
RESULT -->|No| FAIL[Transaction Reverts]
50+
end
51+
52+
subgraph "6. Aztec Network"
53+
SANDBOX[Aztec Sandbox<br/>localhost:8080]
54+
PXE[Private Execution<br/>Environment]
55+
SANDBOX --> PXE
56+
CONTRACT -->|Deployed to| SANDBOX
57+
end
58+
59+
style NC fill:#e1f5fe
60+
style CONTRACT fill:#c8e6c9
61+
style PROOF_DATA fill:#fff9c4
62+
style SANDBOX fill:#f3e5f5
63+
```
64+
65+
### Data Flow Sequence
66+
67+
```mermaid
68+
sequenceDiagram
69+
participant Dev as Developer
70+
participant Circuit as Noir Circuit
71+
participant BB as Barretenberg
72+
participant Contract as Aztec Contract
73+
participant Sandbox as Aztec Sandbox
74+
75+
Dev->>Circuit: 1. Define proof logic (x ≠ y)
76+
Dev->>Circuit: 2. Compile circuit
77+
Circuit->>Circuit: Generate bytecode
78+
79+
Dev->>BB: 3. Execute circuit with inputs
80+
BB->>BB: Generate UltraHonk proof
81+
BB->>Dev: Return proof, VK, public inputs
82+
83+
Dev->>Contract: 4. Compile smart contract
84+
Dev->>Sandbox: 5. Start local network
85+
86+
Dev->>Sandbox: 6. Deploy contract
87+
Sandbox-->>Dev: Contract address
88+
89+
Dev->>Contract: 7. Call increment() with proof
90+
Contract->>Contract: Verify proof on-chain
91+
Contract->>Contract: Update private state
92+
Contract-->>Dev: Transaction success
93+
```
94+
95+
## 🎓 Core Concepts Explained
96+
97+
### 1. Zero-Knowledge Proofs (Simple Analogy)
98+
99+
**Think of it like**: Proving you know a password without revealing the password itself.
100+
101+
**In this project**: The circuit proves that two numbers are different (x ≠ y) without revealing what x is. Only y is public.
102+
103+
```
104+
Regular Proof: "x is 1 and y is 2, so they're different"
105+
Zero-Knowledge Proof: "I can prove x ≠ 2, but I won't tell you x"
106+
```
107+
108+
### 2. Noir Circuit (The Proof Logic)
109+
110+
**File**: `circuit/src/main.nr`
111+
112+
```rust
113+
fn main(x: Field, y: pub Field) {
114+
assert(x != y); // This is the statement we're proving
115+
}
116+
```
117+
118+
**Key Points**:
119+
120+
- `x: Field` - Private input (hidden)
121+
- `y: pub Field` - Public input (visible to everyone)
122+
- `assert(x != y)` - The condition that must be true
123+
124+
**How it works**:
125+
126+
1. Prover knows both x and y
127+
2. Prover generates proof that x ≠ y
128+
3. Verifier only sees y and the proof
129+
4. Verifier confirms the proof is valid without learning x
130+
131+
### 3. Aztec Smart Contract (The Verifier)
132+
133+
**File**: `contract/src/main.nr`
134+
135+
The contract has three main functions:
136+
137+
```rust
138+
// 1. Initialize with a starting counter value
139+
fn initialize(headstart: u64, owner: AztecAddress)
140+
141+
// 2. Verify proof and increment counter
142+
fn increment(
143+
owner: AztecAddress,
144+
verification_key: [Field; 115],
145+
proof: [Field; 457],
146+
public_inputs: [Field; 1]
147+
)
148+
149+
// 3. Read current counter value
150+
fn get_counter(owner: AztecAddress) -> Field
151+
```
152+
153+
### 4. UltraHonk Proving System
154+
155+
**What is it?** A high-performance proof generation system that creates compact, verifiable proofs.
156+
157+
**Size breakdown**:
158+
159+
- **Verification Key**: 115 field elements (~3.7KB)
160+
- **Proof**: 457 field elements (~14.6KB)
161+
- **Public Inputs**: 1 field element (the value of y)
162+
163+
## 📝 Step-by-Step Code Breakdown
164+
165+
### Step 1: Circuit Execution (`scripts/generate_data.ts`)
166+
167+
```typescript
168+
// 1. Load the compiled circuit
169+
const helloWorld = new Noir(circuitJson);
170+
171+
// 2. Execute circuit with specific inputs
172+
const { witness } = await helloWorld.execute({
173+
x: 1, // Private: only prover knows
174+
y: 2, // Public: everyone can see
175+
});
176+
177+
// 3. Generate the proof
178+
const backend = new UltraHonkBackend(circuitJson.bytecode);
179+
const proofData = await backend.generateProof(witness);
180+
181+
// 4. Extract verification key
182+
const vk = await backend.getVerificationKey();
183+
184+
// 5. Convert to field elements for on-chain use
185+
const proofAsFields = deflattenFields(new RawBuffer(proofData.proof));
186+
const vkAsFields = await barretenbergAPI.acirVkAsFieldsUltraHonk(vk);
187+
```
188+
189+
**What happens here**:
190+
191+
1. Circuit proves "1 ≠ 2" is true
192+
2. Barretenberg creates cryptographic proof
193+
3. Proof is serialized for blockchain storage
194+
195+
### Step 2: Contract Verification (`contract/src/main.nr`)
196+
197+
```rust
198+
#[private]
199+
fn increment(
200+
owner: AztecAddress,
201+
verification_key: [Field; HONK_VK_SIZE], // 115 elements
202+
proof: [Field; HONK_PROOF_SIZE], // 457 elements
203+
public_inputs: [Field; 1], // Just 'y' value
204+
) {
205+
// This is the magic line - on-chain proof verification!
206+
std::verify_proof_with_type(
207+
verification_key,
208+
proof,
209+
public_inputs,
210+
0x0, // Key hash (0 for self-verification)
211+
HONK_IDENTIFIER // Proof system type (1 = UltraHonk)
212+
);
213+
214+
// If proof is valid, increment the counter
215+
let counters = storage.counters;
216+
counters.at(owner).add(1, owner);
217+
}
218+
```
219+
220+
### Step 3: Deployment & Interaction (`scripts/run_recursion.ts`)
221+
222+
```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"
232+
)
233+
.send()
234+
.deployed();
235+
236+
// 3. Submit proof for verification
237+
const tx = await contract.methods
238+
.increment(
239+
wallets.owner.getAddress(),
240+
data.vkAsFields, // Verification key
241+
data.proofAsFields, // The proof
242+
data.publicInputs // Public input (y=2)
243+
)
244+
.send()
245+
.wait();
246+
247+
// 4. Check the counter increased
248+
const counter = await contract.methods
249+
.get_counter(wallets.owner.getAddress())
250+
.simulate();
251+
// Counter is now 11 (10 + 1)
252+
```

0 commit comments

Comments
 (0)