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)]
28pub struct RlpInteger<'a> {
29 scalar: RlpScalar<'a>,
30}
31
32impl<'a> RlpInteger<'a> {
33 pub fn try_from_scalar(scalar: RlpScalar<'a>) -> Result<Self, DecodeError> {
35 validate_integer_payload(scalar.payload())?;
36 Ok(Self { scalar })
37 }
38
39 #[must_use]
41 pub const fn scalar(self) -> RlpScalar<'a> {
42 self.scalar
43 }
44
45 #[must_use]
47 pub const fn payload(self) -> &'a [u8] {
48 self.scalar.payload()
49 }
50
51 #[must_use]
53 pub const fn encoded_len(self) -> usize {
54 self.scalar.encoded_len()
55 }
56
57 #[must_use]
59 pub const fn header_len(self) -> usize {
60 self.scalar.header_len()
61 }
62
63 #[must_use]
65 pub const fn form(self) -> RlpScalarForm {
66 self.scalar.form()
67 }
68
69 #[must_use]
71 pub const fn is_zero(self) -> bool {
72 self.scalar.payload().is_empty()
73 }
74
75 pub fn to_u64(self) -> Result<u64, DecodeError> {
77 fold_u64(self.payload())
78 }
79
80 pub fn to_u128(self) -> Result<u128, DecodeError> {
82 fold_u128(self.payload())
83 }
84
85 pub fn to_be_bytes32(self) -> Result<[u8; 32], DecodeError> {
87 to_be_bytes32(self.payload())
88 }
89}
90
91impl<'a> TryFrom<RlpScalar<'a>> for RlpInteger<'a> {
92 type Error = DecodeError;
93
94 fn try_from(value: RlpScalar<'a>) -> Result<Self, Self::Error> {
95 Self::try_from_scalar(value)
96 }
97}
98
99pub fn decode_rlp_integer<'a>(
101 input: &'a [u8],
102 limits: DecodeLimits,
103) -> Result<RlpInteger<'a>, DecodeError> {
104 let mut accumulator = limits.accumulator();
105 let integer = decode_rlp_integer_partial(input, &mut accumulator)?;
106 require_exact_consumption(integer.encoded_len(), input.len())?;
107 Ok(integer)
108}
109
110pub fn decode_rlp_integer_partial<'a>(
119 input: &'a [u8],
120 accumulator: &mut DecodeAccumulator,
121) -> Result<RlpInteger<'a>, DecodeError> {
122 let scalar = decode_rlp_scalar_partial(input, accumulator)?;
123 RlpInteger::try_from_scalar(scalar)
124}
125
126pub fn decode_rlp_u64(input: &[u8], limits: DecodeLimits) -> Result<u64, DecodeError> {
128 decode_rlp_integer(input, limits)?.to_u64()
129}
130
131pub fn decode_rlp_u128(input: &[u8], limits: DecodeLimits) -> Result<u128, DecodeError> {
133 decode_rlp_integer(input, limits)?.to_u128()
134}
135
136pub fn decode_rlp_u256_bytes(input: &[u8], limits: DecodeLimits) -> Result<[u8; 32], DecodeError> {
138 decode_rlp_integer(input, limits)?.to_be_bytes32()
139}
140
141pub(super) fn validate_integer_payload(payload: &[u8]) -> Result<(), DecodeError> {
142 if payload.first().is_some_and(|byte| *byte == 0) {
143 return Err(DecodeError::Malformed);
144 }
145 Ok(())
146}
147
148fn fold_u64(payload: &[u8]) -> Result<u64, DecodeError> {
149 if payload.len() > MAX_U64_BYTES {
152 return Err(DecodeError::LengthOverflow);
153 }
154
155 let mut value = 0_u64;
156 for byte in payload {
157 value = value
158 .checked_mul(INTEGER_RADIX_U64)
159 .ok_or(DecodeError::LengthOverflow)?;
160 value = value
161 .checked_add(u64::from(*byte))
162 .ok_or(DecodeError::LengthOverflow)?;
163 }
164 Ok(value)
165}
166
167fn fold_u128(payload: &[u8]) -> Result<u128, DecodeError> {
168 if payload.len() > MAX_U128_BYTES {
171 return Err(DecodeError::LengthOverflow);
172 }
173
174 let mut value = 0_u128;
175 for byte in payload {
176 value = value
177 .checked_mul(INTEGER_RADIX_U128)
178 .ok_or(DecodeError::LengthOverflow)?;
179 value = value
180 .checked_add(u128::from(*byte))
181 .ok_or(DecodeError::LengthOverflow)?;
182 }
183 Ok(value)
184}
185
186fn to_be_bytes32(payload: &[u8]) -> Result<[u8; 32], DecodeError> {
187 if payload.len() > MAX_RLP_U256_BYTES {
190 return Err(DecodeError::LengthOverflow);
191 }
192
193 let mut output = [0_u8; 32];
194 let start = MAX_RLP_U256_BYTES
195 .checked_sub(payload.len())
196 .ok_or(DecodeError::LengthOverflow)?;
197 let target = output
200 .get_mut(start..)
201 .ok_or(DecodeError::OffsetOutOfBounds)?;
202 target.copy_from_slice(payload);
203 Ok(output)
204}