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 Self {
74 mast_forest: Arc::new((*self.mast_forest).clone().with_advice_map(advice_map)),
75 ..self
76 }
77 }
78}
79
80impl Program {
83 pub fn hash(&self) -> Word {
87 self.mast_forest[self.entrypoint].digest()
88 }
89
90 pub fn entrypoint(&self) -> MastNodeId {
92 self.entrypoint
93 }
94
95 pub fn mast_forest(&self) -> &Arc<MastForest> {
97 &self.mast_forest
98 }
99
100 pub fn kernel(&self) -> &Kernel {
102 &self.kernel
103 }
104
105 #[inline(always)]
110 pub fn get_node_by_id(&self, node_id: MastNodeId) -> Option<&MastNode> {
111 self.mast_forest.get_node_by_id(node_id)
112 }
113
114 #[inline(always)]
116 pub fn find_procedure_root(&self, digest: Word) -> Option<MastNodeId> {
117 self.mast_forest.find_procedure_root(digest)
118 }
119
120 pub fn num_procedures(&self) -> u32 {
122 self.mast_forest.num_procedures()
123 }
124
125 pub fn to_info(&self) -> ProgramInfo {
127 ProgramInfo::new(self.hash(), self.kernel().clone())
128 }
129}
130
131#[cfg(feature = "std")]
134impl Program {
135 pub fn write_to_file<P>(&self, path: P) -> std::io::Result<()>
137 where
138 P: AsRef<std::path::Path>,
139 {
140 let path = path.as_ref();
141 if let Some(dir) = path.parent() {
142 std::fs::create_dir_all(dir)?;
143 }
144
145 std::panic::catch_unwind(|| match std::fs::File::create(path) {
150 Ok(ref mut file) => {
151 self.write_into(file);
152 Ok(())
153 },
154 Err(err) => Err(err),
155 })
156 .map_err(|p| match p.downcast::<std::io::Error>() {
157 Ok(err) => *err,
158 Err(err) => std::panic::resume_unwind(err),
160 })?
161 }
162}
163
164impl Serializable for Program {
165 fn write_into<W: ByteWriter>(&self, target: &mut W) {
166 self.mast_forest.write_into(target);
167 self.kernel.write_into(target);
168 target.write_u32(self.entrypoint.into());
169 }
170}
171
172impl Deserializable for Program {
173 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
174 let mast_forest = Arc::new(source.read()?);
175 let kernel = source.read()?;
176 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
177
178 if !mast_forest.is_procedure_root(entrypoint) {
179 return Err(DeserializationError::InvalidValue(format!(
180 "entrypoint {entrypoint} is not a procedure"
181 )));
182 }
183
184 Ok(Self::with_kernel(mast_forest, entrypoint, kernel))
185 }
186}
187
188impl crate::prettier::PrettyPrint for Program {
192 fn render(&self) -> crate::prettier::Document {
193 use crate::prettier::*;
194 let entrypoint = self.mast_forest[self.entrypoint()].to_pretty_print(&self.mast_forest);
195
196 indent(4, const_text("begin") + nl() + entrypoint.render()) + nl() + const_text("end")
197 }
198}
199
200impl fmt::Display for Program {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 use crate::prettier::PrettyPrint;
203 self.pretty_print(f)
204 }
205}
206
207#[derive(Debug, Clone, Default, PartialEq, Eq)]
219pub struct ProgramInfo {
220 program_hash: Word,
221 kernel: Kernel,
222}
223
224impl ProgramInfo {
225 pub const fn new(program_hash: Word, kernel: Kernel) -> Self {
227 Self { program_hash, kernel }
228 }
229
230 pub const fn program_hash(&self) -> &Word {
232 &self.program_hash
233 }
234
235 pub const fn kernel(&self) -> &Kernel {
237 &self.kernel
238 }
239
240 pub fn kernel_procedures(&self) -> &[Word] {
242 self.kernel.proc_hashes()
243 }
244}
245
246impl From<Program> for ProgramInfo {
247 fn from(program: Program) -> Self {
248 let program_hash = program.hash();
249 let kernel = program.kernel().clone();
250
251 Self { program_hash, kernel }
252 }
253}
254
255impl Serializable for ProgramInfo {
259 fn write_into<W: ByteWriter>(&self, target: &mut W) {
260 self.program_hash.write_into(target);
261 self.kernel.write_into(target);
262 }
263}
264
265impl Deserializable for ProgramInfo {
266 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
267 let program_hash = source.read()?;
268 let kernel = source.read()?;
269 Ok(Self { program_hash, kernel })
270 }
271}
272
273impl ToElements for ProgramInfo {
277 fn to_elements(&self) -> Vec<Felt> {
278 let num_kernel_proc_elements = self.kernel.proc_hashes().len() * WORD_SIZE;
279 let mut result = Vec::with_capacity(2 * WORD_SIZE + num_kernel_proc_elements);
280
281 result.extend_from_slice(self.program_hash.as_elements());
285 result.extend_from_slice(&[Felt::ZERO; 4]);
286
287 for proc_hash in self.kernel.proc_hashes() {
291 let mut proc_hash_elements = proc_hash.as_elements().to_vec();
292 pad_next_mul_8(&mut proc_hash_elements);
293 proc_hash_elements.reverse();
294 result.extend_from_slice(&proc_hash_elements);
295 }
296 result
297 }
298}
299
300fn pad_next_mul_8(input: &mut Vec<Felt>) {
305 let output_len = input.len().next_multiple_of(8);
306 input.resize(output_len, Felt::ZERO);
307}