ruint/support/
alloy_rlp.rs
1#![cfg(feature = "alloy-rlp")]
4#![cfg_attr(docsrs, doc(cfg(feature = "alloy-rlp")))]
5
6use crate::Uint;
7use alloy_rlp::{
8 length_of_length, BufMut, Decodable, Encodable, Error, Header, MaxEncodedLen,
9 MaxEncodedLenAssoc, EMPTY_STRING_CODE,
10};
11
12const MAX_BITS: usize = 55 * 8;
13
14impl<const BITS: usize, const LIMBS: usize> Encodable for Uint<BITS, LIMBS> {
18 #[inline]
19 fn length(&self) -> usize {
20 let bits = self.bit_len();
21 if bits <= 7 {
22 1
23 } else {
24 let bytes = (bits + 7) / 8;
25 bytes + length_of_length(bytes)
26 }
27 }
28
29 #[inline]
30 fn encode(&self, out: &mut dyn BufMut) {
31 match LIMBS {
33 0 => return out.put_u8(EMPTY_STRING_CODE),
34 1 => return self.limbs[0].encode(out),
35 #[allow(clippy::cast_lossless)]
36 2 => return (self.limbs[0] as u128 | ((self.limbs[1] as u128) << 64)).encode(out),
37 _ => {}
38 }
39
40 match self.bit_len() {
41 0 => out.put_u8(EMPTY_STRING_CODE),
42 1..=7 => {
43 #[allow(clippy::cast_possible_truncation)] out.put_u8(self.limbs[0] as u8);
45 }
46 bits => {
47 #[cfg(target_endian = "little")]
50 let mut copy = *self;
51 #[cfg(target_endian = "little")]
52 let bytes = unsafe { copy.as_le_slice_mut() };
53 #[cfg(target_endian = "little")]
54 bytes.reverse();
55
56 #[cfg(target_endian = "big")]
57 let bytes = self.to_be_bytes_vec();
58
59 let leading_zero_bytes = Self::BYTES - (bits + 7) / 8;
60 let trimmed = &bytes[leading_zero_bytes..];
61 if bits > MAX_BITS {
62 trimmed.encode(out);
63 } else {
64 #[allow(clippy::cast_possible_truncation)] out.put_u8(EMPTY_STRING_CODE + trimmed.len() as u8);
66 out.put_slice(trimmed);
67 }
68 }
69 }
70 }
71}
72
73impl<const BITS: usize, const LIMBS: usize> Decodable for Uint<BITS, LIMBS> {
77 #[inline]
78 fn decode(buf: &mut &[u8]) -> Result<Self, Error> {
79 let bytes = Header::decode_bytes(buf, false)?;
80
81 if !bytes.is_empty() && bytes[0] == 0 {
90 return Err(Error::LeadingZero);
91 }
92
93 Self::try_from_be_slice(bytes).ok_or(Error::Overflow)
94 }
95}
96
97#[cfg(feature = "generic_const_exprs")]
98unsafe impl<const BITS: usize, const LIMBS: usize>
99 MaxEncodedLen<{ Self::BYTES + length_of_length(Self::BYTES) }> for Uint<BITS, LIMBS>
100{
101}
102
103#[cfg(not(feature = "generic_const_exprs"))]
104const _: () = {
105 crate::const_for!(BITS in [0, 1, 2, 8, 16, 32, 64, 128, 160, 192, 256, 384, 512, 4096] {
106 const LIMBS: usize = crate::nlimbs(BITS);
107 const BYTES: usize = Uint::<BITS, LIMBS>::BYTES;
108 unsafe impl MaxEncodedLen<{ BYTES + length_of_length(BYTES) }> for Uint<BITS, LIMBS> {}
109 });
110};
111
112unsafe impl<const BITS: usize, const LIMBS: usize> MaxEncodedLenAssoc for Uint<BITS, LIMBS> {
113 const LEN: usize = Self::BYTES + length_of_length(Self::BYTES);
114}
115
116#[cfg(test)]
117mod test {
118 use super::*;
119 use crate::{
120 aliases::{U0, U256},
121 const_for, nlimbs,
122 };
123 use hex_literal::hex;
124 use proptest::proptest;
125
126 fn encode<T: Encodable>(value: T) -> Vec<u8> {
127 let mut buf = vec![];
128 value.encode(&mut buf);
129 buf
130 }
131
132 #[test]
133 fn test_rlp() {
134 assert_eq!(encode(U0::from(0))[..], hex!("80"));
136 assert_eq!(encode(U256::from(0))[..], hex!("80"));
137 assert_eq!(encode(U256::from(15))[..], hex!("0f"));
138 assert_eq!(encode(U256::from(1024))[..], hex!("820400"));
139 assert_eq!(encode(U256::from(0x1234_5678))[..], hex!("8412345678"));
140 }
141
142 #[test]
143 fn test_roundtrip() {
144 const_for!(BITS in SIZES {
145 const LIMBS: usize = nlimbs(BITS);
146 proptest!(|(value: Uint<BITS, LIMBS>)| {
147 let serialized = encode(value);
148
149 #[cfg(feature = "rlp")]
150 {
151 use rlp::Encodable as _;
152 let serialized_rlp = value.rlp_bytes();
153 assert_eq!(serialized, serialized_rlp.freeze()[..]);
154 }
155
156 assert_eq!(serialized.len(), value.length());
157 let mut reader = &serialized[..];
158 let deserialized = Uint::decode(&mut reader).unwrap();
159 assert_eq!(reader.len(), 0);
160 assert_eq!(value, deserialized);
161 });
162 });
163 }
164
165 #[test]
166 fn test_invalid_uints() {
167 assert_eq!(
169 U256::decode(&mut &hex!("820000")[..]),
170 Err(Error::LeadingZero)
171 );
172 assert_eq!(U256::decode(&mut &hex!("00")[..]), Err(Error::LeadingZero));
175 assert_eq!(
178 U256::decode(&mut &hex!("8100")[..]),
179 Err(Error::NonCanonicalSingleByte)
180 );
181 assert_eq!(
182 U256::decode(&mut &hex!("817f")[..]),
183 Err(Error::NonCanonicalSingleByte)
184 );
185 assert_eq!(
186 U256::decode(&mut &hex!("8133")[..]),
187 Err(Error::NonCanonicalSingleByte)
188 );
189 }
190}