Overflow semantics changed
This commit is contained in:
parent
b1e986cbdd
commit
9b78a89f96
@ -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:
|
||||||
|
227
src/uint.rs
227
src/uint.rs
@ -26,6 +26,7 @@ use std::cmp::*;
|
|||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::num::wrapping::OverflowingOps;
|
||||||
use rustc_serialize::hex::{FromHex, FromHexError};
|
use rustc_serialize::hex::{FromHex, FromHexError};
|
||||||
|
|
||||||
pub trait FromDecStr: Sized {
|
pub trait FromDecStr: Sized {
|
||||||
@ -43,6 +44,14 @@ macro_rules! impl_map_from {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! panic_on_overflow {
|
||||||
|
($name:expr) => {
|
||||||
|
if $name {
|
||||||
|
panic!("arithmetic operation overflow")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! construct_uint {
|
macro_rules! construct_uint {
|
||||||
($name:ident, $n_words:expr) => (
|
($name:ident, $n_words:expr) => (
|
||||||
/// Little-endian large integer type
|
/// Little-endian large integer type
|
||||||
@ -157,6 +166,31 @@ macro_rules! construct_uint {
|
|||||||
}
|
}
|
||||||
$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 From<u64> for $name {
|
impl From<u64> for $name {
|
||||||
@ -214,6 +248,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;
|
||||||
|
|
||||||
@ -224,10 +329,14 @@ 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 {
|
||||||
ret[i] = me[i].wrapping_add(you[i]);
|
if i < $n_words - 1 {
|
||||||
if i < $n_words - 1 && ret[i] < me[i] {
|
ret[i] = me[i].wrapping_add(you[i]);
|
||||||
carry[i + 1] = 1;
|
if ret[i] < me[i] {
|
||||||
b_carry = true;
|
carry[i + 1] = 1;
|
||||||
|
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) }
|
||||||
@ -239,7 +348,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +393,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; }
|
||||||
@ -370,7 +483,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
|
||||||
@ -567,6 +680,7 @@ mod tests {
|
|||||||
use uint::U512;
|
use uint::U512;
|
||||||
use uint::FromDecStr;
|
use uint::FromDecStr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::num::wrapping::OverflowingOps;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn uint256_from() {
|
pub fn uint256_from() {
|
||||||
@ -692,7 +806,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);
|
||||||
@ -740,7 +854,7 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,12 +869,22 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn uint128_add_overflow() {
|
pub fn uint128_add_overflow() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U128::from_str("ffffffffffffffffffffffffffffffff").unwrap()
|
U128::from_str("ffffffffffffffffffffffffffffffff").unwrap()
|
||||||
+ U128::from_str("ffffffffffffffffffffffffffffffff").unwrap(),
|
.overflowing_add(
|
||||||
U128::from_str("fffffffffffffffffffffffffffffffe").unwrap()
|
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]
|
#[test]
|
||||||
pub fn uint128_mul() {
|
pub fn uint128_mul() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -782,14 +906,85 @@ mod tests {
|
|||||||
pub fn uint256_mul_overflow() {
|
pub fn uint256_mul_overflow() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
||||||
*
|
.overflowing_mul(
|
||||||
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(),
|
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
||||||
U256::from_str("1").unwrap()
|
),
|
||||||
|
(U256::from_str("1").unwrap(), true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn uint256_mul_overflow2() {
|
#[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!(
|
assert_eq!(
|
||||||
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user