8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use std:: num:: One ;
11
+ use std:: num:: { One , Zero , CheckedAdd } ;
12
12
use std:: vec:: bytes:: { MutableByteVector , copy_memory} ;
13
13
14
14
@@ -36,6 +36,18 @@ pub fn write_u32_be(dst: &mut[u8], input: u32) {
36
36
}
37
37
}
38
38
39
+ /// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
40
+ /// format.
41
+ pub fn write_u32_le ( dst : & mut [ u8 ] , input : u32 ) {
42
+ use std:: cast:: transmute;
43
+ use std:: unstable:: intrinsics:: to_le32;
44
+ assert ! ( dst. len( ) == 4 ) ;
45
+ unsafe {
46
+ let x: * mut i32 = transmute ( dst. unsafe_mut_ref ( 0 ) ) ;
47
+ * x = to_le32 ( input as i32 ) ;
48
+ }
49
+ }
50
+
39
51
/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
40
52
pub fn read_u64v_be ( dst : & mut [ u64 ] , input : & [ u8 ] ) {
41
53
use std:: cast:: transmute;
@@ -68,51 +80,90 @@ pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
68
80
}
69
81
}
70
82
83
+ /// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
84
+ pub fn read_u32v_le ( dst : & mut [ u32 ] , input : & [ u8 ] ) {
85
+ use std:: cast:: transmute;
86
+ use std:: unstable:: intrinsics:: to_le32;
87
+ assert ! ( dst. len( ) * 4 == input. len( ) ) ;
88
+ unsafe {
89
+ let mut x: * mut i32 = transmute ( dst. unsafe_mut_ref ( 0 ) ) ;
90
+ let mut y: * i32 = transmute ( input. unsafe_ref ( 0 ) ) ;
91
+ do dst. len ( ) . times ( ) {
92
+ * x = to_le32 ( * y) ;
93
+ x = x. offset ( 1 ) ;
94
+ y = y. offset ( 1 ) ;
95
+ }
96
+ }
97
+ }
98
+
71
99
72
- /// Returns true if adding the two parameters will result in integer overflow
73
- pub fn will_add_overflow < T : Int + Unsigned > ( x : T , y : T ) -> bool {
74
- // This doesn't handle negative values! Don't copy this code elsewhere without considering if
75
- // negative values are important to you!
76
- let max: T = Bounded :: max_value ( ) ;
77
- return x > max - y;
100
+ trait ToBits {
101
+ /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
102
+ /// high-order value and the 2nd item is the low order value.
103
+ fn to_bits ( self ) -> ( Self , Self ) ;
78
104
}
79
105
80
- /// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned
81
- /// integer overflow.
82
- pub fn shift_add_check_overflow < T : Int + Unsigned + Clone > ( x : T , mut y : T , shift : T ) -> T {
83
- if y. leading_zeros ( ) < shift {
84
- fail ! ( "Could not add values - integer overflow." ) ;
106
+ impl ToBits for u64 {
107
+ fn to_bits ( self ) -> ( u64 , u64 ) {
108
+ return ( self >> 61 , self << 3 ) ;
85
109
}
86
- y = y << shift ;
110
+ }
87
111
88
- if will_add_overflow ( x. clone ( ) , y. clone ( ) ) {
89
- fail ! ( "Could not add values - integer overflow." ) ;
90
- }
112
+ /// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
113
+ /// overflow.
114
+ pub fn add_bytes_to_bits < T : Int + CheckedAdd + ToBits > ( bits : T , bytes : T ) -> T {
115
+ let ( new_high_bits, new_low_bits) = bytes. to_bits ( ) ;
91
116
92
- return x + y;
93
- }
117
+ if new_high_bits > Zero :: zero ( ) {
118
+ fail ! ( "Numeric overflow occured." )
119
+ }
94
120
95
- /// Shifts the second parameter and then adds it to the first, which is a tuple where the first
96
- /// element is the high order value. fails!() if there would be unsigned integer overflow.
97
- pub fn shift_add_check_overflow_tuple
98
- < T : Int + Unsigned + Clone >
99
- ( x : ( T , T ) , mut y : T , shift : T ) -> ( T , T ) {
100
- if y. leading_zeros ( ) < shift {
101
- fail ! ( "Could not add values - integer overflow." ) ;
121
+ match bits. checked_add ( & new_low_bits) {
122
+ Some ( x) => return x,
123
+ None => fail ! ( "Numeric overflow occured." )
102
124
}
103
- y = y << shift ;
125
+ }
104
126
105
- match x {
106
- ( hi, low) => {
107
- let one: T = One :: one ( ) ;
108
- if will_add_overflow ( low. clone ( ) , y. clone ( ) ) {
109
- if will_add_overflow ( hi. clone ( ) , one. clone ( ) ) {
110
- fail ! ( "Could not add values - integer overflow." ) ;
111
- } else {
112
- return ( hi + one, low + y) ;
113
- }
127
+ /// Adds the specified number of bytes to the bit count, which is a tuple where the first element is
128
+ /// the high order value. fail!() if this would cause numeric overflow.
129
+ pub fn add_bytes_to_bits_tuple
130
+ < T : Int + Unsigned + CheckedAdd + ToBits >
131
+ ( bits : ( T , T ) , bytes : T ) -> ( T , T ) {
132
+ let ( new_high_bits, new_low_bits) = bytes. to_bits ( ) ;
133
+ let ( hi, low) = bits;
134
+
135
+ // Add the low order value - if there is no overflow, then add the high order values
136
+ // If the addition of the low order values causes overflow, add one to the high order values
137
+ // before adding them.
138
+ match low. checked_add ( & new_low_bits) {
139
+ Some ( x) => {
140
+ if new_high_bits == Zero :: zero ( ) {
141
+ // This is the fast path - every other alternative will rarely occur in practice
142
+ // considering how large an input would need to be for those paths to be used.
143
+ return ( hi, x) ;
114
144
} else {
115
- return ( hi, low + y) ;
145
+ match hi. checked_add ( & new_high_bits) {
146
+ Some ( y) => return ( y, x) ,
147
+ None => fail ! ( "Numeric overflow occured." )
148
+ }
149
+ }
150
+ } ,
151
+ None => {
152
+ let one: T = One :: one ( ) ;
153
+ let z = match new_high_bits. checked_add ( & one) {
154
+ Some ( w) => w,
155
+ None => fail ! ( "Numeric overflow occured." )
156
+ } ;
157
+ match hi. checked_add ( & z) {
158
+ // This re-executes the addition that was already performed earlier when overflow
159
+ // occured, this time allowing the overflow to happen. Technically, this could be
160
+ // avoided by using the checked add intrinsic directly, but that involves using
161
+ // unsafe code and is not really worthwhile considering how infrequently code will
162
+ // run in practice. This is the reason that this function requires that the type T
163
+ // be Unsigned - overflow is not defined for Signed types. This function could be
164
+ // implemented for signed types as well if that were needed.
165
+ Some ( y) => return ( y, low + new_low_bits) ,
166
+ None => fail ! ( "Numeric overflow occured." )
116
167
}
117
168
}
118
169
}
@@ -300,6 +351,7 @@ mod test {
300
351
use std:: rand:: RngUtil ;
301
352
use std:: vec;
302
353
354
+ use cryptoutil:: { add_bytes_to_bits, add_bytes_to_bits_tuple} ;
303
355
use digest:: Digest ;
304
356
305
357
/// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
@@ -324,4 +376,50 @@ mod test {
324
376
325
377
assert ! ( expected == result_str) ;
326
378
}
379
+
380
+ // A normal addition - no overflow occurs
381
+ #[ test]
382
+ fn test_add_bytes_to_bits_ok ( ) {
383
+ assert ! ( add_bytes_to_bits:: <u64 >( 100 , 10 ) == 180 ) ;
384
+ }
385
+
386
+ // A simple failure case - adding 1 to the max value
387
+ #[ test]
388
+ #[ should_fail]
389
+ fn test_add_bytes_to_bits_overflow ( ) {
390
+ add_bytes_to_bits :: < u64 > ( Bounded :: max_value ( ) , 1 ) ;
391
+ }
392
+
393
+ // A normal addition - no overflow occurs (fast path)
394
+ #[ test]
395
+ fn test_add_bytes_to_bits_tuple_ok ( ) {
396
+ assert ! ( add_bytes_to_bits_tuple:: <u64 >( ( 5 , 100 ) , 10 ) == ( 5 , 180 ) ) ;
397
+ }
398
+
399
+ // The low order value overflows into the high order value
400
+ #[ test]
401
+ fn test_add_bytes_to_bits_tuple_ok2 ( ) {
402
+ assert ! ( add_bytes_to_bits_tuple:: <u64 >( ( 5 , Bounded :: max_value( ) ) , 1 ) == ( 6 , 7 ) ) ;
403
+ }
404
+
405
+ // The value to add is too large to be converted into bits without overflowing its type
406
+ #[ test]
407
+ fn test_add_bytes_to_bits_tuple_ok3 ( ) {
408
+ assert ! ( add_bytes_to_bits_tuple:: <u64 >( ( 5 , 0 ) , 0x4000000000000001 ) == ( 7 , 8 ) ) ;
409
+ }
410
+
411
+ // A simple failure case - adding 1 to the max value
412
+ #[ test]
413
+ #[ should_fail]
414
+ fn test_add_bytes_to_bits_tuple_overflow ( ) {
415
+ add_bytes_to_bits_tuple :: < u64 > ( ( Bounded :: max_value ( ) , Bounded :: max_value ( ) ) , 1 ) ;
416
+ }
417
+
418
+ // The value to add is too large to convert to bytes without overflowing its type, but the high
419
+ // order value from this conversion overflows when added to the existing high order value
420
+ #[ test]
421
+ #[ should_fail]
422
+ fn test_add_bytes_to_bits_tuple_overflow2 ( ) {
423
+ add_bytes_to_bits_tuple :: < u64 > ( ( Bounded :: max_value :: < u64 > ( ) - 1 , 0 ) , 0x8000000000000000 ) ;
424
+ }
327
425
}
0 commit comments