1use alloc::vec::Vec;
2
3use crate::{
4 Felt, Word,
5 crypto::merkle::MerkleStore,
6 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8
9mod map;
10pub use map::AdviceMap;
11
12mod stack;
13pub use stack::AdviceStack;
14
15#[derive(Clone, Debug, Default, PartialEq, Eq)]
30pub struct AdviceInputs {
31 advice_stack: AdviceStack,
32 pub map: AdviceMap,
33 pub store: MerkleStore,
34}
35
36impl AdviceInputs {
37 pub fn with_advice_stack(mut self, stack: AdviceStack) -> Self {
42 self.advice_stack = stack;
43 self
44 }
45
46 pub fn advice_stack(&self) -> AdviceStack {
48 self.advice_stack.clone()
49 }
50
51 pub fn with_map<I>(mut self, iter: I) -> Self
53 where
54 I: IntoIterator<Item = (Word, Vec<Felt>)>,
55 {
56 self.map.extend(iter);
57 self
58 }
59
60 pub fn with_merkle_store(mut self, store: MerkleStore) -> Self {
62 self.store = store;
63 self
64 }
65
66 pub fn extend(&mut self, other: Self) {
71 self.advice_stack.append_elements(other.advice_stack.into_elements());
72 self.map.extend(other.map);
73 self.store.extend(other.store.inner_nodes());
74 }
75
76 pub fn into_parts(self) -> (AdviceStack, AdviceMap, MerkleStore) {
78 (self.advice_stack, self.map, self.store)
79 }
80}
81
82impl Serializable for AdviceInputs {
83 fn write_into<W: ByteWriter>(&self, target: &mut W) {
84 let Self { advice_stack, map, store } = self;
85 let stack: Vec<Felt> = advice_stack.iter().copied().collect();
86 stack.write_into(target);
87 map.write_into(target);
88 store.write_into(target);
89 }
90}
91
92impl Deserializable for AdviceInputs {
93 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
94 let stack = Vec::<Felt>::read_from(source)?;
95 let map = AdviceMap::read_from(source)?;
96 let store = MerkleStore::read_from(source)?;
97 Ok(Self { advice_stack: stack.into(), map, store })
98 }
99}
100
101#[cfg(test)]
105mod tests {
106 use alloc::vec::Vec;
107
108 use super::{AdviceInputs, AdviceStack};
109 use crate::{
110 Felt, Word,
111 serde::{Deserializable, Serializable},
112 };
113
114 #[test]
115 fn test_advice_inputs_eq() {
116 let advice1 = AdviceInputs::default();
117 let advice2 = AdviceInputs::default();
118
119 assert_eq!(advice1, advice2);
120
121 let advice1 = AdviceInputs::default()
122 .with_advice_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
123 let advice2 = AdviceInputs::default()
124 .with_advice_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
125
126 assert_eq!(advice1, advice2);
127 }
128
129 #[test]
130 fn test_advice_inputs_serialization() {
131 let advice1 = AdviceInputs::default()
132 .with_advice_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
133 let bytes = advice1.to_bytes();
134 let advice2 = AdviceInputs::read_from_bytes(&bytes).unwrap();
135
136 assert_eq!(advice1, advice2);
137 }
138
139 #[test]
140 fn advice_inputs_accept_typed_advice_stack() {
141 let mut stack = AdviceStack::new();
142 stack.append_element(Felt::new_unchecked(1));
143 stack.append_word(
144 [
145 Felt::new_unchecked(2),
146 Felt::new_unchecked(3),
147 Felt::new_unchecked(4),
148 Felt::new_unchecked(5),
149 ]
150 .into(),
151 );
152
153 let advice = AdviceInputs::default().with_advice_stack(stack.clone());
154
155 assert_eq!(advice.advice_stack(), stack);
156 }
157
158 #[test]
159 fn advice_stack_consumes_word_sized_groups_top_first() {
160 let word0: Word = [
161 Felt::new_unchecked(1),
162 Felt::new_unchecked(2),
163 Felt::new_unchecked(3),
164 Felt::new_unchecked(4),
165 ]
166 .into();
167 let word1: Word = [
168 Felt::new_unchecked(5),
169 Felt::new_unchecked(6),
170 Felt::new_unchecked(7),
171 Felt::new_unchecked(8),
172 ]
173 .into();
174 let mut stack = AdviceStack::new();
175
176 stack.append_element(Felt::new_unchecked(0));
177 stack.append_word(word0);
178 stack.append_dword([word1, word0]);
179
180 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(0)));
181 assert_eq!(stack.consume_word(), Some(word0));
182 assert_eq!(stack.consume_dword(), Some([word1, word0]));
183 assert!(stack.is_empty());
184 }
185
186 #[test]
187 fn advice_stack_rejects_partial_dword_without_consuming() {
188 let word: Word = [
189 Felt::new_unchecked(1),
190 Felt::new_unchecked(2),
191 Felt::new_unchecked(3),
192 Felt::new_unchecked(4),
193 ]
194 .into();
195 let mut stack = AdviceStack::new();
196 stack.append_word(word);
197
198 assert_eq!(stack.consume_dword(), None);
199 assert_eq!(stack.consume_word(), Some(word));
200 }
201
202 #[test]
203 fn advice_stack_append_for_adv_push_matches_repeated_consumption() {
204 let values = [Felt::new_unchecked(1), Felt::new_unchecked(2), Felt::new_unchecked(3)];
205 let mut stack = AdviceStack::new();
206 stack.append_for_adv_push(&values);
207
208 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(3)));
209 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(2)));
210 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(1)));
211 assert!(stack.is_empty());
212 }
213
214 #[test]
215 fn advice_stack_append_for_adv_pipe_requires_dword_alignment() {
216 let values: Vec<Felt> = (1..=16).map(Felt::new_unchecked).collect();
217 let mut stack = AdviceStack::new();
218 stack.append_for_adv_pipe(&values);
219
220 assert_eq!(stack.into_elements(), values);
221 }
222
223 #[test]
224 #[should_panic(expected = "append_for_adv_pipe requires slice length to be a multiple of 8")]
225 fn advice_stack_append_for_adv_pipe_panics_on_misalignment() {
226 let values: Vec<Felt> = (1..=7).map(Felt::new_unchecked).collect();
227 let mut stack = AdviceStack::new();
228 stack.append_for_adv_pipe(&values);
229 }
230
231 #[test]
232 fn advice_stack_prepends_new_top_elements() {
233 let mut stack = AdviceStack::from(vec![Felt::new_unchecked(3), Felt::new_unchecked(4)]);
234
235 stack.push_element(Felt::new_unchecked(2));
236 stack.prepend_elements([Felt::new_unchecked(0), Felt::new_unchecked(1)]);
237
238 assert_eq!(
239 stack.into_elements(),
240 vec![
241 Felt::new_unchecked(0),
242 Felt::new_unchecked(1),
243 Felt::new_unchecked(2),
244 Felt::new_unchecked(3),
245 Felt::new_unchecked(4),
246 ]
247 );
248 }
249
250 #[test]
254 fn advice_stack_try_from_values_keeps_top_first_order() {
255 let stack = AdviceStack::try_from_values([1, 2, 3, 4]).unwrap();
256
257 assert_eq!(
258 stack.into_elements(),
259 vec![
260 Felt::new_unchecked(1),
261 Felt::new_unchecked(2),
262 Felt::new_unchecked(3),
263 Felt::new_unchecked(4)
264 ]
265 );
266 }
267}