From 19a298e56c745be142568690bf254bc954ccfafa Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Fri, 28 Sep 2018 18:46:01 -0500 Subject: [PATCH] Barrett reduction! And number formatting. --- generate.hs | 24 +++++++------ src/unsigned/barrett.rs | 71 +++++++++++++++++++++++++++++++++++-- src/unsigned/formatter.rs | 73 +++++++++++++++++++++++++++++++++++++++ src/unsigned/invoc.rs | 34 ++++++++++++++++++ src/unsigned/mod.rs | 10 ++++-- 5 files changed, 196 insertions(+), 16 deletions(-) create mode 100644 src/unsigned/formatter.rs diff --git a/generate.hs b/generate.hs index f7a9e77..cf56e19 100644 --- a/generate.hs +++ b/generate.hs @@ -93,16 +93,18 @@ generateInvocs = "U" ++ show b ++ ");") hPutStrLn hndl "\n#[cfg(test)]" hPutStrLn hndl "mod tests {" - generateTestBlock hndl "base" Base True [] - generateTestBlock hndl "conversion" Base False [] - generateTestBlock hndl "codec" Base False [] - generateTestBlock hndl "cmp" Base True [] - generateTestBlock hndl "sub" Base True [] - generateTestBlock hndl "shiftl" Base True [] - generateTestBlock hndl "shiftr" Base True [] - generateTestBlock hndl "add" DivMul True [(+ 64)] - generateTestBlock hndl "mul" DivMul True [(* 2)] - generateTestBlock hndl "div" DivMul True [] + generateTestBlock hndl "base" Base True [] + generateTestBlock hndl "conversion" Base False [] + generateTestBlock hndl "codec" Base False [] + generateTestBlock hndl "cmp" Base True [] + generateTestBlock hndl "sub" Base True [] + generateTestBlock hndl "shiftl" Base True [] + generateTestBlock hndl "shiftr" Base True [] + 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 diff --git a/src/unsigned/barrett.rs b/src/unsigned/barrett.rs index 172c792..f51c07e 100644 --- a/src/unsigned/barrett.rs +++ b/src/unsigned/barrett.rs @@ -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/bk−1⌋, 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)); + }); + } + }; +} \ No newline at end of file diff --git a/src/unsigned/formatter.rs b/src/unsigned/formatter.rs new file mode 100644 index 0000000..5807a17 --- /dev/null +++ b/src/unsigned/formatter.rs @@ -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.") + } +} \ No newline at end of file diff --git a/src/unsigned/invoc.rs b/src/unsigned/invoc.rs index fc1f694..3724cfc 100644 --- a/src/unsigned/invoc.rs +++ b/src/unsigned/invoc.rs @@ -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); + } } diff --git a/src/unsigned/mod.rs b/src/unsigned/mod.rs index 18e91ee..f9366a8 100644 --- a/src/unsigned/mod.rs +++ b/src/unsigned/mod.rs @@ -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);