Skip to content

Commit ae9ae5a

Browse files
committed
Round up bits_precision when decoding from bytes
1 parent 56479f2 commit ae9ae5a

File tree

2 files changed

+93
-35
lines changed

2 files changed

+93
-35
lines changed

src/limb/encoding.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,28 @@ impl Encoding for Limb {
3434
impl Limb {
3535
/// Decode limb from a big endian byte slice.
3636
///
37-
/// Panics if the slice is not the same size as [`Limb::Repr`].
37+
/// Panics if the slice is larger than [`Limb::Repr`].
3838
pub(crate) fn from_be_slice(bytes: &[u8]) -> Self {
39-
Self::from_be_bytes(bytes.try_into().expect("slice not limb-sized"))
39+
let mut repr = Self::ZERO.to_be_bytes();
40+
let repr_len = repr.len();
41+
if bytes.len() > repr_len {
42+
panic!("The given slice is larger than the limb size");
43+
}
44+
repr[(repr_len - bytes.len())..].copy_from_slice(bytes);
45+
Self::from_be_bytes(repr)
4046
}
4147

4248
/// Decode limb from a little endian byte slice.
4349
///
4450
/// Panics if the slice is not the same size as [`Limb::Repr`].
4551
pub(crate) fn from_le_slice(bytes: &[u8]) -> Self {
46-
Self::from_le_bytes(bytes.try_into().expect("slice not limb-sized"))
52+
let mut repr = Self::ZERO.to_le_bytes();
53+
let repr_len = repr.len();
54+
if bytes.len() > repr_len {
55+
panic!("The given slice is larger than the limb size");
56+
}
57+
repr[..bytes.len()].copy_from_slice(bytes);
58+
Self::from_le_bytes(repr)
4759
}
4860
}
4961

src/uint/boxed/encoding.rs

Lines changed: 78 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,62 +7,64 @@ use alloc::boxed::Box;
77
/// Decoding errors for [`BoxedUint`].
88
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
99
pub enum DecodeError {
10-
/// Input is not a valid size.
10+
/// Input size is too small to fit in the given precision.
1111
InputSize,
1212

13-
/// Precision is not a multiple of [`Limb::BYTES`].
13+
/// The deserialized number is larger than the given precision.
1414
Precision,
1515
}
1616

1717
impl BoxedUint {
1818
/// Create a new [`BoxedUint`] from the provided big endian bytes.
1919
///
2020
/// The `bits_precision` argument represents the precision of the resulting integer, which is
21-
/// fixed as this type is not arbitrary-precision. It MUST be a multiple of the limb size, i.e.
22-
/// [`Limb::BITS`], or otherwise this function will return [`DecodeError::Precision`].
21+
/// fixed as this type is not arbitrary-precision.
22+
/// The new [`BoxedUint`] will be created with `bits_precision`
23+
/// rounded up to a multiple of [`Limb::BITS`].
2324
///
24-
/// If the length of `bytes` (when interpreted as bits) is larger than `bits_precision`, this
25-
/// function will return [`DecodeError::InputSize`].
25+
/// If the length of `bytes` is larger than `bits_precision` (rounded up to a multiple of 8)
26+
/// this function will return [`DecodeError::InputSize`].
27+
/// If the size of the decoded integer is larger than `bits_precision`,
28+
/// this function will return [`DecodeError::Precision`].
2629
pub fn from_be_slice(bytes: &[u8], bits_precision: usize) -> Result<Self, DecodeError> {
2730
if bytes.is_empty() && bits_precision == 0 {
2831
return Ok(Self::zero());
2932
}
3033

31-
if bits_precision % Limb::BITS != 0 {
32-
return Err(DecodeError::Precision);
33-
}
34-
35-
if bytes.len() % Limb::BYTES != 0 || bytes.len() * 8 > bits_precision {
34+
if bytes.len() > (bits_precision + 7) / 8 {
3635
return Err(DecodeError::InputSize);
3736
}
3837

3938
let mut ret = Self::zero_with_precision(bits_precision);
4039

41-
for (chunk, limb) in bytes.chunks(Limb::BYTES).rev().zip(ret.limbs.iter_mut()) {
40+
for (chunk, limb) in bytes.rchunks(Limb::BYTES).zip(ret.limbs.iter_mut()) {
4241
*limb = Limb::from_be_slice(chunk);
4342
}
4443

44+
if bits_precision < ret.bits() {
45+
return Err(DecodeError::Precision);
46+
}
47+
4548
Ok(ret)
4649
}
4750

4851
/// Create a new [`BoxedUint`] from the provided little endian bytes.
4952
///
5053
/// The `bits_precision` argument represents the precision of the resulting integer, which is
51-
/// fixed as this type is not arbitrary-precision. It MUST be a multiple of the limb size, i.e.
52-
/// [`Limb::BITS`], or otherwise this function will return [`DecodeError::Precision`].
54+
/// fixed as this type is not arbitrary-precision.
55+
/// The new [`BoxedUint`] will be created with `bits_precision`
56+
/// rounded up to a multiple of [`Limb::BITS`].
5357
///
54-
/// If the length of `bytes` (when interpreted as bits) is larger than `bits_precision`, this
55-
/// function will return [`DecodeError::InputSize`].
58+
/// If the length of `bytes` is larger than `bits_precision` (rounded up to a multiple of 8)
59+
/// this function will return [`DecodeError::InputSize`].
60+
/// If the size of the decoded integer is larger than `bits_precision`,
61+
/// this function will return [`DecodeError::Precision`].
5662
pub fn from_le_slice(bytes: &[u8], bits_precision: usize) -> Result<Self, DecodeError> {
5763
if bytes.is_empty() && bits_precision == 0 {
5864
return Ok(Self::zero());
5965
}
6066

61-
if bits_precision % Limb::BITS != 0 {
62-
return Err(DecodeError::Precision);
63-
}
64-
65-
if bytes.len() % Limb::BYTES != 0 || bytes.len() * 8 > bits_precision {
67+
if bytes.len() > (bits_precision + 7) / 8 {
6668
return Err(DecodeError::InputSize);
6769
}
6870

@@ -72,6 +74,10 @@ impl BoxedUint {
7274
*limb = Limb::from_le_slice(chunk);
7375
}
7476

77+
if bits_precision < ret.bits() {
78+
return Err(DecodeError::Precision);
79+
}
80+
7581
Ok(ret)
7682
}
7783

@@ -173,19 +179,39 @@ mod tests {
173179
}
174180

175181
#[test]
182+
#[cfg(target_pointer_width = "32")]
176183
fn from_be_slice_not_word_sized() {
177-
let bytes = hex!("00112233445566778899aabbccddee");
184+
let bytes = hex!("112233445566778899aabbccddeeff");
185+
let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
178186
assert_eq!(
179-
BoxedUint::from_be_slice(&bytes, 128),
180-
Err(DecodeError::InputSize)
187+
n.as_limbs(),
188+
&[
189+
Limb(0xccddeeff),
190+
Limb(0x8899aabb),
191+
Limb(0x44556677),
192+
Limb(0x00112233)
193+
]
181194
);
195+
assert_eq!(n.bits_precision(), 128);
182196
}
183197

184198
#[test]
185-
fn from_be_slice_bad_precision() {
186-
let bytes = hex!("00112233445566778899aabbccddeeff");
199+
#[cfg(target_pointer_width = "64")]
200+
fn from_be_slice_not_word_sized() {
201+
let bytes = hex!("112233445566778899aabbccddeeff");
202+
let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
187203
assert_eq!(
188-
BoxedUint::from_be_slice(&bytes, 127),
204+
n.as_limbs(),
205+
&[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
206+
);
207+
assert_eq!(n.bits_precision(), 128);
208+
}
209+
210+
#[test]
211+
fn from_be_slice_non_multiple_precision() {
212+
let bytes = hex!("0f112233445566778899aabbccddeeff");
213+
assert_eq!(
214+
BoxedUint::from_be_slice(&bytes, 121),
189215
Err(DecodeError::Precision)
190216
);
191217
}
@@ -246,19 +272,39 @@ mod tests {
246272
}
247273

248274
#[test]
275+
#[cfg(target_pointer_width = "32")]
249276
fn from_le_slice_not_word_sized() {
250277
let bytes = hex!("ffeeddccbbaa998877665544332211");
278+
let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
251279
assert_eq!(
252-
BoxedUint::from_be_slice(&bytes, 128),
253-
Err(DecodeError::InputSize)
280+
n.as_limbs(),
281+
&[
282+
Limb(0xbbccddee),
283+
Limb(0x778899aa),
284+
Limb(0x33445566),
285+
Limb(0x00001122)
286+
]
254287
);
288+
assert_eq!(n.bits_precision(), 128);
255289
}
256290

257291
#[test]
258-
fn from_le_slice_bad_precision() {
259-
let bytes = hex!("ffeeddccbbaa99887766554433221100");
292+
#[cfg(target_pointer_width = "64")]
293+
fn from_le_slice_not_word_sized() {
294+
let bytes = hex!("ffeeddccbbaa998877665544332211");
295+
let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
296+
assert_eq!(
297+
n.as_limbs(),
298+
&[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
299+
);
300+
assert_eq!(n.bits_precision(), 128);
301+
}
302+
303+
#[test]
304+
fn from_le_slice_non_multiple_precision() {
305+
let bytes = hex!("ffeeddccbbaa998877665544332211f0");
260306
assert_eq!(
261-
BoxedUint::from_le_slice(&bytes, 127),
307+
BoxedUint::from_le_slice(&bytes, 121),
262308
Err(DecodeError::Precision)
263309
);
264310
}

0 commit comments

Comments
 (0)