miden_objects/
lib.rs

1#![no_std]
2
3#[macro_use]
4extern crate alloc;
5
6#[cfg(feature = "std")]
7extern crate std;
8
9pub mod account;
10pub mod asset;
11pub mod batch;
12pub mod block;
13pub mod note;
14pub mod transaction;
15
16#[cfg(any(feature = "testing", test))]
17pub mod testing;
18
19mod constants;
20mod errors;
21
22// RE-EXPORTS
23// ================================================================================================
24
25pub use constants::*;
26pub use errors::{
27    AccountDeltaError, AccountError, AccountIdError, AssetError, AssetVaultError, BlockError,
28    ChainMmrError, NoteError, ProvenTransactionError, TransactionInputError,
29    TransactionOutputError, TransactionScriptError,
30};
31pub use miden_crypto::hash::rpo::{Rpo256 as Hasher, RpoDigest as Digest};
32pub use vm_core::{Felt, FieldElement, StarkField, Word, EMPTY_WORD, ONE, WORD_SIZE, ZERO};
33
34pub mod assembly {
35    pub use assembly::{
36        mast, Assembler, AssemblyError, DefaultSourceManager, KernelLibrary, Library,
37        LibraryNamespace, LibraryPath, SourceManager, Version,
38    };
39}
40
41pub mod crypto {
42    pub use miden_crypto::{dsa, hash, merkle, rand, utils};
43}
44
45pub mod utils {
46    use alloc::string::{String, ToString};
47
48    pub use miden_crypto::utils::{bytes_to_hex_string, collections, hex_to_bytes, HexParseError};
49    pub use vm_core::utils::*;
50    use vm_core::{Felt, StarkField};
51
52    pub mod serde {
53        pub use miden_crypto::utils::{
54            ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
55        };
56    }
57
58    pub const fn parse_hex_string_as_word(hex: &str) -> Result<[Felt; 4], &'static str> {
59        const fn parse_hex_digit(digit: u8) -> Result<u8, &'static str> {
60            match digit {
61                b'0'..=b'9' => Ok(digit - b'0'),
62                b'A'..=b'F' => Ok(digit - b'A' + 0x0a),
63                b'a'..=b'f' => Ok(digit - b'a' + 0x0a),
64                _ => Err("Invalid hex character"),
65            }
66        }
67        // Enforce and skip the '0x' prefix.
68        let hex_bytes = match hex.as_bytes() {
69            [b'0', b'x', rest @ ..] => rest,
70            _ => return Err("Hex string must have a \"0x\" prefix"),
71        };
72
73        if hex_bytes.len() > 64 {
74            return Err("Hex string has more than 64 characters");
75        }
76
77        let mut felts = [0u64; 4];
78        let mut i = 0;
79        while i < hex_bytes.len() {
80            let hex_digit = match parse_hex_digit(hex_bytes[i]) {
81                // SAFETY: u8 cast to u64 is safe. We cannot use u64::from in const context so we
82                // are forced to cast.
83                Ok(v) => v as u64,
84                Err(e) => return Err(e),
85            };
86
87            // This digit's nibble offset within the felt. We need to invert the nibbles per
88            // byte for endianess reasons i.e. ABCD -> BADC.
89            let inibble = if i % 2 == 0 { (i + 1) % 16 } else { (i - 1) % 16 };
90
91            let value = hex_digit << (inibble * 4);
92            felts[i / 2 / 8] += value;
93
94            i += 1;
95        }
96
97        // Ensure each felt is within bounds as `Felt::new` silently wraps around.
98        // This matches the behaviour of `Digest::try_from(String)`.
99        let mut idx = 0;
100        while idx < felts.len() {
101            if felts[idx] > Felt::MODULUS {
102                return Err("Felt overflow");
103            }
104            idx += 1;
105        }
106
107        Ok([
108            Felt::new(felts[0]),
109            Felt::new(felts[1]),
110            Felt::new(felts[2]),
111            Felt::new(felts[3]),
112        ])
113    }
114
115    /// Construct a new `Digest` from a hex value.
116    ///
117    /// Expects a '0x' prefixed hex string followed by up to 64 hex digits.
118    #[macro_export]
119    macro_rules! digest {
120        ($hex:expr) => {{
121            let felts: [$crate::Felt; 4] = match $crate::utils::parse_hex_string_as_word($hex) {
122                Ok(v) => v,
123                Err(e) => panic!("{}", e),
124            };
125
126            $crate::Digest::new(felts)
127        }};
128    }
129
130    pub fn parse_hex_to_felts(hex: &str) -> Result<[Felt; 4], String> {
131        match parse_hex_string_as_word(hex) {
132            Ok(felts) => Ok(felts),
133            Err(e) => Err(e.to_string()),
134        }
135    }
136
137    #[cfg(test)]
138    mod tests {
139        #[rstest::rstest]
140        #[case::missing_prefix("1234")]
141        #[case::invalid_character("1234567890abcdefg")]
142        #[case::too_long("0xx00000000000000000000000000000000000000000000000000000000000000001")]
143        #[case::overflow_felt0(
144            "0xffffffffffffffff000000000000000000000000000000000000000000000000"
145        )]
146        #[case::overflow_felt1(
147            "0x0000000000000000ffffffffffffffff00000000000000000000000000000000"
148        )]
149        #[case::overflow_felt2(
150            "0x00000000000000000000000000000000ffffffffffffffff0000000000000000"
151        )]
152        #[case::overflow_felt3(
153            "0x000000000000000000000000000000000000000000000000ffffffffffffffff"
154        )]
155        #[should_panic]
156        fn digest_macro_invalid(#[case] bad_input: &str) {
157            digest!(bad_input);
158        }
159
160        #[rstest::rstest]
161        #[case::each_digit("0x1234567890abcdef")]
162        #[case::empty("0x")]
163        #[case::zero("0x0")]
164        #[case::zero_full("0x0000000000000000000000000000000000000000000000000000000000000000")]
165        #[case::one_lsb("0x1")]
166        #[case::one_msb("0x0000000000000000000000000000000000000000000000000000000000000001")]
167        #[case::one_partial("0x0001")]
168        #[case::odd("0x123")]
169        #[case::even("0x1234")]
170        #[case::touch_each_felt(
171            "0x00000000000123450000000000067890000000000000abcd00000000000000ef"
172        )]
173        #[case::unique_felt("0x111111111111111155555555555555559999999999999999cccccccccccccccc")]
174        #[case::digits_on_repeat(
175            "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
176        )]
177        fn digest_macro(#[case] input: &str) {
178            let uut = digest!(input);
179
180            // Right pad to 64 hex digits (66 including prefix). This is required by the
181            // Digest::try_from(String) implementation.
182            let padded_input = format!("{input:<66}").replace(" ", "0");
183            let expected = crate::Digest::try_from(std::dbg!(padded_input)).unwrap();
184
185            assert_eq!(uut, expected);
186        }
187    }
188}
189
190pub mod vm {
191    pub use miden_verifier::ExecutionProof;
192    pub use vm_core::{sys_events::SystemEvent, AdviceMap, Program, ProgramInfo};
193    pub use vm_processor::{AdviceInputs, RowIndex, StackInputs, StackOutputs};
194}