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| match p.downcast::<std::io::Error>() {
159 Ok(err) => *err,
160 Err(err) => std::panic::resume_unwind(err),
162 })?
163 }
164}
165
166impl Serializable for Program {
167 fn write_into<W: ByteWriter>(&self, target: &mut W) {
168 self.mast_forest.write_into(target);
169 self.kernel.write_into(target);
170 target.write_u32(self.entrypoint.into());
171 }
172}
173
174impl Deserializable for Program {
175 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
176 let mast_forest = Arc::new(source.read()?);
177 let kernel = source.read()?;
178 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
179
180 if !mast_forest.is_procedure_root(entrypoint) {
181 return Err(DeserializationError::InvalidValue(format!(
182 "entrypoint {entrypoint} is not a procedure"
183 )));
184 }
185
186 Ok(Self::with_kernel(mast_forest, entrypoint, kernel))
187 }
188}
189
190impl crate::prettier::PrettyPrint for Program {
194 fn render(&self) -> crate::prettier::Document {
195 use crate::prettier::*;
196 let entrypoint = self.mast_forest[self.entrypoint()].to_pretty_print(&self.mast_forest);
197
198 indent(4, const_text("begin") + nl() + entrypoint.render()) + nl() + const_text("end")
199 }
200}
201
202impl fmt::Display for Program {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 use crate::prettier::PrettyPrint;
205 self.pretty_print(f)
206 }
207}
208
209#[derive(Debug, Clone, Default, PartialEq, Eq)]
221pub struct ProgramInfo {
222 program_hash: Word,
223 kernel: Kernel,
224}
225
226impl ProgramInfo {
227 pub const fn new(program_hash: Word, kernel: Kernel) -> Self {
229 Self { program_hash, kernel }
230 }
231
232 pub const fn program_hash(&self) -> &Word {
234 &self.program_hash
235 }
236
237 pub const fn kernel(&self) -> &Kernel {
239 &self.kernel
240 }
241
242 pub fn kernel_procedures(&self) -> &[Word] {
244 self.kernel.proc_hashes()
245 }
246}
247
248impl From<Program> for ProgramInfo {
249 fn from(program: Program) -> Self {
250 let program_hash = program.hash();
251 let kernel = program.kernel().clone();
252
253 Self { program_hash, kernel }
254 }
255}
256
257impl Serializable for ProgramInfo {
261 fn write_into<W: ByteWriter>(&self, target: &mut W) {
262 self.program_hash.write_into(target);
263 self.kernel.write_into(target);
264 }
265}
266
267impl Deserializable for ProgramInfo {
268 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
269 let program_hash = source.read()?;
270 let kernel = source.read()?;
271 Ok(Self { program_hash, kernel })
272 }
273}
274
275impl ToElements for ProgramInfo {
279 fn to_elements(&self) -> Vec<Felt> {
280 let num_kernel_proc_elements = self.kernel.proc_hashes().len() * WORD_SIZE;
281 let mut result = Vec::with_capacity(2 * WORD_SIZE + num_kernel_proc_elements);
282
283 result.extend_from_slice(self.program_hash.as_elements());
287 result.extend_from_slice(&[Felt::ZERO; 4]);
288
289 for proc_hash in self.kernel.proc_hashes() {
293 let mut proc_hash_elements = proc_hash.as_elements().to_vec();
294 pad_next_mul_8(&mut proc_hash_elements);
295 proc_hash_elements.reverse();
296 result.extend_from_slice(&proc_hash_elements);
297 }
298 result
299 }
300}
301
302fn pad_next_mul_8(input: &mut Vec<Felt>) {
307 let output_len = input.len().next_multiple_of(8);
308 input.resize(output_len, Felt::ZERO);
309}