Barrett reduction! And number formatting.

This commit is contained in:
2018-09-28 18:46:01 -05:00
parent 304d009a67
commit 19a298e56c
5 changed files with 196 additions and 16 deletions

View File

@@ -103,6 +103,8 @@ generateInvocs =
generateTestBlock hndl "add" DivMul True [(+ 64)]
generateTestBlock hndl "mul" DivMul True [(* 2)]
generateTestBlock hndl "div" DivMul True []
generateTestBlock hndl "barrett_gen" Barrett True [(+ 64)]
generateTestBlock hndl "barrett_red" Barrett True [(+ 64), (* 2)]
hPutStrLn hndl "}"
log :: String -> IO ()
@@ -181,7 +183,7 @@ generateAllTheTests =
let (m, memory1) = generateNum memory0 "m" size
k = computeK m
u = barrett m
in (Map.fromList [("m", showX m), ("k", showX k), ("u", showX u)], memory1)
in (Map.fromList [("m", showX m), ("k", showX k), ("u", showX u)],memory1)
let (db3, gen3) = emptyDatabase gen1
generateTests Barrett "barrett_reduce" db3 $ \ size memory0 ->
let (m, memory1) = generateNum memory0 "m" size

View File

@@ -31,9 +31,9 @@ macro_rules! barrett_impl {
pub fn reduce(&self, x: &$dbl) -> $name {
let m2: $dbl64 = $dbl64::from(&self.m);
// 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
let q1: $name64 = $name64::from(x >> (self.k - 1));
let q1: $name64 = $name64::from(x >> ((self.k - 1) * 64));
let q2: $dbl64 = $dbl64::from(q1 * &self.mu);
let q3: $name64 = $name64::from(q2 >> (self.k + 1));
let q3: $name64 = $name64::from(q2 >> ((self.k + 1) * 64));
// 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 r2.
let mut r: $dbl64 = $dbl64::from(x);
r.mask(self.k + 1);
@@ -55,5 +55,72 @@ macro_rules! barrett_impl {
$name::from(&r)
}
}
impl $name {
pub fn generate_barrett(&self) -> $bar {
$bar::new(self.clone())
}
#[cfg(test)]
pub(crate) fn new_barrett(k: usize, m: $name64, mu: $name64) -> $bar {
$bar{ k: k, m: m, mu: mu }
}
}
};
}
#[cfg(test)]
macro_rules! generate_barrett_gen_tests {
($name: ident, $lname: ident, $bname: ident) => {
#[test]
fn $lname() {
let fname = format!("testdata/barrett_gen/{}.tests", stringify!($name));
run_test(fname.to_string(), 3, |case| {
let (neg0, mbytes) = case.get("m").unwrap();
let (neg1, kbytes) = case.get("k").unwrap();
let (neg2, ubytes) = case.get("u").unwrap();
assert!(!neg0 && !neg1 && !neg2);
let m = $name::from_bytes(mbytes);
let kbig = $name::from_bytes(kbytes);
let mu = $bname::from_bytes(ubytes);
//
let mbig = $bname::from(&m);
let k = usize::from(&kbig);
//
let bar = m.generate_barrett();
assert_eq!(k, bar.k);
assert_eq!(mbig, bar.m);
assert_eq!(mu, bar.mu);
});
}
};
}
#[cfg(test)]
macro_rules! generate_barrett_red_tests {
($name: ident, $lname: ident, $bname: ident, $dbl: ident) => {
#[test]
fn $lname() {
let fname = format!("testdata/barrett_reduce/{}.tests", stringify!($name));
run_test(fname.to_string(), 5, |case| {
let (neg0, mbytes) = case.get("m").unwrap();
let (neg1, kbytes) = case.get("k").unwrap();
let (neg2, ubytes) = case.get("u").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
let m = $name::from_bytes(mbytes);
let kbig = $name::from_bytes(kbytes);
let k = usize::from(&kbig);
let mu = $bname::from_bytes(ubytes);
let bar = $name::new_barrett(usize::from(k), $bname::from(m), mu);
let x = $dbl::from_bytes(xbytes);
let r = $name::from_bytes(rbytes);
//
assert_eq!(r, bar.reduce(&x));
});
}
};
}

73
src/unsigned/formatter.rs Normal file
View File

@@ -0,0 +1,73 @@
macro_rules! generate_formatter {
($name: ident) => {
impl fmt::UpperHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for x in self.value.iter().rev() {
f.write_char(tochar(true, x >> 60))?;
f.write_char(tochar(true, x >> 56))?;
f.write_char(tochar(true, x >> 52))?;
f.write_char(tochar(true, x >> 48))?;
f.write_char(tochar(true, x >> 44))?;
f.write_char(tochar(true, x >> 40))?;
f.write_char(tochar(true, x >> 36))?;
f.write_char(tochar(true, x >> 32))?;
f.write_char(tochar(true, x >> 28))?;
f.write_char(tochar(true, x >> 24))?;
f.write_char(tochar(true, x >> 20))?;
f.write_char(tochar(true, x >> 16))?;
f.write_char(tochar(true, x >> 12))?;
f.write_char(tochar(true, x >> 8))?;
f.write_char(tochar(true, x >> 4))?;
f.write_char(tochar(true, x >> 0))?;
}
Ok(())
}
}
impl fmt::LowerHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for x in self.value.iter().rev() {
f.write_char(tochar(false, x >> 60))?;
f.write_char(tochar(false, x >> 56))?;
f.write_char(tochar(false, x >> 52))?;
f.write_char(tochar(false, x >> 48))?;
f.write_char(tochar(false, x >> 44))?;
f.write_char(tochar(false, x >> 40))?;
f.write_char(tochar(false, x >> 36))?;
f.write_char(tochar(false, x >> 32))?;
f.write_char(tochar(false, x >> 28))?;
f.write_char(tochar(false, x >> 24))?;
f.write_char(tochar(false, x >> 20))?;
f.write_char(tochar(false, x >> 16))?;
f.write_char(tochar(false, x >> 12))?;
f.write_char(tochar(false, x >> 8))?;
f.write_char(tochar(false, x >> 4))?;
f.write_char(tochar(false, x >> 0))?;
}
Ok(())
}
}
};
}
pub fn tochar(upper: bool, val: u64) -> char {
match val & 0xF {
0x0 => '0',
0x1 => '1',
0x2 => '2',
0x3 => '3',
0x4 => '4',
0x5 => '5',
0x6 => '6',
0x7 => '7',
0x8 => '8',
0x9 => '9',
0xA => if upper { 'A' } else { 'a' },
0xB => if upper { 'B' } else { 'b' },
0xC => if upper { 'C' } else { 'c' },
0xD => if upper { 'D' } else { 'd' },
0xE => if upper { 'E' } else { 'e' },
0xF => if upper { 'F' } else { 'f' },
_ => panic!("The world is broken, rejoice, rejoice.")
}
}

View File

@@ -1695,4 +1695,38 @@ mod tests {
generate_div_tests!(U16448, u16448);
generate_div_tests!(U30784, u30784);
}
mod barrett_gen {
use super::super::*;
use testing::run_test;
generate_barrett_gen_tests!(U192, u192, U256);
generate_barrett_gen_tests!(U256, u256, U320);
generate_barrett_gen_tests!(U384, u384, U448);
generate_barrett_gen_tests!(U512, u512, U576);
generate_barrett_gen_tests!(U576, u576, U640);
generate_barrett_gen_tests!(U1024, u1024, U1088);
generate_barrett_gen_tests!(U2048, u2048, U2112);
generate_barrett_gen_tests!(U3072, u3072, U3136);
generate_barrett_gen_tests!(U4096, u4096, U4160);
generate_barrett_gen_tests!(U7680, u7680, U7744);
generate_barrett_gen_tests!(U8192, u8192, U8256);
generate_barrett_gen_tests!(U15360, u15360, U15424);
}
mod barrett_red {
use super::super::*;
use testing::run_test;
generate_barrett_red_tests!(U192, u192, U256, U384);
generate_barrett_red_tests!(U256, u256, U320, U512);
generate_barrett_red_tests!(U384, u384, U448, U768);
generate_barrett_red_tests!(U512, u512, U576, U1024);
generate_barrett_red_tests!(U576, u576, U640, U1152);
generate_barrett_red_tests!(U1024, u1024, U1088, U2048);
generate_barrett_red_tests!(U2048, u2048, U2112, U4096);
generate_barrett_red_tests!(U3072, u3072, U3136, U6144);
generate_barrett_red_tests!(U4096, u4096, U4160, U8192);
generate_barrett_red_tests!(U7680, u7680, U7744, U15360);
generate_barrett_red_tests!(U8192, u8192, U8256, U16384);
generate_barrett_red_tests!(U15360, u15360, U15424, U30720);
}
}

View File

@@ -13,6 +13,8 @@ mod conversion;
#[macro_use]
mod div;
#[macro_use]
mod formatter;
#[macro_use]
mod mul;
#[macro_use]
mod shifts;
@@ -22,19 +24,20 @@ mod sub;
use self::add::{addition,unsafe_addition};
use self::base::CryptoNum;
use self::cmp::compare;
use self::div::{DivMod,get_number_size};
use self::codec::{Encoder,Decoder,raw_decoder};
use self::div::{DivMod,get_number_size};
use self::formatter::tochar;
use self::mul::multiply;
use self::shifts::{shiftl,shiftr};
use self::sub::subtract;
use std::cmp::{Ordering,min};
use std::fmt;
use std::fmt::Write;
use std::ops::{Add,AddAssign};
use std::ops::{Div,Mul,Rem};
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
use std::ops::{Sub,SubAssign};
#[cfg(test)]
use std::fmt;
#[cfg(test)]
use quickcheck::{Arbitrary,Gen};
@@ -44,6 +47,7 @@ macro_rules! generate_number
generate_base!($name, $size);
generate_base_conversions!($name);
generate_codec!($name);
generate_formatter!($name);
cmp_impls!($name);