use cryptonum::signed::SCN; use num::{BigUint,ToPrimitive,Zero}; use rand::Rng; use std::fmt; use std::fmt::Write; use std::cmp::Ordering; use std::ops::*; /// In case you were wondering, it stands for "Unsigned Crypto Num". #[derive(Clone,Debug,PartialEq,Eq)] pub struct UCN { pub(crate) contents: Vec } pub struct BarrettUCN { pub(crate) u: UCN, pub(crate) k: usize, pub(crate) m: UCN } static SMALL_PRIMES: [u32; 310] = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053]; impl UCN { pub fn zero() -> UCN { UCN{ contents: vec![] } } pub fn bits(&self) -> usize { self.contents.len() * 64 } pub fn is_zero(&self) -> bool { self.contents.len() == 0 } pub fn is_odd(&self) -> bool { if self.contents.len() == 0 { false } else { (self.contents[0] & 1) == 1 } } pub fn is_even(&self) -> bool { if self.contents.len() == 0 { false } else { (self.contents[0] & 1) == 0 } } fn clean(&mut self) { loop { match self.contents.pop() { None => break, Some(0) => continue, Some(x) => { self.contents.push(x); break } } } } fn expand(&mut self, rhs: &UCN) { while self.contents.len() < rhs.contents.len() { self.contents.push(0); } } pub fn from_str(x: &str) -> UCN { let mut outvec = Vec::new(); let mut worker = 0; let mut shift = 0; for c in x.chars().rev() { match c.to_digit(16) { None => panic!("Bad character in string: {}", c), Some(v) => { worker = worker + ((v as u64) << shift); shift += 4; } } if shift == 64 { outvec.push(worker); worker = 0; shift = 0; } } outvec.push(worker); let mut res = UCN{ contents: outvec }; res.clean(); res } pub fn modinv(&self, phi: &UCN) -> UCN { let (_, mut x, _) = self.extended_euclidean(&phi); let int_phi = SCN::from(phi.clone()); while x.is_negative() { x = x + &int_phi; } x.into() } fn extended_euclidean(&self, b: &UCN) -> (SCN, SCN, SCN) { let posinta = SCN::from(self.clone()); let posintb = SCN::from(b.clone()); let (d, x, y) = posinta.egcd(posintb); if d.is_negative() { (d.neg(), x.neg(), y.neg()) } else { (d, x, y) } } pub fn generate_prime(rng: &mut G, bitlen: usize, iterations: usize, ok_value: F) -> UCN where G: Rng, F: Fn(&UCN) -> bool { let one = UCN::from(1 as u8); let topbit = &one << (bitlen - 1); loop { let base = random_number(rng, bitlen); let candidate = base | &topbit | &one; if !ok_value(&candidate) { continue; } if candidate.probably_prime(rng, iterations) { return candidate } } } pub fn probably_prime(&self, g: &mut G, iters: usize) -> bool { for tester in SMALL_PRIMES.iter() { if (self % UCN::from(*tester)).is_zero() { return false; } } miller_rabin(g, &self, iters) } pub fn barrett_u(&self) -> BarrettUCN { let k = self.contents.len(); let b = UCN::from(1 as u8) << (64 * 2 * k); println!(""); println!("b: {:X}", b); println!("s: {:X}", self); let u = b / self; println!("u: {:X}", u); BarrettUCN{ u: u, k: k, m: self.clone() } } pub fn reduce(&self, u: &BarrettUCN) -> UCN { println!("------"); println!("u.m: {:X}", u.m); println!("u.u: {:X}", u.u); println!("u.k: {}", u.k); println!("self: {:X}", self); // 1. q1←⌊x/bk−1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋. let q1 = self >> (64 * (u.k - 1)); println!("q1: {:X}", q1); let q2 = q1 * &u.u; println!("q2: {:X}", q2); let q3 = q2 >> (64 * (u.k + 1)); println!("q3: {:X}", q3); // 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 − r2. // 3. If r<0 then r←r+bk+1. let mut r1 = self.clone(); r1.contents.resize(u.k + 1, 0); println!("r1: {:X}", r1); let mut r2 = q3 * &u.m; r2.contents.resize(u.k + 1, 0); let mut r = if r1 >= r2 { r1 - r2 } else { let mut bk1cont = Vec::with_capacity(u.k + 1); bk1cont.resize(u.k, 0); bk1cont.push(1); (r1 + UCN{ contents: bk1cont }) - r2 }; // 4. Whiler≥mdo:r←r−m. while &r >= &u.m { r -= &u.m; } // 5. Return(r). r } pub fn modexp(&self, e: &UCN, m: &UCN) -> UCN { let mut b = self.clone() % m; let mut eprime = e.clone(); let mut result = UCN::from(1 as u8); loop { if eprime.is_zero() { return result; } if eprime.is_odd() { result = (result * &b) % m; } b = (&b * &b) % m; eprime >>= 1; } } } fn miller_rabin(g: &mut G, n: &UCN, iters: usize) -> bool { let one = UCN::from(1 as u8); let two = UCN::from(2 as u8); let nm1 = n - &one; // Quoth Wikipedia: // write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1 let mut d = nm1.clone(); let mut r = 0; while d.is_even() { d >>= 1; r += 1; assert!(r < n.bits()); } // WitnessLoop: repeat k times 'WitnessLoop: for _k in 0..iters { // pick a random integer a in the range [2, n - 2] let a = random_in_range(g, &two, &nm1); // x <- a^d mod n let mut x = a.modexp(&d, &n); // if x = 1 or x = n - 1 then if (&x == &one) || (&x == &nm1) { // continue WitnessLoop continue 'WitnessLoop; } // repeat r - 1 times: for _i in 0..r { // x <- x^2 mod n x = x.modexp(&two, &n); // if x = 1 then if &x == &one { // return composite return false; } // if x = n - 1 then if &x == &nm1 { // continue WitnessLoop continue 'WitnessLoop; } } // return composite return false; } // return probably prime true } fn random_in_range(rng: &mut G, min: &UCN, max: &UCN) -> UCN { let bitlen = ((max.bits() + 31) / 32) * 32; loop { let candidate = random_number(rng, bitlen); if (&candidate >= min) && (&candidate < max) { return candidate; } } } fn random_number(rng: &mut G, bitlen: usize) -> UCN { assert!(bitlen % 32 == 0); let wordlen = bitlen / 32; let components = rng.gen_iter().take(wordlen).collect(); UCN{ contents: components } } impl fmt::UpperHex for UCN { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> { for x in self.contents.iter().rev() { fmt.write_char(tochar_upper(x >> 60))?; fmt.write_char(tochar_upper(x >> 56))?; fmt.write_char(tochar_upper(x >> 52))?; fmt.write_char(tochar_upper(x >> 48))?; fmt.write_char(tochar_upper(x >> 44))?; fmt.write_char(tochar_upper(x >> 40))?; fmt.write_char(tochar_upper(x >> 36))?; fmt.write_char(tochar_upper(x >> 32))?; fmt.write_char(tochar_upper(x >> 28))?; fmt.write_char(tochar_upper(x >> 24))?; fmt.write_char(tochar_upper(x >> 20))?; fmt.write_char(tochar_upper(x >> 16))?; fmt.write_char(tochar_upper(x >> 12))?; fmt.write_char(tochar_upper(x >> 8))?; fmt.write_char(tochar_upper(x >> 4))?; fmt.write_char(tochar_upper(x >> 0))?; } Ok(()) } } fn tochar_upper(x: u64) -> char { match (x as u8) & (0xF as u8) { 0x0 => '0', 0x1 => '1', 0x2 => '2', 0x3 => '3', 0x4 => '4', 0x5 => '5', 0x6 => '6', 0x7 => '7', 0x8 => '8', 0x9 => '9', 0xA => 'A', 0xB => 'B', 0xC => 'C', 0xD => 'D', 0xE => 'E', 0xF => 'F', _ => panic!("the world is broken") } } impl fmt::LowerHex for UCN { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> { for x in self.contents.iter().rev() { fmt.write_char(tochar_lower(x >> 60))?; fmt.write_char(tochar_lower(x >> 56))?; fmt.write_char(tochar_lower(x >> 52))?; fmt.write_char(tochar_lower(x >> 48))?; fmt.write_char(tochar_lower(x >> 44))?; fmt.write_char(tochar_lower(x >> 40))?; fmt.write_char(tochar_lower(x >> 36))?; fmt.write_char(tochar_lower(x >> 32))?; fmt.write_char(tochar_lower(x >> 28))?; fmt.write_char(tochar_lower(x >> 24))?; fmt.write_char(tochar_lower(x >> 20))?; fmt.write_char(tochar_lower(x >> 16))?; fmt.write_char(tochar_lower(x >> 12))?; fmt.write_char(tochar_lower(x >> 8))?; fmt.write_char(tochar_lower(x >> 4))?; fmt.write_char(tochar_lower(x >> 0))?; } Ok(()) } } fn tochar_lower(x: u64) -> char { match (x as u8) & (0xF as u8) { 0x0 => '0', 0x1 => '1', 0x2 => '2', 0x3 => '3', 0x4 => '4', 0x5 => '5', 0x6 => '6', 0x7 => '7', 0x8 => '8', 0x9 => '9', 0xA => 'a', 0xB => 'b', 0xC => 'c', 0xD => 'd', 0xE => 'e', 0xF => 'f', _ => panic!("the world is broken") } } //------------------------------------------------------------------------------ // // Conversions to/from crypto nums. // //------------------------------------------------------------------------------ define_from!(UCN, u8); define_from!(UCN, u16); define_from!(UCN, u32); define_from!(UCN, u64); define_from!(UCN, usize); define_into!(UCN, u8); define_into!(UCN, u16); define_into!(UCN, u32); define_into!(UCN, u64); define_into!(UCN, usize); impl From for UCN { fn from(mut x: BigUint) -> UCN { let mut dest = Vec::new(); let mask = BigUint::from(0xFFFFFFFFFFFFFFFF as u64); while !x.is_zero() { match (&x & &mask).to_u64() { None => panic!("Can't use BigUint in From"), Some(val) => dest.push(val) } x >>= 64; } UCN{ contents: dest } } } impl Into for UCN { fn into(self) -> BigUint { let mut result = BigUint::zero(); for part in self.contents.iter().rev() { result <<= 64; result += BigUint::from(*part); } result } } //------------------------------------------------------------------------------ // // Comparisons // //------------------------------------------------------------------------------ impl PartialOrd for UCN { fn partial_cmp(&self, other: &UCN) -> Option { Some(self.cmp(other)) } } impl Ord for UCN { fn cmp(&self, other: &UCN) -> Ordering { match self.contents.len().cmp(&other.contents.len()) { Ordering::Equal => { let mut me = self.contents.iter().rev(); let mut them = other.contents.iter().rev(); for (m, t) in me.zip(them) { match m.cmp(t) { Ordering::Equal => continue, res => return res } } Ordering::Equal } x => x } } } //------------------------------------------------------------------------------ // // Bit Operations // //------------------------------------------------------------------------------ impl Not for UCN { type Output = UCN; fn not(self) -> UCN { let mut contents = self.contents; for x in contents.iter_mut() { *x = !*x; } let mut res = UCN{ contents: contents }; res.clean(); res } } impl<'a> Not for &'a UCN { type Output = UCN; fn not(self) -> UCN { let res = self.clone(); res.not() } } impl<'a> BitOrAssign<&'a UCN> for UCN { fn bitor_assign(&mut self, rhs: &UCN) { self.expand(&rhs); { let mut iter_me = self.contents.iter_mut(); let mut iter_tm = rhs.contents.iter(); loop { match (iter_me.next(), iter_tm.next()) { (Some(dest), Some(val)) => *dest |= val, _ => break } } } self.clean(); } } impl<'a> BitXorAssign<&'a UCN> for UCN { fn bitxor_assign(&mut self, rhs: &UCN) { self.expand(&rhs); { let mut iter_me = self.contents.iter_mut(); let mut iter_tm = rhs.contents.iter(); loop { match (iter_me.next(), iter_tm.next()) { (Some(dest), Some(val)) => *dest ^= val, _ => break } } } self.clean(); } } impl<'a> BitAndAssign<&'a UCN> for UCN { fn bitand_assign(&mut self, rhs: &UCN) { if self.contents.len() > rhs.contents.len() { self.contents.resize(rhs.contents.len(), 0); } { let mut iter_me = self.contents.iter_mut(); let mut iter_tm = rhs.contents.iter(); loop { match (iter_me.next(), iter_tm.next()) { (Some(dest), Some(val)) => *dest &= val, _ => break } } } self.clean(); } } derive_arithmetic_operators!(UCN, BitOr, bitor, BitOrAssign, bitor_assign); derive_arithmetic_operators!(UCN, BitXor, bitxor, BitXorAssign, bitxor_assign); derive_arithmetic_operators!(UCN, BitAnd, bitand, BitAndAssign, bitand_assign); //------------------------------------------------------------------------------ // // Shifts // //------------------------------------------------------------------------------ impl ShlAssign for UCN { fn shl_assign(&mut self, rhs: u64) { let mut digits = rhs / 64; let bits = rhs % 64; let mut carry = 0; // ripple the bit-level shift through if bits != 0 { for x in self.contents.iter_mut() { let new_carry = *x >> (64 - bits); *x = (*x << bits) | carry; carry = new_carry; } } // if we pulled some stuff off the end, add it back if carry != 0 { self.contents.push(carry); } // add the appropriate digits on the low side while digits > 0 { self.contents.insert(0,0); digits -= 1; } } } impl Shl for UCN { type Output = UCN; fn shl(self, rhs: u64) -> UCN { let mut copy = self.clone(); copy.shl_assign(rhs); copy } } derive_shift_operators!(UCN, ShlAssign, Shl, shl_assign, shl, usize); derive_shift_operators!(UCN, ShlAssign, Shl, shl_assign, shl, u32); derive_shift_operators!(UCN, ShlAssign, Shl, shl_assign, shl, u16); derive_shift_operators!(UCN, ShlAssign, Shl, shl_assign, shl, u8); impl ShrAssign for UCN { fn shr_assign(&mut self, rhs: u64) { let mut digits = rhs / 64; let bits = rhs % 64; // remove the appropriate digits on the low side while (digits > 0) && (self.contents.len() > 0) { self.contents.remove(0); digits -= 1; } // ripple the shifts over let mut carry = 0; let mask = !(0xFFFFFFFFFFFFFFFF << bits); for x in self.contents.iter_mut().rev() { let base = *x >> bits; let (new_carry, _) = (*x & mask).overflowing_shl((64-bits) as u32); *x = base | carry; carry = new_carry; } // in this case, we just junk the extra carry bits, but we do need to // cleanup possible zeros at the end. self.clean(); } } impl Shr for UCN { type Output = UCN; fn shr(self, rhs: u64) -> UCN { let mut copy = self.clone(); copy.shr_assign(rhs); copy } } derive_shift_operators!(UCN, ShrAssign, Shr, shr_assign, shr, usize); derive_shift_operators!(UCN, ShrAssign, Shr, shr_assign, shr, u32); derive_shift_operators!(UCN, ShrAssign, Shr, shr_assign, shr, u16); derive_shift_operators!(UCN, ShrAssign, Shr, shr_assign, shr, u8); derive_signed_shift_operators!(UCN, usize, isize); derive_signed_shift_operators!(UCN, u64, i64); derive_signed_shift_operators!(UCN, u32, i32); derive_signed_shift_operators!(UCN, u16, i16); derive_signed_shift_operators!(UCN, u8, i8); //------------------------------------------------------------------------------ // // Addition, Subtraction and Multiplication // //------------------------------------------------------------------------------ impl<'a> AddAssign<&'a UCN> for UCN { fn add_assign(&mut self, rhs: &UCN) { let mut iter_tm = rhs.contents.iter(); let mut stolen = None; let mut carry = 0; // loop through every element on the left hand side, breaking early // on if we right the end of the left hand side. { let mut iter_me = self.contents.iter_mut(); loop { match(iter_me.next(), iter_tm.next()) { (None, None) => break, (Some(dest), None) => { let dest128 = *dest as u128; let newdest = dest128 + carry; *dest = newdest as u64; carry = newdest >> 64; } (None, Some(x)) => { stolen = Some(*x); break; } (Some(dest), Some(r)) => { let newdest = (*dest as u128) + (*r as u128) + carry; *dest = newdest as u64; carry = newdest >> 64; } } } } // if we accidentally stole something form the right iterator, // push it back on. if let Some(x) = stolen { let stolen128 = (x as u128) + carry; self.contents.push(stolen128 as u64); carry = stolen128 >> 64; } // now loop through any remaining items on the right hand side, // pushing them onto the result. for x in iter_tm { let x128 = (*x as u128) + carry; self.contents.push(x128 as u64); carry = x128 >> 64; } // finally, if there's still a carry, push it on the end. if carry > 0 { self.contents.push(carry as u64); } } } impl<'a> SubAssign<&'a UCN> for UCN { fn sub_assign(&mut self, rhs: &UCN) { { let mut borrow = 0; let mut iter_me = self.contents.iter_mut(); let mut iter_tm = rhs.contents.iter(); loop { assert!( (borrow == 0) | (borrow == 1) ); match (iter_me.next(), iter_tm.next()) { (None, None) if borrow == 0 => break, (None, None) => panic!("Generated negative UCN in subtraction (1)."), (Some(x), None) => { if borrow == 0 { break; } if *x == 0 { *x = 0xFFFFFFFFFFFFFFFF; borrow = 1; } else { *x = *x - borrow; break; } } (None, Some(_)) => { panic!("Generated negative UCN in subtraction (2)."); } (Some(x), Some(y)) => { if (*x >= borrow) && ((*x - borrow) >= *y) { *x = (*x - borrow) - *y; borrow = 0; } else { let x128 = (*x as u128) + 0x10000000000000000; let res = x128 - (*y as u128) - (borrow as u128); *x = res as u64; borrow = 1; } } } } } self.clean(); } } impl<'a> MulAssign<&'a UCN> for UCN { fn mul_assign(&mut self, rhs: &UCN) { // Handle the quick and easy multiplication by zero cases first. if self.contents.len() == 0 { return; } if rhs.contents.len() == 0 { self.contents.resize(0,0); return; } // OK, do some real multiplication let x = self.contents.clone(); let y = rhs.contents.clone(); let outlen = x.len() + y.len(); let n = y.len() - 1; // this algorithm is 14.12 from "Handbook of Applied Cryptography" self.contents.resize(0, 0); self.contents.resize(outlen, 0); for (i,xi) in x.iter().enumerate() { let mut c = 0; for (j,yj) in y.iter().enumerate() { let wij = self.contents[i+j] as u128; let xjyi = (*xi as u128) * (*yj as u128); let uv = wij + xjyi + c; self.contents[i+j] = uv as u64; c = uv >> 64; } self.contents[i+n+1] = c as u64; } self.clean(); } } pub fn divmod(quotient: &mut Vec, remainder: &mut Vec, inx: &Vec, iny: &Vec) { quotient.resize(0,0); remainder.resize(0,0); // This algorithm is 14.20 from "Handbook of Applied Cryptography" // // It requires that y[t] is not zero, which it isn't due to our invariant // that we don't have unnecessary zeros at the end of the array. We note // that it's also very convienent if the top bit of y[t] is set, as well, // so we shift everything left so that things work out. let mut xbuffer = Vec::with_capacity(inx.len() + 2); let mut ybuffer = Vec::with_capacity(iny.len() + 2); xbuffer.extend_from_slice(&inx); ybuffer.extend_from_slice(&iny); let mut x = UCN{ contents: xbuffer }; let mut y = UCN{ contents: ybuffer }; let additional_shift = iny[iny.len() - 1].leading_zeros() as usize; x <<= additional_shift; y <<= additional_shift; println!("additional_shift: {}", additional_shift); // Once we've done this, we should be good to go with our mostly-correct // x and y. The only trick is that the algorithm requires that n >= t. If // this is not true, then the answer is zero, because the divisor is greater // than the dividend. let n = x.contents.len(); let t = y.contents.len(); if n < t { remainder.extend_from_slice(&inx); return; } println!("n: {} t: {}", n, t); // Also, it's real convient for n and t to be greater than one, which we // achieve by pushing a zero into the low digit. Because we do this, we // don't have to do a lot of testing against negative indices later. x.contents.insert(0,0); y.contents.insert(0,0); println!("y[t] = {:x}", y.contents[t]); // 1. For j from 0 to (n-t) do: qj <- 0. let mut q = Vec::with_capacity(n - t + 1); q.resize(n - t + 1, 0); // 2. While (x >= yb^(n-t)) do the following: // q_(n-t) <- q_(n-t) + 1 // x <- x - yb^(n-t) let ybnt = &y << (64 * (n - t)); while &x >= &ybnt { q[n-t] = q[n-t] + 1; x -= &ybnt; } println!("q: {:X}", UCN{ contents: q.clone() }); // 3. For i from n down to (t + 1) do the following: let mut i = n; while i >= (t + 1) { // 3.1. if xi = yt, then set q_(i-t-1) <- b - 1; otherwise set // q_(i-t-1) <- floor((x_i * b + x_(i-1)) /y_t). if x.contents[i] == y.contents[t] { q[i-t-1] = 0xFFFFFFFFFFFFFFFF; } else { let top = ((x.contents[i] as u128)<<64) + (x.contents[i-1] as u128); let bot = y.contents[t] as u128; let solution = top / bot; q[i-t-1] = solution as u64; } // 3.2. While (q_(i-t-1)(y_t * b + y_(t-1)) > x_i(b2) + x_(i-1)b + // x_(i-2)) do: // q_(i - t - 1) <- q_(i - t 1) - 1. loop { let qit1 = UCN{ contents: vec![q[i - t - 1]] }; let ytbyt1 = UCN{ contents: vec![y.contents[t-1], y.contents[t]] }; let left = qit1 * ytbyt1; let right = UCN{ contents: vec![x.contents[i-2], x.contents[i-1], x.contents[i]] }; if left <= right { break } q[i - t - 1] -= 1; } // 3.3. x <- x - q_(i - t - 1) * y * b^(i-t-1) let qit1 = UCN{ contents: vec![q[i - t - 1]] }; let ybit1 = &y << (64 * (i - t - 1)); let subbit = &qit1 * &ybit1; if subbit <= x { x -= subbit; } else { // 3.4. if x < 0 then set z <- x + yb^(i-t-1) and // q_(i-t-1) <- q(i-t-1) - 1 x -= subbit - ybit1; q[i - t - 1] -= 1; } i -= 1; } // 4. r <- x x >>= additional_shift; if x.contents.len() > 0 { // remember, we added a zero to the front of // everything earlier; this removes it. x.contents.remove(0); } remainder.append(&mut x.contents); // 5. return (q,r) while (q.len() > 0) && (q[q.len() - 1] == 0) { q.pop(); } quotient.append(&mut q); } impl<'a> DivAssign<&'a UCN> for UCN { fn div_assign(&mut self, rhs: &UCN) { let copy = self.contents.clone(); let mut dead = Vec::new(); divmod(&mut self.contents, &mut dead, ©, &rhs.contents); } } impl<'a> RemAssign<&'a UCN> for UCN { fn rem_assign(&mut self, rhs: &UCN) { let copy = self.contents.clone(); let mut dead = Vec::new(); divmod(&mut dead, &mut self.contents, ©, &rhs.contents); } } derive_arithmetic_operators!(UCN, Add, add, AddAssign, add_assign); derive_arithmetic_operators!(UCN, Sub, sub, SubAssign, sub_assign); derive_arithmetic_operators!(UCN, Mul, mul, MulAssign, mul_assign); derive_arithmetic_operators!(UCN, Div, div, DivAssign, div_assign); derive_arithmetic_operators!(UCN, Rem, rem, RemAssign, rem_assign); //------------------------------------------------------------------------------ // // Tests! // //------------------------------------------------------------------------------ #[cfg(test)] mod test { use quickcheck::{Arbitrary,Gen}; use super::*; #[test] fn test_clean() { let mut val1 = UCN{ contents: vec![1,0,0] }; val1.clean(); assert_eq!(val1, UCN{ contents: vec![1] }); // let mut val2 = UCN{ contents: vec![0,0,0] }; val2.clean(); assert_eq!(val2, UCN{ contents: vec![] }); // let mut val3 = UCN{ contents: vec![1,0,1] }; val3.clean(); assert_eq!(val3, UCN{ contents: vec![1,0,1] }); // let mut val4 = UCN{ contents: vec![] }; val4.clean(); assert_eq!(val4, UCN{ contents: vec![] }); } #[test] #[allow(overflowing_literals)] fn test_builders() { assert_eq!(UCN{ contents: vec![] }, UCN::from(0 as u8)); assert_eq!(UCN{ contents: vec![0x7F] }, UCN::from(0x7F as u8)); assert_eq!(UCN{ contents: vec![0x7F7F] }, UCN::from(0x7F7F as u16)); assert_eq!(UCN{ contents: vec![0xCA5CADE5] }, UCN::from(0xCA5CADE5 as u32)); assert_eq!(UCN{ contents: vec![0xFFFFFFFFFFFFFFFF] }, UCN::from(0xFFFFFFFFFFFFFFFF as u64)); assert_eq!(UCN{ contents: vec![0x00000000FFFFFFFF] }, UCN::from(0xFFFFFFFFFFFFFFFF as u32)); } quickcheck! { fn builder_u8_upgrade_u16(x: u8) -> bool { UCN::from(x) == UCN::from(x as u16) } fn builder_u16_upgrade_u32(x: u16) -> bool { UCN::from(x) == UCN::from(x as u32) } fn builder_u32_upgrade_u64(x: u32) -> bool { UCN::from(x) == UCN::from(x as u64) } fn builder_u8_roundtrips(x: u8) -> bool { let thereback: u8 = UCN::from(x).into(); x == thereback } fn builder_u16_roundtrips(x: u16) -> bool { let thereback: u16 = UCN::from(x).into(); x == thereback } fn builder_u32_roundtrips(x: u32) -> bool { let thereback: u32 = UCN::from(x).into(); x == thereback } fn builder_u64_roundtrips(x: u64) -> bool { let thereback: u64 = UCN::from(x).into(); x == thereback } } quickcheck! { fn u64_comparison_sane(x: u64, y: u64) -> bool { let ucnx = UCN::from(x); let ucny = UCN::from(y); ucnx.cmp(&ucny) == x.cmp(&y) } fn longer_is_greater(x: u64, y: u64) -> bool { if x == 0 { true } else { let ucnx = UCN{ contents: vec![x, 1] }; let ucny = UCN::from(y); ucnx.cmp(&ucny) == Ordering::Greater } } fn self_is_equal(x: Vec) -> bool { let val = UCN{ contents: x }; let copy = val.clone(); (&val == ©) && (val.cmp(©) == Ordering::Equal) } } impl Arbitrary for UCN { fn arbitrary(g: &mut G) -> UCN { let lenopts = [4,8]; //,16,32,48,64,112,128,240]; let mut len = *g.choose(&lenopts).unwrap(); let mut contents = Vec::with_capacity(len); while len > 0 { contents.push(g.gen()); len -= 1; } UCN{ contents: contents } } } fn expand_to_match(a: &mut UCN, b: &UCN) { assert!(a.contents.len() <= b.contents.len()); while a.contents.len() < b.contents.len() { a.contents.push(0); } } quickcheck! { fn double_negation(x: UCN) -> bool { let mut x2 = x.clone().not(); expand_to_match(&mut x2, &x); let mut x3 = x2.not(); expand_to_match(&mut x3, &x); x3 == x } } quickcheck! { fn or_associative(a: UCN, b: UCN, c: UCN) -> bool { ((&a | &b) | &c) == (&a | (&b | &c)) } fn xor_associative(a: UCN, b: UCN, c: UCN) -> bool { ((&a ^ &b) ^ &c) == (&a ^ (&b ^ &c)) } fn and_associative(a: UCN, b: UCN, c: UCN) -> bool { ((&a & &b) & &c) == (&a & (&b & &c)) } fn add_associative(a: UCN, b: UCN, c: UCN) -> bool { ((&a + &b) + &c) == (&a + (&b + &c)) } fn mul_associative(a: UCN, b: UCN, c: UCN) -> bool { ((&a * &b) * &c) == (&a * (&b * &c)) } } quickcheck! { fn or_commutative(a: UCN, b: UCN) -> bool { (&a | &b) == (&b | &a) } fn xor_commutative(a: UCN, b: UCN) -> bool { (&a ^ &b) == (&b ^ &a) } fn and_commutative(a: UCN, b: UCN) -> bool { (&a & &b) == (&b & &a) } fn add_commutative(a: UCN, b: UCN) -> bool { let ab = &a + &b; let ba = &b + &a; (ab == ba) } fn mul_commutative(a: UCN, b: UCN) -> bool { let ab = &a * &b; let ba = &b * &a; (ab == ba) } } quickcheck! { fn or_identity(a: UCN) -> bool { (&a | &UCN{ contents: vec![] }) == a } fn xor_identity(a: UCN) -> bool { (&a ^ &UCN{ contents: vec![] }) == a } fn and_identity(a: UCN) -> bool { let mut contents = Vec::new(); contents.resize(a.contents.len(), 0xFFFFFFFFFFFFFFFF); let effs = UCN{ contents: contents }; (&a & &effs) == a } fn shl_identity(a: UCN) -> bool { (&a << 0) == a } fn shr_identity(a: UCN) -> bool { (&a >> 0) == a } fn add_identity(a: UCN) -> bool { (&a + &UCN{ contents: vec![] }) == a } fn sub_identity(a: UCN) -> bool { (&a - &UCN{ contents: vec![] }) == a } fn mul_identity(a: UCN) -> bool { let one = UCN{ contents: vec![1] }; (&a * &one) == a } fn div_identity(a: UCN) -> bool { let one = UCN{ contents: vec![1] }; (&a / &one) == a } } quickcheck! { fn or_annihilator(a: UCN) -> bool { let mut contents = Vec::new(); contents.resize(a.contents.len(), 0xFFFFFFFFFFFFFFFF); let effs = UCN{ contents: contents }; (&a | &effs) == effs } fn and_annihilator(a: UCN) -> bool { let zero = UCN{ contents: vec![] }; (&a & &zero) == zero } fn shl_shr_annihilate(a: UCN, b: u8) -> bool { let left = &a << b; let right = &left >> b; right == a } fn sub_annihilation(a: UCN) -> bool { (&a - &a) == UCN{ contents: vec![] } } fn mul_annihilation(a: UCN) -> bool { let zero = UCN{ contents: vec![] }; (&a * &zero) == zero } } quickcheck! { fn xor_inverse(a: UCN, b: UCN) -> bool { ((&a ^ &b) ^ &b) == a } fn or_idempotent(a: UCN, b: UCN) -> bool { (&a | &b) == ((&a | &b) | &b) } fn and_idempotent(a: UCN, b: UCN) -> bool { (&a & &b) == ((&a & &b) & &b) } fn andor_absorbtion(a: UCN, b: UCN) -> bool { (&a & (&a | &b)) == a } fn orand_absorbtion(a: UCN, b: UCN) -> bool { (&a | (&a & &b)) == a } } quickcheck! { fn mod_plus1_identity(a: UCN) -> bool { let one = UCN{ contents: vec![1] }; let ap1 = &a + &one; (&a % ap1) == a } fn mod_min1_is_one(a: UCN) -> bool { let one = UCN{ contents: vec![1] }; let am1 = &a - &one; (&a % am1) == one } #[should_panic] fn div0_fails(a: UCN) -> bool { (&a / &UCN{ contents: vec![] }) == a } fn euclid_is_alive(a: UCN, b: UCN) -> bool { let zero = UCN{ contents: vec![] }; if &b == &zero { return true; } let q = &a / &b; let r = &a % &b; let res = (b * q) + r; a == res } } quickcheck! { fn and_over_or_distribution(a: UCN, b: UCN, c: UCN) -> bool { (&a & (&b | &c)) == ((&a & &b) | (&a & &c)) } fn and_over_xor_distribution(a: UCN, b: UCN, c: UCN) -> bool { (&a & (&b ^ &c)) == ((&a & &b) ^ (&a & &c)) } fn or_over_and_distribution(a: UCN, b: UCN, c: UCN) -> bool { (&a | (&b & &c)) == ((&a | &b) & (&a | &c)) } fn demorgans(a: UCN, b: UCN) -> bool { let mut a2 = if a.contents.len() < b.contents.len() {a.clone()} else {b.clone()}; let b2 = if a.contents.len() < b.contents.len() {b.clone()} else {a.clone()}; expand_to_match(&mut a2, &b2); (!(&a2 | &b2)) == (!a2 & !b2) } fn shift_multiply_equiv(a: UCN, b: u8) -> bool { let one = UCN{ contents: vec![1] }; let pow2 = one << b; (&a << b) == (&a * pow2) } fn shl_mul_equiv(a: UCN) -> bool { (&a << 1) == (&a * UCN::from(2 as u64)) && (&a << 3) == (&a * UCN::from(8 as u64)) && (&a << 4) == (&a * UCN::from(16 as u64)) && (&a << 43) == (&a * UCN::from(8796093022208 as u64)) } fn shr_div_equiv(a: UCN) -> bool { (&a >> 1) == (&a / UCN::from(2 as u64)) && (&a >> 3) == (&a / UCN::from(8 as u64)) && (&a >> 4) == (&a / UCN::from(16 as u64)) && (&a >> 43) == (&a / UCN::from(8796093022208 as u64)) } } quickcheck! { fn barrett_check(a: UCN, b: UCN) -> bool { let barrett = b.barrett_u(); println!("-----"); println!("a: {:X}", a); println!("b: {:X}", b); (&a % &b) == a.reduce(&barrett) } } }