eth_valkyoth_codec/rlp/
integer.rs1use core::convert::TryFrom;
2
3use crate::{DecodeAccumulator, DecodeError, DecodeLimits, require_exact_consumption};
4
5use super::{RlpScalar, RlpScalarForm, decode_rlp_scalar_partial};
6
7pub const MAX_RLP_U256_BYTES: usize = 32;
12
13const MAX_U64_BYTES: usize = 8;
14const MAX_U128_BYTES: usize = 16;
15const INTEGER_RADIX_U64: u64 = 256;
17const INTEGER_RADIX_U128: u128 = 256;
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
25pub struct RlpInteger<'a> {
26 scalar: RlpScalar<'a>,
27}
28
29impl<'a> RlpInteger<'a> {
30 pub fn try_from_scalar(scalar: RlpScalar<'a>) -> Result<Self, DecodeError> {
32 validate_integer_payload(scalar.payload())?;
33 Ok(Self { scalar })
34 }
35
36 #[must_use]
38 pub const fn scalar(self) -> RlpScalar<'a> {
39 self.scalar
40 }
41
42 #[must_use]
44 pub const fn payload(self) -> &'a [u8] {
45 self.scalar.payload()
46 }
47
48 #[must_use]
50 pub const fn encoded_len(self) -> usize {
51 self.scalar.encoded_len()
52 }
53
54 #[must_use]
56 pub const fn header_len(self) -> usize {
57 self.scalar.header_len()
58 }
59
60 #[must_use]
62 pub const fn form(self) -> RlpScalarForm {
63 self.scalar.form()
64 }
65
66 #[must_use]
68 pub const fn is_zero(self) -> bool {
69 self.scalar.payload().is_empty()
70 }
71
72 pub fn to_u64(self) -> Result<u64, DecodeError> {
74 fold_u64(self.payload())
75 }
76
77 pub fn to_u128(self) -> Result<u128, DecodeError> {
79 fold_u128(self.payload())
80 }
81
82 pub fn to_be_bytes32(self) -> Result<[u8; 32], DecodeError> {
84 to_be_bytes32(self.payload())
85 }
86}
87
88impl<'a> TryFrom<RlpScalar<'a>> for RlpInteger<'a> {
89 type Error = DecodeError;
90
91 fn try_from(value: RlpScalar<'a>) -> Result<Self, Self::Error> {
92 Self::try_from_scalar(value)
93 }
94}
95
96pub fn decode_rlp_integer<'a>(
98 input: &'a [u8],
99 limits: DecodeLimits,
100) -> Result<RlpInteger<'a>, DecodeError> {
101 let mut accumulator = limits.accumulator();
102 let integer = decode_rlp_integer_partial(input, &mut accumulator)?;
103 require_exact_consumption(integer.encoded_len(), input.len())?;
104 Ok(integer)
105}
106
107pub fn decode_rlp_integer_partial<'a>(
116 input: &'a [u8],
117 accumulator: &mut DecodeAccumulator,
118) -> Result<RlpInteger<'a>, DecodeError> {
119 let scalar = decode_rlp_scalar_partial(input, accumulator)?;
120 RlpInteger::try_from_scalar(scalar)
121}
122
123pub fn decode_rlp_u64(input: &[u8], limits: DecodeLimits) -> Result<u64, DecodeError> {
125 decode_rlp_integer(input, limits)?.to_u64()
126}
127
128pub fn decode_rlp_u128(input: &[u8], limits: DecodeLimits) -> Result<u128, DecodeError> {
130 decode_rlp_integer(input, limits)?.to_u128()
131}
132
133pub fn decode_rlp_u256_bytes(input: &[u8], limits: DecodeLimits) -> Result<[u8; 32], DecodeError> {
135 decode_rlp_integer(input, limits)?.to_be_bytes32()
136}
137
138fn validate_integer_payload(payload: &[u8]) -> Result<(), DecodeError> {
139 if payload.first().is_some_and(|byte| *byte == 0) {
140 return Err(DecodeError::Malformed);
141 }
142 Ok(())
143}
144
145fn fold_u64(payload: &[u8]) -> Result<u64, DecodeError> {
146 if payload.len() > MAX_U64_BYTES {
149 return Err(DecodeError::LengthOverflow);
150 }
151
152 let mut value = 0_u64;
153 for byte in payload {
154 value = value
155 .checked_mul(INTEGER_RADIX_U64)
156 .ok_or(DecodeError::LengthOverflow)?;
157 value = value
158 .checked_add(u64::from(*byte))
159 .ok_or(DecodeError::LengthOverflow)?;
160 }
161 Ok(value)
162}
163
164fn fold_u128(payload: &[u8]) -> Result<u128, DecodeError> {
165 if payload.len() > MAX_U128_BYTES {
168 return Err(DecodeError::LengthOverflow);
169 }
170
171 let mut value = 0_u128;
172 for byte in payload {
173 value = value
174 .checked_mul(INTEGER_RADIX_U128)
175 .ok_or(DecodeError::LengthOverflow)?;
176 value = value
177 .checked_add(u128::from(*byte))
178 .ok_or(DecodeError::LengthOverflow)?;
179 }
180 Ok(value)
181}
182
183fn to_be_bytes32(payload: &[u8]) -> Result<[u8; 32], DecodeError> {
184 if payload.len() > MAX_RLP_U256_BYTES {
187 return Err(DecodeError::LengthOverflow);
188 }
189
190 let mut output = [0_u8; 32];
191 let start = MAX_RLP_U256_BYTES
192 .checked_sub(payload.len())
193 .ok_or(DecodeError::LengthOverflow)?;
194 let target = output
197 .get_mut(start..)
198 .ok_or(DecodeError::OffsetOutOfBounds)?;
199 target.copy_from_slice(payload);
200 Ok(output)
201}