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 claim;
16pub use claim::{
17 CLAIM_DOMAIN_TAG, ExecutionClaim, NUM_CLAIM_ELEMENTS, REQUEST_DOMAIN_TAG, claim_commitment,
18 request_key,
19};
20
21pub mod domain;
22
23mod kernel;
24pub use kernel::{KERNEL_DOMAIN_TAG, KernelDescriptor, KernelError};
25
26mod stack;
27pub use stack::{InputError, MIN_STACK_DEPTH, OutputError, StackInputs, StackOutputs};
28
29#[derive(Clone, Debug, PartialEq, Eq)]
38#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
39#[cfg_attr(
40 all(feature = "arbitrary", test),
41 miden_test_serde_macros::serde_test(binary_serde(true))
42)]
43pub struct Program {
44 mast_forest: Arc<MastForest>,
45 entrypoint: MastNodeId,
47 kernel: KernelDescriptor,
48}
49
50impl Program {
52 pub fn new(mast_forest: Arc<MastForest>, entrypoint: MastNodeId) -> Self {
59 Self::with_kernel(mast_forest, entrypoint, KernelDescriptor::default())
60 }
61
62 pub fn with_kernel(
68 mast_forest: Arc<MastForest>,
69 entrypoint: MastNodeId,
70 kernel: KernelDescriptor,
71 ) -> Self {
72 assert!(mast_forest.get_node_by_id(entrypoint).is_some(), "invalid entrypoint");
73 assert!(mast_forest.is_procedure_root(entrypoint), "entrypoint not a procedure");
74
75 Self { mast_forest, entrypoint, kernel }
76 }
77
78 pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
81 Self {
82 mast_forest: Arc::new((*self.mast_forest).clone().with_advice_map(advice_map)),
83 ..self
84 }
85 }
86}
87
88impl Program {
91 pub fn hash(&self) -> Word {
95 self.mast_forest[self.entrypoint].digest()
96 }
97
98 pub fn entrypoint(&self) -> MastNodeId {
100 self.entrypoint
101 }
102
103 pub fn mast_forest(&self) -> &Arc<MastForest> {
105 &self.mast_forest
106 }
107
108 pub fn kernel(&self) -> &KernelDescriptor {
110 &self.kernel
111 }
112
113 #[inline(always)]
118 pub fn get_node_by_id(&self, node_id: MastNodeId) -> Option<&MastNode> {
119 self.mast_forest.get_node_by_id(node_id)
120 }
121
122 #[inline(always)]
124 pub fn find_procedure_root(&self, digest: Word) -> Option<MastNodeId> {
125 self.mast_forest.find_procedure_root(digest)
126 }
127
128 pub fn num_procedures(&self) -> u32 {
130 self.mast_forest.num_procedures()
131 }
132
133 pub fn to_info(&self) -> ProgramInfo {
135 ProgramInfo::new(self.hash(), self.kernel().clone())
136 }
137}
138
139#[cfg(feature = "std")]
142impl Program {
143 pub fn write_to_file<P>(&self, path: P) -> std::io::Result<()>
145 where
146 P: AsRef<std::path::Path>,
147 {
148 let path = path.as_ref();
149 if let Some(dir) = path.parent() {
150 std::fs::create_dir_all(dir)?;
151 }
152
153 std::panic::catch_unwind(|| match std::fs::File::create(path) {
158 Ok(ref mut file) => {
159 self.write_into(file);
160 Ok(())
161 },
162 Err(err) => Err(err),
163 })
164 .map_err(|p| match p.downcast::<std::io::Error>() {
165 Ok(err) => *err,
166 Err(err) => std::panic::resume_unwind(err),
168 })?
169 }
170}
171
172impl Serializable for Program {
173 fn write_into<W: ByteWriter>(&self, target: &mut W) {
174 self.mast_forest.write_into(target);
175 self.kernel.write_into(target);
176 target.write_u32(self.entrypoint.into());
177 }
178}
179
180impl Deserializable for Program {
181 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
182 let mast_forest = Arc::new(source.read()?);
183 let kernel = source.read()?;
184 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
185
186 if !mast_forest.is_procedure_root(entrypoint) {
187 return Err(DeserializationError::InvalidValue(format!(
188 "entrypoint {entrypoint} is not a procedure"
189 )));
190 }
191
192 Ok(Self::with_kernel(mast_forest, entrypoint, kernel))
193 }
194}
195
196impl crate::prettier::PrettyPrint for Program {
200 fn render(&self) -> crate::prettier::Document {
201 use crate::prettier::*;
202 let entrypoint = self.mast_forest[self.entrypoint()].to_pretty_print(&self.mast_forest);
203
204 indent(4, const_text("begin") + nl() + entrypoint.render()) + nl() + const_text("end")
205 }
206}
207
208impl fmt::Display for Program {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 use crate::prettier::PrettyPrint;
211 self.pretty_print(f)
212 }
213}
214
215#[derive(Debug, Clone, Default, PartialEq, Eq)]
227pub struct ProgramInfo {
228 program_hash: Word,
229 kernel: KernelDescriptor,
230}
231
232impl ProgramInfo {
233 pub const fn new(program_hash: Word, kernel: KernelDescriptor) -> Self {
235 Self { program_hash, kernel }
236 }
237
238 pub const fn program_hash(&self) -> &Word {
240 &self.program_hash
241 }
242
243 pub const fn kernel(&self) -> &KernelDescriptor {
245 &self.kernel
246 }
247
248 pub fn kernel_procedures(&self) -> &[Word] {
250 self.kernel.proc_hashes()
251 }
252
253 pub fn kernel_commitment(&self) -> Word {
258 self.kernel.commitment()
259 }
260
261 pub fn into_parts(self) -> (Word, KernelDescriptor) {
263 (self.program_hash, self.kernel)
264 }
265}
266
267impl From<Program> for ProgramInfo {
268 fn from(program: Program) -> Self {
269 let program_hash = program.hash();
270 let kernel = program.kernel().clone();
271
272 Self { program_hash, kernel }
273 }
274}
275
276impl Serializable for ProgramInfo {
280 fn write_into<W: ByteWriter>(&self, target: &mut W) {
281 self.program_hash.write_into(target);
282 self.kernel.write_into(target);
283 }
284}
285
286impl Deserializable for ProgramInfo {
287 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
288 let program_hash = source.read()?;
289 let kernel = source.read()?;
290 Ok(Self { program_hash, kernel })
291 }
292}
293
294impl ToElements for ProgramInfo {
298 fn to_elements(&self) -> Vec<Felt> {
299 let num_kernel_proc_elements = self.kernel.proc_hashes().len() * WORD_SIZE;
300 let mut result = Vec::with_capacity(2 * WORD_SIZE + num_kernel_proc_elements);
301
302 result.extend_from_slice(self.program_hash.as_elements());
306 result.extend_from_slice(&[Felt::ZERO; 4]);
307
308 for proc_hash in self.kernel.proc_hashes() {
312 let mut proc_hash_elements = proc_hash.as_elements().to_vec();
313 pad_next_mul_8(&mut proc_hash_elements);
314 proc_hash_elements.reverse();
315 result.extend_from_slice(&proc_hash_elements);
316 }
317 result
318 }
319}
320
321fn pad_next_mul_8(input: &mut Vec<Felt>) {
326 let output_len = input.len().next_multiple_of(8);
327 input.resize(output_len, Felt::ZERO);
328}