@@ -8,18 +8,21 @@ use core::fmt;
8
8
/// Decoding errors for [`BoxedUint`].
9
9
#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
10
10
pub enum DecodeError {
11
- /// Input is not a valid size .
11
+ /// Input size is too small to fit in the given precision .
12
12
InputSize ,
13
13
14
- /// Precision is not a multiple of [`Limb::BYTES`] .
14
+ /// The deserialized number is larger than the given precision .
15
15
Precision ,
16
16
}
17
17
18
18
impl fmt:: Display for DecodeError {
19
19
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
20
20
match self {
21
- Self :: InputSize => write ! ( f, "input is not a valid size" ) ,
22
- Self :: Precision => write ! ( f, "precision is not a multiple of the word size" ) ,
21
+ Self :: InputSize => write ! ( f, "input size is too small to fit in the given precision" ) ,
22
+ Self :: Precision => write ! (
23
+ f,
24
+ "the deserialized number is larger than the given precision"
25
+ ) ,
23
26
}
24
27
}
25
28
}
@@ -31,51 +34,53 @@ impl BoxedUint {
31
34
/// Create a new [`BoxedUint`] from the provided big endian bytes.
32
35
///
33
36
/// The `bits_precision` argument represents the precision of the resulting integer, which is
34
- /// fixed as this type is not arbitrary-precision. It MUST be a multiple of the limb size, i.e.
35
- /// [`Limb::BITS`], or otherwise this function will return [`DecodeError::Precision`].
37
+ /// fixed as this type is not arbitrary-precision.
38
+ /// The new [`BoxedUint`] will be created with `bits_precision`
39
+ /// rounded up to a multiple of [`Limb::BITS`].
36
40
///
37
- /// If the length of `bytes` (when interpreted as bits) is larger than `bits_precision`, this
38
- /// function will return [`DecodeError::InputSize`].
41
+ /// If the length of `bytes` is larger than `bits_precision` (rounded up to a multiple of 8)
42
+ /// this function will return [`DecodeError::InputSize`].
43
+ /// If the size of the decoded integer is larger than `bits_precision`,
44
+ /// this function will return [`DecodeError::Precision`].
39
45
pub fn from_be_slice ( bytes : & [ u8 ] , bits_precision : u32 ) -> Result < Self , DecodeError > {
40
46
if bytes. is_empty ( ) && bits_precision == 0 {
41
47
return Ok ( Self :: zero ( ) ) ;
42
48
}
43
49
44
- if bits_precision % Limb :: BITS != 0 {
45
- return Err ( DecodeError :: Precision ) ;
46
- }
47
-
48
- if bytes. len ( ) % Limb :: BYTES != 0 || bytes. len ( ) * 8 > bits_precision as usize {
50
+ if bytes. len ( ) > ( bits_precision as usize + 7 ) / 8 {
49
51
return Err ( DecodeError :: InputSize ) ;
50
52
}
51
53
52
54
let mut ret = Self :: zero_with_precision ( bits_precision) ;
53
55
54
- for ( chunk, limb) in bytes. chunks ( Limb :: BYTES ) . rev ( ) . zip ( ret. limbs . iter_mut ( ) ) {
56
+ for ( chunk, limb) in bytes. rchunks ( Limb :: BYTES ) . zip ( ret. limbs . iter_mut ( ) ) {
55
57
* limb = Limb :: from_be_slice ( chunk) ;
56
58
}
57
59
60
+ if bits_precision < ret. bits ( ) {
61
+ return Err ( DecodeError :: Precision ) ;
62
+ }
63
+
58
64
Ok ( ret)
59
65
}
60
66
61
67
/// Create a new [`BoxedUint`] from the provided little endian bytes.
62
68
///
63
69
/// The `bits_precision` argument represents the precision of the resulting integer, which is
64
- /// fixed as this type is not arbitrary-precision. It MUST be a multiple of the limb size, i.e.
65
- /// [`Limb::BITS`], or otherwise this function will return [`DecodeError::Precision`].
70
+ /// fixed as this type is not arbitrary-precision.
71
+ /// The new [`BoxedUint`] will be created with `bits_precision`
72
+ /// rounded up to a multiple of [`Limb::BITS`].
66
73
///
67
- /// If the length of `bytes` (when interpreted as bits) is larger than `bits_precision`, this
68
- /// function will return [`DecodeError::InputSize`].
74
+ /// If the length of `bytes` is larger than `bits_precision` (rounded up to a multiple of 8)
75
+ /// this function will return [`DecodeError::InputSize`].
76
+ /// If the size of the decoded integer is larger than `bits_precision`,
77
+ /// this function will return [`DecodeError::Precision`].
69
78
pub fn from_le_slice ( bytes : & [ u8 ] , bits_precision : u32 ) -> Result < Self , DecodeError > {
70
79
if bytes. is_empty ( ) && bits_precision == 0 {
71
80
return Ok ( Self :: zero ( ) ) ;
72
81
}
73
82
74
- if bits_precision % Limb :: BITS != 0 {
75
- return Err ( DecodeError :: Precision ) ;
76
- }
77
-
78
- if bytes. len ( ) % Limb :: BYTES != 0 || bytes. len ( ) * 8 > bits_precision as usize {
83
+ if bytes. len ( ) > ( bits_precision as usize + 7 ) / 8 {
79
84
return Err ( DecodeError :: InputSize ) ;
80
85
}
81
86
@@ -85,6 +90,10 @@ impl BoxedUint {
85
90
* limb = Limb :: from_le_slice ( chunk) ;
86
91
}
87
92
93
+ if bits_precision < ret. bits ( ) {
94
+ return Err ( DecodeError :: Precision ) ;
95
+ }
96
+
88
97
Ok ( ret)
89
98
}
90
99
@@ -186,19 +195,39 @@ mod tests {
186
195
}
187
196
188
197
#[ test]
198
+ #[ cfg( target_pointer_width = "32" ) ]
189
199
fn from_be_slice_not_word_sized ( ) {
190
- let bytes = hex ! ( "00112233445566778899aabbccddee" ) ;
200
+ let bytes = hex ! ( "112233445566778899aabbccddeeff" ) ;
201
+ let n = BoxedUint :: from_be_slice ( & bytes, 127 ) . unwrap ( ) ;
191
202
assert_eq ! (
192
- BoxedUint :: from_be_slice( & bytes, 128 ) ,
193
- Err ( DecodeError :: InputSize )
203
+ n. as_limbs( ) ,
204
+ & [
205
+ Limb ( 0xccddeeff ) ,
206
+ Limb ( 0x8899aabb ) ,
207
+ Limb ( 0x44556677 ) ,
208
+ Limb ( 0x00112233 )
209
+ ]
194
210
) ;
211
+ assert_eq ! ( n. bits_precision( ) , 128 ) ;
195
212
}
196
213
197
214
#[ test]
198
- fn from_be_slice_bad_precision ( ) {
199
- let bytes = hex ! ( "00112233445566778899aabbccddeeff" ) ;
215
+ #[ cfg( target_pointer_width = "64" ) ]
216
+ fn from_be_slice_not_word_sized ( ) {
217
+ let bytes = hex ! ( "112233445566778899aabbccddeeff" ) ;
218
+ let n = BoxedUint :: from_be_slice ( & bytes, 127 ) . unwrap ( ) ;
200
219
assert_eq ! (
201
- BoxedUint :: from_be_slice( & bytes, 127 ) ,
220
+ n. as_limbs( ) ,
221
+ & [ Limb ( 0x8899aabbccddeeff ) , Limb ( 0x0011223344556677 ) ]
222
+ ) ;
223
+ assert_eq ! ( n. bits_precision( ) , 128 ) ;
224
+ }
225
+
226
+ #[ test]
227
+ fn from_be_slice_non_multiple_precision ( ) {
228
+ let bytes = hex ! ( "0f112233445566778899aabbccddeeff" ) ;
229
+ assert_eq ! (
230
+ BoxedUint :: from_be_slice( & bytes, 121 ) ,
202
231
Err ( DecodeError :: Precision )
203
232
) ;
204
233
}
@@ -259,19 +288,39 @@ mod tests {
259
288
}
260
289
261
290
#[ test]
291
+ #[ cfg( target_pointer_width = "32" ) ]
262
292
fn from_le_slice_not_word_sized ( ) {
263
293
let bytes = hex ! ( "ffeeddccbbaa998877665544332211" ) ;
294
+ let n = BoxedUint :: from_le_slice ( & bytes, 127 ) . unwrap ( ) ;
264
295
assert_eq ! (
265
- BoxedUint :: from_be_slice( & bytes, 128 ) ,
266
- Err ( DecodeError :: InputSize )
296
+ n. as_limbs( ) ,
297
+ & [
298
+ Limb ( 0xccddeeff ) ,
299
+ Limb ( 0x8899aabb ) ,
300
+ Limb ( 0x44556677 ) ,
301
+ Limb ( 0x00112233 )
302
+ ]
267
303
) ;
304
+ assert_eq ! ( n. bits_precision( ) , 128 ) ;
268
305
}
269
306
270
307
#[ test]
271
- fn from_le_slice_bad_precision ( ) {
272
- let bytes = hex ! ( "ffeeddccbbaa99887766554433221100" ) ;
308
+ #[ cfg( target_pointer_width = "64" ) ]
309
+ fn from_le_slice_not_word_sized ( ) {
310
+ let bytes = hex ! ( "ffeeddccbbaa998877665544332211" ) ;
311
+ let n = BoxedUint :: from_le_slice ( & bytes, 127 ) . unwrap ( ) ;
312
+ assert_eq ! (
313
+ n. as_limbs( ) ,
314
+ & [ Limb ( 0x8899aabbccddeeff ) , Limb ( 0x0011223344556677 ) ]
315
+ ) ;
316
+ assert_eq ! ( n. bits_precision( ) , 128 ) ;
317
+ }
318
+
319
+ #[ test]
320
+ fn from_le_slice_non_multiple_precision ( ) {
321
+ let bytes = hex ! ( "ffeeddccbbaa998877665544332211f0" ) ;
273
322
assert_eq ! (
274
- BoxedUint :: from_le_slice( & bytes, 127 ) ,
323
+ BoxedUint :: from_le_slice( & bytes, 121 ) ,
275
324
Err ( DecodeError :: Precision )
276
325
) ;
277
326
}
0 commit comments