diff --git a/src/cryptonum/builder.rs b/src/cryptonum/builder.rs index 8351890..740bf33 100644 --- a/src/cryptonum/builder.rs +++ b/src/cryptonum/builder.rs @@ -1,10 +1,16 @@ macro_rules! construct_unsigned { - ($type: ident, $modname: ident, $count: expr) => { + ($type: ident, $barrett: ident, $modname: ident, $count: expr) => { #[derive(Clone)] pub struct $type { contents: [u64; $count] } + pub struct $barrett { + k: usize, + progenitor: $type, + contents: [u64; $count + 1] + } + impl PartialEq for $type { fn eq(&self, other: &$type) -> bool { for i in 0..$count { @@ -26,21 +32,15 @@ macro_rules! construct_unsigned { } } - impl $type { - /// 0! - pub fn zero() -> $type { - $type { contents: [0; $count] } + impl Debug for $barrett { + fn fmt(&self, f: &mut Formatter) -> Result<(),Error> { + f.write_str("BarrettMu{{ ")?; + f.write_fmt(format_args!("k = {}, ", self.k))?; + f.write_fmt(format_args!("progen = {:?}, ",self.progenitor))?; + f.write_str("contents: ")?; + f.debug_list().entries(self.contents.iter()).finish()?; + f.write_str(" }}") } - - /// The maximum possible value we can hold. - pub fn max() -> $type { - $type { contents: [0xFFFFFFFFFFFFFFFF; $count] } - } - - from_to!($type, $count, u8, from_u8, to_u8); - from_to!($type, $count, u16, from_u16, to_u16); - from_to!($type, $count, u32, from_u32, to_u32); - from_to!($type, $count, u64, from_u64, to_u64); } impl PartialOrd for $type { @@ -226,6 +226,38 @@ macro_rules! construct_unsigned { } impl CryptoNum for $type { + type BarrettMu = $barrett; + + fn zero() -> $type { + $type { contents: [0; $count] } + } + + fn max_value() -> $type { + $type { contents: [0xFFFFFFFFFFFFFFFF; $count] } + } + + fn is_zero(&self) -> bool { + for x in self.contents.iter() { + if *x != 0 { + return false; + } + } + true + } + + fn is_odd(&self) -> bool { + (self.contents[0] & 1) == 1 + } + + fn is_even(&self) -> bool { + (self.contents[0] & 1) == 0 + } + + from_to!($type, $count, u8, from_u8, to_u8); + from_to!($type, $count, u16, from_u16, to_u16); + from_to!($type, $count, u32, from_u32, to_u32); + from_to!($type, $count, u64, from_u64, to_u64); + fn divmod(&self, a: &$type, q: &mut $type, r: &mut $type) { generic_div(&self.contents, &a.contents, &mut q.contents, &mut r.contents); @@ -266,6 +298,109 @@ macro_rules! construct_unsigned { assert!(i == $count); res } + + fn barrett_mu(&self) -> Option<$barrett> { + // Step #0: Don't divide by 0. + if self.is_zero() { + return None + } + // Step #1: Compute k. + let mut k = $count; + while self.contents[k - 1] == 0 { k -= 1 }; + // Step #2: The algorithm below only works if x has at most 2k + // digits, so if k*2 < count, abort this whole process. + if (k * 2) < $count { + return None + } + // Step #2: Compute floor(b^2k / m), where m is this value. + let mut widebody_b2k = [0; ($count * 2) + 1]; + let mut widebody_self = [0; ($count * 2) + 1]; + let mut quotient = [0; ($count * 2) + 1]; + let mut remainder = [0; ($count * 2) + 1]; + widebody_b2k[$count * 2] = 1; + for i in 0..k { + widebody_self[i] = self.contents[i]; + } + generic_div(&widebody_b2k, &widebody_self, + &mut quotient, &mut remainder); + let mut result = [0; $count + 1]; + for (idx, val) in quotient.iter().enumerate() { + if idx < ($count + 1) { + result[idx] = *val; + } else { + if quotient[idx] != 0 { + return None; + } + } + } + Some($barrett{k: k, progenitor: self.clone(), contents: result}) + } + + fn fastmod(&self, mu: &$barrett) -> $type { + // This algorithm is from our friends at the Handbook of + // Applied Cryptography, Chapter 14, Algorithm 14.42. + // Step #0: + // Expand x so that it has the same size as the Barrett + // value. + let mut x = [0; $count + 1]; + for i in 0..$count { + x[i] = self.contents[i]; + } + // Step #1: + // q1 <- floor(x / b^(k-1)) + let mut q1 = x.clone(); + generic_shr(&mut q1, &x, 64 * (mu.k - 1)); + // q2 <- q1 * mu + let q2 = expanding_mul(&q1, &mu.contents); + // q3 <- floor(q2 / b^(k+1)) + let mut q3big = q2.clone(); + generic_shr(&mut q3big, &q2, 64 * (mu.k + 1)); + let mut q3 = [0; $count + 1]; + for (idx, val) in q3big.iter().enumerate() { + if idx <= $count { + q3[idx] = *val; + } else { + assert_eq!(*val, 0); + } + } + // Step #2: + // r1 <- x mod b^(k+1) + let mut r1 = x.clone(); + for i in mu.k..($count+1) { + r1[i] = 0; + } + // r2 <- q3 * m mod b^(k+1) + let mut moddedm = [0; $count + 1]; + for i in 0..mu.k { + moddedm[i] = mu.progenitor.contents[i]; + } + let mut r2 = q3.clone(); + generic_mul(&mut r2, &q3, &moddedm); + // r <- r1 - r2 + let mut r = r1.clone(); + generic_sub(&mut r, &r2); + let is_negative = !ge(&r1, &r2); + // Step #3: + // if r < 0 then r <- r + b^(k + 1) + if is_negative { + let mut bk1 = [0; $count + 1]; + bk1[mu.k] = 1; + generic_add(&mut r, &bk1); + } + // Step #4: + // while r >= m do: r <- r - m. + while ge(&r, &moddedm) { + generic_sub(&mut r, &moddedm); + } + // Step #5: + // return r + let mut retval = [0; $count]; + for i in 0..$count { + retval[i] = r[i]; + } + assert_eq!(r[$count], 0); + $type{ contents: retval } + } } #[cfg(test)] @@ -306,8 +441,8 @@ macro_rules! construct_unsigned { fn test_max() { assert_eq!($type::from_u64(u64::max_value()).to_u64(), u64::max_value()); - assert_eq!($type::max().to_u64(), u64::max_value()); - assert_eq!($type::max() + $type::from_u8(1), $type::zero()); + assert_eq!($type::max_value().to_u64(), u64::max_value()); + assert_eq!($type::max_value() + $type::from_u8(1), $type::zero()); } quickcheck! { @@ -352,10 +487,10 @@ macro_rules! construct_unsigned { (x & $type::zero()) == $type::zero() } fn or_annulment(x: $type) -> bool { - (x | $type::max()) == $type::max() + (x | $type::max_value()) == $type::max_value() } fn and_identity(x: $type) -> bool { - (&x & $type::max()) == x + (&x & $type::max_value()) == x } fn or_identity(x: $type) -> bool { (&x | $type::zero()) == x @@ -370,7 +505,7 @@ macro_rules! construct_unsigned { (&x & &x) == x } fn or_complement(x: $type) -> bool { - (&x | !&x) == $type::max() + (&x | !&x) == $type::max_value() } fn and_commutative(x: $type, y: $type) -> bool { (&x & &y) == (&y & &x) @@ -484,14 +619,14 @@ macro_rules! construct_unsigned { quickcheck! { fn shift_mask_equivr(x: $type, in_shift: usize) -> bool { let shift = in_shift % ($count * 64); - let mask = $type::max() << shift; + let mask = $type::max_value() << shift; let masked_x = &x & mask; let shift_maskr = (x >> shift) << shift; shift_maskr == masked_x } fn shift_mask_equivl(x: $type, in_shift: usize) -> bool { let shift = in_shift % ($count * 64); - let mask = $type::max() >> shift; + let mask = $type::max_value() >> shift; let masked_x = &x & mask; let shift_maskl = (x << shift) >> shift; shift_maskl == masked_x @@ -537,9 +672,10 @@ macro_rules! construct_unsigned { $type::from_u64(0)); let mut buffer = [0; $count]; buffer[1] = 1; - assert_eq!($type{ contents: buffer.clone() } - $type::from_u64(1), + assert_eq!($type{contents:buffer.clone()} - $type::from_u64(1), $type::from_u64(0xFFFFFFFFFFFFFFFF)); - assert_eq!($type::zero() - $type::from_u8(1), $type::max()); + assert_eq!($type::zero() - $type::from_u8(1), + $type::max_value()); } quickcheck! { @@ -681,23 +817,32 @@ macro_rules! construct_unsigned { a == b } } + + quickcheck! { + fn fastmod_works(a: $type, b: $type) -> bool { + assert!(b != $type::zero()); + match b.barrett_mu() { + None => + true, + Some(barrett) => { + a.fastmod(&barrett) == (&a % &b) + } + } + } + } } }; } macro_rules! from_to { ($type: ident, $count: expr, $base: ty, $from: ident, $to: ident) => { - /// Convert the given base type into this type. This is always safe. - pub fn $from(x: $base) -> $type { + fn $from(x: $base) -> $type { let mut res = $type { contents: [0; $count] }; res.contents[0] = x as u64; res } - /// Convert this back into a base type. This is the equivalent of - /// masking off the relevant number of bits, and should work just - /// like the `as` keyword with normal word types. - pub fn $to(&self) -> $base { + fn $to(&self) -> $base { self.contents[0] as $base } }; diff --git a/src/cryptonum/core.rs b/src/cryptonum/core.rs index 1978779..1f3eda5 100644 --- a/src/cryptonum/core.rs +++ b/src/cryptonum/core.rs @@ -21,7 +21,7 @@ fn le(a: &[u64], b: &[u64]) -> bool { generic_cmp(a, b) != Ordering::Greater } -fn ge(a: &[u64], b: &[u64]) -> bool { +pub fn ge(a: &[u64], b: &[u64]) -> bool { generic_cmp(a, b) != Ordering::Less } @@ -183,6 +183,32 @@ pub fn generic_mul(a: &mut [u64], orig: &[u64], b: &[u64]) { } } +#[inline(always)] +pub fn expanding_mul(a: &[u64], b: &[u64]) -> Vec { + assert!(a.len() == b.len()); + // The maximum size of an n x n digit multiplication is 2n digits, so + // here's our output array. + let mut result = Vec::with_capacity(a.len() * 2); + result.resize(a.len() * 2, 0); + + for (base_idx, digit) in b.iter().enumerate() { + let mut myrow = Vec::with_capacity(a.len() * 2); + let mut carry = 0; + + myrow.resize(a.len() * 2, 0); + for (col_idx, digit2) in a.iter().enumerate() { + let left = *digit2 as u128; + let right = *digit as u128; + let combo = (left * right) + carry; + + myrow[base_idx + col_idx] = combo as u64; + carry = combo >> 64; + } + generic_add(&mut result, &myrow); + } + result +} + #[inline(always)] pub fn generic_div(inx: &[u64], iny: &[u64], outq: &mut [u64], outr: &mut [u64]) diff --git a/src/cryptonum/mod.rs b/src/cryptonum/mod.rs index c3c37ed..e99ded9 100644 --- a/src/cryptonum/mod.rs +++ b/src/cryptonum/mod.rs @@ -14,11 +14,11 @@ use std::cmp::Ordering; use std::fmt::{Debug,Error,Formatter}; use std::ops::*; -construct_unsigned!(U512, u512, 8); -construct_unsigned!(U1024, u1024, 16); -construct_unsigned!(U2048, u2048, 32); -construct_unsigned!(U3072, u3072, 48); -construct_unsigned!(U4096, u4096, 64); -construct_unsigned!(U7680, u7680, 120); -construct_unsigned!(U8192, u8192, 128); -construct_unsigned!(U15360, u15360, 240); +construct_unsigned!(U512, BarretMu512, u512, 8); +construct_unsigned!(U1024, BarretMu1024, u1024, 16); +construct_unsigned!(U2048, BarretMu2048, u2048, 32); +construct_unsigned!(U3072, BarretMu3072, u3072, 48); +construct_unsigned!(U4096, BarretMu4096, u4096, 64); +construct_unsigned!(U7680, BarretMu7680, u7680, 120); +construct_unsigned!(U8192, BarretMu8192, u8192, 128); +construct_unsigned!(U15360, BarretMu15360, u15360, 240); diff --git a/src/cryptonum/traits.rs b/src/cryptonum/traits.rs index 9a12600..67d2d40 100644 --- a/src/cryptonum/traits.rs +++ b/src/cryptonum/traits.rs @@ -1,4 +1,38 @@ pub trait CryptoNum { + /// A related type that can hold the constant required for Barrett + /// reduction. + type BarrettMu; + + /// Generate the zero value for this type. + fn zero() -> Self; + /// Generate the maximum possible value for this type. + fn max_value() -> Self; + /// Test if the number is zero. + fn is_zero(&self) -> bool; + /// Test if the number is odd (a.k.a., the low bit is set) + fn is_odd(&self) -> bool; + /// Test if the number is even (a.k.a., the low bit is clear) + fn is_even(&self) -> bool; + /// Translate a `u8` to this type. This must be safe. + fn from_u8(x: u8) -> Self; + /// Convert this back into a `u8`. This is the equivalent of masking off + /// the lowest 8 bits and then casting to a `u8`. + fn to_u8(&self) -> u8; + /// Translate a `u16` to this type. This must be safe. + fn from_u16(x: u16) -> Self; + /// Convert this back into a `u16`. This is the equivalent of masking off + /// the lowest 16 bits and then casting to a `u16`. + fn to_u16(&self) -> u16; + /// Translate a `u32` to this type. This must be safe. + fn from_u32(x: u32) -> Self; + /// Convert this back into a `u32`. This is the equivalent of masking off + /// the lowest 32 bits and then casting to a `u32`. + fn to_u32(&self) -> u32; + /// Translate a `u64` to this type. This must be safe. + fn from_u64(x: u64) -> Self; + /// Convert this back into a `u64`. This is the equivalent of masking off + /// the lowest 64 bits and then casting to a `u64`. + fn to_u64(&self) -> u64; /// Simultaneously compute the quotient and remainder of this number and /// the given divisor. fn divmod(&self, a: &Self, q: &mut Self, r: &mut Self); @@ -9,4 +43,9 @@ pub trait CryptoNum { /// must be greater than or equal to the size of the number, and must be /// a multiple of 8 bytes long. Unused bytes should be ignored. fn from_bytes(&[u8]) -> Self; + /// Compute the Barett constant mu, using this as a modulus, which we can + /// use later to perform faster mod operations. + fn barrett_mu(&self) -> Option; + /// Faster modulo through the use of the Barrett constant, above. + fn fastmod(&self, &Self::BarrettMu) -> Self; }