Skip to main content

miden_core/advice/
stack.rs

1use alloc::{collections::VecDeque, vec::Vec};
2
3use crate::{Felt, Word, field::QuotientMap, program::InputError};
4
5// ADVICE STACK
6// ================================================================================================
7
8/// Advice stack values ordered from top to bottom.
9///
10/// The front of the stack is the next element consumed by `adv_push`.
11#[derive(Clone, Debug, Default, PartialEq, Eq)]
12pub struct AdviceStack {
13    stack: VecDeque<Felt>,
14}
15
16impl AdviceStack {
17    /// Creates a new empty advice stack.
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    /// Creates an advice stack from integer values ordered from top to bottom.
23    ///
24    /// # Errors
25    ///
26    /// Returns an error if any value is not a valid field element.
27    pub fn try_from_values<I>(values: I) -> Result<Self, InputError>
28    where
29        I: IntoIterator<Item = u64>,
30    {
31        values
32            .into_iter()
33            .map(|value| {
34                Felt::from_canonical_checked(value).ok_or(InputError::InvalidStackElement(value))
35            })
36            .collect()
37    }
38
39    /// Returns the number of elements on this advice stack.
40    pub fn len(&self) -> usize {
41        self.stack.len()
42    }
43
44    /// Returns true if this advice stack has no elements.
45    pub fn is_empty(&self) -> bool {
46        self.stack.is_empty()
47    }
48
49    /// Returns an iterator over elements from top to bottom.
50    pub fn iter(&self) -> impl Iterator<Item = &Felt> {
51        self.stack.iter()
52    }
53
54    /// Appends a single element to the bottom of the advice stack.
55    ///
56    /// The appended element is consumed after all existing advice stack elements.
57    pub fn append_element(&mut self, value: Felt) -> &mut Self {
58        self.stack.push_back(value);
59        self
60    }
61
62    /// Appends raw elements to the bottom of the advice stack.
63    ///
64    /// Values are ordered from top to bottom within the appended block.
65    pub fn append_elements<I>(&mut self, values: I) -> &mut Self
66    where
67        I: IntoIterator<Item = Felt>,
68    {
69        self.stack.extend(values);
70        self
71    }
72
73    /// Prepends raw elements ordered from top to bottom.
74    ///
75    /// The first element in `values` becomes the next element consumed by advice operations.
76    pub fn prepend_elements<I>(&mut self, values: I) -> &mut Self
77    where
78        I: IntoIterator<Item = Felt>,
79    {
80        let values: Vec<Felt> = values.into_iter().collect();
81        for value in values.into_iter().rev() {
82            self.stack.push_front(value);
83        }
84        self
85    }
86
87    /// Pushes a single element onto the top of the advice stack.
88    pub fn push_element(&mut self, value: Felt) -> &mut Self {
89        self.stack.push_front(value);
90        self
91    }
92
93    /// Prepends a word to the top of the advice stack.
94    pub fn prepend_word(&mut self, word: Word) -> &mut Self {
95        self.prepend_elements(word.iter().copied())
96    }
97
98    /// Prepends another advice stack to the top of this stack.
99    pub fn prepend_stack(&mut self, stack: AdviceStack) -> &mut Self {
100        self.prepend_elements(stack.into_elements())
101    }
102
103    /// Appends elements for consumption by multiple sequential `adv_push` instructions.
104    ///
105    /// After `repeat.n adv_push end`, the operand stack will have `slice[0]` on top.
106    pub fn append_for_adv_push(&mut self, slice: &[Felt]) -> &mut Self {
107        for elem in slice.iter().rev() {
108            self.stack.push_back(*elem);
109        }
110        self
111    }
112
113    /// Appends a word for consumption by `adv_loadw` or `adv_pushw`.
114    pub fn append_word(&mut self, word: Word) -> &mut Self {
115        self.stack.extend(word.iter().copied());
116        self
117    }
118
119    /// Appends two words for consumption by `adv_pipe`.
120    pub fn append_dword(&mut self, words: [Word; 2]) -> &mut Self {
121        for word in words {
122            self.append_word(word);
123        }
124        self
125    }
126
127    /// Appends elements for sequential consumption by `adv_pipe` operations.
128    ///
129    /// # Panics
130    ///
131    /// Panics if the slice length is not a multiple of 8 (double-word aligned).
132    pub fn append_for_adv_pipe(&mut self, slice: &[Felt]) -> &mut Self {
133        assert!(
134            slice.len().is_multiple_of(8),
135            "append_for_adv_pipe requires slice length to be a multiple of 8, got {}",
136            slice.len()
137        );
138
139        self.stack.extend(slice.iter().copied());
140        self
141    }
142
143    /// Consumes a single element from the top of the advice stack.
144    pub fn consume_element(&mut self) -> Option<Felt> {
145        self.stack.pop_front()
146    }
147
148    /// Consumes a word from the top of the advice stack.
149    pub fn consume_word(&mut self) -> Option<Word> {
150        if self.stack.len() < 4 {
151            return None;
152        }
153
154        Some(Word::new([
155            self.consume_element().expect("checked len"),
156            self.consume_element().expect("checked len"),
157            self.consume_element().expect("checked len"),
158            self.consume_element().expect("checked len"),
159        ]))
160    }
161
162    /// Consumes two words from the top of the advice stack.
163    pub fn consume_dword(&mut self) -> Option<[Word; 2]> {
164        if self.stack.len() < 8 {
165            return None;
166        }
167
168        Some([self.consume_word()?, self.consume_word()?])
169    }
170
171    /// Consumes `self` and returns elements ordered from top to bottom.
172    pub fn into_elements(self) -> Vec<Felt> {
173        self.stack.into_iter().collect()
174    }
175}
176
177impl From<Vec<Felt>> for AdviceStack {
178    fn from(stack: Vec<Felt>) -> Self {
179        Self { stack: stack.into() }
180    }
181}
182
183impl From<VecDeque<Felt>> for AdviceStack {
184    fn from(stack: VecDeque<Felt>) -> Self {
185        Self { stack }
186    }
187}
188
189impl From<AdviceStack> for Vec<Felt> {
190    fn from(stack: AdviceStack) -> Self {
191        stack.into_elements()
192    }
193}
194
195impl FromIterator<Felt> for AdviceStack {
196    fn from_iter<T: IntoIterator<Item = Felt>>(iter: T) -> Self {
197        Self { stack: iter.into_iter().collect() }
198    }
199}