/ console / program / src / state_path / verify.rs
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  }