tasm_lib/mmr/
calculate_new_peaks_from_append.rs1use triton_vm::prelude::*;
2
3use crate::arithmetic::u64::incr::Incr;
4use crate::arithmetic::u64::trailing_zeros::TrailingZeros;
5use crate::list::new::New;
6use crate::list::pop::Pop;
7use crate::list::push::Push;
8use crate::prelude::*;
9
10#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
11pub struct CalculateNewPeaksFromAppend;
12
13impl BasicSnippet for CalculateNewPeaksFromAppend {
14 fn inputs(&self) -> Vec<(DataType, String)> {
15 let list_type = DataType::List(Box::new(DataType::Digest));
16
17 vec![
18 (DataType::U64, "old_num_leafs".to_string()),
19 (list_type, "peaks".to_string()),
20 (DataType::Digest, "new_leaf".to_string()),
21 ]
22 }
23
24 fn outputs(&self) -> Vec<(DataType, String)> {
25 let list_type = DataType::List(Box::new(DataType::Digest));
26
27 vec![
28 (list_type.clone(), "*new_peaks".to_string()),
29 (list_type, "*auth_path".to_string()),
30 ]
31 }
32
33 fn entrypoint(&self) -> String {
34 "tasmlib_mmr_calculate_new_peaks_from_append".into()
35 }
36
37 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
38 let entrypoint = self.entrypoint();
39 let while_loop_label = format!("{entrypoint}_while");
40
41 let new_list = library.import(Box::new(New));
42 let push = library.import(Box::new(Push::new(DataType::Digest)));
43 let pop = library.import(Box::new(Pop::new(DataType::Digest)));
44 let u64incr = library.import(Box::new(Incr));
45 let right_lineage_count = library.import(Box::new(TrailingZeros));
46
47 triton_asm!(
48 {entrypoint}:
51 dup 5
52 place 5
53 call {push}
54 call {new_list}
58 pick 3 pick 3
61 call {u64incr}
64 call {right_lineage_count}
65 call {while_loop_label}
68 pop 1
71 return
74
75 {while_loop_label}:
77 dup 0
78 push 0
79 eq
80 skiz
81 return
82 dup 2
85 dup 0
86 call {pop}
87 dup 5
90 call {pop}
93 dup 12
97 dup 5 dup 5 dup 5 dup 5 dup 5
98 call {push}
99 hash
102 call {push}
105 addi -1
108 recurse
111 )
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator;
118
119 use super::*;
120 use crate::memory::FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
121 use crate::memory::dyn_malloc::DYN_MALLOC_FIRST_ADDRESS;
122 use crate::rust_shadowing_helper_functions::list::list_pop;
123 use crate::rust_shadowing_helper_functions::list::list_push;
124 use crate::test_prelude::*;
125 use crate::twenty_first::prelude::Mmr;
126 use crate::twenty_first::util_types::mmr::shared_basic::calculate_new_peaks_from_append;
127
128 impl CalculateNewPeaksFromAppend {
129 fn set_up_initial_state(
130 &self,
131 mmr: MmrAccumulator,
132 new_leaf: Digest,
133 ) -> FunctionInitialState {
134 let peaks_pointer = FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
135
136 let mut stack = self.init_stack_for_isolated_run();
137 push_encodable(&mut stack, &mmr.num_leafs());
138 push_encodable(&mut stack, &peaks_pointer);
139 push_encodable(&mut stack, &new_leaf.reversed());
140
141 let mut memory = HashMap::default();
142 encode_to_memory(&mut memory, peaks_pointer, &mmr.peaks());
143
144 FunctionInitialState { stack, memory }
145 }
146 }
147
148 impl Function for CalculateNewPeaksFromAppend {
149 fn rust_shadow(
150 &self,
151 stack: &mut Vec<BFieldElement>,
152 memory: &mut HashMap<BFieldElement, BFieldElement>,
153 ) {
154 let new_leaf = pop_encodable::<Digest>(stack);
155 let peaks_pointer = stack.pop().unwrap();
156 let old_num_leafs = pop_encodable::<u64>(stack);
157 let old_peaks = *Vec::decode_from_memory(memory, peaks_pointer).unwrap();
158
159 list_push(peaks_pointer, new_leaf.encode(), memory);
162 let old_num_peaks = old_num_leafs.count_ones();
163 for _ in 0..old_num_peaks {
164 let left = list_pop(peaks_pointer, memory, Digest::LEN);
165 let right = list_pop(peaks_pointer, memory, Digest::LEN);
166 let new = Tip5::hash_pair(right.try_into().unwrap(), left.try_into().unwrap());
167 list_push(peaks_pointer, new.encode(), memory);
168 }
169
170 let (new_peaks, proof) =
172 calculate_new_peaks_from_append(old_num_leafs, old_peaks, new_leaf);
173
174 let auth_path_pointer = DYN_MALLOC_FIRST_ADDRESS;
175 encode_to_memory(memory, peaks_pointer, &new_peaks);
176 encode_to_memory(memory, auth_path_pointer, &proof.authentication_path);
177 stack.push(peaks_pointer);
178 stack.push(auth_path_pointer);
179 }
180
181 fn pseudorandom_initial_state(
182 &self,
183 seed: [u8; 32],
184 bench_case: Option<BenchmarkCase>,
185 ) -> FunctionInitialState {
186 let mut rng = StdRng::from_seed(seed);
187
188 let old_num_leafs: u64 = match bench_case {
189 Some(BenchmarkCase::CommonCase) => (1 << 31) - 1,
190 Some(BenchmarkCase::WorstCase) => (1 << 62) - 1,
191 None => rng.random_range(0..1 << 63),
192 };
193 let peaks = (0..old_num_leafs.count_ones())
194 .map(|_| rng.random())
195 .collect();
196 let mmr = MmrAccumulator::init(peaks, old_num_leafs);
197
198 self.set_up_initial_state(mmr, rng.random())
199 }
200
201 fn corner_case_initial_states(&self) -> Vec<FunctionInitialState> {
202 let mut states = vec![];
203 for num_leafs in (0_u64..=17).chain([100, 1000, 1 << 31, 1 << 32, 1 << 33]) {
204 let num_peaks = num_leafs.count_ones();
205 let peaks = (0..num_peaks).map(|i| Tip5::hash(&i)).collect();
206 let mmr = MmrAccumulator::init(peaks, num_leafs);
207 let new_leaf = Tip5::hash(&num_leafs);
208 states.push(self.set_up_initial_state(mmr, new_leaf));
209 }
210
211 states
212 }
213 }
214
215 #[test]
216 fn rust_shadow() {
217 ShadowedFunction::new(CalculateNewPeaksFromAppend).test();
218 }
219}
220
221#[cfg(test)]
222mod benches {
223 use super::*;
224 use crate::test_prelude::*;
225
226 #[test]
227 fn calculate_new_peaks_from_append_benchmark() {
228 ShadowedFunction::new(CalculateNewPeaksFromAppend).bench();
229 }
230}