miden_core/program/
mod.rs1use alloc::{sync::Arc, vec::Vec};
2use core::fmt;
3
4use crate::{
5 Felt, WORD_SIZE, Word,
6 advice::AdviceMap,
7 mast::{MastForest, MastNode, MastNodeExt, MastNodeId},
8 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
9 utils::ToElements,
10};
11
12mod claim;
13pub use claim::{CLAIM_DOMAIN_TAG, ExecutionClaim, NUM_CLAIM_ELEMENTS, claim_commitment};
14
15pub mod domain;
16
17mod request;
18pub use request::{PROOF_REQUEST_DOMAIN_TAG, proof_request_key};
19
20mod kernel;
21pub use kernel::{KERNEL_DOMAIN_TAG, KernelDescriptor, KernelError};
22
23mod stack;
24pub use stack::{InputError, MIN_STACK_DEPTH, OutputError, StackInputs, StackOutputs};
25
26#[derive(Clone, Debug, PartialEq, Eq)]
35#[cfg_attr(
36 all(feature = "arbitrary", test),
37 miden_test_serialization_macros::serialization_test
38)]
39pub struct Program {
40 mast_forest: Arc<MastForest>,
41 entrypoint: MastNodeId,
43 kernel: KernelDescriptor,
44}
45
46impl Program {
48 pub fn new(mast_forest: Arc<MastForest>, entrypoint: MastNodeId) -> Self {
55 Self::with_kernel(mast_forest, entrypoint, KernelDescriptor::default())
56 }
57
58 pub fn with_kernel(
64 mast_forest: Arc<MastForest>,
65 entrypoint: MastNodeId,
66 kernel: KernelDescriptor,
67 ) -> Self {
68 assert!(mast_forest.get_node_by_id(entrypoint).is_some(), "invalid entrypoint");
69 assert!(mast_forest.is_procedure_root(entrypoint), "entrypoint not a procedure");
70
71 Self { mast_forest, entrypoint, kernel }
72 }
73
74 pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
77 Self {
78 mast_forest: Arc::new((*self.mast_forest).clone().with_advice_map(advice_map)),
79 ..self
80 }
81 }
82}
83
84impl Program {
87 pub fn hash(&self) -> Word {
91 self.mast_forest[self.entrypoint].digest()
92 }
93
94 pub fn entrypoint(&self) -> MastNodeId {
96 self.entrypoint
97 }
98
99 pub fn mast_forest(&self) -> &Arc<MastForest> {
101 &self.mast_forest
102 }
103
104 pub fn kernel(&self) -> &KernelDescriptor {
106 &self.kernel
107 }
108
109 #[inline(always)]
114 pub fn get_node_by_id(&self, node_id: MastNodeId) -> Option<&MastNode> {
115 self.mast_forest.get_node_by_id(node_id)
116 }
117
118 #[inline(always)]
120 pub fn find_procedure_root(&self, digest: Word) -> Option<MastNodeId> {
121 self.mast_forest.find_procedure_root(digest)
122 }
123
124 pub fn num_procedures(&self) -> u32 {
126 self.mast_forest.num_procedures()
127 }
128
129 pub fn to_info(&self) -> ProgramInfo {
131 ProgramInfo::new(self.hash(), self.kernel().clone())
132 }
133}
134
135#[cfg(feature = "std")]
138impl Program {
139 pub fn write_to_file<P>(&self, path: P) -> std::io::Result<()>
141 where
142 P: AsRef<std::path::Path>,
143 {
144 let path = path.as_ref();
145 if let Some(dir) = path.parent() {
146 std::fs::create_dir_all(dir)?;
147 }
148
149 std::panic::catch_unwind(|| match std::fs::File::create(path) {
154 Ok(ref mut file) => {
155 self.write_into(file);
156 Ok(())
157 },
158 Err(err) => Err(err),
159 })
160 .map_err(|p| match p.downcast::<std::io::Error>() {
161 Ok(err) => *err,
162 Err(err) => std::panic::resume_unwind(err),
164 })?
165 }
166}
167
168impl Serializable for Program {
169 fn write_into<W: ByteWriter>(&self, target: &mut W) {
170 self.mast_forest.write_into(target);
171 self.kernel.write_into(target);
172 target.write_u32(self.entrypoint.into());
173 }
174}
175
176impl Deserializable for Program {
177 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
178 let mast_forest = Arc::new(source.read()?);
179 let kernel = source.read()?;
180 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
181
182 if !mast_forest.is_procedure_root(entrypoint) {
183 return Err(DeserializationError::InvalidValue(format!(
184 "entrypoint {entrypoint} is not a procedure"
185 )));
186 }
187
188 Ok(Self::with_kernel(mast_forest, entrypoint, kernel))
189 }
190}
191
192impl crate::prettier::PrettyPrint for Program {
196 fn render(&self) -> crate::prettier::Document {
197 use crate::prettier::*;
198 let entrypoint = self.mast_forest[self.entrypoint()].to_pretty_print(&self.mast_forest);
199
200 indent(4, const_text("begin") + nl() + entrypoint.render()) + nl() + const_text("end")
201 }
202}
203
204impl fmt::Display for Program {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 use crate::prettier::PrettyPrint;
207 self.pretty_print(f)
208 }
209}
210
211#[derive(Debug, Clone, Default, PartialEq, Eq)]
223pub struct ProgramInfo {
224 program_hash: Word,
225 kernel: KernelDescriptor,
226}
227
228impl ProgramInfo {
229 pub const fn new(program_hash: Word, kernel: KernelDescriptor) -> Self {
231 Self { program_hash, kernel }
232 }
233
234 pub const fn program_hash(&self) -> &Word {
236 &self.program_hash
237 }
238
239 pub const fn kernel(&self) -> &KernelDescriptor {
241 &self.kernel
242 }
243
244 pub fn kernel_procedures(&self) -> &[Word] {
246 self.kernel.proc_hashes()
247 }
248
249 pub fn kernel_commitment(&self) -> Word {
254 self.kernel.commitment()
255 }
256
257 pub fn into_parts(self) -> (Word, KernelDescriptor) {
259 (self.program_hash, self.kernel)
260 }
261}
262
263impl From<Program> for ProgramInfo {
264 fn from(program: Program) -> Self {
265 let program_hash = program.hash();
266 let kernel = program.kernel().clone();
267
268 Self { program_hash, kernel }
269 }
270}
271
272impl Serializable for ProgramInfo {
276 fn write_into<W: ByteWriter>(&self, target: &mut W) {
277 self.program_hash.write_into(target);
278 self.kernel.write_into(target);
279 }
280}
281
282impl Deserializable for ProgramInfo {
283 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
284 let program_hash = source.read()?;
285 let kernel = source.read()?;
286 Ok(Self { program_hash, kernel })
287 }
288}
289
290impl ToElements for ProgramInfo {
294 fn to_elements(&self) -> Vec<Felt> {
295 let num_kernel_proc_elements = self.kernel.proc_hashes().len() * WORD_SIZE;
296 let mut result = Vec::with_capacity(2 * WORD_SIZE + num_kernel_proc_elements);
297
298 result.extend_from_slice(self.program_hash.as_elements());
302 result.extend_from_slice(&[Felt::ZERO; 4]);
303
304 for proc_hash in self.kernel.proc_hashes() {
308 let mut proc_hash_elements = proc_hash.as_elements().to_vec();
309 pad_next_mul_8(&mut proc_hash_elements);
310 proc_hash_elements.reverse();
311 result.extend_from_slice(&proc_hash_elements);
312 }
313 result
314 }
315}
316
317fn pad_next_mul_8(input: &mut Vec<Felt>) {
322 let output_len = input.len().next_multiple_of(8);
323 input.resize(output_len, Felt::ZERO);
324}