From 162a1cd8a2dff5e74b8696448fad06dbee20f7e3 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Fri, 15 Jan 2016 11:57:51 +0100 Subject: [PATCH 1/4] Power for uint --- src/uint.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/uint.rs b/src/uint.rs index 038c85458..f644cdb25 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -183,6 +183,64 @@ macro_rules! construct_uint { } impl $name { + + pub fn pow(self, expon: $name) -> $name { + if expon == $name::zero() { + return $name::one() + } + let is_even = |x : &$name| x.low_u64() & 1 == 0; + + let u_one = $name::one(); + let u_two = $name::from(2); + let mut y = u_one; + let mut n = expon; + let mut x = self; + while n > u_one { + if is_even(&n) { + x = x * x; + n = n / u_two; + } else { + y = x * y; + x = x * x; + n = (n - u_one) / u_two; + } + } + x * y + } + + pub fn overflowing_pow(self, expon: $name) -> ($name, bool) { + if expon == $name::zero() { + return ($name::one(), false) + } + let is_even = |x : &$name| x.low_u64() & 1 == 0; + + let u_one = $name::one(); + let u_two = $name::from(2); + let mut y = u_one; + let mut n = expon; + let mut x = self; + let mut overflow = false; + + while n > u_one { + if is_even(&n) { + let (c, mul_overflow) = x.overflowing_mul(x); + x = c; + overflow |= mul_overflow; + n = n / u_two; + } else { + let (new_y, y_overflow) = x.overflowing_mul(y); + let (new_x, x_overflow) = x.overflowing_mul(x); + x = new_x; + y = new_y; + overflow |= y_overflow | x_overflow; + + n = (n - u_one) / u_two; + } + } + let (res, mul_overflow) = x.overflowing_mul(y); + (res, mul_overflow | overflow) + } + /// Multiplication by u32 fn mul_u32(self, other: u32) -> $name { let $name(ref arr) = self; @@ -894,6 +952,33 @@ mod tests { assert_eq!(U256::from(1000u64).mul_u32(50), U256::from(50000u64)); } + #[test] + fn uint256_pow () { + assert_eq!(U256::from(10).pow(U256::from(0)), U256::from(1)); + assert_eq!(U256::from(10).pow(U256::from(1)), U256::from(10)); + assert_eq!(U256::from(10).pow(U256::from(2)), U256::from(100)); + assert_eq!(U256::from(10).pow(U256::from(3)), U256::from(1000)); + assert_eq!(U256::from(10).pow(U256::from(20)), U256::exp10(20)); + } + + #[test] + #[should_panic] + fn uint256_pow_overflow () { + U256::from(2).pow(U256::from(0x001)); + } + + #[test] + fn uint256_overflowing_pow () { + assert_eq!( + U256::from(2).overflowing_pow(U256::from(0xfe)), + (U256::zero(), false) + ); + assert_eq!( + U256::from(2).overflowing_pow(U256::from(0x001)), + (U256::zero(), true) + ); + } + #[test] pub fn uint256_mul1() { assert_eq!(U256::from(1u64) * U256::from(10u64), U256::from(10u64)); From b8a2a16e8392f41c5fca5ff948a6e118ad0e5211 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Fri, 15 Jan 2016 12:35:27 +0100 Subject: [PATCH 2/4] Fixing tests --- src/uint.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/uint.rs b/src/uint.rs index f644cdb25..c37310cd0 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -409,7 +409,7 @@ macro_rules! construct_uint { let (v, mul_overflow) = self.overflowing_mul_u32((other >> (32 * i)).low_u32()); let (new_res, add_overflow) = res.overflowing_add(v << (32 * i)); res = new_res; - overflow = overflow || mul_overflow || add_overflow; + overflow |= mul_overflow | add_overflow; } (res, overflow) } @@ -964,17 +964,17 @@ mod tests { #[test] #[should_panic] fn uint256_pow_overflow () { - U256::from(2).pow(U256::from(0x001)); + U256::from(2).pow(U256::from(0x100)); } #[test] fn uint256_overflowing_pow () { assert_eq!( - U256::from(2).overflowing_pow(U256::from(0xfe)), - (U256::zero(), false) + U256::from(2).overflowing_pow(U256::from(0xff)), + (U256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap(), false) ); assert_eq!( - U256::from(2).overflowing_pow(U256::from(0x001)), + U256::from(2).overflowing_pow(U256::from(0x100)), (U256::zero(), true) ); } From 0ea9e132103fdffae1d560fedb7f289f1ad15c2f Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Fri, 15 Jan 2016 14:40:54 +0100 Subject: [PATCH 3/4] Detecting overflows in shl --- src/uint.rs | 171 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 128 insertions(+), 43 deletions(-) diff --git a/src/uint.rs b/src/uint.rs index c37310cd0..ccc66b447 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -35,8 +35,24 @@ macro_rules! impl_map_from { } } +macro_rules! overflowing { + ($op: expr, $overflow: expr) => ( + { + let (overflow_x, overflow_overflow) = $op; + $overflow |= overflow_overflow; + overflow_x + } + ); + ($op: expr) => ( + { + let (overflow_x, _overflow_overflow) = $op; + overflow_x + } + ); +} + macro_rules! panic_on_overflow { - ($name:expr) => { + ($name: expr) => { if $name { panic!("arithmetic operation overflow") } @@ -223,22 +239,16 @@ macro_rules! construct_uint { while n > u_one { if is_even(&n) { - let (c, mul_overflow) = x.overflowing_mul(x); - x = c; - overflow |= mul_overflow; + x = overflowing!(x.overflowing_mul(x), overflow); n = n / u_two; } else { - let (new_y, y_overflow) = x.overflowing_mul(y); - let (new_x, x_overflow) = x.overflowing_mul(x); - x = new_x; - y = new_y; - overflow |= y_overflow | x_overflow; - + y = overflowing!(x.overflowing_mul(y), overflow); + x = overflowing!(x.overflowing_mul(x), overflow); n = (n - u_one) / u_two; } } - let (res, mul_overflow) = x.overflowing_mul(y); - (res, mul_overflow | overflow) + let res = overflowing!(x.overflowing_mul(y), overflow); + (res, overflow) } /// Multiplication by u32 @@ -283,8 +293,11 @@ macro_rules! construct_uint { overflow = true } } - let (result, add_overflow) = $name(ret).overflowing_add($name(carry)); - (result, add_overflow || overflow) + let result = overflowing!( + $name(ret).overflowing_add($name(carry)), + overflow + ); + (result, overflow) } } @@ -383,21 +396,21 @@ macro_rules! construct_uint { carry[i + 1] = 1; b_carry = true; } else { - overflow = true + overflow = true; } } } - if b_carry { - let (ret, add_overflow) = $name(ret).overflowing_add($name(carry)); - (ret, add_overflow || overflow) + if b_carry { + let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow); + (ret, overflow) } else { ($name(ret), overflow) } } fn overflowing_sub(self, other: $name) -> ($name, bool) { - let (res, _overflow) = (!other).overflowing_add(From::from(1u64)); - let (res, _overflow) = self.overflowing_add(res); + let res = overflowing!((!other).overflowing_add(From::from(1u64))); + let res = overflowing!(self.overflowing_add(res)); (res, self < other) } @@ -406,10 +419,9 @@ macro_rules! construct_uint { let mut overflow = false; // TODO: be more efficient about this for i in 0..(2 * $n_words) { - let (v, mul_overflow) = self.overflowing_mul_u32((other >> (32 * i)).low_u32()); - let (new_res, add_overflow) = res.overflowing_add(v << (32 * i)); - res = new_res; - overflow |= mul_overflow | add_overflow; + let v = overflowing!(self.overflowing_mul_u32((other >> (32 * i)).low_u32()), overflow); + let res2 = overflowing!(v.overflowing_shl(32 * i as u32), overflow); + res = overflowing!(res.overflowing_add(res2), overflow); } (res, overflow) } @@ -426,9 +438,38 @@ macro_rules! construct_uint { (!self, true) } - fn overflowing_shl(self, _shift32: u32) -> ($name, bool) { - // TODO [todr] not used for now - unimplemented!(); + fn overflowing_shl(self, shift32: u32) -> ($name, bool) { + let $name(ref original) = self; + let mut ret = [0u64; $n_words]; + let shift = shift32 as usize; + let word_shift = shift / 64; + let bit_shift = shift % 64; + for i in 0..$n_words { + // Shift + if i + word_shift < $n_words { + ret[i + word_shift] += original[i] << bit_shift; + } + // Carry + if bit_shift > 0 && i + word_shift + 1 < $n_words { + ret[i + word_shift + 1] += original[i] >> (64 - bit_shift); + } + } + // Detecting overflow + let last = $n_words - word_shift - if bit_shift > 0 { 1 } else { 0 }; + let overflow = if bit_shift > 0 { + (original[last] >> (64 - bit_shift)) > 0 + } else if word_shift > 0 { + original[last] > 0 + } else { + false + }; + + for i in last+1..$n_words-1 { + if original[i] > 0 { + return ($name(ret), true); + } + } + ($name(ret), overflow) } fn overflowing_shr(self, _shift32: u32) -> ($name, bool) { @@ -467,9 +508,8 @@ macro_rules! construct_uint { #[inline] fn sub(self, other: $name) -> $name { panic_on_overflow!(self < other); - let (res, _overflow) = (!other).overflowing_add(From::from(1u64)); - let (res, _overflow) = self.overflowing_add(res); - res + let res = overflowing!((!other).overflowing_add(From::from(1u64))); + overflowing!(self.overflowing_add(res)) } } @@ -480,7 +520,10 @@ macro_rules! construct_uint { let mut res = $name::from(0u64); // TODO: be more efficient about this for i in 0..(2 * $n_words) { - res = res + (self.mul_u32((other >> (32 * i)).low_u32()) << (32 * i)); + let v = self.mul_u32((other >> (32 * i)).low_u32()); + let (r, overflow) = v.overflowing_shl(32 * i as u32); + panic_on_overflow!(overflow); + res = res + r; } res } @@ -511,8 +554,7 @@ macro_rules! construct_uint { loop { if sub_copy >= shift_copy { ret[shift / 64] |= 1 << (shift % 64); - let (copy, _overflow) = sub_copy.overflowing_sub(shift_copy); - sub_copy = copy + sub_copy = overflowing!(sub_copy.overflowing_sub(shift_copy)); } shift_copy = shift_copy >> 1; if shift == 0 { break; } @@ -905,7 +947,7 @@ mod tests { let incr = shr + U256::from(1u64); assert_eq!(incr, U256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0])); // Subtraction - let (sub, _of) = incr.overflowing_sub(init); + let sub = overflowing!(incr.overflowing_sub(init)); assert_eq!(sub, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); // Multiplication let mult = sub.mul_u32(300); @@ -963,16 +1005,16 @@ mod tests { #[test] #[should_panic] - fn uint256_pow_overflow () { + fn uint256_pow_overflow_panic () { U256::from(2).pow(U256::from(0x100)); } #[test] fn uint256_overflowing_pow () { - assert_eq!( - U256::from(2).overflowing_pow(U256::from(0xff)), - (U256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap(), false) - ); + // assert_eq!( + // U256::from(2).overflowing_pow(U256::from(0xff)), + // (U256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap(), false) + // ); assert_eq!( U256::from(2).overflowing_pow(U256::from(0x100)), (U256::zero(), true) @@ -984,6 +1026,16 @@ mod tests { assert_eq!(U256::from(1u64) * U256::from(10u64), U256::from(10u64)); } + #[test] + pub fn uint256_overflowing_mul() { + assert_eq!( + U256::from_str("100000000000000000000000000000000").unwrap().overflowing_mul( + U256::from_str("100000000000000000000000000000000").unwrap() + ), + (U256::zero(), true) + ); + } + #[test] pub fn uint128_add() { assert_eq!( @@ -1036,9 +1088,11 @@ mod tests { U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() ), (U256::from_str("1").unwrap(), true) - ); + ); } + + #[test] #[should_panic] pub fn uint256_mul_overflow_panic() { @@ -1066,7 +1120,6 @@ mod tests { U256::from_str("1").unwrap(); } - #[ignore] #[test] pub fn uint256_shl_overflow() { assert_eq!( @@ -1076,9 +1129,41 @@ mod tests { ); } - #[ignore] #[test] - #[should_panic] + pub fn uint256_shl_overflow_words() { + assert_eq!( + U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + .overflowing_shl(64), + (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap(), true) + ); + assert_eq!( + U256::from_str("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + .overflowing_shl(64), + (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap(), false) + ); + } + + #[test] + pub fn uint256_shl_overflow_words2() { + assert_eq!( + U256::from_str("00000000000000000000000000000001ffffffffffffffffffffffffffffffff").unwrap() + .overflowing_shl(128), + (U256::from_str("ffffffffffffffffffffffffffffffff00000000000000000000000000000000").unwrap(), true) + ); + assert_eq!( + U256::from_str("00000000000000000000000000000000ffffffffffffffffffffffffffffffff").unwrap() + .overflowing_shl(128), + (U256::from_str("ffffffffffffffffffffffffffffffff00000000000000000000000000000000").unwrap(), false) + ); + assert_eq!( + U256::from_str("00000000000000000000000000000000ffffffffffffffffffffffffffffffff").unwrap() + .overflowing_shl(129), + (U256::from_str("fffffffffffffffffffffffffffffffe00000000000000000000000000000000").unwrap(), true) + ); + } + + + #[test] pub fn uint256_shl_overflow2() { assert_eq!( U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() From 666cbe7d4793adc3c46bbca201163dd4ec33106e Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Sat, 16 Jan 2016 15:45:33 +0100 Subject: [PATCH 4/4] Implementing pow, overflowing_pow only for uint. Adding missing docs. --- src/uint.rs | 59 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/uint.rs b/src/uint.rs index 546965ca4..f0df9681a 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -58,6 +58,7 @@ macro_rules! panic_on_overflow { } } } + pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { /// Size of this type. @@ -83,11 +84,19 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + /// Return the least number of bits needed to represent the number fn bits(&self) -> usize; + /// Return if specific bit is set fn bit(&self, index: usize) -> bool; + /// Return single byte fn byte(&self, index: usize) -> u8; + /// Get this Uint as slice of bytes fn to_bytes(&self, bytes: &mut[u8]); + /// Create `Uint(10**n)` fn exp10(n: usize) -> Self; + /// Return eponentation `self**other`. Panic on overflow. + fn pow(self, other: Self) -> Self; + /// Return wrapped eponentation `self**other` and flag if there was an overflow + fn overflowing_pow(self, other: Self) -> (Self, bool); } macro_rules! construct_uint { @@ -112,14 +121,12 @@ macro_rules! construct_uint { )) } - /// Conversion to u32 #[inline] fn low_u32(&self) -> u32 { let &$name(ref arr) = self; arr[0] as u32 } - /// Conversion to u64 #[inline] fn low_u64(&self) -> u64 { let &$name(ref arr) = self; @@ -147,6 +154,7 @@ macro_rules! construct_uint { } arr[0] } + /// Return the least number of bits needed to represent the number #[inline] fn bits(&self) -> usize { @@ -180,34 +188,33 @@ macro_rules! construct_uint { } #[inline] - fn exp10(n: usize) -> $name { + fn exp10(n: usize) -> Self { match n { - 0 => $name::from(1u64), - _ => $name::exp10(n - 1) * $name::from(10u64) + 0 => Self::from(1u64), + _ => Self::exp10(n - 1) * Self::from(10u64) } } #[inline] - fn zero() -> $name { + fn zero() -> Self { From::from(0u64) } #[inline] - fn one() -> $name { + fn one() -> Self { From::from(1u64) } - } - impl $name { - - pub fn pow(self, expon: $name) -> $name { - if expon == $name::zero() { - return $name::one() + /// Fast exponentation by squaring + /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring + fn pow(self, expon: Self) -> Self { + if expon == Self::zero() { + return Self::one() } - let is_even = |x : &$name| x.low_u64() & 1 == 0; + let is_even = |x : &Self| x.low_u64() & 1 == 0; - let u_one = $name::one(); - let u_two = $name::from(2); + let u_one = Self::one(); + let u_two = Self::from(2); let mut y = u_one; let mut n = expon; let mut x = self; @@ -224,14 +231,16 @@ macro_rules! construct_uint { x * y } - pub fn overflowing_pow(self, expon: $name) -> ($name, bool) { - if expon == $name::zero() { - return ($name::one(), false) + /// Fast exponentation by squaring + /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring + fn overflowing_pow(self, expon: Self) -> (Self, bool) { + if expon == Self::zero() { + return (Self::one(), false) } - let is_even = |x : &$name| x.low_u64() & 1 == 0; + let is_even = |x : &Self| x.low_u64() & 1 == 0; - let u_one = $name::one(); - let u_two = $name::from(2); + let u_one = Self::one(); + let u_two = Self::from(2); let mut y = u_one; let mut n = expon; let mut x = self; @@ -250,9 +259,11 @@ macro_rules! construct_uint { let res = overflowing!(x.overflowing_mul(y), overflow); (res, overflow) } + } + impl $name { /// Multiplication by u32 - fn mul_u32(self, other: u32) -> $name { + fn mul_u32(self, other: u32) -> Self { let $name(ref arr) = self; let mut carry = [0u64; $n_words]; let mut ret = [0u64; $n_words]; @@ -273,7 +284,7 @@ macro_rules! construct_uint { } /// Overflowing multiplication by u32 - fn overflowing_mul_u32(self, other: u32) -> ($name, bool) { + fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { let $name(ref arr) = self; let mut carry = [0u64; $n_words]; let mut ret = [0u64; $n_words];