verify.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphavm library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 use super::*; 20 21 impl<N: Network> StatePath<N> { 22 /// Checks if the state path is valid. 23 /// 24 /// # Parameters 25 /// - `local_state_root` is the local transaction root for the current execution. 26 /// - `is_global` is a boolean indicating whether this is a global or local state root. 27 /// 28 /// # Diagram 29 /// The `[[ ]]` notation is used to denote public inputs. 30 /// ```ignore 31 /// 32 /// [[ global_state_root ]] 33 /// | 34 /// block_path 35 /// | 36 /// block_hash := Hash( previous_block_hash || header_root ) 37 /// | 38 /// header_path 39 /// | 40 /// header_leaf 41 /// | 42 /// transactions_path [[ local_state_root ]] 43 /// | | 44 /// (true) ------ is_global ------ (false) 45 /// | 46 /// transaction_id 47 /// | 48 /// transaction_path 49 /// | 50 /// transaction_leaf 51 /// | 52 /// transition_id := Hash( transition_root || tcm ) 53 /// | 54 /// transition_path 55 /// | 56 /// transition_leaf 57 /// ``` 58 pub fn verify(&self, is_global: bool, local_state_root: Field<N>) -> Result<()> { 59 // Ensure the transition leaf variant is 3 (Input::Record). 60 ensure!(self.transition_leaf.variant() == 3, "Transition leaf variant must be 3 (Input::Record)"); 61 // Ensure the transition path is valid. 62 ensure!( 63 N::verify_merkle_path_bhp(&self.transition_path, &self.transition_root, &self.transition_leaf.to_bits_le()), 64 "'{}' (an input or output ID) does not belong to '{}' (a function or transition)", 65 self.transition_leaf.id(), 66 self.transaction_leaf.id() 67 ); 68 69 // Ensure the transaction leaf is correct. 70 ensure!( 71 *self.transaction_leaf.id() == *N::hash_bhp512(&(*self.transition_root, self.tcm).to_bits_le())?, 72 "Transaction leaf id '{}' is incorrect. Double-check the tcm and transition root.", 73 self.transaction_leaf.id() 74 ); 75 76 // Ensure the transaction leaf variant is 1 (Transaction::Execution). 77 ensure!(self.transaction_leaf.variant() == 1, "Transaction leaf variant must be 1 (Transaction::Execution)"); 78 // Ensure the transaction path is valid. 79 ensure!( 80 N::verify_merkle_path_bhp( 81 &self.transaction_path, 82 &self.transaction_id, 83 &self.transaction_leaf.to_bits_le() 84 ), 85 "'{}' (a function or transition) does not belong to transaction '{}'", 86 self.transaction_leaf.id(), 87 self.transaction_id 88 ); 89 90 if is_global { 91 // Ensure the header leaf index is 1 (Header::transactions_root). 92 ensure!(self.header_leaf.index() == 1, "Header leaf index must be 1 (Header::transactions_root)"); 93 // Ensure the transactions path is valid. 94 ensure!( 95 N::verify_merkle_path_bhp( 96 &self.transactions_path, 97 &self.header_leaf.id(), 98 &self.transaction_id.to_bits_le() 99 ), 100 "Transaction '{}' does not belong to '{}' (a header leaf)", 101 self.transaction_id, 102 self.header_leaf 103 ); 104 // Ensure the header path is valid. 105 ensure!( 106 N::verify_merkle_path_bhp(&self.header_path, &self.header_root, &self.header_leaf.to_bits_le()), 107 "'{}' (a header leaf) does not belong to '{}' (a block header)", 108 self.header_leaf, 109 self.block_hash 110 ); 111 // Ensure the block hash is correct. 112 ensure!( 113 *self.block_hash == N::hash_bhp1024(&to_bits_le![(*self.previous_block_hash), self.header_root])?, 114 "Block hash '{}' is incorrect. Double-check the previous block hash and block header root.", 115 self.block_hash 116 ); 117 // Ensure the global state root is correct. 118 ensure!( 119 N::verify_merkle_path_bhp(&self.block_path, &self.global_state_root, &self.block_hash.to_bits_le()), 120 "'{}' (a block hash) does not belong to '{}' (a global state root)", 121 self.block_hash, 122 self.global_state_root 123 ); 124 } else { 125 // Ensure the local state root is correct. 126 ensure!( 127 *self.transaction_id == local_state_root, 128 "'{}' (a decoded transaction ID) does not match the '{local_state_root}' (a local state root)", 129 *self.transaction_id 130 ); 131 } 132 133 Ok(()) 134 } 135 } 136 137 #[cfg(test)] 138 mod tests { 139 use super::*; 140 use alphavm_console_network::{prelude::TestRng, MainnetV0}; 141 142 type CurrentNetwork = MainnetV0; 143 144 const ITERATIONS: usize = 100; 145 146 #[test] 147 fn test_verify_global() { 148 let rng = &mut TestRng::default(); 149 150 for _ in 0..ITERATIONS { 151 // Sample the state path. 152 let state_path = 153 crate::state_path::test_helpers::sample_global_state_path::<CurrentNetwork>(None, rng).unwrap(); 154 // Sample the local state root. 155 let local_state_root = Field::rand(rng); 156 157 // Ensure the state path is valid. 158 state_path.verify(true, local_state_root).unwrap(); 159 // Ensure the state path is *not* valid for a random local state root. 160 state_path.verify(false, local_state_root).unwrap_err(); 161 } 162 } 163 164 #[test] 165 fn test_verify_local() { 166 let rng = &mut TestRng::default(); 167 168 for _ in 0..ITERATIONS { 169 // Sample the state path. 170 let state_path = 171 crate::state_path::test_helpers::sample_local_state_path::<CurrentNetwork>(None, rng).unwrap(); 172 // Retrieve the local state root. 173 let local_state_root = **state_path.transaction_id(); 174 175 // Ensure the state path is valid. 176 state_path.verify(false, local_state_root).unwrap(); 177 // Ensure the state path does *not* match a random local state root. 178 state_path.verify(false, Field::rand(rng)).unwrap_err(); 179 // Ensure the state path does *not* match to the random global state root. 180 state_path.verify(true, local_state_root).unwrap_err(); 181 // Ensure the state path does *not* match to the random global state root. 182 state_path.verify(true, Field::rand(rng)).unwrap_err(); 183 } 184 } 185 186 #[test] 187 fn test_verify_new_local() { 188 let rng = &mut TestRng::default(); 189 190 for _ in 0..ITERATIONS { 191 // Sample the state path. 192 let state_path = 193 crate::state_path::test_helpers::sample_local_state_path::<CurrentNetwork>(None, rng).unwrap(); 194 195 // Initialize the state path using `new_local`. 196 let new_local_state_path = StatePath::new_local( 197 state_path.global_state_root(), 198 *state_path.transaction_id(), 199 state_path.transaction_path().clone(), 200 *state_path.transaction_leaf(), 201 *state_path.transition_root(), 202 *state_path.tcm(), 203 state_path.transition_path().clone(), 204 *state_path.transition_leaf(), 205 ) 206 .unwrap(); 207 208 // Retrieve the local state root. 209 let local_state_root = **new_local_state_path.transaction_id(); 210 211 // Ensure the state path is valid. 212 new_local_state_path.verify(false, local_state_root).unwrap(); 213 // Ensure the state path does *not* match a random local state root. 214 new_local_state_path.verify(false, Field::rand(rng)).unwrap_err(); 215 // Ensure the state path does *not* match to the random global state root. 216 new_local_state_path.verify(true, local_state_root).unwrap_err(); 217 // Ensure the state path does *not* match to the random global state root. 218 new_local_state_path.verify(true, Field::rand(rng)).unwrap_err(); 219 } 220 } 221 }