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