Switch to using 64-bit digits, adding a dependency on u128 support.

This commit is contained in:
2018-02-28 10:25:14 -08:00
parent 8746bf3e08
commit 093555b17d
2 changed files with 113 additions and 96 deletions

View File

@@ -10,35 +10,31 @@ use std::ops::*;
/// A 512-bit unsigned value /// A 512-bit unsigned value
#[derive(PartialEq,Eq,Debug,Clone)] #[derive(PartialEq,Eq,Debug,Clone)]
pub struct U512 { pub struct U512 {
// Why 9? Remember, we represent numbers in base 2^63, so that we can contents: [u64; 8]
// recover the carry bit as necessary. So we actually need ceiling(512/63)
// = 9 bytes to hold a 512-bit number.
contents: [u64; 9]
} }
impl U512 { impl U512 {
/// 0! /// 0!
pub fn zero() -> U512 { pub fn zero() -> U512 {
U512 { U512 {
contents: [0, 0, 0, 0, 0, 0, 0, 0, 0] contents: [0, 0, 0, 0, 0, 0, 0, 0]
} }
} }
/// The maximum possible value: 2^512 - 1. /// The maximum possible value: 2^512 - 1.
pub fn max() -> U512 { pub fn max() -> U512 {
U512 { U512 {
contents: [0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, contents: [0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF]
0xFF]
} }
} }
/// Convert a `u8` to a `U512`. This is always safe. /// Convert a `u8` to a `U512`. This is always safe.
pub fn from_u8(x: u8) -> U512 { pub fn from_u8(x: u8) -> U512 {
U512 { U512 {
contents: [x as u64, 0, 0, 0, 0, 0, 0, 0, 0] contents: [x as u64, 0, 0, 0, 0, 0, 0, 0]
} }
} }
@@ -51,7 +47,7 @@ impl U512 {
/// Convert a `u16` to a `U512`. This is always safe. /// Convert a `u16` to a `U512`. This is always safe.
pub fn from_u16(x: u16) -> U512 { pub fn from_u16(x: u16) -> U512 {
U512 { U512 {
contents: [x as u64, 0, 0, 0, 0, 0, 0, 0, 0] contents: [x as u64, 0, 0, 0, 0, 0, 0, 0]
} }
} }
@@ -64,7 +60,7 @@ impl U512 {
/// Convert a `u32` to a `U512`. This is always safe. /// Convert a `u32` to a `U512`. This is always safe.
pub fn from_u32(x: u32) -> U512 { pub fn from_u32(x: u32) -> U512 {
U512 { U512 {
contents: [x as u64, 0, 0, 0, 0, 0, 0, 0, 0] contents: [x as u64, 0, 0, 0, 0, 0, 0, 0]
} }
} }
@@ -77,14 +73,14 @@ impl U512 {
/// Convert a `u64` to a `U512`. This is always safe. /// Convert a `u64` to a `U512`. This is always safe.
pub fn from_u64(x: u64) -> U512 { pub fn from_u64(x: u64) -> U512 {
U512 { U512 {
contents: [x & 0x7FFFFFFFFFFFFFFF, x >> 63, 0, 0, 0, 0, 0, 0, 0] contents: [x, 0, 0, 0, 0, 0, 0, 0]
} }
} }
/// Convert a U512 into a `u64`. This should be the equivalent of masking /// Convert a U512 into a `u64`. This should be the equivalent of masking
/// the U512 with `0xFFFFFFFFFFFFFFFF` and then converting to a `u64`. /// the U512 with `0xFFFFFFFFFFFFFFFF` and then converting to a `u64`.
pub fn to_u64(&self) -> u64 { pub fn to_u64(&self) -> u64 {
(self.contents[0] as u64) | (self.contents[1] << 63) self.contents[0]
} }
} }
@@ -98,15 +94,21 @@ impl PartialOrd for U512 {
impl Ord for U512 { impl Ord for U512 {
fn cmp(&self, other: &U512) -> Ordering { fn cmp(&self, other: &U512) -> Ordering {
let sback = self.contents.iter().rev(); let mut i = 7;
let oback = other.contents.iter().rev();
for (x,y) in sback.zip(oback) { loop {
match x.cmp(y) { match self.contents[i].cmp(&other.contents[i]) {
Ordering::Equal => {}, Ordering::Equal => {
res => return res if i == 0 {
return Ordering::Equal;
} else {
i -= 1;
}
}
res =>
return res
} }
} }
Ordering::Equal
} }
} }
@@ -187,9 +189,8 @@ impl<'a> Not for &'a U512 {
let mut output = self.clone(); let mut output = self.clone();
for x in output.contents.iter_mut() { for x in output.contents.iter_mut() {
*x = !*x & 0x7FFFFFFFFFFFFFFF; *x = !*x;
} }
output.contents[8] &= 0xFF;
output output
} }
} }
@@ -318,22 +319,21 @@ impl<'a> BitXor<&'a U512> for &'a U512 {
impl ShlAssign<usize> for U512 { impl ShlAssign<usize> for U512 {
fn shl_assign(&mut self, amount: usize) { fn shl_assign(&mut self, amount: usize) {
let digits = amount / 63; let digits = amount / 64;
let bits = amount % 63; let bits = amount % 64;
let orig = self.contents.clone(); let orig = self.contents.clone();
for i in 0..9 { for i in 0..8 {
if i < digits { if i < digits {
self.contents[i] = 0; self.contents[i] = 0;
} else { } else {
let origidx = i - digits; let origidx = i - digits;
let prev = if origidx == 0 { 0 } else { orig[origidx - 1] }; let prev = if origidx == 0 { 0 } else { orig[origidx - 1] };
let carry = prev >> (63 - bits); let (carry,_) = if bits == 0 { (0, false) }
else { prev.overflowing_shr(64 - bits as u32) };
self.contents[i] = (orig[origidx] << bits) | carry; self.contents[i] = (orig[origidx] << bits) | carry;
self.contents[i] &= 0x7FFFFFFFFFFFFFFF;
} }
} }
self.contents[8] &= 0xFF;
} }
} }
@@ -361,20 +361,18 @@ impl<'a> Shl<usize> for &'a U512 {
impl ShrAssign<usize> for U512 { impl ShrAssign<usize> for U512 {
fn shr_assign(&mut self, amount: usize) { fn shr_assign(&mut self, amount: usize) {
let digits = amount / 63; let digits = amount / 64;
let bits = amount % 63; let bits = amount % 64;
let orig = self.contents.clone(); let orig = self.contents.clone();
for i in 0..9 { for i in 0..8 {
let oldidx = i + digits; let oldidx = i + digits;
let caridx = i + digits + 1; let caridx = i + digits + 1;
let old = if oldidx > 8 { 0 } else { orig[oldidx] }; let old = if oldidx > 7 { 0 } else { orig[oldidx] };
let carry = if caridx > 8 { 0 } else { orig[caridx] }; let carry = if caridx > 7 { 0 } else { orig[caridx] };
let (cb,_) = carry.overflowing_shl(63 - bits as u32); let cb = if bits == 0 { 0 } else { carry << (64 - bits) };
self.contents[i] = (old >> bits) | cb; self.contents[i] = (old >> bits) | cb;
self.contents[i] &= 0x7FFFFFFFFFFFFFFF;
} }
self.contents[8] &= 0xFF;
} }
} }
@@ -410,15 +408,13 @@ impl<'a> AddAssign<&'a U512> for U512 {
fn add_assign(&mut self, rhs: &U512) { fn add_assign(&mut self, rhs: &U512) {
let mut carry = 0; let mut carry = 0;
for i in 0..9 { for i in 0..8 {
let a = self.contents[i]; let a = self.contents[i] as u128;
let b = rhs.contents[i]; let b = rhs.contents[i] as u128;
let total = a + b + carry; let total = a + b + carry;
self.contents[i] = total as u64;
carry = total >> 63; carry = total >> 64;
self.contents[i] = total & 0x7FFFFFFFFFFFFFFF;
} }
self.contents[8] &= 0xFF;
} }
} }
@@ -471,17 +467,17 @@ mod test {
#[test] #[test]
fn test_builders() { fn test_builders() {
assert_eq!(U512{ contents: [0,0,0,0,0,0,0,0,0] }, assert_eq!(U512{ contents: [0,0,0,0,0,0,0,0] },
U512::from_u8(0)); U512::from_u8(0));
assert_eq!(U512{ contents: [0x7F,0,0,0,0,0,0,0,0] }, assert_eq!(U512{ contents: [0x7F,0,0,0,0,0,0,0] },
U512::from_u8(0x7F)); U512::from_u8(0x7F));
assert_eq!(U512{ contents: [0x7F7F,0,0,0,0,0,0,0,0] }, assert_eq!(U512{ contents: [0x7F7F,0,0,0,0,0,0,0] },
U512::from_u16(0x7F7F)); U512::from_u16(0x7F7F));
assert_eq!(U512{ contents: [0xCA5CADE5,0,0,0,0,0,0,0,0] }, assert_eq!(U512{ contents: [0xCA5CADE5,0,0,0,0,0,0,0] },
U512::from_u32(0xCA5CADE5)); U512::from_u32(0xCA5CADE5));
assert_eq!(U512{ contents: [0xCA5CADE5,0,0,0,0,0,0,0,0] }, assert_eq!(U512{ contents: [0xCA5CADE5,0,0,0,0,0,0,0] },
U512::from_u64(0xCA5CADE5)); U512::from_u64(0xCA5CADE5));
assert_eq!(U512{ contents: [0x7FFFFFFFFFFFFFFF,1,0,0,0,0,0,0,0] }, assert_eq!(U512{ contents: [0xFFFFFFFFFFFFFFFF,0,0,0,0,0,0,0] },
U512::from_u64(0xFFFFFFFFFFFFFFFF)); U512::from_u64(0xFFFFFFFFFFFFFFFF));
} }
@@ -531,16 +527,15 @@ mod test {
impl Arbitrary for U512 { impl Arbitrary for U512 {
fn arbitrary<G: Gen>(g: &mut G) -> U512 { fn arbitrary<G: Gen>(g: &mut G) -> U512 {
let x1 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x1 = g.next_u64();
let x2 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x2 = g.next_u64();
let x3 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x3 = g.next_u64();
let x4 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x4 = g.next_u64();
let x5 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x5 = g.next_u64();
let x6 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x6 = g.next_u64();
let x7 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x7 = g.next_u64();
let x8 = g.next_u64() & 0x7FFFFFFFFFFFFFFF; let x8 = g.next_u64();
let x9 = g.next_u64() & 0xFF; U512{ contents: [x1, x2, x3, x4, x5, x6, x7, x8] }
U512{ contents: [x1, x2, x3, x4, x5, x6, x7, x8, x9] }
} }
} }
@@ -626,49 +621,70 @@ mod test {
#[test] #[test]
fn shl_tests() { fn shl_tests() {
assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1,1] } << 0, assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1] } << 0,
U512{ contents: [1,1,1,1,1,1,1,1,1] }); U512{ contents: [1,1,1,1,1,1,1,1] });
assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1,1] } << 512, assert_eq!(U512{ contents: [1,2,3,4,5,6,7,8] } << 0,
U512{ contents: [0,0,0,0,0,0,0,0,0] }); U512{ contents: [1,2,3,4,5,6,7,8] });
assert_eq!(U512{ contents: [2,0,0,0,0,0,0,0,0] } << 1, assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1] } << 512,
U512{ contents: [4,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,0] } << 63, assert_eq!(U512{ contents: [2,0,0,0,0,0,0,0] } << 1,
U512{ contents: [0,1,0,0,0,0,0,0,0] }); U512{ contents: [4,0,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0,0] } << 65, assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } << 64,
U512{ contents: [0,4,0,0,0,0,0,0,0] }); U512{ contents: [0,1,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [0x4000000000000000,0,0,0,0,0,0,0,0] } << 1, assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } << 66,
U512{ contents: [0,1,0,0,0,0,0,0,0] }); U512{ contents: [0,4,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0,0xFF] } << 1, assert_eq!(U512{ contents: [0x8000000000000000,0,0,0,0,0,0,0] } << 1,
U512{ contents: [2,0,0,0,0,0,0,0,0xFE] }); U512{ contents: [0,1,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } << 1,
U512{ contents: [2,0,0,0,0,0,0,0] });
} }
#[test] #[test]
fn shr_tests() { fn shr_tests() {
assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1,1] } >> 0, assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1] } >> 0,
U512{ contents: [1,1,1,1,1,1,1,1,1] }); U512{ contents: [1,1,1,1,1,1,1,1] });
assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1,1] } >> 512, assert_eq!(U512{ contents: [1,2,3,4,5,6,7,8] } >> 0,
U512{ contents: [0,0,0,0,0,0,0,0,0] }); U512{ contents: [1,2,3,4,5,6,7,8] });
assert_eq!(U512{ contents: [2,0,0,0,0,0,0,0,0] } >> 1, assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1] } >> 512,
U512{ contents: [1,0,0,0,0,0,0,0,0] }); U512{ contents: [0,0,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [0,1,0,0,0,0,0,0,0] } >> 1, assert_eq!(U512{ contents: [2,0,0,0,0,0,0,0] } >> 1,
U512{ contents: [0x4000000000000000,0,0,0,0,0,0,0,0] }); U512{ contents: [1,0,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [0,1,0,0,0,0,0,0,0] } >> 63, assert_eq!(U512{ contents: [0,1,0,0,0,0,0,0] } >> 1,
U512{ contents: [1,0,0,0,0,0,0,0,0] }); U512{ contents: [0x8000000000000000,0,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [0,4,0,0,0,0,0,0,0] } >> 65, assert_eq!(U512{ contents: [0,1,0,0,0,0,0,0] } >> 64,
U512{ contents: [1,0,0,0,0,0,0,0,0] }); U512{ contents: [1,0,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [0,4,0,0,0,0,0,0] } >> 66,
U512{ contents: [1,0,0,0,0,0,0,0] });
}
quickcheck! {
fn shift_mask_equivr(x: U512, in_shift: usize) -> bool {
let shift = in_shift % 512;
let mask = U512::max() << shift;
let masked_x = &x & mask;
let shift_maskr = (x >> shift) << shift;
shift_maskr == masked_x
}
fn shift_mask_equivl(x: U512, in_shift: usize) -> bool {
let shift = in_shift % 512;
let mask = U512::max() >> shift;
let masked_x = &x & mask;
let shift_maskl = (x << shift) >> shift;
shift_maskl == masked_x
}
} }
#[test] #[test]
fn add_tests() { fn add_tests() {
assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1,1] } + assert_eq!(U512{ contents: [1,1,1,1,1,1,1,1] } +
U512{ contents: [1,1,1,1,1,1,1,1,1] }, U512{ contents: [1,1,1,1,1,1,1,1] },
U512{ contents: [2,2,2,2,2,2,2,2,2] }); U512{ contents: [2,2,2,2,2,2,2,2] });
assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0,0] } + assert_eq!(U512{ contents: [1,0,0,0,0,0,0,0] } +
U512{ contents: [0x7FFFFFFFFFFFFFFF,0,0,0,0,0,0,0,0] }, U512{ contents: [0xFFFFFFFFFFFFFFFF,0,0,0,0,0,0,0] },
U512{ contents: [0,1,0,0,0,0,0,0,0] }); U512{ contents: [0,1,0,0,0,0,0,0] });
assert_eq!(U512{ contents: [0,0,0,0,0,0,0,0,1] } + assert_eq!(U512{ contents: [0,0,0,0,0,0,0,1] } +
U512{ contents: [0,0,0,0,0,0,0,0,0xFF] }, U512{ contents: [0,0,0,0,0,0,0,0xFFFFFFFFFFFFFFFF] },
U512{ contents: [0,0,0,0,0,0,0,0,0] }); U512{ contents: [0,0,0,0,0,0,0,0] });
} }
quickcheck! { quickcheck! {

View File

@@ -1,3 +1,4 @@
#![feature(i128_type)]
//! # Simple Crypto: A quaint little crypto library for rust. //! # Simple Crypto: A quaint little crypto library for rust.
//! //!
//! This is the simple_crypto library. Its goal is to provide straightforward //! This is the simple_crypto library. Its goal is to provide straightforward