diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 1f45ff3b..06d7ff1a 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -3,5 +3,10 @@ extern crate rustc_serialize; pub mod bytes; pub mod hash; +pub mod uint; pub use rustc_serialize::hex; + +pub use uint::U256; +pub use hash::{H160, H256}; +pub use bytes::Bytes; diff --git a/primitives/src/uint.rs b/primitives/src/uint.rs new file mode 100644 index 00000000..ae2a8a36 --- /dev/null +++ b/primitives/src/uint.rs @@ -0,0 +1,1738 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +// Code derived from original work by Andrew Poelstra + +// Rust Bitcoin Library +// Written in 2014 by +// Andrew Poelstra +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! Big unsigned integer types. +//! +//! Implementation of a various large-but-fixed sized unsigned integer types. +//! The functions here are designed to be fast. There are optional `x86_64` +//! implementations for even more speed, hidden behind the `x64_arithmetic` +//! feature flag. + +use std::{mem, fmt}; +use std::str::{FromStr}; +use std::hash::Hash; +use std::ops::{Shr, Shl, BitAnd, BitOr, BitXor, Not, Div, Rem, Mul, Add, Sub}; +use std::cmp::Ordering; +use hex::{FromHex, FromHexError}; + +/// Conversion from decimal string error +#[derive(Debug, PartialEq)] +pub enum FromDecStrErr { + /// Char not from range 0-9 + InvalidCharacter, + /// Value does not fit into type + InvalidLength, +} + +macro_rules! impl_map_from { + ($thing:ident, $from:ty, $to:ty) => { + impl From<$from> for $thing { + fn from(value: $from) -> $thing { + From::from(value as $to) + } + } + } +} + +#[cfg(not(all(asm_available, target_arch="x86_64")))] +macro_rules! uint_overflowing_add { + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_add_reg { + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + + let mut ret = [0u64; $n_words]; + let mut carry = 0u64; + + for i in 0..$n_words { + let (res1, overflow1) = me[i].overflowing_add(you[i]); + let (res2, overflow2) = res1.overflowing_add(carry); + + ret[i] = res2; + carry = overflow1 as u64 + overflow2 as u64; + } + + ($name(ret), carry > 0) + }) +} + +#[cfg(all(asm_available, target_arch="x86_64"))] +macro_rules! uint_overflowing_add { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; $n_words] = unsafe { mem::uninitialized() }; + let self_t: &[u64; $n_words] = &$self_expr.0; + let other_t: &[u64; $n_words] = &$other.0; + + let overflow: u8; + unsafe { + asm!(" + add $9, $0 + adc $10, $1 + adc $11, $2 + adc $12, $3 + setc %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) + : + : + ); + } + (U256(result), overflow != 0) + }); + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( + uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) + ) +} + +#[cfg(not(all(asm_available, target_arch="x86_64")))] +macro_rules! uint_overflowing_sub { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_sub_reg { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + + let mut ret = [0u64; $n_words]; + let mut carry = 0u64; + + for i in 0..$n_words { + let (res1, overflow1) = me[i].overflowing_sub(you[i]); + let (res2, overflow2) = res1.overflowing_sub(carry); + + ret[i] = res2; + carry = overflow1 as u64 + overflow2 as u64; + } + + ($name(ret), carry > 0) + + }) +} + +#[cfg(all(asm_available, target_arch="x86_64"))] +macro_rules! uint_overflowing_sub { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; $n_words] = unsafe { mem::uninitialized() }; + let self_t: &[u64; $n_words] = &$self_expr.0; + let other_t: &[u64; $n_words] = &$other.0; + + let overflow: u8; + unsafe { + asm!(" + sub $9, $0 + sbb $10, $1 + sbb $11, $2 + sbb $12, $3 + setb %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) + : + : + ); + } + (U256(result), overflow != 0) + }); + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other) + }) +} + +#[cfg(all(asm_available, target_arch="x86_64"))] +macro_rules! uint_overflowing_mul { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; $n_words] = unsafe { mem::uninitialized() }; + let self_t: &[u64; $n_words] = &$self_expr.0; + let other_t: &[u64; $n_words] = &$other.0; + + let overflow: u64; + unsafe { + asm!(" + mov $5, %rax + mulq $9 + mov %rax, $0 + mov %rdx, $1 + + mov $5, %rax + mulq $10 + add %rax, $1 + adc $$0, %rdx + mov %rdx, $2 + + mov $5, %rax + mulq $11 + add %rax, $2 + adc $$0, %rdx + mov %rdx, $3 + + mov $5, %rax + mulq $12 + add %rax, $3 + adc $$0, %rdx + mov %rdx, %rcx + + mov $6, %rax + mulq $9 + add %rax, $1 + adc %rdx, $2 + adc $$0, $3 + adc $$0, %rcx + + mov $6, %rax + mulq $10 + add %rax, $2 + adc %rdx, $3 + adc $$0, %rcx + adc $$0, $3 + adc $$0, %rcx + + mov $6, %rax + mulq $11 + add %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + + mov $7, %rax + mulq $9 + add %rax, $2 + adc %rdx, $3 + adc $$0, %rcx + + mov $7, %rax + mulq $10 + add %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + + mov $8, %rax + mulq $9 + add %rax, $3 + or %rdx, %rcx + + cmpq $$0, %rcx + jne 2f + + mov $8, %rcx + jrcxz 12f + + mov $12, %rcx + mov $11, %rax + or %rax, %rcx + mov $10, %rax + or %rax, %rcx + jmp 2f + + 12: + mov $12, %rcx + jrcxz 11f + + mov $7, %rcx + mov $6, %rax + or %rax, %rcx + + cmpq $$0, %rcx + jne 2f + + 11: + mov $11, %rcx + jrcxz 2f + mov $7, %rcx + + 2: + " + : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), + /* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow) + + : /* $5 */ "m"(self_t[0]), /* $6 */ "m"(self_t[1]), /* $7 */ "m"(self_t[2]), + /* $8 */ "m"(self_t[3]), /* $9 */ "m"(other_t[0]), /* $10 */ "m"(other_t[1]), + /* $11 */ "m"(other_t[2]), /* $12 */ "m"(other_t[3]) + : "rax", "rdx" + : + + ); + } + (U256(result), overflow > 0) + }); + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( + uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) + ) +} + +#[cfg(not(all(asm_available, target_arch="x86_64")))] +macro_rules! uint_overflowing_mul { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_mul_reg { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + let mut ret = [0u64; 2*$n_words]; + + for i in 0..$n_words { + if you[i] == 0 { + continue; + } + + let mut carry2 = 0u64; + let (b_u, b_l) = split(you[i]); + + for j in 0..$n_words { + if me[j] == 0 && carry2 == 0 { + continue; + } + + let a = split(me[j]); + + // multiply parts + let (c_l, overflow_l) = mul_u32(a, b_l, ret[i + j]); + let (c_u, overflow_u) = mul_u32(a, b_u, c_l >> 32); + ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32); + + // No overflow here + let res = (c_u >> 32) + (overflow_u << 32); + // possible overflows + let (res, o1) = res.overflowing_add(overflow_l); + let (res, o2) = res.overflowing_add(carry2); + let (res, o3) = res.overflowing_add(ret[i + j + 1]); + ret[i + j + 1] = res; + + // Only single overflow possible there + carry2 = (o1 | o2 | o3) as u64; + } + } + + let mut res = [0u64; $n_words]; + let mut overflow = false; + for i in 0..$n_words { + res[i] = ret[i]; + } + + for i in $n_words..2*$n_words { + overflow |= ret[i] != 0; + } + + ($name(res), overflow) + }) +} + +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) => { + if $name { + panic!("arithmetic operation overflow") + } + } +} + +#[inline(always)] +fn mul_u32(a: (u64, u64), b: u64, carry: u64) -> (u64, u64) { + let upper = b * a.0; + let lower = b * a.1; + + let (res1, overflow1) = lower.overflowing_add(upper << 32); + let (res2, overflow2) = res1.overflowing_add(carry); + + let carry = (upper >> 32) + overflow1 as u64 + overflow2 as u64; + (res2, carry) +} + +#[inline(always)] +fn split(a: u64) -> (u64, u64) { + (a >> 32, a & 0xFFFFFFFF) +} + +/// Large, fixed-length unsigned integer type. +pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { + + /// Returns new instance equalling zero. + fn zero() -> Self; + /// Returns new instance equalling one. + fn one() -> Self; + /// Returns the largest value that can be represented by this integer type. + fn max_value() -> Self; + + /// Convert from a decimal string. + fn from_dec_str(value: &str) -> Result; + + /// Conversion to u32 + fn low_u32(&self) -> u32; + + /// Conversion to u64 + fn low_u64(&self) -> u64; + + /// Conversion to u32 with overflow checking + fn as_u32(&self) -> u32; + + /// Conversion to u64 with overflow checking + fn as_u64(&self) -> u64; + + /// 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; + /// Convert U256 to the sequence of bytes with a big endian + fn to_big_endian(&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); + + /// Add this `Uint` to other returning result and possible overflow + fn overflowing_add(self, other: Self) -> (Self, bool); + + /// Subtract another `Uint` from this returning result and possible overflow + fn overflowing_sub(self, other: Self) -> (Self, bool); + + /// Multiple this `Uint` with other returning result and possible overflow + fn overflowing_mul(self, other: Self) -> (Self, bool); + + /// Divide this `Uint` by other returning result and possible overflow + fn overflowing_div(self, other: Self) -> (Self, bool); + + /// Returns reminder of division of this `Uint` by other and possible overflow + fn overflowing_rem(self, other: Self) -> (Self, bool); + + /// Returns negation of this `Uint` and overflow (always true) + fn overflowing_neg(self) -> (Self, bool); + + /// Returns + fn is_zero(&self) -> bool; +} + +macro_rules! construct_uint { + ($name:ident, $n_words:expr) => ( + /// Little-endian large integer type + #[repr(C)] + #[derive(Copy, Clone, Eq, PartialEq, Hash)] + pub struct $name(pub [u64; $n_words]); + + impl Uint for $name { + + fn from_dec_str(value: &str) -> Result { + if !value.bytes().all(|b| b >= 48 && b <= 57) { + return Err(FromDecStrErr::InvalidCharacter) + } + + let mut res = Self::default(); + for b in value.bytes().map(|b| b - 48) { + let (r, overflow) = res.overflowing_mul_u32(10); + if overflow { + return Err(FromDecStrErr::InvalidLength); + } + let (r, overflow) = r.overflowing_add(b.into()); + if overflow { + return Err(FromDecStrErr::InvalidLength); + } + res = r; + } + Ok(res) + } + + #[inline] + fn low_u32(&self) -> u32 { + let &$name(ref arr) = self; + arr[0] as u32 + } + + #[inline] + fn low_u64(&self) -> u64 { + let &$name(ref arr) = self; + arr[0] + } + + /// Conversion to u32 with overflow checking + #[inline] + fn as_u32(&self) -> u32 { + let &$name(ref arr) = self; + if (arr[0] & (0xffffffffu64 << 32)) != 0 { + panic!("Integer overflow when casting U256") + } + self.as_u64() as u32 + } + + /// Conversion to u64 with overflow checking + #[inline] + fn as_u64(&self) -> u64 { + let &$name(ref arr) = self; + for i in 1..$n_words { + if arr[i] != 0 { + panic!("Integer overflow when casting U256") + } + } + arr[0] + } + + #[inline] + fn is_zero(&self) -> bool { + let &$name(ref arr) = self; + for i in 0..$n_words { if arr[i] != 0 { return false; } } + return true; + } + + /// Return the least number of bits needed to represent the number + #[inline] + fn bits(&self) -> usize { + let &$name(ref arr) = self; + for i in 1..$n_words { + if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; } + } + 0x40 - arr[0].leading_zeros() as usize + } + + #[inline] + fn bit(&self, index: usize) -> bool { + let &$name(ref arr) = self; + arr[index / 64] & (1 << (index % 64)) != 0 + } + + #[inline] + fn byte(&self, index: usize) -> u8 { + let &$name(ref arr) = self; + (arr[index / 8] >> (((index % 8)) * 8)) as u8 + } + + #[cfg(any( + target_arch = "arm", + target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "powerpc64"))] + #[inline] + fn to_big_endian(&self, bytes: &mut[u8]) { + debug_assert!($n_words * 8 == bytes.len()); + let &$name(ref arr) = self; + unsafe { + let mut out: *mut u64 = mem::transmute(bytes.as_mut_ptr()); + out = out.offset($n_words); + for i in 0..$n_words { + out = out.offset(-1); + *out = arr[i].swap_bytes(); + } + } + } + + #[cfg(not(any( + target_arch = "arm", + target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "powerpc64")))] + #[inline] + fn to_big_endian(&self, bytes: &mut[u8]) { + debug_assert!($n_words * 8 == bytes.len()); + let &$name(ref arr) = self; + for i in 0..bytes.len() { + let rev = bytes.len() - 1 - i; + let pos = rev / 8; + bytes[i] = (arr[pos] >> ((rev % 8) * 8)) as u8; + } + } + + #[inline] + fn exp10(n: usize) -> Self { + match n { + 0 => Self::from(1u64), + _ => Self::exp10(n - 1).mul_u32(10) + } + } + + #[inline] + fn zero() -> Self { + From::from(0u64) + } + + #[inline] + fn one() -> Self { + From::from(1u64) + } + + #[inline] + fn max_value() -> Self { + let mut result = [0; $n_words]; + for i in 0..$n_words { + result[i] = u64::max_value(); + } + $name(result) + } + + /// Fast exponentation by squaring + /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring + fn pow(self, expon: Self) -> Self { + if expon.is_zero() { + return Self::one() + } + let is_even = |x : &Self| x.low_u64() & 1 == 0; + + let u_one = Self::one(); + 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 >> 1; + } else { + y = x * y; + x = x * x; + // to reduce odd number by 1 we should just clear the last bit + n.0[$n_words-1] = n.0[$n_words-1] & ((!0u64)>>1); + n = n >> 1; + } + } + x * y + } + + /// Fast exponentation by squaring + /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring + fn overflowing_pow(self, expon: Self) -> (Self, bool) { + if expon.is_zero() { return (Self::one(), false) } + + let is_even = |x : &Self| x.low_u64() & 1 == 0; + + let u_one = Self::one(); + 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 >> 1; + } else { + y = overflowing!(x.overflowing_mul(y), overflow); + x = overflowing!(x.overflowing_mul(x), overflow); + n = (n - u_one) >> 1; + } + } + let res = overflowing!(x.overflowing_mul(y), overflow); + (res, overflow) + } + + /// Optimized instructions + #[inline(always)] + fn overflowing_add(self, other: $name) -> ($name, bool) { + uint_overflowing_add!($name, $n_words, self, other) + } + + #[inline(always)] + fn overflowing_sub(self, other: $name) -> ($name, bool) { + uint_overflowing_sub!($name, $n_words, self, other) + } + + #[inline(always)] + fn overflowing_mul(self, other: $name) -> ($name, bool) { + uint_overflowing_mul!($name, $n_words, self, other) + } + + 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) + } + } + + impl $name { + /// Multiplication by u32 + #[allow(dead_code)] // not used when multiplied with inline assembly + fn mul_u32(self, other: u32) -> Self { + let (ret, overflow) = self.overflowing_mul_u32(other); + panic_on_overflow!(overflow); + ret + } + + /// Overflowing multiplication by u32 + #[allow(dead_code)] // not used when multiplied with inline assembly + fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { + let $name(ref arr) = self; + let mut ret = [0u64; $n_words]; + let mut carry = 0; + let o = other as u64; + + for i in 0..$n_words { + let (res, carry2) = mul_u32(split(arr[i]), o, carry); + ret[i] = res; + carry = carry2; + } + + ($name(ret), carry > 0) + } + } + + impl Default for $name { + fn default() -> Self { + $name::zero() + } + } + + impl From for $name { + fn from(value: u64) -> $name { + let mut ret = [0; $n_words]; + ret[0] = value; + $name(ret) + } + } + + + impl_map_from!($name, u8, u64); + impl_map_from!($name, u16, u64); + impl_map_from!($name, u32, u64); + impl_map_from!($name, usize, u64); + + impl From for $name { + fn from(value: i64) -> $name { + match value >= 0 { + true => From::from(value as u64), + false => { panic!("Unsigned integer can't be created from negative value"); } + } + } + } + + impl_map_from!($name, i8, i64); + impl_map_from!($name, i16, i64); + impl_map_from!($name, i32, i64); + impl_map_from!($name, isize, i64); + + impl<'a> From<&'a [u8]> for $name { + fn from(bytes: &[u8]) -> $name { + assert!($n_words * 8 >= bytes.len()); + + let mut ret = [0; $n_words]; + for i in 0..bytes.len() { + let rev = bytes.len() - 1 - i; + let pos = rev / 8; + ret[pos] += (bytes[i] as u64) << ((rev % 8) * 8); + } + $name(ret) + } + } + + impl FromStr for $name { + type Err = FromHexError; + + fn from_str(value: &str) -> Result<$name, Self::Err> { + let bytes: Vec = match value.len() % 2 == 0 { + true => try!(value.from_hex()), + false => try!(("0".to_owned() + value).from_hex()) + }; + + let bytes_ref: &[u8] = &bytes; + Ok(From::from(bytes_ref)) + } + } + + impl Add<$name> for $name { + type Output = $name; + + fn add(self, other: $name) -> $name { + let (result, overflow) = self.overflowing_add(other); + panic_on_overflow!(overflow); + result + } + } + + impl Sub<$name> for $name { + type Output = $name; + + #[inline] + fn sub(self, other: $name) -> $name { + let (result, overflow) = self.overflowing_sub(other); + panic_on_overflow!(overflow); + result + } + } + + impl Mul<$name> for $name { + type Output = $name; + + fn mul(self, other: $name) -> $name { + let (result, overflow) = self.overflowing_mul(other); + panic_on_overflow!(overflow); + result + } + } + + impl Div<$name> for $name { + type Output = $name; + + fn div(self, other: $name) -> $name { + let mut sub_copy = self; + let mut shift_copy = other; + let mut ret = [0u64; $n_words]; + + let my_bits = self.bits(); + let your_bits = other.bits(); + + // Check for division by 0 + assert!(your_bits != 0); + + // Early return in case we are dividing by a larger number than us + if my_bits < your_bits { + return $name(ret); + } + + // Bitwise long division + let mut shift = my_bits - your_bits; + shift_copy = shift_copy << shift; + loop { + if sub_copy >= shift_copy { + ret[shift / 64] |= 1 << (shift % 64); + sub_copy = overflowing!(sub_copy.overflowing_sub(shift_copy)); + } + shift_copy = shift_copy >> 1; + if shift == 0 { break; } + shift -= 1; + } + + $name(ret) + } + } + + impl Rem<$name> for $name { + type Output = $name; + + fn rem(self, other: $name) -> $name { + let times = self / other; + self - (times * other) + } + } + + impl BitAnd<$name> for $name { + type Output = $name; + + #[inline] + fn bitand(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] & arr2[i]; + } + $name(ret) + } + } + + impl BitXor<$name> for $name { + type Output = $name; + + #[inline] + fn bitxor(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] ^ arr2[i]; + } + $name(ret) + } + } + + impl BitOr<$name> for $name { + type Output = $name; + + #[inline] + fn bitor(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] | arr2[i]; + } + $name(ret) + } + } + + impl Not for $name { + type Output = $name; + + #[inline] + fn not(self) -> $name { + let $name(ref arr) = self; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = !arr[i]; + } + $name(ret) + } + } + + impl Shl for $name { + type Output = $name; + + fn shl(self, shift: usize) -> $name { + let $name(ref original) = self; + let mut ret = [0u64; $n_words]; + let word_shift = shift / 64; + let bit_shift = shift % 64; + + // shift + for i in word_shift..$n_words { + ret[i] = original[i - word_shift] << bit_shift; + } + // carry + if bit_shift > 0 { + for i in word_shift+1..$n_words { + ret[i] += original[i - 1 - word_shift] >> (64 - bit_shift); + } + } + $name(ret) + } + } + + impl Shr for $name { + type Output = $name; + + fn shr(self, shift: usize) -> $name { + let $name(ref original) = self; + let mut ret = [0u64; $n_words]; + let word_shift = shift / 64; + let bit_shift = shift % 64; + + // shift + for i in word_shift..$n_words { + ret[i - word_shift] = original[i] >> bit_shift; + } + + // Carry + if bit_shift > 0 { + for i in word_shift+1..$n_words { + ret[i - word_shift - 1] += original[i] << (64 - bit_shift); + } + } + + $name(ret) + } + } + + impl Ord for $name { + fn cmp(&self, other: &$name) -> Ordering { + let &$name(ref me) = self; + let &$name(ref you) = other; + let mut i = $n_words; + while i > 0 { + i -= 1; + if me[i] < you[i] { return Ordering::Less; } + if me[i] > you[i] { return Ordering::Greater; } + } + Ordering::Equal + } + } + + impl PartialOrd for $name { + fn partial_cmp(&self, other: &$name) -> Option { + Some(self.cmp(other)) + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } + + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_zero() { + return write!(f, "0"); + } + + let mut s = String::new(); + let mut current = *self; + let ten = $name::from(10); + + while !current.is_zero() { + s = format!("{}{}", (current % ten).low_u32(), s); + current = current / ten; + } + + write!(f, "{}", s) + } + } + + impl fmt::LowerHex for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let &$name(ref data) = self; + try!(write!(f, "0x")); + let mut latch = false; + for ch in data.iter().rev() { + for x in 0..16 { + let nibble = (ch & (15u64 << ((15 - x) * 4) as u64)) >> (((15 - x) * 4) as u64); + if !latch { latch = nibble != 0 } + if latch { + try!(write!(f, "{:x}", nibble)); + } + } + } + Ok(()) + } + } + + impl From<&'static str> for $name { + fn from(s: &'static str) -> Self { + s.parse().unwrap() + } + } + ); +} + +construct_uint!(U256, 4); +construct_uint!(U128, 2); + +impl From for U128 { + fn from(value: U256) -> U128 { + let U256(ref arr) = value; + if arr[2] | arr[3] != 0 { + panic!("Overflow"); + } + let mut ret = [0; 2]; + ret[0] = arr[0]; + ret[1] = arr[1]; + U128(ret) + } +} + +impl From for U256 { + fn from(value: U128) -> U256 { + let U128(ref arr) = value; + let mut ret = [0; 4]; + ret[0] = arr[0]; + ret[1] = arr[1]; + U256(ret) + } +} + +impl From for u64 { + fn from(value: U256) -> u64 { + value.as_u64() + } +} + +impl From for u32 { + fn from(value: U256) -> u32 { + value.as_u32() + } +} + +known_heap_size!(0, U128, U256); + +#[cfg(test)] +mod tests { + use uint::{Uint, U128, U256}; + use std::str::FromStr; + use super::FromDecStrErr; + + #[test] + pub fn uint256_from() { + let e = U256([10, 0, 0, 0]); + + // test unsigned initialization + let ua = U256::from(10u8); + let ub = U256::from(10u16); + let uc = U256::from(10u32); + let ud = U256::from(10u64); + assert_eq!(e, ua); + assert_eq!(e, ub); + assert_eq!(e, uc); + assert_eq!(e, ud); + + // test initialization from bytes + let va = U256::from(&[10u8][..]); + assert_eq!(e, va); + + // more tests for initialization from bytes + assert_eq!(U256([0x1010, 0, 0, 0]), U256::from(&[0x10u8, 0x10][..])); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from(&[0, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from(&[1, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from(&[ + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x00192437100019fa, 0x243710, 0, 0]), U256::from(&[ + 0x24u8, 0x37, 0x10, + 0, 0x19, 0x24, 0x37, 0x10, 0, 0x19, 0xfa][..])); + + // test initializtion from string + let sa = U256::from_str("0a").unwrap(); + assert_eq!(e, sa); + assert_eq!(U256([0x1010, 0, 0, 0]), U256::from_str("1010").unwrap()); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); + assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from_str("0000000012f0").unwrap()); + assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from_str("0100000000000012f0").unwrap()); + assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap()); + } + + #[test] + pub fn uint256_to() { + let hex = "8090a0b0c0d0e0f00910203040506077583a2cf8264910e1436bda32571012f0"; + let uint = U256::from_str(hex).unwrap(); + let mut bytes = [0u8; 32]; + uint.to_big_endian(&mut bytes); + let uint2 = U256::from(&bytes[..]); + assert_eq!(uint, uint2); + } + + #[test] + pub fn uint256_bits_test() { + assert_eq!(U256::from(0u64).bits(), 0); + assert_eq!(U256::from(255u64).bits(), 8); + assert_eq!(U256::from(256u64).bits(), 9); + assert_eq!(U256::from(300u64).bits(), 9); + assert_eq!(U256::from(60000u64).bits(), 16); + assert_eq!(U256::from(70000u64).bits(), 17); + + //// Try to read the following lines out loud quickly + let mut shl = U256::from(70000u64); + shl = shl << 100; + assert_eq!(shl.bits(), 117); + shl = shl << 100; + assert_eq!(shl.bits(), 217); + shl = shl << 100; + assert_eq!(shl.bits(), 0); + + //// Bit set check + //// 01010 + assert!(!U256::from(10u8).bit(0)); + assert!(U256::from(10u8).bit(1)); + assert!(!U256::from(10u8).bit(2)); + assert!(U256::from(10u8).bit(3)); + assert!(!U256::from(10u8).bit(4)); + + //// byte check + assert_eq!(U256::from(10u8).byte(0), 10); + assert_eq!(U256::from(0xffu64).byte(0), 0xff); + assert_eq!(U256::from(0xffu64).byte(1), 0); + assert_eq!(U256::from(0x01ffu64).byte(0), 0xff); + assert_eq!(U256::from(0x01ffu64).byte(1), 0x1); + assert_eq!(U256([0u64, 0xfc, 0, 0]).byte(8), 0xfc); + assert_eq!(U256([0u64, 0, 0, u64::max_value()]).byte(31), 0xff); + assert_eq!(U256([0u64, 0, 0, (u64::max_value() >> 8) + 1]).byte(31), 0x01); + } + + #[test] + #[cfg_attr(feature="dev", allow(eq_op))] + pub fn uint256_comp_test() { + let small = U256([10u64, 0, 0, 0]); + let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); + let bigger = U256([0x9C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); + let biggest = U256([0x5C8C3EE70C644118u64, 0x0209E7378231E632, 0, 1]); + + assert!(small < big); + assert!(big < bigger); + assert!(bigger < biggest); + assert!(bigger <= biggest); + assert!(biggest <= biggest); + assert!(bigger >= big); + assert!(bigger >= small); + assert!(small <= small); + } + + #[test] + pub fn uint256_arithmetic_test() { + let init = U256::from(0xDEADBEEFDEADBEEFu64); + let copy = init; + + let add = init + copy; + assert_eq!(add, U256([0xBD5B7DDFBD5B7DDEu64, 1, 0, 0])); + // Bitshifts + let shl = add << 88; + assert_eq!(shl, U256([0u64, 0xDFBD5B7DDE000000, 0x1BD5B7D, 0])); + let shr = shl >> 40; + assert_eq!(shr, U256([0x7DDE000000000000u64, 0x0001BD5B7DDFBD5B, 0, 0])); + // Increment + let incr = shr + U256::from(1u64); + assert_eq!(incr, U256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0])); + // Subtraction + let sub = overflowing!(incr.overflowing_sub(init)); + assert_eq!(sub, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); + // Multiplication + let mult = sub.mul_u32(300); + assert_eq!(mult, U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0])); + // Division + assert_eq!(U256::from(105u8) / U256::from(5u8), U256::from(21u8)); + let div = mult / U256::from(300u16); + assert_eq!(div, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); + + let a = U256::from_str("ff000000000000000000000000000000000000000000000000000000000000d1").unwrap(); + let b = U256::from_str("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e").unwrap(); + println!("{:x}", a); + println!("{:x}", b); + assert_eq!(!a, b); + assert_eq!(a, !b); + } + + #[test] + pub fn uint256_simple_mul() { + let a = U256::from_str("10000000000000000").unwrap(); + let b = U256::from_str("10000000000000000").unwrap(); + + let c = U256::from_str("100000000000000000000000000000000").unwrap(); + println!("Multiplying"); + let result = a.overflowing_mul(b); + println!("Got result"); + assert_eq!(result, (c, false)) + } + + #[test] + pub fn uint256_extreme_bitshift_test() { + //// Shifting a u64 by 64 bits gives an undefined value, so make sure that + //// we're doing the Right Thing here + let init = U256::from(0xDEADBEEFDEADBEEFu64); + + assert_eq!(init << 64, U256([0, 0xDEADBEEFDEADBEEF, 0, 0])); + let add = (init << 64) + init; + assert_eq!(add, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add >> 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add << 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add >> 64, U256([0xDEADBEEFDEADBEEF, 0, 0, 0])); + assert_eq!(add << 64, U256([0, 0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0])); + } + + #[test] + pub fn uint256_exp10() { + assert_eq!(U256::exp10(0), U256::from(1u64)); + println!("\none: {:?}", U256::from(1u64)); + println!("ten: {:?}", U256::from(10u64)); + assert_eq!(U256::from(2u64) * U256::from(10u64), U256::from(20u64)); + assert_eq!(U256::exp10(1), U256::from(10u64)); + assert_eq!(U256::exp10(2), U256::from(100u64)); + assert_eq!(U256::exp10(5), U256::from(100000u64)); + } + + #[test] + pub fn uint256_mul32() { + assert_eq!(U256::from(0u64).mul_u32(2), U256::from(0u64)); + assert_eq!(U256::from(1u64).mul_u32(2), U256::from(2u64)); + assert_eq!(U256::from(10u64).mul_u32(2), U256::from(20u64)); + assert_eq!(U256::from(10u64).mul_u32(5), U256::from(50u64)); + 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] + pub fn uint256_mul1() { + 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!( + 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] + // overflows panic only in debug builds. Running this test with `--release` flag, always fails + #[ignore] + 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 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(); + } + + #[test] + pub fn uint256_shl() { + assert_eq!( + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 4, + U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap() + ); + } + + #[test] + pub fn uint256_shl_words() { + assert_eq!( + U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 64, + U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap() + ); + assert_eq!( + U256::from_str("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 64, + U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap() + ); + } + + #[test] + pub fn uint256_mul() { + assert_eq!( + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + * + U256::from_str("2").unwrap(), + U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").unwrap() + ); + } + + #[test] + fn uint256_div() { + assert_eq!(U256::from(10u64) / U256::from(1u64), U256::from(10u64)); + assert_eq!(U256::from(10u64) / U256::from(2u64), U256::from(5u64)); + assert_eq!(U256::from(10u64) / U256::from(3u64), U256::from(3u64)); + } + + #[test] + fn uint256_rem() { + assert_eq!(U256::from(10u64) % U256::from(1u64), U256::from(0u64)); + assert_eq!(U256::from(10u64) % U256::from(3u64), U256::from(1u64)); + } + + #[test] + fn uint256_from_dec_str() { + assert_eq!(U256::from_dec_str("10").unwrap(), U256::from(10u64)); + assert_eq!(U256::from_dec_str("1024").unwrap(), U256::from(1024u64)); + assert_eq!(U256::from_dec_str("115792089237316195423570985008687907853269984665640564039457584007913129639936"), Err(FromDecStrErr::InvalidLength)); + assert_eq!(U256::from_dec_str("0x11"), Err(FromDecStrErr::InvalidCharacter)); + } + + #[test] + fn display_uint() { + let s = "12345678987654321023456789"; + assert_eq!(format!("{}", U256::from_dec_str(s).unwrap()), s); + } + + #[test] + fn display_uint_zero() { + assert_eq!(format!("{}", U256::from(0)), "0"); + } + + #[test] + fn u256_multi_adds() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_add(U256([0, 0, 0, 0])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_add(U256([0, 0, 0, 1])); + assert_eq!(result, U256([0, 0, 0, 2])); + + let (result, overflow) = U256([0, 0, 2, 1]).overflowing_add(U256([0, 0, 3, 1])); + assert_eq!(result, U256([0, 0, 5, 2])); + assert!(!overflow); + + let (_, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_add(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_add(U256([0, 0, 0, ::std::u64::MAX])); + assert!(overflow); + } + + #[test] + fn u256_multi_subs() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_sub(U256([0, 0, 0, 0])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 0, 1])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (_, overflow) = U256([0, 0, 2, 1]).overflowing_sub(U256([0, 0, 3, 1])); + assert!(overflow); + + let (result, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_sub(U256([::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1]), result); + + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 1, 0])); + assert!(!overflow); + assert_eq!(U256([0, 0, ::std::u64::MAX, 0]), result); + + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([1, 0, 0, 0])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + } + + #[test] + fn u256_multi_carry_all() { + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX-1, 0, 0]), result); + + let (result, _) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([0, 1, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX-1, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul( + U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, 0, 0]), result); + } + + #[test] + fn u256_multi_muls() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([1, 0, 0, 0]), result); + + let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); + assert_eq!(U256([25, 0, 0, 0]), result); + + let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 25, 0]), result); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 1]), result); + + let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 10]), result); + + let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 0, 5]), result); + + let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 10, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + } + + #[test] + fn u256_multi_muls_overflow() { + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(!overflow); + + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 1, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([0, 1, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 1, 0, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([0, ::std::u64::MAX, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([10, 0, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX / 2])); + assert!(!overflow); + + let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert!(overflow); + } + + #[test] + fn big_endian() { + let source = U256([1, 0, 0, 0]); + let mut target = vec![0u8; 32]; + + assert_eq!(source, U256::from(1)); + + source.to_big_endian(&mut target); + assert_eq!( + vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8], + target); + + let source = U256([512, 0, 0, 0]); + let mut target = vec![0u8; 32]; + + source.to_big_endian(&mut target); + assert_eq!( + vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8], + target); + + let source = U256([0, 512, 0, 0]); + let mut target = vec![0u8; 32]; + + source.to_big_endian(&mut target); + assert_eq!( + vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + target); + + let source = U256::from_str("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20").unwrap(); + source.to_big_endian(&mut target); + assert_eq!( + vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20], + target); + } + + #[test] + fn u256_multi_muls2() { + + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([1, 0, 0, 0]), result); + + let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); + assert_eq!(U256([25, 0, 0, 0]), result); + + let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 25, 0]), result); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 1]), result); + + let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 10]), result); + + let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 0, 5]), result); + + let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 10, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, u64::max_value()])); + assert_eq!(U256([0, 0, 0, u64::max_value()]), result); + + let x1: U256 = "0000000000000000000000000000000000000000000000000000012365124623".into(); + let x2sqr_right: U256 = "000000000000000000000000000000000000000000014baeef72e0378e2328c9".into(); + let x1sqr = x1 * x1; + assert_eq!(x2sqr_right, x1sqr); + + let x1cube = x1sqr * x1; + let x1cube_right: U256 = "0000000000000000000000000000000001798acde139361466f712813717897b".into(); + assert_eq!(x1cube_right, x1cube); + + let x1quad = x1cube * x1; + let x1quad_right: U256 = "000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1".into(); + assert_eq!(x1quad_right, x1quad); + + let x1penta = x1quad * x1; + let x1penta_right: U256 = "00000000000001e92875ac24be246e1c57e0507e8c46cc8d233b77f6f4c72993".into(); + assert_eq!(x1penta_right, x1penta); + + let x1septima = x1penta * x1; + let x1septima_right: U256 = "00022cca1da3f6e5722b7d3cc5bbfb486465ebc5a708dd293042f932d7eee119".into(); + assert_eq!(x1septima_right, x1septima); + } +}