|
| 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