snarkvm_circuit_program/state_path/
mod.rs1mod helpers;
17pub use helpers::*;
18
19mod verify;
20
21#[cfg(test)]
22use snarkvm_circuit_types::environment::assert_scope;
23
24use snarkvm_circuit_collections::merkle_tree::MerklePath;
25use snarkvm_circuit_network::Aleo;
26use snarkvm_circuit_types::{Boolean, Field, U8, environment::prelude::*};
27
28const BLOCKS_DEPTH: u8 = console::BLOCKS_DEPTH;
30const HEADER_DEPTH: u8 = console::HEADER_DEPTH;
32const TRANSACTIONS_DEPTH: u8 = console::TRANSACTIONS_DEPTH;
34const TRANSACTION_DEPTH: u8 = console::TRANSACTION_DEPTH;
36const TRANSITION_DEPTH: u8 = console::TRANSITION_DEPTH;
38
39type BlockPath<A> = MerklePath<A, BLOCKS_DEPTH>;
40type HeaderPath<A> = MerklePath<A, HEADER_DEPTH>;
41type TransactionsPath<A> = MerklePath<A, TRANSACTIONS_DEPTH>;
42type TransactionPath<A> = MerklePath<A, TRANSACTION_DEPTH>;
43type TransitionPath<A> = MerklePath<A, TRANSITION_DEPTH>;
44
45pub struct StatePath<A: Aleo> {
47 global_state_root: Field<A>,
49 block_path: BlockPath<A>,
51 block_hash: Field<A>,
53 previous_block_hash: Field<A>,
55 header_root: Field<A>,
57 header_path: HeaderPath<A>,
59 header_leaf: HeaderLeaf<A>,
61 transactions_path: TransactionsPath<A>,
63 transaction_id: Field<A>,
65 transaction_path: TransactionPath<A>,
67 transaction_leaf: TransactionLeaf<A>,
69 transition_root: Field<A>,
71 tcm: Field<A>,
73 transition_path: TransitionPath<A>,
75 transition_leaf: TransitionLeaf<A>,
77}
78
79impl<A: Aleo> StatePath<A> {
80 pub const fn transition_leaf(&self) -> &TransitionLeaf<A> {
82 &self.transition_leaf
83 }
84
85 pub const fn block_path(&self) -> &BlockPath<A> {
87 &self.block_path
88 }
89}
90
91impl<A: Aleo> Inject for StatePath<A> {
92 type Primitive = console::StatePath<A::Network>;
93
94 fn new(mode: Mode, state_path: Self::Primitive) -> Self {
96 Self {
97 global_state_root: Field::new(Mode::Public, *state_path.global_state_root()),
98 block_path: BlockPath::new(mode, state_path.block_path().clone()),
99 block_hash: Field::new(mode, *state_path.block_hash()),
100 previous_block_hash: Field::new(mode, *state_path.previous_block_hash()),
101 header_root: Field::new(mode, *state_path.header_root()),
102 header_path: HeaderPath::new(mode, state_path.header_path().clone()),
103 header_leaf: HeaderLeaf::new(mode, *state_path.header_leaf()),
104 transactions_path: TransactionsPath::new(mode, state_path.transactions_path().clone()),
105 transaction_id: Field::new(mode, **state_path.transaction_id()),
106 transaction_path: TransactionPath::new(mode, state_path.transaction_path().clone()),
107 transaction_leaf: TransactionLeaf::new(mode, *state_path.transaction_leaf()),
108 transition_root: Field::new(mode, *state_path.transition_root()),
109 tcm: Field::new(mode, *state_path.tcm()),
110 transition_path: TransitionPath::new(mode, state_path.transition_path().clone()),
111 transition_leaf: TransitionLeaf::new(mode, *state_path.transition_leaf()),
112 }
113 }
114}
115
116impl<A: Aleo> Eject for StatePath<A> {
117 type Primitive = console::StatePath<A::Network>;
118
119 fn eject_mode(&self) -> Mode {
121 Mode::combine(self.global_state_root.eject_mode(), [
122 self.block_path.eject_mode(),
123 self.block_hash.eject_mode(),
124 self.previous_block_hash.eject_mode(),
125 self.header_root.eject_mode(),
126 self.header_path.eject_mode(),
127 self.header_leaf.eject_mode(),
128 self.transactions_path.eject_mode(),
129 self.transaction_id.eject_mode(),
130 self.transaction_path.eject_mode(),
131 self.transaction_leaf.eject_mode(),
132 self.transition_root.eject_mode(),
133 self.tcm.eject_mode(),
134 self.transition_path.eject_mode(),
135 self.transition_leaf.eject_mode(),
136 ])
137 }
138
139 fn eject_value(&self) -> Self::Primitive {
141 Self::Primitive::from(
142 self.global_state_root.eject_value().into(),
143 self.block_path.eject_value(),
144 self.block_hash.eject_value().into(),
145 self.previous_block_hash.eject_value().into(),
146 self.header_root.eject_value(),
147 self.header_path.eject_value(),
148 self.header_leaf.eject_value(),
149 self.transactions_path.eject_value(),
150 self.transaction_id.eject_value().into(),
151 self.transaction_path.eject_value(),
152 self.transaction_leaf.eject_value(),
153 self.transition_root.eject_value(),
154 self.tcm.eject_value(),
155 self.transition_path.eject_value(),
156 self.transition_leaf.eject_value(),
157 )
158 }
159}
160
161#[cfg(all(test, feature = "console"))]
162mod tests {
163 use super::*;
164 use crate::Circuit;
165
166 use snarkvm_utilities::TestRng;
167
168 use anyhow::Result;
169
170 type CurrentNetwork = <Circuit as Environment>::Network;
171
172 const ITERATIONS: u64 = 250;
173
174 fn check_new(
175 mode: Mode,
176 num_constants: u64,
177 num_public: u64,
178 num_private: u64,
179 num_constraints: u64,
180 ) -> Result<()> {
181 let rng = &mut TestRng::default();
182
183 for _ in 0..ITERATIONS {
184 let console_state_path =
186 console::state_path::test_helpers::sample_local_state_path::<CurrentNetwork>(None, rng).unwrap();
187
188 Circuit::scope(format!("New {mode}"), || {
189 let candidate = StatePath::<Circuit>::new(mode, console_state_path.clone());
190 assert_eq!(console_state_path, candidate.eject_value());
191 assert_scope!(num_constants, num_public, num_private, num_constraints);
192 });
193 Circuit::reset();
194 }
195 Ok(())
196 }
197
198 #[test]
199 fn test_state_path_new_constant() -> Result<()> {
200 check_new(Mode::Constant, 450, 1, 0, 0)
201 }
202
203 #[test]
204 fn test_state_path_new_public() -> Result<()> {
205 check_new(Mode::Public, 0, 451, 0, 376)
206 }
207
208 #[test]
209 fn test_state_path_new_private() -> Result<()> {
210 check_new(Mode::Private, 0, 1, 450, 376)
211 }
212}