miden_core/mast/serialization/
mod.rs

1//! The serialization format of MastForest is as follows:
2//!
3//! (Metadata)
4//! - MAGIC
5//! - VERSION
6//!
7//! (sections metadata)
8//! - nodes length (`usize`)
9//! - decorator data section offset (`usize`) (not implemented, see issue #1580)
10//! - decorators length (`usize`)
11//!
12//! (procedure roots section)
13//! - procedure roots (`Vec<MastNodeId>`)
14//!
15//! (basic block data section)
16//! - basic block data
17//!
18//! (node info section)
19//! - MAST node infos (`Vec<MastNodeInfo>`)
20//!
21//! (advice map section)
22//! - Advice map (AdviceMap)
23//!
24//! (error_codes map section)
25//! - Error codes map (BTreeMap<u64, String>)
26//!
27//! (decorator data section)
28//! - Decorator data
29//! - String table
30//!
31//! (decorator info section)
32//! - decorator infos (`Vec<DecoratorInfo>`)
33//!
34//! (basic block decorator lists section)
35//! - basic block decorator lists (`Vec<(MastNodeId, Vec<(usize, DecoratorId)>)>`)
36//!
37//! (before enter and after exit decorators section)
38//! - before enter decorators (`Vec<(MastNodeId, Vec<DecoratorId>)>`)
39//! - after exit decorators (`Vec<(MastNodeId, Vec<DecoratorId>)>`)
40
41use alloc::{
42    collections::BTreeMap,
43    string::{String, ToString},
44    sync::Arc,
45    vec::Vec,
46};
47
48use decorator::{DecoratorDataBuilder, DecoratorInfo};
49use string_table::StringTable;
50
51use super::{DecoratedOpLink, DecoratorId, MastForest, MastNode, MastNodeId};
52use crate::{
53    AdviceMap,
54    mast::{MastForestContributor, MastNodeBuilder},
55    utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
56};
57
58mod decorator;
59
60mod info;
61use info::MastNodeInfo;
62
63mod basic_blocks;
64use basic_blocks::{BasicBlockDataBuilder, BasicBlockDataDecoder};
65
66use crate::DecoratorList;
67
68mod string_table;
69
70#[cfg(test)]
71mod tests;
72
73// TYPE ALIASES
74// ================================================================================================
75
76/// Specifies an offset into the `node_data` section of an encoded [`MastForest`].
77type NodeDataOffset = u32;
78
79/// Specifies an offset into the `decorator_data` section of an encoded [`MastForest`].
80type DecoratorDataOffset = u32;
81
82/// Specifies an offset into the `strings_data` section of an encoded [`MastForest`].
83type StringDataOffset = usize;
84
85/// Specifies an offset into the strings table of an encoded [`MastForest`].
86type StringIndex = usize;
87
88// CONSTANTS
89// ================================================================================================
90
91/// Magic string for detecting that a file is binary-encoded MAST.
92const MAGIC: &[u8; 5] = b"MAST\0";
93
94/// The format version.
95///
96/// If future modifications are made to this format, the version should be incremented by 1. A
97/// version of `[255, 255, 255]` is reserved for future extensions that require extending the
98/// version field itself, but should be considered invalid for now.
99const VERSION: [u8; 3] = [0, 0, 0];
100
101// MAST FOREST SERIALIZATION/DESERIALIZATION
102// ================================================================================================
103
104impl Serializable for MastForest {
105    fn write_into<W: ByteWriter>(&self, target: &mut W) {
106        let mut basic_block_data_builder = BasicBlockDataBuilder::new();
107
108        // Set up "before enter" and "after exit" decorators by `MastNodeId`
109        let mut before_enter_decorators: Vec<(usize, Vec<DecoratorId>)> = Vec::new();
110        let mut after_exit_decorators: Vec<(usize, Vec<DecoratorId>)> = Vec::new();
111
112        let mut basic_block_decorators: Vec<(usize, Vec<DecoratedOpLink>)> = Vec::new();
113
114        // magic & version
115        target.write_bytes(MAGIC);
116        target.write_bytes(&VERSION);
117
118        // decorator & node counts
119        target.write_usize(self.nodes.len());
120        target.write_usize(self.debug_info.num_decorators());
121
122        // roots
123        let roots: Vec<u32> = self.roots.iter().copied().map(u32::from).collect();
124        roots.write_into(target);
125
126        // Prepare MAST node infos, but don't store them yet. We store them at the end to make
127        // deserialization more efficient.
128        let mast_node_infos: Vec<MastNodeInfo> = self
129            .nodes
130            .iter()
131            .enumerate()
132            .map(|(mast_node_id, mast_node)| {
133                let node_id = MastNodeId::new_unchecked(mast_node_id as u32);
134
135                // Use centralized NodeToDecoratorIds for node-level decorators
136                let before_decorators = self.before_enter_decorators(node_id);
137                if !before_decorators.is_empty() {
138                    before_enter_decorators.push((mast_node_id, before_decorators.to_vec()));
139                }
140
141                let after_decorators = self.after_exit_decorators(node_id);
142                if !after_decorators.is_empty() {
143                    after_exit_decorators.push((mast_node_id, after_decorators.to_vec()));
144                }
145
146                let ops_offset = if let MastNode::Block(basic_block) = mast_node {
147                    let ops_offset = basic_block_data_builder.encode_basic_block(basic_block);
148
149                    basic_block_decorators
150                        .push((mast_node_id, basic_block.raw_op_indexed_decorators(self)));
151
152                    ops_offset
153                } else {
154                    0
155                };
156
157                MastNodeInfo::new(mast_node, ops_offset)
158            })
159            .collect();
160
161        let basic_block_data = basic_block_data_builder.finalize();
162        basic_block_data.write_into(target);
163
164        // Write node infos
165        for mast_node_info in mast_node_infos {
166            mast_node_info.write_into(target);
167        }
168
169        self.advice_map.write_into(target);
170        let error_codes: BTreeMap<u64, String> =
171            self.debug_info.error_codes().map(|(k, v)| (*k, v.to_string())).collect();
172        error_codes.write_into(target);
173
174        // write all decorator data below
175
176        let mut decorator_data_builder = DecoratorDataBuilder::new();
177        for decorator in self.debug_info.decorators() {
178            decorator_data_builder.add_decorator(decorator)
179        }
180
181        let (decorator_data, decorator_infos, string_table) = decorator_data_builder.finalize();
182
183        // decorator data buffers
184        decorator_data.write_into(target);
185        string_table.write_into(target);
186
187        // Write decorator infos
188        for decorator_info in decorator_infos {
189            decorator_info.write_into(target);
190        }
191
192        basic_block_decorators.write_into(target);
193
194        // Write "before enter" and "after exit" decorators
195        before_enter_decorators.write_into(target);
196        after_exit_decorators.write_into(target);
197    }
198}
199
200impl Deserializable for MastForest {
201    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
202        read_and_validate_magic(source)?;
203        read_and_validate_version(source)?;
204
205        // Reading sections metadata
206        let node_count = source.read_usize()?;
207        let decorator_count = source.read_usize()?;
208
209        // Reading procedure roots
210        let roots: Vec<u32> = Deserializable::read_from(source)?;
211
212        // Reading nodes
213        let basic_block_data: Vec<u8> = Deserializable::read_from(source)?;
214        let mast_node_infos: Vec<MastNodeInfo> = node_infos_iter(source, node_count)
215            .collect::<Result<Vec<MastNodeInfo>, DeserializationError>>()?;
216
217        let advice_map = AdviceMap::read_from(source)?;
218
219        let error_codes: BTreeMap<u64, String> = Deserializable::read_from(source)?;
220        let error_codes: BTreeMap<u64, Arc<str>> =
221            error_codes.into_iter().map(|(k, v)| (k, Arc::from(v))).collect();
222
223        // Reading Decorators
224        let decorator_data: Vec<u8> = Deserializable::read_from(source)?;
225        let string_table: StringTable = Deserializable::read_from(source)?;
226        let decorator_infos = decorator_infos_iter(source, decorator_count);
227
228        // Constructing MastForest
229        let mut mast_forest = {
230            let mut mast_forest = MastForest::new();
231
232            for decorator_info in decorator_infos {
233                let decorator_info = decorator_info?;
234                let decorator =
235                    decorator_info.try_into_decorator(&string_table, &decorator_data)?;
236
237                mast_forest.add_decorator(decorator).map_err(|e| {
238                    DeserializationError::InvalidValue(format!(
239                        "failed to add decorator to MAST forest while deserializing: {e}",
240                    ))
241                })?;
242            }
243
244            // nodes
245            let basic_block_data_decoder = BasicBlockDataDecoder::new(&basic_block_data);
246            let mut mast_builders = mast_node_infos
247                .into_iter()
248                .map(|node_info| {
249                    node_info.try_into_mast_node_builder(node_count, &basic_block_data_decoder)
250                })
251                .collect::<Result<Vec<_>, _>>()?;
252
253            let basic_block_decorators: Vec<(usize, DecoratorList)> =
254                read_block_decorators(source, mast_forest.debug_info.num_decorators())?;
255            for (node_id, decorator_list) in basic_block_decorators {
256                match &mut mast_builders[node_id] {
257                    MastNodeBuilder::BasicBlock(basic_block) => {
258                        basic_block.set_decorators(decorator_list);
259                    },
260                    other => {
261                        return Err(DeserializationError::InvalidValue(format!(
262                            "expected mast node with id {node_id} to be a basic block, found {other:?}"
263                        )));
264                    },
265                }
266            }
267
268            // read "before enter" and "after exit" decorators, and update the corresponding nodes
269            let before_enter_decorators: Vec<(usize, Vec<DecoratorId>)> =
270                read_before_after_decorators(source, mast_forest.debug_info.num_decorators())?;
271            for (node_id, decorator_ids) in before_enter_decorators {
272                mast_builders[node_id].append_before_enter(decorator_ids);
273            }
274
275            let after_exit_decorators: Vec<(usize, Vec<DecoratorId>)> =
276                read_before_after_decorators(source, mast_forest.debug_info.num_decorators())?;
277            for (node_id, decorator_ids) in after_exit_decorators {
278                mast_builders[node_id].append_after_exit(decorator_ids);
279            }
280
281            for mast_node_builder in mast_builders {
282                mast_node_builder.add_to_forest_relaxed(&mut mast_forest).map_err(|e| {
283                    DeserializationError::InvalidValue(format!(
284                        "failed to add node to MAST forest while deserializing: {e}",
285                    ))
286                })?;
287            }
288
289            // roots
290            for root in roots {
291                // make sure the root is valid in the context of the MAST forest
292                let root = MastNodeId::from_u32_safe(root, &mast_forest)?;
293                mast_forest.make_root(root);
294            }
295
296            mast_forest.advice_map = advice_map;
297
298            mast_forest
299        };
300
301        mast_forest.debug_info.clear_error_codes();
302        mast_forest
303            .debug_info
304            .extend_error_codes(error_codes.iter().map(|(k, v)| (*k, v.clone())));
305
306        Ok(mast_forest)
307    }
308}
309
310fn read_and_validate_magic<R: ByteReader>(source: &mut R) -> Result<[u8; 5], DeserializationError> {
311    let magic: [u8; 5] = source.read_array()?;
312    if magic != *MAGIC {
313        return Err(DeserializationError::InvalidValue(format!(
314            "Invalid magic bytes. Expected '{:?}', got '{:?}'",
315            *MAGIC, magic
316        )));
317    }
318    Ok(magic)
319}
320
321fn read_and_validate_version<R: ByteReader>(
322    source: &mut R,
323) -> Result<[u8; 3], DeserializationError> {
324    let version: [u8; 3] = source.read_array()?;
325    if version != VERSION {
326        return Err(DeserializationError::InvalidValue(format!(
327            "Unsupported version. Got '{version:?}', but only '{VERSION:?}' is supported",
328        )));
329    }
330    Ok(version)
331}
332
333fn read_block_decorators<R: ByteReader>(
334    source: &mut R,
335    decorator_count: usize,
336) -> Result<Vec<(usize, DecoratorList)>, DeserializationError> {
337    let vec_len: usize = source.read()?;
338    let mut out_vec: Vec<_> = Vec::with_capacity(vec_len);
339
340    for _ in 0..vec_len {
341        let node_id: usize = source.read()?;
342
343        let decorator_vec_len: usize = source.read()?;
344        let mut inner_vec: Vec<DecoratedOpLink> = Vec::with_capacity(decorator_vec_len);
345        for _ in 0..decorator_vec_len {
346            let op_id: usize = source.read()?;
347            let decorator_id = DecoratorId::from_u32_bounded(source.read()?, decorator_count)?;
348            inner_vec.push((op_id, decorator_id));
349        }
350
351        out_vec.push((node_id, inner_vec));
352    }
353
354    Ok(out_vec)
355}
356
357fn decorator_infos_iter<'a, R>(
358    source: &'a mut R,
359    decorator_count: usize,
360) -> impl Iterator<Item = Result<DecoratorInfo, DeserializationError>> + 'a
361where
362    R: ByteReader + 'a,
363{
364    let mut remaining = decorator_count;
365    core::iter::from_fn(move || {
366        if remaining == 0 {
367            return None;
368        }
369        remaining -= 1;
370        Some(DecoratorInfo::read_from(source))
371    })
372}
373
374fn node_infos_iter<'a, R>(
375    source: &'a mut R,
376    node_count: usize,
377) -> impl Iterator<Item = Result<MastNodeInfo, DeserializationError>> + 'a
378where
379    R: ByteReader + 'a,
380{
381    let mut remaining = node_count;
382    core::iter::from_fn(move || {
383        if remaining == 0 {
384            return None;
385        }
386        remaining -= 1;
387        Some(MastNodeInfo::read_from(source))
388    })
389}
390
391/// Reads the `before_enter_decorators` and `after_exit_decorators` of the serialized `MastForest`
392/// format.
393///
394/// Note that we need this custom format because we cannot implement `Deserializable` for
395/// `DecoratorId` (in favor of using [`DecoratorId::from_u32_bounded`]).
396fn read_before_after_decorators<R: ByteReader>(
397    source: &mut R,
398    decorator_count: usize,
399) -> Result<Vec<(usize, Vec<DecoratorId>)>, DeserializationError> {
400    let vec_len: usize = source.read()?;
401    let mut out_vec: Vec<_> = Vec::with_capacity(vec_len);
402
403    for _ in 0..vec_len {
404        let node_id: usize = source.read()?;
405
406        let inner_vec_len: usize = source.read()?;
407        let mut inner_vec: Vec<DecoratorId> = Vec::with_capacity(inner_vec_len);
408        for _ in 0..inner_vec_len {
409            let decorator_id = DecoratorId::from_u32_bounded(source.read()?, decorator_count)?;
410            inner_vec.push(decorator_id);
411        }
412
413        out_vec.push((node_id, inner_vec));
414    }
415
416    Ok(out_vec)
417}