1#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct U256(bnum::BUintD8<32>);
8
9impl U256 {
10 pub const ZERO: Self = Self(bnum::BUintD8::<32>::ZERO);
12
13 pub const ONE: Self = Self(bnum::BUintD8::<32>::ONE);
15
16 pub const fn from_digits(digits: [u8; 32]) -> Self {
18 Self(bnum::BUintD8::<32>::from_digits(digits))
19 }
20
21 pub const fn digits(&self) -> &[u8; 32] {
23 self.0.digits()
24 }
25
26 pub const fn from_le(value: Self) -> Self {
29 Self(bnum::BUintD8::<32>::from_le(value.0))
30 }
31
32 pub const fn from_be(value: Self) -> Self {
35 Self(bnum::BUintD8::<32>::from_be(value.0))
36 }
37
38 pub const fn to_le(self) -> Self {
41 Self(self.0.to_le())
42 }
43
44 pub const fn to_be(self) -> Self {
47 Self(self.0.to_be())
48 }
49
50 pub const fn from_str_radix(s: &str, radix: u32) -> Result<Self, U256ParseError> {
52 match bnum::BUintD8::<32>::from_str_radix(s, radix) {
53 Ok(v) => Ok(Self(v)),
54 Err(e) => Err(U256ParseError(e)),
55 }
56 }
57
58 pub fn to_str_radix(&self, radix: u32) -> String {
60 self.0.to_str_radix(radix)
61 }
62
63 pub fn from_radix_be(buf: &[u8], radix: u32) -> Option<Self> {
67 bnum::BUintD8::<32>::from_radix_be(buf, radix).map(Self)
68 }
69
70 pub fn to_radix_be(&self, radix: u32) -> Vec<u8> {
72 self.0.to_radix_be(radix)
73 }
74
75 pub fn from_le_slice(slice: &[u8]) -> Option<Self> {
78 bnum::BUintD8::<32>::from_le_slice(slice).map(Self)
79 }
80}
81
82#[derive(Debug)]
87pub struct U256ParseError(bnum::errors::ParseIntError);
88
89impl std::fmt::Display for U256ParseError {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 write!(f, "unable to parse U256: {}", self.0)
92 }
93}
94
95impl std::error::Error for U256ParseError {}
96
97impl From<u8> for U256 {
98 fn from(value: u8) -> Self {
99 Self(bnum::BUintD8::<32>::from(value))
100 }
101}
102
103impl From<u64> for U256 {
104 fn from(value: u64) -> Self {
105 Self(bnum::BUintD8::<32>::from(value))
106 }
107}
108
109impl std::str::FromStr for U256 {
110 type Err = U256ParseError;
111
112 fn from_str(s: &str) -> Result<Self, Self::Err> {
113 Self::from_str_radix(s, 10)
114 }
115}
116
117impl std::fmt::Display for U256 {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 f.write_str(&self.0.to_str_radix(10))
120 }
121}
122
123#[cfg(feature = "serde")]
124#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
125impl serde::Serialize for U256 {
126 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
127 serde::Serialize::serialize(self.digits(), serializer)
129 }
130}
131
132#[cfg(feature = "serde")]
133#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
134impl<'de> serde::Deserialize<'de> for U256 {
135 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
136 let digits: [u8; 32] = serde::Deserialize::deserialize(deserializer)?;
137 Ok(Self::from_digits(digits))
138 }
139}
140
141#[allow(unused)]
143const ASSERT_32_BYTES: () = {
144 let u256 = U256::ZERO;
145
146 let _digits: &[u8; 32] = u256.digits();
147};
148
149#[allow(unused)]
151const ASSERT_ENDIANNESS: () = {
152 const fn const_bytes_equal(lhs: &[u8], rhs: &[u8]) -> bool {
153 if lhs.len() != rhs.len() {
154 return false;
155 }
156 let mut i = 0;
157 while i < lhs.len() {
158 if lhs[i] != rhs[i] {
159 return false;
160 }
161 i += 1;
162 }
163 true
164 }
165
166 let one_platform = U256::ONE;
167 let one_le = {
168 let mut buf = [0; 32];
169 buf[0] = 1;
170 buf
171 };
172
173 let one_be = {
174 let mut buf = [0; 32];
175 buf[31] = 1;
176 buf
177 };
178
179 let le = one_platform.to_le();
181 assert!(const_bytes_equal(one_le.as_slice(), le.digits().as_slice()));
182
183 let be = one_platform.to_be();
185 assert!(const_bytes_equal(one_be.as_slice(), be.digits().as_slice()));
186
187 assert!(const_bytes_equal(
189 one_platform.digits().as_slice(),
190 U256::from_le(U256::from_digits(one_le)).digits().as_slice()
191 ));
192
193 assert!(const_bytes_equal(
195 one_platform.digits().as_slice(),
196 U256::from_be(U256::from_digits(one_be)).digits().as_slice()
197 ));
198};
199
200#[cfg(test)]
201mod test {
202 use super::*;
203 use num_bigint::BigUint;
204 use proptest::prelude::*;
205 use std::str::FromStr;
206 use test_strategy::proptest;
207
208 #[cfg(target_arch = "wasm32")]
209 use wasm_bindgen_test::wasm_bindgen_test as test;
210
211 #[test]
212 fn endianness() {
213 let one_platform = U256::ONE;
214 let one_le = {
215 let mut buf = [0; 32];
216 buf[0] = 1;
217 buf
218 };
219
220 let one_be = {
221 let mut buf = [0; 32];
222 buf[31] = 1;
223 buf
224 };
225
226 let le = one_platform.to_le();
228 assert_eq!(&one_le, le.digits());
229
230 let be = one_platform.to_be();
232 assert_eq!(&one_be, be.digits());
233
234 assert_eq!(one_platform, U256::from_le(U256::from_digits(one_le)));
236 assert_eq!(one_platform, U256::from_be(U256::from_digits(one_be)));
238 }
239
240 #[proptest]
241 fn dont_crash_on_large_inputs(
242 #[strategy(proptest::collection::vec(any::<u8>(), 33..1024))] bytes: Vec<u8>,
243 ) {
244 let big_int = BigUint::from_bytes_be(&bytes);
245 let radix10 = big_int.to_str_radix(10);
246
247 let _ = U256::from_str_radix(&radix10, 10);
249 }
250
251 #[proptest]
252 fn valid_u256_strings(
253 #[strategy(proptest::collection::vec(any::<u8>(), 1..=32))] bytes: Vec<u8>,
254 ) {
255 let big_int = BigUint::from_bytes_be(&bytes);
256 let radix10 = big_int.to_str_radix(10);
257
258 let u256 = U256::from_str_radix(&radix10, 10).unwrap();
259
260 assert_eq!(radix10, u256.to_str_radix(10));
261
262 let from_str = U256::from_str(&radix10).unwrap();
263 assert_eq!(from_str, u256);
264 assert_eq!(radix10, from_str.to_string());
265 }
266
267 #[cfg(feature = "serde")]
268 #[test]
269 fn bcs_roundtrip_is_32_little_endian_bytes() {
270 let one = U256::ONE;
271 let bytes = bcs::to_bytes(&one).unwrap();
272 let mut expected = [0u8; 32];
273 expected[0] = 1;
274 assert_eq!(bytes, expected);
275
276 let back: U256 = bcs::from_bytes(&bytes).unwrap();
277 assert_eq!(back, one);
278 }
279}