miden_core/program/
mod.rs1use alloc::{sync::Arc, vec::Vec};
2use core::fmt;
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 Felt, WORD_SIZE, Word,
9 advice::AdviceMap,
10 mast::{MastForest, MastNode, MastNodeExt, MastNodeId},
11 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
12 utils::ToElements,
13};
14
15mod kernel;
16pub use kernel::{Kernel, KernelError};
17
18mod stack;
19pub use stack::{InputError, MIN_STACK_DEPTH, OutputError, StackInputs, StackOutputs};
20
21#[derive(Clone, Debug, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31#[cfg_attr(
32 all(feature = "arbitrary", test),
33 miden_test_serde_macros::serde_test(binary_serde(true))
34)]
35pub struct Program {
36 mast_forest: Arc<MastForest>,
37 entrypoint: MastNodeId,
39 kernel: Kernel,
40}
41
42impl Program {
44 pub fn new(mast_forest: Arc<MastForest>, entrypoint: MastNodeId) -> Self {
51 Self::with_kernel(mast_forest, entrypoint, Kernel::default())
52 }
53
54 pub fn with_kernel(
60 mast_forest: Arc<MastForest>,
61 entrypoint: MastNodeId,
62 kernel: Kernel,
63 ) -> Self {
64 assert!(mast_forest.get_node_by_id(entrypoint).is_some(), "invalid entrypoint");
65 assert!(mast_forest.is_procedure_root(entrypoint), "entrypoint not a procedure");
66
67 Self { mast_forest, entrypoint, kernel }
68 }
69
70 pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
73 let mut mast_forest = (*self.mast_forest).clone();
74 mast_forest.advice_map_mut().extend(advice_map);
75 Self {
76 mast_forest: Arc::new(mast_forest),
77 ..self
78 }
79 }
80}
81
82impl Program {
85 pub fn hash(&self) -> Word {
89 self.mast_forest[self.entrypoint].digest()
90 }
91
92 pub fn entrypoint(&self) -> MastNodeId {
94 self.entrypoint
95 }
96
97 pub fn mast_forest(&self) -> &Arc<MastForest> {
99 &self.mast_forest
100 }
101
102 pub fn kernel(&self) -> &Kernel {
104 &self.kernel
105 }
106
107 #[inline(always)]
112 pub fn get_node_by_id(&self, node_id: MastNodeId) -> Option<&MastNode> {
113 self.mast_forest.get_node_by_id(node_id)
114 }
115
116 #[inline(always)]
118 pub fn find_procedure_root(&self, digest: Word) -> Option<MastNodeId> {
119 self.mast_forest.find_procedure_root(digest)
120 }
121
122 pub fn num_procedures(&self) -> u32 {
124 self.mast_forest.num_procedures()
125 }
126
127 pub fn to_info(&self) -> ProgramInfo {
129 ProgramInfo::new(self.hash(), self.kernel().clone())
130 }
131}
132
133#[cfg(feature = "std")]
136impl Program {
137 pub fn write_to_file<P>(&self, path: P) -> std::io::Result<()>
139 where
140 P: AsRef<std::path::Path>,
141 {
142 let path = path.as_ref();
143 if let Some(dir) = path.parent() {
144 std::fs::create_dir_all(dir)?;
145 }
146
147 std::panic::catch_unwind(|| match std::fs::File::create(path) {
152 Ok(ref mut file) => {
153 self.write_into(file);
154 Ok(())
155 },
156 Err(err) => Err(err),
157 })
158 .map_err(|p| {
159 match p.downcast::<std::io::Error>() {
160 Ok(err) => unsafe { core::ptr::read(&*err) },
162 Err(err) => std::panic::resume_unwind(err),
164 }
165 })?
166 }
167}
168
169impl Serializable for Program {
170 fn write_into<W: ByteWriter>(&self, target: &mut W) {
171 self.mast_forest.write_into(target);
172 self.kernel.write_into(target);
173 target.write_u32(self.entrypoint.into());
174 }
175}
176
177impl Deserializable for Program {
178 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
179 let mast_forest = Arc::new(source.read()?);
180 let kernel = source.read()?;
181 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
182
183 if !mast_forest.is_procedure_root(entrypoint) {
184 return Err(DeserializationError::InvalidValue(format!(
185 "entrypoint {entrypoint} is not a procedure"
186 )));
187 }
188
189 Ok(Self::with_kernel(mast_forest, entrypoint, kernel))
190 }
191}
192
193impl crate::prettier::PrettyPrint for Program {
197 fn render(&self) -> crate::prettier::Document {
198 use crate::prettier::*;
199 let entrypoint = self.mast_forest[self.entrypoint()].to_pretty_print(&self.mast_forest);
200
201 indent(4, const_text("begin") + nl() + entrypoint.render()) + nl() + const_text("end")
202 }
203}
204
205impl fmt::Display for Program {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 use crate::prettier::PrettyPrint;
208 self.pretty_print(f)
209 }
210}
211
212#[derive(Debug, Clone, Default, PartialEq, Eq)]
224pub struct ProgramInfo {
225 program_hash: Word,
226 kernel: Kernel,
227}
228
229impl ProgramInfo {
230 pub const fn new(program_hash: Word, kernel: Kernel) -> Self {
232 Self { program_hash, kernel }
233 }
234
235 pub const fn program_hash(&self) -> &Word {
237 &self.program_hash
238 }
239
240 pub const fn kernel(&self) -> &Kernel {
242 &self.kernel
243 }
244
245 pub fn kernel_procedures(&self) -> &[Word] {
247 self.kernel.proc_hashes()
248 }
249}
250
251impl From<Program> for ProgramInfo {
252 fn from(program: Program) -> Self {
253 let program_hash = program.hash();
254 let kernel = program.kernel().clone();
255
256 Self { program_hash, kernel }
257 }
258}
259
260impl Serializable for ProgramInfo {
264 fn write_into<W: ByteWriter>(&self, target: &mut W) {
265 self.program_hash.write_into(target);
266 self.kernel.write_into(target);
267 }
268}
269
270impl Deserializable for ProgramInfo {
271 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
272 let program_hash = source.read()?;
273 let kernel = source.read()?;
274 Ok(Self { program_hash, kernel })
275 }
276}
277
278impl ToElements for ProgramInfo {
282 fn to_elements(&self) -> Vec<Felt> {
283 let num_kernel_proc_elements = self.kernel.proc_hashes().len() * WORD_SIZE;
284 let mut result = Vec::with_capacity(2 * WORD_SIZE + num_kernel_proc_elements);
285
286 result.extend_from_slice(self.program_hash.as_elements());
290 result.extend_from_slice(&[Felt::ZERO; 4]);
291
292 for proc_hash in self.kernel.proc_hashes() {
296 let mut proc_hash_elements = proc_hash.as_elements().to_vec();
297 pad_next_mul_8(&mut proc_hash_elements);
298 proc_hash_elements.reverse();
299 result.extend_from_slice(&proc_hash_elements);
300 }
301 result
302 }
303}
304
305fn pad_next_mul_8(input: &mut Vec<Felt>) {
310 let output_len = input.len().next_multiple_of(8);
311 input.resize(output_len, Felt::ZERO);
312}