Add support for Barrett reduction, which should be a faster way to do mods.
This commit is contained in:
@@ -1,10 +1,16 @@
|
|||||||
macro_rules! construct_unsigned {
|
macro_rules! construct_unsigned {
|
||||||
($type: ident, $modname: ident, $count: expr) => {
|
($type: ident, $barrett: ident, $modname: ident, $count: expr) => {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct $type {
|
pub struct $type {
|
||||||
contents: [u64; $count]
|
contents: [u64; $count]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct $barrett {
|
||||||
|
k: usize,
|
||||||
|
progenitor: $type,
|
||||||
|
contents: [u64; $count + 1]
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for $type {
|
impl PartialEq for $type {
|
||||||
fn eq(&self, other: &$type) -> bool {
|
fn eq(&self, other: &$type) -> bool {
|
||||||
for i in 0..$count {
|
for i in 0..$count {
|
||||||
@@ -26,21 +32,15 @@ macro_rules! construct_unsigned {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $type {
|
impl Debug for $barrett {
|
||||||
/// 0!
|
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||||
pub fn zero() -> $type {
|
f.write_str("BarrettMu{{ ")?;
|
||||||
$type { contents: [0; $count] }
|
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 {
|
impl PartialOrd for $type {
|
||||||
@@ -226,6 +226,38 @@ macro_rules! construct_unsigned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CryptoNum for $type {
|
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) {
|
fn divmod(&self, a: &$type, q: &mut $type, r: &mut $type) {
|
||||||
generic_div(&self.contents, &a.contents,
|
generic_div(&self.contents, &a.contents,
|
||||||
&mut q.contents, &mut r.contents);
|
&mut q.contents, &mut r.contents);
|
||||||
@@ -266,6 +298,109 @@ macro_rules! construct_unsigned {
|
|||||||
assert!(i == $count);
|
assert!(i == $count);
|
||||||
res
|
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)]
|
#[cfg(test)]
|
||||||
@@ -306,8 +441,8 @@ macro_rules! construct_unsigned {
|
|||||||
fn test_max() {
|
fn test_max() {
|
||||||
assert_eq!($type::from_u64(u64::max_value()).to_u64(),
|
assert_eq!($type::from_u64(u64::max_value()).to_u64(),
|
||||||
u64::max_value());
|
u64::max_value());
|
||||||
assert_eq!($type::max().to_u64(), u64::max_value());
|
assert_eq!($type::max_value().to_u64(), u64::max_value());
|
||||||
assert_eq!($type::max() + $type::from_u8(1), $type::zero());
|
assert_eq!($type::max_value() + $type::from_u8(1), $type::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
@@ -352,10 +487,10 @@ macro_rules! construct_unsigned {
|
|||||||
(x & $type::zero()) == $type::zero()
|
(x & $type::zero()) == $type::zero()
|
||||||
}
|
}
|
||||||
fn or_annulment(x: $type) -> bool {
|
fn or_annulment(x: $type) -> bool {
|
||||||
(x | $type::max()) == $type::max()
|
(x | $type::max_value()) == $type::max_value()
|
||||||
}
|
}
|
||||||
fn and_identity(x: $type) -> bool {
|
fn and_identity(x: $type) -> bool {
|
||||||
(&x & $type::max()) == x
|
(&x & $type::max_value()) == x
|
||||||
}
|
}
|
||||||
fn or_identity(x: $type) -> bool {
|
fn or_identity(x: $type) -> bool {
|
||||||
(&x | $type::zero()) == x
|
(&x | $type::zero()) == x
|
||||||
@@ -370,7 +505,7 @@ macro_rules! construct_unsigned {
|
|||||||
(&x & &x) == x
|
(&x & &x) == x
|
||||||
}
|
}
|
||||||
fn or_complement(x: $type) -> bool {
|
fn or_complement(x: $type) -> bool {
|
||||||
(&x | !&x) == $type::max()
|
(&x | !&x) == $type::max_value()
|
||||||
}
|
}
|
||||||
fn and_commutative(x: $type, y: $type) -> bool {
|
fn and_commutative(x: $type, y: $type) -> bool {
|
||||||
(&x & &y) == (&y & &x)
|
(&x & &y) == (&y & &x)
|
||||||
@@ -484,14 +619,14 @@ macro_rules! construct_unsigned {
|
|||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn shift_mask_equivr(x: $type, in_shift: usize) -> bool {
|
fn shift_mask_equivr(x: $type, in_shift: usize) -> bool {
|
||||||
let shift = in_shift % ($count * 64);
|
let shift = in_shift % ($count * 64);
|
||||||
let mask = $type::max() << shift;
|
let mask = $type::max_value() << shift;
|
||||||
let masked_x = &x & mask;
|
let masked_x = &x & mask;
|
||||||
let shift_maskr = (x >> shift) << shift;
|
let shift_maskr = (x >> shift) << shift;
|
||||||
shift_maskr == masked_x
|
shift_maskr == masked_x
|
||||||
}
|
}
|
||||||
fn shift_mask_equivl(x: $type, in_shift: usize) -> bool {
|
fn shift_mask_equivl(x: $type, in_shift: usize) -> bool {
|
||||||
let shift = in_shift % ($count * 64);
|
let shift = in_shift % ($count * 64);
|
||||||
let mask = $type::max() >> shift;
|
let mask = $type::max_value() >> shift;
|
||||||
let masked_x = &x & mask;
|
let masked_x = &x & mask;
|
||||||
let shift_maskl = (x << shift) >> shift;
|
let shift_maskl = (x << shift) >> shift;
|
||||||
shift_maskl == masked_x
|
shift_maskl == masked_x
|
||||||
@@ -539,7 +674,8 @@ macro_rules! construct_unsigned {
|
|||||||
buffer[1] = 1;
|
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));
|
$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! {
|
quickcheck! {
|
||||||
@@ -681,23 +817,32 @@ macro_rules! construct_unsigned {
|
|||||||
a == b
|
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 {
|
macro_rules! from_to {
|
||||||
($type: ident, $count: expr, $base: ty, $from: ident, $to: ident) => {
|
($type: ident, $count: expr, $base: ty, $from: ident, $to: ident) => {
|
||||||
/// Convert the given base type into this type. This is always safe.
|
fn $from(x: $base) -> $type {
|
||||||
pub fn $from(x: $base) -> $type {
|
|
||||||
let mut res = $type { contents: [0; $count] };
|
let mut res = $type { contents: [0; $count] };
|
||||||
res.contents[0] = x as u64;
|
res.contents[0] = x as u64;
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert this back into a base type. This is the equivalent of
|
fn $to(&self) -> $base {
|
||||||
/// masking off the relevant number of bits, and should work just
|
|
||||||
/// like the `as` keyword with normal word types.
|
|
||||||
pub fn $to(&self) -> $base {
|
|
||||||
self.contents[0] as $base
|
self.contents[0] as $base
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ fn le(a: &[u64], b: &[u64]) -> bool {
|
|||||||
generic_cmp(a, b) != Ordering::Greater
|
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
|
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<u64> {
|
||||||
|
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)]
|
#[inline(always)]
|
||||||
pub fn generic_div(inx: &[u64], iny: &[u64],
|
pub fn generic_div(inx: &[u64], iny: &[u64],
|
||||||
outq: &mut [u64], outr: &mut [u64])
|
outq: &mut [u64], outr: &mut [u64])
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ use std::cmp::Ordering;
|
|||||||
use std::fmt::{Debug,Error,Formatter};
|
use std::fmt::{Debug,Error,Formatter};
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
|
||||||
construct_unsigned!(U512, u512, 8);
|
construct_unsigned!(U512, BarretMu512, u512, 8);
|
||||||
construct_unsigned!(U1024, u1024, 16);
|
construct_unsigned!(U1024, BarretMu1024, u1024, 16);
|
||||||
construct_unsigned!(U2048, u2048, 32);
|
construct_unsigned!(U2048, BarretMu2048, u2048, 32);
|
||||||
construct_unsigned!(U3072, u3072, 48);
|
construct_unsigned!(U3072, BarretMu3072, u3072, 48);
|
||||||
construct_unsigned!(U4096, u4096, 64);
|
construct_unsigned!(U4096, BarretMu4096, u4096, 64);
|
||||||
construct_unsigned!(U7680, u7680, 120);
|
construct_unsigned!(U7680, BarretMu7680, u7680, 120);
|
||||||
construct_unsigned!(U8192, u8192, 128);
|
construct_unsigned!(U8192, BarretMu8192, u8192, 128);
|
||||||
construct_unsigned!(U15360, u15360, 240);
|
construct_unsigned!(U15360, BarretMu15360, u15360, 240);
|
||||||
|
|||||||
@@ -1,4 +1,38 @@
|
|||||||
pub trait CryptoNum {
|
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
|
/// Simultaneously compute the quotient and remainder of this number and
|
||||||
/// the given divisor.
|
/// the given divisor.
|
||||||
fn divmod(&self, a: &Self, q: &mut Self, r: &mut Self);
|
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
|
/// 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.
|
/// a multiple of 8 bytes long. Unused bytes should be ignored.
|
||||||
fn from_bytes(&[u8]) -> Self;
|
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<Self::BarrettMu>;
|
||||||
|
/// Faster modulo through the use of the Barrett constant, above.
|
||||||
|
fn fastmod(&self, &Self::BarrettMu) -> Self;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user