Add multiplication.
This commit is contained in:
160
src/cryptonum.rs
160
src/cryptonum.rs
@@ -460,6 +460,102 @@ impl<'a,'b> Add<&'a U512> for &'b U512 {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
impl MulAssign<U512> for U512 {
|
||||
fn mul_assign(&mut self, rhs: U512) {
|
||||
self.mul_assign(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MulAssign<&'a U512> for U512 {
|
||||
fn mul_assign(&mut self, rhs: &U512) {
|
||||
let orig = self.contents.clone();
|
||||
let mut table = [[0 as u128; 8]; 8];
|
||||
// This uses "simple" grade school techniques to work things out. But,
|
||||
// for reference, consider two 4 digit numbers:
|
||||
//
|
||||
// l0c3 l0c2 l0c1 l0c0 [orig]
|
||||
// x l1c3 l1c2 l1c1 l1c0 [rhs.contents]
|
||||
// ------------------------------------------------------------
|
||||
// (l0c3*l1c0) (l0c2*l1c0) (l0c1*l1c0) (l0c0*l1c0)
|
||||
// (l0c2*l1c1) (l0c1*l1c1) (l0c0*l1c1)
|
||||
// (l0c1*l1c2) (l0c0*l1c2)
|
||||
// (l0c0*l1c3)
|
||||
// ------------------------------------------------------------
|
||||
// AAAAA BBBBB CCCCC DDDDD
|
||||
for line in 0..8 {
|
||||
let maxcol = 8 - line;
|
||||
for col in 0..maxcol {
|
||||
let left = orig[col] as u128;
|
||||
let right = rhs.contents[line] as u128;
|
||||
table[line][col + line] = left * right;
|
||||
}
|
||||
}
|
||||
// ripple the carry across each line, ensuring that each entry in the
|
||||
// table is 64-bits
|
||||
for line in 0..8 {
|
||||
let mut carry = 0;
|
||||
for col in 0..8 {
|
||||
table[line][col] = table[line][col] + carry;
|
||||
carry = table[line][col] >> 64;
|
||||
table[line][col] &= 0xFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
}
|
||||
// now do the final addition across the lines, rippling the carry as
|
||||
// normal
|
||||
let mut carry = 0;
|
||||
for col in 0..8 {
|
||||
let mut total = carry;
|
||||
for line in 0..8 {
|
||||
total += table[line][col];
|
||||
}
|
||||
self.contents[col] = total as u64;
|
||||
carry = total >> 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<U512> for U512 {
|
||||
type Output = U512;
|
||||
|
||||
fn mul(self, rhs: U512) -> U512 {
|
||||
let mut res = self.clone();
|
||||
res.mul_assign(rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Mul<U512> for &'a U512 {
|
||||
type Output = U512;
|
||||
|
||||
fn mul(self, rhs: U512) -> U512 {
|
||||
let mut res = self.clone();
|
||||
res.mul_assign(rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Mul<&'a U512> for U512 {
|
||||
type Output = U512;
|
||||
|
||||
fn mul(self, rhs: &U512) -> U512 {
|
||||
let mut res = self.clone();
|
||||
res.mul_assign(rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Mul<&'a U512> for &'b U512 {
|
||||
type Output = U512;
|
||||
|
||||
fn mul(self, rhs: &U512) -> U512 {
|
||||
let mut res = self.clone();
|
||||
res.mul_assign(rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
@@ -694,5 +790,69 @@ mod test {
|
||||
fn add_commutivity(a: U512, b: U512, c: U512) -> bool {
|
||||
(&a + (&b + &c)) == ((&a + &b) + &c)
|
||||
}
|
||||
fn add_identity(a: U512) -> bool {
|
||||
(&a + U512::zero()) == a
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul_tests() {
|
||||
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } *
|
||||
U512{ contents: [1,0,0,0,0,0,0,0] },
|
||||
U512{ contents: [1,0,0,0,0,0,0,0] });
|
||||
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } *
|
||||
U512{ contents: [0,0,0,0,0,0,0,0] },
|
||||
U512{ contents: [0,0,0,0,0,0,0,0] });
|
||||
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } *
|
||||
U512{ contents: [2,0,0,0,0,0,0,0] },
|
||||
U512{ contents: [2,0,0,0,0,0,0,0] });
|
||||
assert_eq!(U512{ contents: [0xFFFFFFFFFFFFFFFF,0,0,0,0,0,0,0] } *
|
||||
U512{ contents: [0xFFFFFFFFFFFFFFFF,0,0,0,0,0,0,0] },
|
||||
U512{ contents: [1,0xFFFFFFFFFFFFFFFE,0,0,0,0,0,0] });
|
||||
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } *
|
||||
U512{ contents: [0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF] },
|
||||
U512{ contents: [0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF] });
|
||||
assert_eq!(U512{ contents: [2,0,0,0,0,0,0,0] } *
|
||||
U512{ contents: [0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF] },
|
||||
U512{ contents: [0xFFFFFFFFFFFFFFFE,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF] });
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn mul_symmetry(a: U512, b: U512) -> bool {
|
||||
(&a * &b) == (&b * &a)
|
||||
}
|
||||
fn mul_commutivity(a: U512, b: U512, c: U512) -> bool {
|
||||
(&a * (&b * &c)) == ((&a * &b) * &c)
|
||||
}
|
||||
fn mul_identity(a: U512) -> bool {
|
||||
(&a * U512::from_u64(1)) == a
|
||||
}
|
||||
fn mul_zero(a: U512) -> bool {
|
||||
(&a * U512::zero()) == U512::zero()
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn addmul_distribution(a: U512, b: U512, c: U512) -> bool {
|
||||
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
|
||||
}
|
||||
fn mul2shift1_equiv(a: U512) -> bool {
|
||||
(&a << 1) == (&a * U512::from_u64(2))
|
||||
}
|
||||
fn mul16shift4_equiv(a: U512) -> bool {
|
||||
(&a << 4) == (&a * U512::from_u64(16))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user