Skip to main content

iota_sdk_types/
u256.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5// Before we can expose this in the public interface it likely needs to be
6// wrapped so that the type from our dependency doesn't leak
7pub(crate) type U256 = bnum::BUintD8<32>;
8
9// This is a constant time assert to ensure that the backing storage for U256 is
10// 32 bytes long
11#[allow(unused)]
12const ASSERT_32_BYTES: () = {
13    let u256 = U256::ZERO;
14
15    let _digits: &[u8; 32] = u256.digits();
16};
17
18// This is a constant time assert to ensure endianness of the underlying storage
19// is as expected
20#[allow(unused)]
21const ASSERT_ENDIANNESS: () = {
22    const fn const_bytes_equal(lhs: &[u8], rhs: &[u8]) -> bool {
23        if lhs.len() != rhs.len() {
24            return false;
25        }
26        let mut i = 0;
27        while i < lhs.len() {
28            if lhs[i] != rhs[i] {
29                return false;
30            }
31            i += 1;
32        }
33        true
34    }
35
36    let one_platform = U256::ONE;
37    let one_le = {
38        let mut buf = [0; 32];
39        buf[0] = 1;
40        buf
41    };
42
43    let one_be = {
44        let mut buf = [0; 32];
45        buf[31] = 1;
46        buf
47    };
48
49    // To little endian
50    let le = one_platform.to_le();
51    assert!(const_bytes_equal(&one_le, le.digits().as_slice()));
52
53    // To big endian
54    let be = one_platform.to_be();
55    assert!(const_bytes_equal(&one_be, be.digits().as_slice()));
56
57    // From little endian
58    assert!(const_bytes_equal(
59        one_platform.digits().as_slice(),
60        U256::from_le(U256::from_digits(one_le)).digits().as_slice()
61    ));
62
63    // From big endian
64    assert!(const_bytes_equal(
65        one_platform.digits().as_slice(),
66        U256::from_be(U256::from_digits(one_be)).digits().as_slice()
67    ));
68};
69
70#[cfg(test)]
71mod tests {
72    #[cfg(feature = "proptest")]
73    mod proptests {
74        use std::str::FromStr;
75
76        use num_bigint::BigUint;
77        use proptest::prelude::*;
78        use test_strategy::proptest;
79
80        use super::super::U256;
81
82        #[proptest]
83        fn dont_crash_on_large_inputs(
84            #[strategy(proptest::collection::vec(any::<u8>(), 33..1024))] bytes: Vec<u8>,
85        ) {
86            let big_int = BigUint::from_bytes_be(&bytes);
87            let radix10 = big_int.to_str_radix(10);
88
89            // doesn't crash
90            let _ = U256::from_str_radix(&radix10, 10);
91        }
92
93        #[proptest]
94        fn valid_u256_strings(
95            #[strategy(proptest::collection::vec(any::<u8>(), 1..=32))] bytes: Vec<u8>,
96        ) {
97            let big_int = BigUint::from_bytes_be(&bytes);
98            let radix10 = big_int.to_str_radix(10);
99
100            let u256 = U256::from_str_radix(&radix10, 10).unwrap();
101
102            assert_eq!(radix10, u256.to_str_radix(10));
103
104            let from_str = U256::from_str(&radix10).unwrap();
105            assert_eq!(from_str, u256);
106            assert_eq!(radix10, from_str.to_string());
107        }
108    }
109
110    #[cfg(target_arch = "wasm32")]
111    use wasm_bindgen_test::wasm_bindgen_test as test;
112
113    use super::*;
114
115    #[test]
116    fn endianness() {
117        let one_platform = U256::ONE;
118        let one_le = {
119            let mut buf = [0; 32];
120            buf[0] = 1;
121            buf
122        };
123
124        let one_be = {
125            let mut buf = [0; 32];
126            buf[31] = 1;
127            buf
128        };
129
130        // To little endian
131        let le = one_platform.to_le();
132        assert_eq!(one_le, *le.digits());
133
134        // To big endian
135        let be = one_platform.to_be();
136        assert_eq!(one_be, *be.digits());
137
138        // From little endian
139        assert_eq!(one_platform, U256::from_le(U256::from_digits(one_le)));
140        // From big endian
141        assert_eq!(one_platform, U256::from_be(U256::from_digits(one_be)));
142    }
143}