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;
9
10const MAX_U64_BYTES: usize = 8;
11const MAX_U128_BYTES: usize = 16;
12const INTEGER_RADIX_U64: u64 = 256;
13const INTEGER_RADIX_U128: u128 = 256;
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct RlpInteger<'a> {
25 scalar: RlpScalar<'a>,
26}
27
28impl<'a> RlpInteger<'a> {
29 pub fn try_from_scalar(scalar: RlpScalar<'a>) -> Result<Self, DecodeError> {
31 validate_rlp_integer_payload(scalar.payload())?;
32 Ok(Self { scalar })
33 }
34
35 #[must_use]
37 pub const fn scalar(self) -> RlpScalar<'a> {
38 self.scalar
39 }
40
41 #[must_use]
43 pub const fn payload(self) -> &'a [u8] {
44 self.scalar.payload()
45 }
46
47 #[must_use]
49 pub const fn encoded_len(self) -> usize {
50 self.scalar.encoded_len()
51 }
52
53 #[must_use]
55 pub const fn header_len(self) -> usize {
56 self.scalar.header_len()
57 }
58
59 #[must_use]
61 pub const fn form(self) -> RlpScalarForm {
62 self.scalar.form()
63 }
64
65 #[must_use]
67 pub const fn is_zero(self) -> bool {
68 self.scalar.payload().is_empty()
69 }
70
71 pub fn to_u64(self) -> Result<u64, DecodeError> {
77 rlp_integer_payload_to_u64(self.payload())
78 }
79
80 pub fn to_u128(self) -> Result<u128, DecodeError> {
86 rlp_integer_payload_to_u128(self.payload())
87 }
88
89 pub fn to_be_bytes32(self) -> Result<[u8; 32], DecodeError> {
95 rlp_integer_payload_to_u256_bytes(self.payload())
96 }
97}
98
99impl<'a> TryFrom<RlpScalar<'a>> for RlpInteger<'a> {
100 type Error = DecodeError;
101
102 fn try_from(value: RlpScalar<'a>) -> Result<Self, Self::Error> {
103 Self::try_from_scalar(value)
104 }
105}
106
107pub fn decode_rlp_integer<'a>(
109 input: &'a [u8],
110 limits: DecodeLimits,
111) -> Result<RlpInteger<'a>, DecodeError> {
112 let mut accumulator = limits.accumulator();
113 let integer = decode_rlp_integer_partial(input, &mut accumulator)?;
114 require_exact_consumption(integer.encoded_len(), input.len())?;
115 Ok(integer)
116}
117
118pub fn decode_rlp_integer_partial<'a>(
127 input: &'a [u8],
128 accumulator: &mut DecodeAccumulator,
129) -> Result<RlpInteger<'a>, DecodeError> {
130 let scalar = decode_rlp_scalar_partial(input, accumulator)?;
131 RlpInteger::try_from_scalar(scalar)
132}
133
134pub fn decode_rlp_u64(input: &[u8], limits: DecodeLimits) -> Result<u64, DecodeError> {
136 decode_rlp_integer(input, limits)?.to_u64()
137}
138
139pub fn decode_rlp_u128(input: &[u8], limits: DecodeLimits) -> Result<u128, DecodeError> {
141 decode_rlp_integer(input, limits)?.to_u128()
142}
143
144pub fn decode_rlp_u256_bytes(input: &[u8], limits: DecodeLimits) -> Result<[u8; 32], DecodeError> {
146 decode_rlp_integer(input, limits)?.to_be_bytes32()
147}
148
149pub fn validate_rlp_integer_payload(payload: &[u8]) -> Result<(), DecodeError> {
158 if payload.first().is_some_and(|byte| *byte == 0) {
159 return Err(DecodeError::Malformed);
160 }
161 Ok(())
162}
163
164pub fn rlp_integer_payload_to_u64(payload: &[u8]) -> Result<u64, DecodeError> {
172 validate_rlp_integer_payload(payload)?;
173 if payload.len() > MAX_U64_BYTES {
174 return Err(DecodeError::LengthOverflow);
175 }
176
177 let mut value = 0_u64;
178 for byte in payload {
179 value = value
180 .checked_mul(INTEGER_RADIX_U64)
181 .ok_or(DecodeError::LengthOverflow)?;
182 value = value
183 .checked_add(u64::from(*byte))
184 .ok_or(DecodeError::LengthOverflow)?;
185 }
186 Ok(value)
187}
188
189pub fn rlp_integer_payload_to_u128(payload: &[u8]) -> Result<u128, DecodeError> {
194 validate_rlp_integer_payload(payload)?;
195 if payload.len() > MAX_U128_BYTES {
196 return Err(DecodeError::LengthOverflow);
197 }
198
199 let mut value = 0_u128;
200 for byte in payload {
201 value = value
202 .checked_mul(INTEGER_RADIX_U128)
203 .ok_or(DecodeError::LengthOverflow)?;
204 value = value
205 .checked_add(u128::from(*byte))
206 .ok_or(DecodeError::LengthOverflow)?;
207 }
208 Ok(value)
209}
210
211pub fn rlp_integer_payload_to_u256_bytes(payload: &[u8]) -> Result<[u8; 32], DecodeError> {
217 validate_rlp_integer_payload(payload)?;
218 if payload.len() > MAX_RLP_U256_BYTES {
219 return Err(DecodeError::LengthOverflow);
220 }
221
222 let mut output = [0_u8; 32];
223 let start = MAX_RLP_U256_BYTES
224 .checked_sub(payload.len())
225 .ok_or(DecodeError::LengthOverflow)?;
226 let target = output
229 .get_mut(start..)
230 .ok_or(DecodeError::OffsetOutOfBounds)?;
231 target.copy_from_slice(payload);
232 Ok(output)
233}