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::node::MastNodeExt,
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.decorators.len());
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                if !mast_node.before_enter().is_empty() {
134                    before_enter_decorators.push((mast_node_id, mast_node.before_enter().to_vec()));
135                }
136                if !mast_node.after_exit().is_empty() {
137                    after_exit_decorators.push((mast_node_id, mast_node.after_exit().to_vec()));
138                }
139
140                let ops_offset = if let MastNode::Block(basic_block) = mast_node {
141                    let ops_offset = basic_block_data_builder.encode_basic_block(basic_block);
142
143                    basic_block_decorators.push((
144                        mast_node_id,
145                        basic_block.indexed_decorator_iter().collect::<Vec<_>>(),
146                    ));
147
148                    ops_offset
149                } else {
150                    0
151                };
152
153                MastNodeInfo::new(mast_node, ops_offset)
154            })
155            .collect();
156
157        let basic_block_data = basic_block_data_builder.finalize();
158        basic_block_data.write_into(target);
159
160        // Write node infos
161        for mast_node_info in mast_node_infos {
162            mast_node_info.write_into(target);
163        }
164
165        self.advice_map.write_into(target);
166        let error_codes: BTreeMap<u64, String> =
167            self.error_codes.iter().map(|(k, v)| (*k, v.to_string())).collect();
168        error_codes.write_into(target);
169
170        // write all decorator data below
171
172        let mut decorator_data_builder = DecoratorDataBuilder::new();
173        for decorator in &self.decorators {
174            decorator_data_builder.add_decorator(decorator)
175        }
176
177        let (decorator_data, decorator_infos, string_table) = decorator_data_builder.finalize();
178
179        // decorator data buffers
180        decorator_data.write_into(target);
181        string_table.write_into(target);
182
183        // Write decorator infos
184        for decorator_info in decorator_infos {
185            decorator_info.write_into(target);
186        }
187
188        basic_block_decorators.write_into(target);
189
190        // Write "before enter" and "after exit" decorators
191        before_enter_decorators.write_into(target);
192        after_exit_decorators.write_into(target);
193    }
194}
195
196impl Deserializable for MastForest {
197    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
198        read_and_validate_magic(source)?;
199        read_and_validate_version(source)?;
200
201        // Reading sections metadata
202        let node_count = source.read_usize()?;
203        let decorator_count = source.read_usize()?;
204
205        // Reading procedure roots
206        let roots: Vec<u32> = Deserializable::read_from(source)?;
207
208        // Reading nodes
209        let basic_block_data: Vec<u8> = Deserializable::read_from(source)?;
210        let mast_node_infos: Vec<MastNodeInfo> = node_infos_iter(source, node_count)
211            .collect::<Result<Vec<MastNodeInfo>, DeserializationError>>()?;
212
213        let advice_map = AdviceMap::read_from(source)?;
214
215        let error_codes: BTreeMap<u64, String> = Deserializable::read_from(source)?;
216        let error_codes: BTreeMap<u64, Arc<str>> =
217            error_codes.into_iter().map(|(k, v)| (k, Arc::from(v))).collect();
218
219        // Reading Decorators
220        let decorator_data: Vec<u8> = Deserializable::read_from(source)?;
221        let string_table: StringTable = Deserializable::read_from(source)?;
222        let decorator_infos = decorator_infos_iter(source, decorator_count);
223
224        // Constructing MastForest
225        let mut mast_forest = {
226            let mut mast_forest = MastForest::new();
227
228            for decorator_info in decorator_infos {
229                let decorator_info = decorator_info?;
230                let decorator =
231                    decorator_info.try_into_decorator(&string_table, &decorator_data)?;
232
233                mast_forest.add_decorator(decorator).map_err(|e| {
234                    DeserializationError::InvalidValue(format!(
235                        "failed to add decorator to MAST forest while deserializing: {e}",
236                    ))
237                })?;
238            }
239
240            // nodes
241            let basic_block_data_decoder = BasicBlockDataDecoder::new(&basic_block_data);
242            for mast_node_info in mast_node_infos {
243                let node =
244                    mast_node_info.try_into_mast_node(node_count, &basic_block_data_decoder)?;
245
246                mast_forest.add_node(node).map_err(|e| {
247                    DeserializationError::InvalidValue(format!(
248                        "failed to add node to MAST forest while deserializing: {e}",
249                    ))
250                })?;
251            }
252
253            // roots
254            for root in roots {
255                // make sure the root is valid in the context of the MAST forest
256                let root = MastNodeId::from_u32_safe(root, &mast_forest)?;
257                mast_forest.make_root(root);
258            }
259
260            mast_forest.advice_map = advice_map;
261
262            mast_forest
263        };
264
265        let basic_block_decorators: Vec<(usize, DecoratorList)> =
266            read_block_decorators(source, &mast_forest)?;
267        for (node_id, decorator_list) in basic_block_decorators {
268            let node_id = MastNodeId::from_usize_safe(node_id, &mast_forest)?;
269
270            match &mut mast_forest[node_id] {
271                MastNode::Block(basic_block) => {
272                    basic_block.set_decorators(decorator_list);
273                },
274                other => {
275                    return Err(DeserializationError::InvalidValue(format!(
276                        "expected mast node with id {node_id} to be a basic block, found {other:?}"
277                    )));
278                },
279            }
280        }
281
282        // read "before enter" and "after exit" decorators, and update the corresponding nodes
283        let before_enter_decorators: Vec<(usize, Vec<DecoratorId>)> =
284            read_before_after_decorators(source, &mast_forest)?;
285        for (node_id, decorator_ids) in before_enter_decorators {
286            let node_id = MastNodeId::from_usize_safe(node_id, &mast_forest)?;
287            mast_forest.append_before_enter(node_id, &decorator_ids);
288        }
289
290        let after_exit_decorators: Vec<(usize, Vec<DecoratorId>)> =
291            read_before_after_decorators(source, &mast_forest)?;
292        for (node_id, decorator_ids) in after_exit_decorators {
293            let node_id = MastNodeId::from_usize_safe(node_id, &mast_forest)?;
294            mast_forest.append_after_exit(node_id, &decorator_ids);
295        }
296
297        mast_forest.error_codes = error_codes;
298
299        Ok(mast_forest)
300    }
301}
302
303fn read_and_validate_magic<R: ByteReader>(source: &mut R) -> Result<[u8; 5], DeserializationError> {
304    let magic: [u8; 5] = source.read_array()?;
305    if magic != *MAGIC {
306        return Err(DeserializationError::InvalidValue(format!(
307            "Invalid magic bytes. Expected '{:?}', got '{:?}'",
308            *MAGIC, magic
309        )));
310    }
311    Ok(magic)
312}
313
314fn read_and_validate_version<R: ByteReader>(
315    source: &mut R,
316) -> Result<[u8; 3], DeserializationError> {
317    let version: [u8; 3] = source.read_array()?;
318    if version != VERSION {
319        return Err(DeserializationError::InvalidValue(format!(
320            "Unsupported version. Got '{version:?}', but only '{VERSION:?}' is supported",
321        )));
322    }
323    Ok(version)
324}
325
326fn read_block_decorators<R: ByteReader>(
327    source: &mut R,
328    mast_forest: &MastForest,
329) -> Result<Vec<(usize, DecoratorList)>, DeserializationError> {
330    let vec_len: usize = source.read()?;
331    let mut out_vec: Vec<_> = Vec::with_capacity(vec_len);
332
333    for _ in 0..vec_len {
334        let node_id: usize = source.read()?;
335
336        let decorator_vec_len: usize = source.read()?;
337        let mut inner_vec: Vec<DecoratedOpLink> = Vec::with_capacity(decorator_vec_len);
338        for _ in 0..decorator_vec_len {
339            let op_id: usize = source.read()?;
340            let decorator_id = DecoratorId::from_u32_safe(source.read()?, mast_forest)?;
341            inner_vec.push((op_id, decorator_id));
342        }
343
344        out_vec.push((node_id, inner_vec));
345    }
346
347    Ok(out_vec)
348}
349
350fn decorator_infos_iter<'a, R>(
351    source: &'a mut R,
352    decorator_count: usize,
353) -> impl Iterator<Item = Result<DecoratorInfo, DeserializationError>> + 'a
354where
355    R: ByteReader + 'a,
356{
357    let mut remaining = decorator_count;
358    core::iter::from_fn(move || {
359        if remaining == 0 {
360            return None;
361        }
362        remaining -= 1;
363        Some(DecoratorInfo::read_from(source))
364    })
365}
366
367fn node_infos_iter<'a, R>(
368    source: &'a mut R,
369    node_count: usize,
370) -> impl Iterator<Item = Result<MastNodeInfo, DeserializationError>> + 'a
371where
372    R: ByteReader + 'a,
373{
374    let mut remaining = node_count;
375    core::iter::from_fn(move || {
376        if remaining == 0 {
377            return None;
378        }
379        remaining -= 1;
380        Some(MastNodeInfo::read_from(source))
381    })
382}
383
384/// Reads the `before_enter_decorators` and `after_exit_decorators` of the serialized `MastForest`
385/// format.
386///
387/// Note that we need this custom format because we cannot implement `Deserializable` for
388/// `DecoratorId` (in favor of using [`DecoratorId::from_u32_safe`]).
389fn read_before_after_decorators<R: ByteReader>(
390    source: &mut R,
391    mast_forest: &MastForest,
392) -> Result<Vec<(usize, Vec<DecoratorId>)>, DeserializationError> {
393    let vec_len: usize = source.read()?;
394    let mut out_vec: Vec<_> = Vec::with_capacity(vec_len);
395
396    for _ in 0..vec_len {
397        let node_id: usize = source.read()?;
398
399        let inner_vec_len: usize = source.read()?;
400        let mut inner_vec: Vec<DecoratorId> = Vec::with_capacity(inner_vec_len);
401        for _ in 0..inner_vec_len {
402            let decorator_id = DecoratorId::from_u32_safe(source.read()?, mast_forest)?;
403            inner_vec.push(decorator_id);
404        }
405
406        out_vec.push((node_id, inner_vec));
407    }
408
409    Ok(out_vec)
410}