This commit is contained in:
debris 2016-01-15 02:32:59 +01:00
commit 9a3944d890
2 changed files with 267 additions and 13 deletions

View File

@ -1,5 +1,6 @@
#![feature(op_assign_traits)] #![feature(op_assign_traits)]
#![feature(associated_consts)] #![feature(associated_consts)]
#![feature(wrapping)]
//! Ethcore-util library //! Ethcore-util library
//! //!
//! ### Rust version: //! ### Rust version:

View File

@ -23,6 +23,7 @@
use standard::*; use standard::*;
use from_json::*; use from_json::*;
use std::num::wrapping::OverflowingOps;
macro_rules! impl_map_from { macro_rules! impl_map_from {
($thing:ident, $from:ty, $to:ty) => { ($thing:ident, $from:ty, $to:ty) => {
@ -34,6 +35,13 @@ macro_rules! impl_map_from {
} }
} }
macro_rules! panic_on_overflow {
($name:expr) => {
if $name {
panic!("arithmetic operation overflow")
}
}
}
pub trait Uint: Sized + Default + FromStr + From<u64> + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { pub trait Uint: Sized + Default + FromStr + From<u64> + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash {
/// Size of this type. /// Size of this type.
@ -183,13 +191,43 @@ macro_rules! construct_uint {
for i in 0..$n_words { for i in 0..$n_words {
let upper = other as u64 * (arr[i] >> 32); let upper = other as u64 * (arr[i] >> 32);
let lower = other as u64 * (arr[i] & 0xFFFFFFFF); let lower = other as u64 * (arr[i] & 0xFFFFFFFF);
if i < 3 {
carry[i + 1] += upper >> 32; ret[i] = lower.wrapping_add(upper << 32);
if i < $n_words - 1 {
carry[i + 1] = upper >> 32;
if ret[i] < lower {
carry[i + 1] += 1;
}
} }
ret[i] = lower + (upper << 32);
} }
$name(ret) + $name(carry) $name(ret) + $name(carry)
} }
/// Overflowing multiplication by u32
fn overflowing_mul_u32(self, other: u32) -> ($name, bool) {
let $name(ref arr) = self;
let mut carry = [0u64; $n_words];
let mut ret = [0u64; $n_words];
let mut overflow = false;
for i in 0..$n_words {
let upper = other as u64 * (arr[i] >> 32);
let lower = other as u64 * (arr[i] & 0xFFFFFFFF);
ret[i] = lower.wrapping_add(upper << 32);
if i < $n_words - 1 {
carry[i + 1] = upper >> 32;
if ret[i] < lower {
carry[i + 1] += 1;
}
} else if (upper >> 32) > 0 || ret[i] < lower {
overflow = true
}
}
let (result, add_overflow) = $name(ret).overflowing_add($name(carry));
(result, add_overflow || overflow)
}
} }
impl Default for $name { impl Default for $name {
@ -270,6 +308,77 @@ macro_rules! construct_uint {
} }
} }
impl OverflowingOps for $name {
fn overflowing_add(self, other: $name) -> ($name, bool) {
let $name(ref me) = self;
let $name(ref you) = other;
let mut ret = [0u64; $n_words];
let mut carry = [0u64; $n_words];
let mut b_carry = false;
let mut overflow = false;
for i in 0..$n_words {
ret[i] = me[i].wrapping_add(you[i]);
if ret[i] < me[i] {
if i < $n_words - 1 {
carry[i + 1] = 1;
b_carry = true;
} else {
overflow = true
}
}
}
if b_carry {
let (ret, add_overflow) = $name(ret).overflowing_add($name(carry));
(ret, add_overflow || 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);
(res, self < other)
}
fn overflowing_mul(self, other: $name) -> ($name, bool) {
let mut res = $name::from(0u64);
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 = overflow || mul_overflow || add_overflow;
}
(res, overflow)
}
fn overflowing_div(self, other: $name) -> ($name, bool) {
(self / other, false)
}
fn overflowing_rem(self, other: $name) -> ($name, bool) {
(self % other, false)
}
fn overflowing_neg(self) -> ($name, bool) {
(!self, true)
}
fn overflowing_shl(self, _shift32: u32) -> ($name, bool) {
// TODO [todr] not used for now
unimplemented!();
}
fn overflowing_shr(self, _shift32: u32) -> ($name, bool) {
// TODO [todr] not used for now
unimplemented!();
}
}
impl Add<$name> for $name { impl Add<$name> for $name {
type Output = $name; type Output = $name;
@ -280,11 +389,15 @@ macro_rules! construct_uint {
let mut carry = [0u64; $n_words]; let mut carry = [0u64; $n_words];
let mut b_carry = false; let mut b_carry = false;
for i in 0..$n_words { for i in 0..$n_words {
if i < $n_words - 1 {
ret[i] = me[i].wrapping_add(you[i]); ret[i] = me[i].wrapping_add(you[i]);
if i < $n_words - 1 && ret[i] < me[i] { if ret[i] < me[i] {
carry[i + 1] = 1; carry[i + 1] = 1;
b_carry = true; b_carry = true;
} }
} else {
ret[i] = me[i] + you[i];
}
} }
if b_carry { $name(ret) + $name(carry) } else { $name(ret) } if b_carry { $name(ret) + $name(carry) } else { $name(ret) }
} }
@ -295,7 +408,10 @@ macro_rules! construct_uint {
#[inline] #[inline]
fn sub(self, other: $name) -> $name { fn sub(self, other: $name) -> $name {
self + !other + From::from(1u64) panic_on_overflow!(self < other);
let (res, _overflow) = (!other).overflowing_add(From::from(1u64));
let (res, _overflow) = self.overflowing_add(res);
res
} }
} }
@ -337,7 +453,8 @@ macro_rules! construct_uint {
loop { loop {
if sub_copy >= shift_copy { if sub_copy >= shift_copy {
ret[shift / 64] |= 1 << (shift % 64); ret[shift / 64] |= 1 << (shift % 64);
sub_copy = sub_copy - shift_copy; let (copy, _overflow) = sub_copy.overflowing_sub(shift_copy);
sub_copy = copy
} }
shift_copy = shift_copy >> 1; shift_copy = shift_copy >> 1;
if shift == 0 { break; } if shift == 0 { break; }
@ -426,7 +543,7 @@ macro_rules! construct_uint {
let bit_shift = shift % 64; let bit_shift = shift % 64;
for i in 0..$n_words { for i in 0..$n_words {
// Shift // Shift
if bit_shift < 64 && i + word_shift < $n_words { if i + word_shift < $n_words {
ret[i + word_shift] += original[i] << bit_shift; ret[i + word_shift] += original[i] << bit_shift;
} }
// Carry // Carry
@ -602,8 +719,9 @@ pub const BAD_U256: U256 = U256([0xffffffffffffffffu64; 4]);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use uint::{Uint, U256}; use uint::{Uint, U128, U256, U512};
use std::str::FromStr; use std::str::FromStr;
use std::num::wrapping::OverflowingOps;
#[test] #[test]
pub fn uint256_from() { pub fn uint256_from() {
@ -729,7 +847,7 @@ mod tests {
let incr = shr + U256::from(1u64); let incr = shr + U256::from(1u64);
assert_eq!(incr, U256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0])); assert_eq!(incr, U256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0]));
// Subtraction // Subtraction
let sub = incr - init; let (sub, _of) = incr.overflowing_sub(init);
assert_eq!(sub, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); assert_eq!(sub, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0]));
// Multiplication // Multiplication
let mult = sub.mul_u32(300); let mult = sub.mul_u32(300);
@ -777,10 +895,145 @@ mod tests {
} }
#[test] #[test]
pub fn uint256_mul() { pub fn uint256_mul1() {
assert_eq!(U256::from(1u64) * U256::from(10u64), U256::from(10u64)); assert_eq!(U256::from(1u64) * U256::from(10u64), U256::from(10u64));
} }
#[test]
pub fn uint128_add() {
assert_eq!(
U128::from_str("fffffffffffffffff").unwrap() + U128::from_str("fffffffffffffffff").unwrap(),
U128::from_str("1ffffffffffffffffe").unwrap()
);
}
#[test]
pub fn uint128_add_overflow() {
assert_eq!(
U128::from_str("ffffffffffffffffffffffffffffffff").unwrap()
.overflowing_add(
U128::from_str("ffffffffffffffffffffffffffffffff").unwrap()
),
(U128::from_str("fffffffffffffffffffffffffffffffe").unwrap(), true)
);
}
#[test]
#[should_panic]
pub fn uint128_add_overflow_panic() {
U128::from_str("ffffffffffffffffffffffffffffffff").unwrap()
+
U128::from_str("ffffffffffffffffffffffffffffffff").unwrap();
}
#[test]
pub fn uint128_mul() {
assert_eq!(
U128::from_str("fffffffff").unwrap() * U128::from_str("fffffffff").unwrap(),
U128::from_str("ffffffffe000000001").unwrap());
}
#[test]
pub fn uint512_mul() {
assert_eq!(
U512::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
*
U512::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(),
U512::from_str("3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001").unwrap()
);
}
#[test]
pub fn uint256_mul_overflow() {
assert_eq!(
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
.overflowing_mul(
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
),
(U256::from_str("1").unwrap(), true)
);
}
#[test]
#[should_panic]
pub fn uint256_mul_overflow_panic() {
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
*
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
}
#[test]
pub fn uint256_sub_overflow() {
assert_eq!(
U256::from_str("0").unwrap()
.overflowing_sub(
U256::from_str("1").unwrap()
),
(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), true)
);
}
#[test]
#[should_panic]
pub fn uint256_sub_overflow_panic() {
U256::from_str("0").unwrap()
-
U256::from_str("1").unwrap();
}
#[ignore]
#[test]
pub fn uint256_shl_overflow() {
assert_eq!(
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
.overflowing_shl(4),
(U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap(), true)
);
}
#[ignore]
#[test]
#[should_panic]
pub fn uint256_shl_overflow2() {
assert_eq!(
U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
.overflowing_shl(4),
(U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap(), false)
);
}
#[ignore]
#[test]
pub fn uint256_shr_overflow() {
assert_eq!(
U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
.overflowing_shr(4),
(U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), true)
);
}
#[ignore]
#[test]
pub fn uint256_shr_overflow2() {
assert_eq!(
U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap()
.overflowing_shr(4),
(U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), false)
);
}
#[test]
pub fn uint256_mul() {
assert_eq!(
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
*
U256::from_str("2").unwrap(),
U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").unwrap()
);
}
#[test] #[test]
fn uint256_div() { fn uint256_div() {
assert_eq!(U256::from(10u64) / U256::from(1u64), U256::from(10u64)); assert_eq!(U256::from(10u64) / U256::from(1u64), U256::from(10u64));