commit
d5a7c3415f
251
src/uint.rs
251
src/uint.rs
@ -35,13 +35,30 @@ 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 {
|
macro_rules! panic_on_overflow {
|
||||||
($name:expr) => {
|
($name: expr) => {
|
||||||
if $name {
|
if $name {
|
||||||
panic!("arithmetic operation overflow")
|
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.
|
||||||
@ -67,11 +84,19 @@ pub trait Uint: Sized + Default + FromStr + From<u64> + FromJson + fmt::Debug +
|
|||||||
|
|
||||||
/// Return the least number of bits needed to represent the number
|
/// Return the least number of bits needed to represent the number
|
||||||
fn bits(&self) -> usize;
|
fn bits(&self) -> usize;
|
||||||
|
/// Return if specific bit is set
|
||||||
fn bit(&self, index: usize) -> bool;
|
fn bit(&self, index: usize) -> bool;
|
||||||
|
/// Return single byte
|
||||||
fn byte(&self, index: usize) -> u8;
|
fn byte(&self, index: usize) -> u8;
|
||||||
|
/// Get this Uint as slice of bytes
|
||||||
fn to_bytes(&self, bytes: &mut[u8]);
|
fn to_bytes(&self, bytes: &mut[u8]);
|
||||||
|
|
||||||
|
/// Create `Uint(10**n)`
|
||||||
fn exp10(n: usize) -> Self;
|
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 {
|
macro_rules! construct_uint {
|
||||||
@ -96,14 +121,12 @@ macro_rules! construct_uint {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conversion to u32
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn low_u32(&self) -> u32 {
|
fn low_u32(&self) -> u32 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
arr[0] as u32
|
arr[0] as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conversion to u64
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn low_u64(&self) -> u64 {
|
fn low_u64(&self) -> u64 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
@ -131,6 +154,7 @@ macro_rules! construct_uint {
|
|||||||
}
|
}
|
||||||
arr[0]
|
arr[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the least number of bits needed to represent the number
|
/// Return the least number of bits needed to represent the number
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bits(&self) -> usize {
|
fn bits(&self) -> usize {
|
||||||
@ -164,27 +188,82 @@ macro_rules! construct_uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn exp10(n: usize) -> $name {
|
fn exp10(n: usize) -> Self {
|
||||||
match n {
|
match n {
|
||||||
0 => $name::from(1u64),
|
0 => Self::from(1u64),
|
||||||
_ => $name::exp10(n - 1) * $name::from(10u64)
|
_ => Self::exp10(n - 1) * Self::from(10u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn zero() -> $name {
|
fn zero() -> Self {
|
||||||
From::from(0u64)
|
From::from(0u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn one() -> $name {
|
fn one() -> Self {
|
||||||
From::from(1u64)
|
From::from(1u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 : &Self| x.low_u64() & 1 == 0;
|
||||||
|
|
||||||
|
let u_one = Self::one();
|
||||||
|
let u_two = Self::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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 : &Self| x.low_u64() & 1 == 0;
|
||||||
|
|
||||||
|
let u_one = Self::one();
|
||||||
|
let u_two = Self::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) {
|
||||||
|
x = overflowing!(x.overflowing_mul(x), overflow);
|
||||||
|
n = n / u_two;
|
||||||
|
} else {
|
||||||
|
y = overflowing!(x.overflowing_mul(y), overflow);
|
||||||
|
x = overflowing!(x.overflowing_mul(x), overflow);
|
||||||
|
n = (n - u_one) / u_two;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let res = overflowing!(x.overflowing_mul(y), overflow);
|
||||||
|
(res, overflow)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
/// Multiplication by u32
|
/// Multiplication by u32
|
||||||
fn mul_u32(self, other: u32) -> $name {
|
fn mul_u32(self, other: u32) -> Self {
|
||||||
let $name(ref arr) = self;
|
let $name(ref arr) = self;
|
||||||
let mut carry = [0u64; $n_words];
|
let mut carry = [0u64; $n_words];
|
||||||
let mut ret = [0u64; $n_words];
|
let mut ret = [0u64; $n_words];
|
||||||
@ -205,7 +284,7 @@ macro_rules! construct_uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing multiplication by u32
|
/// 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 $name(ref arr) = self;
|
||||||
let mut carry = [0u64; $n_words];
|
let mut carry = [0u64; $n_words];
|
||||||
let mut ret = [0u64; $n_words];
|
let mut ret = [0u64; $n_words];
|
||||||
@ -225,8 +304,11 @@ macro_rules! construct_uint {
|
|||||||
overflow = true
|
overflow = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (result, add_overflow) = $name(ret).overflowing_add($name(carry));
|
let result = overflowing!(
|
||||||
(result, add_overflow || overflow)
|
$name(ret).overflowing_add($name(carry)),
|
||||||
|
overflow
|
||||||
|
);
|
||||||
|
(result, overflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,21 +407,21 @@ macro_rules! construct_uint {
|
|||||||
carry[i + 1] = 1;
|
carry[i + 1] = 1;
|
||||||
b_carry = true;
|
b_carry = true;
|
||||||
} else {
|
} else {
|
||||||
overflow = true
|
overflow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if b_carry {
|
if b_carry {
|
||||||
let (ret, add_overflow) = $name(ret).overflowing_add($name(carry));
|
let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow);
|
||||||
(ret, add_overflow || overflow)
|
(ret, overflow)
|
||||||
} else {
|
} else {
|
||||||
($name(ret), overflow)
|
($name(ret), overflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_sub(self, other: $name) -> ($name, bool) {
|
fn overflowing_sub(self, other: $name) -> ($name, bool) {
|
||||||
let (res, _overflow) = (!other).overflowing_add(From::from(1u64));
|
let res = overflowing!((!other).overflowing_add(From::from(1u64)));
|
||||||
let (res, _overflow) = self.overflowing_add(res);
|
let res = overflowing!(self.overflowing_add(res));
|
||||||
(res, self < other)
|
(res, self < other)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,10 +430,9 @@ macro_rules! construct_uint {
|
|||||||
let mut overflow = false;
|
let mut overflow = false;
|
||||||
// TODO: be more efficient about this
|
// TODO: be more efficient about this
|
||||||
for i in 0..(2 * $n_words) {
|
for i in 0..(2 * $n_words) {
|
||||||
let (v, mul_overflow) = self.overflowing_mul_u32((other >> (32 * i)).low_u32());
|
let v = overflowing!(self.overflowing_mul_u32((other >> (32 * i)).low_u32()), overflow);
|
||||||
let (new_res, add_overflow) = res.overflowing_add(v << (32 * i));
|
let res2 = overflowing!(v.overflowing_shl(32 * i as u32), overflow);
|
||||||
res = new_res;
|
res = overflowing!(res.overflowing_add(res2), overflow);
|
||||||
overflow = overflow || mul_overflow || add_overflow;
|
|
||||||
}
|
}
|
||||||
(res, overflow)
|
(res, overflow)
|
||||||
}
|
}
|
||||||
@ -368,9 +449,38 @@ macro_rules! construct_uint {
|
|||||||
(!self, true)
|
(!self, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_shl(self, _shift32: u32) -> ($name, bool) {
|
fn overflowing_shl(self, shift32: u32) -> ($name, bool) {
|
||||||
// TODO [todr] not used for now
|
let $name(ref original) = self;
|
||||||
unimplemented!();
|
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) {
|
fn overflowing_shr(self, _shift32: u32) -> ($name, bool) {
|
||||||
@ -409,9 +519,8 @@ macro_rules! construct_uint {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn sub(self, other: $name) -> $name {
|
fn sub(self, other: $name) -> $name {
|
||||||
panic_on_overflow!(self < other);
|
panic_on_overflow!(self < other);
|
||||||
let (res, _overflow) = (!other).overflowing_add(From::from(1u64));
|
let res = overflowing!((!other).overflowing_add(From::from(1u64)));
|
||||||
let (res, _overflow) = self.overflowing_add(res);
|
overflowing!(self.overflowing_add(res))
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +531,10 @@ macro_rules! construct_uint {
|
|||||||
let mut res = $name::from(0u64);
|
let mut res = $name::from(0u64);
|
||||||
// TODO: be more efficient about this
|
// TODO: be more efficient about this
|
||||||
for i in 0..(2 * $n_words) {
|
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
|
res
|
||||||
}
|
}
|
||||||
@ -453,8 +565,7 @@ 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);
|
||||||
let (copy, _overflow) = sub_copy.overflowing_sub(shift_copy);
|
sub_copy = overflowing!(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; }
|
||||||
@ -868,7 +979,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, _of) = incr.overflowing_sub(init);
|
let sub = overflowing!(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);
|
||||||
@ -915,11 +1026,48 @@ mod tests {
|
|||||||
assert_eq!(U256::from(1000u64).mul_u32(50), U256::from(50000u64));
|
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_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(0x100)),
|
||||||
|
(U256::zero(), true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn uint256_mul1() {
|
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 uint256_overflowing_mul() {
|
||||||
|
assert_eq!(
|
||||||
|
U256::from_str("100000000000000000000000000000000").unwrap().overflowing_mul(
|
||||||
|
U256::from_str("100000000000000000000000000000000").unwrap()
|
||||||
|
),
|
||||||
|
(U256::zero(), true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn uint128_add() {
|
pub fn uint128_add() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -972,9 +1120,11 @@ mod tests {
|
|||||||
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
||||||
),
|
),
|
||||||
(U256::from_str("1").unwrap(), true)
|
(U256::from_str("1").unwrap(), true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
pub fn uint256_mul_overflow_panic() {
|
pub fn uint256_mul_overflow_panic() {
|
||||||
@ -1002,7 +1152,6 @@ mod tests {
|
|||||||
U256::from_str("1").unwrap();
|
U256::from_str("1").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn uint256_shl_overflow() {
|
pub fn uint256_shl_overflow() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1012,9 +1161,41 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[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() {
|
pub fn uint256_shl_overflow2() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
|
||||||
|
Loading…
Reference in New Issue
Block a user