88// option. This file may not be copied, modified, or distributed 
99// except according to those terms. 
1010
11- use  std:: num:: One ; 
11+ use  std:: num:: { One ,   Zero ,   CheckedAdd } ; 
1212use  std:: vec:: bytes:: { MutableByteVector ,  copy_memory} ; 
1313
1414
@@ -36,6 +36,18 @@ pub fn write_u32_be(dst: &mut[u8], input: u32) {
3636    } 
3737} 
3838
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+ 
3951/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format. 
4052pub  fn  read_u64v_be ( dst :  & mut [ u64 ] ,  input :  & [ u8 ] )  { 
4153    use  std:: cast:: transmute; 
@@ -68,51 +80,90 @@ pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
6880    } 
6981} 
7082
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+ 
7199
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 ) ; 
78104} 
79105
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 ) ; 
85109    } 
86-     y = y << shift ; 
110+ } 
87111
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 ( ) ; 
91116
92-     return  x + y; 
93- } 
117+     if  new_high_bits > Zero :: zero ( )  { 
118+         fail ! ( "Numeric overflow occured." ) 
119+     } 
94120
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." ) 
102124    } 
103-     y = y << shift ; 
125+ } 
104126
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) ; 
114144            }  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." ) 
116167            } 
117168        } 
118169    } 
@@ -300,6 +351,7 @@ mod test {
300351    use  std:: rand:: RngUtil ; 
301352    use  std:: vec; 
302353
354+     use  cryptoutil:: { add_bytes_to_bits,  add_bytes_to_bits_tuple} ; 
303355    use  digest:: Digest ; 
304356
305357    /// 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 {
324376
325377        assert ! ( expected == result_str) ; 
326378    } 
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+     } 
327425} 
0 commit comments