diff --git a/.gitignore b/.gitignore index 7cb988a..a0dd2c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target .idea -Cargo.lock \ No newline at end of file +Cargo.lock +*.swp diff --git a/benches/bigint.rs b/benches/bigint.rs index dffcc10..c6a1b26 100644 --- a/benches/bigint.rs +++ b/benches/bigint.rs @@ -101,3 +101,28 @@ fn u128_mul(b: &mut Bencher) { }); } +#[bench] +fn u256_from_le(b: &mut Bencher) { + b.iter(|| { + let raw = black_box([ + 1u8, 2, 3, 5, 7, 11, 13, 17, + 19, 23, 29, 31, 37, 41, 43, 47, + 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127 + ]); + let _ = U256::from_little_endian(&raw[..]); + }); +} + +#[bench] +fn u256_from_be(b: &mut Bencher) { + b.iter(|| { + let raw = black_box([ + 1u8, 2, 3, 5, 7, 11, 13, 17, + 19, 23, 29, 31, 37, 41, 43, 47, + 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127 + ]); + let _ = U256::from_big_endian(&raw[..]); + }); +} diff --git a/src/uint.rs b/src/uint.rs index 451d18b..a5c2073 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -29,7 +29,7 @@ //! implementations for even more speed, hidden behind the `x64_arithmetic` //! feature flag. -use core::str; +use core::{str, mem}; use core::ops::{Shr, Shl, BitAnd, BitOr, BitXor, Not, Div, Rem, Mul, Add, Sub}; use byteorder::{ByteOrder, BigEndian, LittleEndian}; @@ -392,16 +392,20 @@ macro_rules! uint_overflowing_mul_reg { let $name(ref you) = $other; let mut ret = [0u64; 2*$n_words]; - for i in 0..$n_words { + let mut i = 0; + for _ in 0..$n_words { if you[i] == 0 { + i += 1; continue; } let mut carry2 = 0u64; let (b_u, b_l) = split(you[i]); - for j in 0..$n_words { + let mut j = 0; + for _ in 0..$n_words { if me[j] == 0 && carry2 == 0 { + j += 1; continue; } @@ -422,17 +426,21 @@ macro_rules! uint_overflowing_mul_reg { // Only single overflow possible there carry2 = (o1 | o2 | o3) as u64; + j += 1; } + i += 1; } let mut res = [0u64; $n_words]; let mut overflow = false; - for i in 0..$n_words { - res[i] = ret[i]; - } + res.copy_from_slice(&ret[0..$n_words]); - for i in $n_words..2*$n_words { - overflow |= ret[i] != 0; + unsafe { + let mut ret_ptr = ret.as_ptr().offset($n_words); + for _ in $n_words..2*$n_words { + overflow |= *ret_ptr != 0; + ret_ptr = ret_ptr.offset(1); + } } ($name(res), overflow) @@ -809,11 +817,17 @@ macro_rules! construct_uint { assert!($n_words * 8 >= slice.len()); let mut ret = [0; $n_words]; - for i in 0..slice.len() { - let rev = slice.len() - 1 - i; - let pos = rev / 8; - ret[pos] += (slice[i] as u64) << ((rev % 8) * 8); + unsafe { + let ret_u8: &mut [u8; $n_words * 8] = mem::transmute(&mut ret); + let mut ret_ptr = ret_u8.as_mut_ptr(); + let mut slice_ptr = slice.as_ptr().offset(slice.len() as isize - 1); + for _ in 0..slice.len() { + *ret_ptr = *slice_ptr; + ret_ptr = ret_ptr.offset(1); + slice_ptr = slice_ptr.offset(-1); + } } + $name(ret) } @@ -822,10 +836,11 @@ macro_rules! construct_uint { assert!($n_words * 8 >= slice.len()); let mut ret = [0; $n_words]; - for i in 0..slice.len() { - let pos = i / 8; - ret[pos] += (slice[i] as u64) << ((i % 8) * 8); + unsafe { + let ret_u8: &mut [u8; $n_words * 8] = mem::transmute(&mut ret); + ret_u8[0..slice.len()].copy_from_slice(&slice); } + $name(ret) } } @@ -2419,6 +2434,24 @@ mod tests { assert_eq!(&raw, &new_raw); } + #[test] + fn slice_roundtrip_le2() { + let raw = [ + 2, 3, 5, 7, 11, 13, 17, + 19, 23, 29, 31, 37, 41, 43, 47, + 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127 + ]; + + let u256 = U256::from_little_endian(&raw[..]); + + let mut new_raw = [0u8; 32]; + + u256.to_little_endian(&mut new_raw); + + assert_eq!(&raw, &new_raw[..31]); + } + #[test] fn fixed_arrays_roundtrip() { let raw: U256 = "7094875209347850239487502394881".into(); @@ -2427,4 +2460,32 @@ mod tests { assert_eq!(raw, new_raw); } + + #[test] + fn from_little_endian() { + let source: [u8; 32] = [ + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + ]; + + let number = U256::from_little_endian(&source[..]); + + assert_eq!(U256::from(1), number); + } + + #[test] + fn from_big_endian() { + let source: [u8; 32] = [ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + ]; + + let number = U256::from_big_endian(&source[..]); + + assert_eq!(U256::from(1), number); + } }