Barrett reduction! And number formatting.
This commit is contained in:
24
generate.hs
24
generate.hs
@@ -93,16 +93,18 @@ generateInvocs =
|
|||||||
"U" ++ show b ++ ");")
|
"U" ++ show b ++ ");")
|
||||||
hPutStrLn hndl "\n#[cfg(test)]"
|
hPutStrLn hndl "\n#[cfg(test)]"
|
||||||
hPutStrLn hndl "mod tests {"
|
hPutStrLn hndl "mod tests {"
|
||||||
generateTestBlock hndl "base" Base True []
|
generateTestBlock hndl "base" Base True []
|
||||||
generateTestBlock hndl "conversion" Base False []
|
generateTestBlock hndl "conversion" Base False []
|
||||||
generateTestBlock hndl "codec" Base False []
|
generateTestBlock hndl "codec" Base False []
|
||||||
generateTestBlock hndl "cmp" Base True []
|
generateTestBlock hndl "cmp" Base True []
|
||||||
generateTestBlock hndl "sub" Base True []
|
generateTestBlock hndl "sub" Base True []
|
||||||
generateTestBlock hndl "shiftl" Base True []
|
generateTestBlock hndl "shiftl" Base True []
|
||||||
generateTestBlock hndl "shiftr" Base True []
|
generateTestBlock hndl "shiftr" Base True []
|
||||||
generateTestBlock hndl "add" DivMul True [(+ 64)]
|
generateTestBlock hndl "add" DivMul True [(+ 64)]
|
||||||
generateTestBlock hndl "mul" DivMul True [(* 2)]
|
generateTestBlock hndl "mul" DivMul True [(* 2)]
|
||||||
generateTestBlock hndl "div" DivMul True []
|
generateTestBlock hndl "div" DivMul True []
|
||||||
|
generateTestBlock hndl "barrett_gen" Barrett True [(+ 64)]
|
||||||
|
generateTestBlock hndl "barrett_red" Barrett True [(+ 64), (* 2)]
|
||||||
hPutStrLn hndl "}"
|
hPutStrLn hndl "}"
|
||||||
|
|
||||||
log :: String -> IO ()
|
log :: String -> IO ()
|
||||||
@@ -181,7 +183,7 @@ generateAllTheTests =
|
|||||||
let (m, memory1) = generateNum memory0 "m" size
|
let (m, memory1) = generateNum memory0 "m" size
|
||||||
k = computeK m
|
k = computeK m
|
||||||
u = barrett 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
|
let (db3, gen3) = emptyDatabase gen1
|
||||||
generateTests Barrett "barrett_reduce" db3 $ \ size memory0 ->
|
generateTests Barrett "barrett_reduce" db3 $ \ size memory0 ->
|
||||||
let (m, memory1) = generateNum memory0 "m" size
|
let (m, memory1) = generateNum memory0 "m" size
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ macro_rules! barrett_impl {
|
|||||||
pub fn reduce(&self, x: &$dbl) -> $name {
|
pub fn reduce(&self, x: &$dbl) -> $name {
|
||||||
let m2: $dbl64 = $dbl64::from(&self.m);
|
let m2: $dbl64 = $dbl64::from(&self.m);
|
||||||
// 1. q1←⌊x/bk−1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
|
// 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 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.
|
// 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 − r2.
|
||||||
let mut r: $dbl64 = $dbl64::from(x);
|
let mut r: $dbl64 = $dbl64::from(x);
|
||||||
r.mask(self.k + 1);
|
r.mask(self.k + 1);
|
||||||
@@ -55,5 +55,72 @@ macro_rules! barrett_impl {
|
|||||||
$name::from(&r)
|
$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
73
src/unsigned/formatter.rs
Normal 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.")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1695,4 +1695,38 @@ mod tests {
|
|||||||
generate_div_tests!(U16448, u16448);
|
generate_div_tests!(U16448, u16448);
|
||||||
generate_div_tests!(U30784, u30784);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ mod conversion;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod div;
|
mod div;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
mod formatter;
|
||||||
|
#[macro_use]
|
||||||
mod mul;
|
mod mul;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod shifts;
|
mod shifts;
|
||||||
@@ -22,19 +24,20 @@ mod sub;
|
|||||||
use self::add::{addition,unsafe_addition};
|
use self::add::{addition,unsafe_addition};
|
||||||
use self::base::CryptoNum;
|
use self::base::CryptoNum;
|
||||||
use self::cmp::compare;
|
use self::cmp::compare;
|
||||||
use self::div::{DivMod,get_number_size};
|
|
||||||
use self::codec::{Encoder,Decoder,raw_decoder};
|
use self::codec::{Encoder,Decoder,raw_decoder};
|
||||||
|
use self::div::{DivMod,get_number_size};
|
||||||
|
use self::formatter::tochar;
|
||||||
use self::mul::multiply;
|
use self::mul::multiply;
|
||||||
use self::shifts::{shiftl,shiftr};
|
use self::shifts::{shiftl,shiftr};
|
||||||
use self::sub::subtract;
|
use self::sub::subtract;
|
||||||
use std::cmp::{Ordering,min};
|
use std::cmp::{Ordering,min};
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::Write;
|
||||||
use std::ops::{Add,AddAssign};
|
use std::ops::{Add,AddAssign};
|
||||||
use std::ops::{Div,Mul,Rem};
|
use std::ops::{Div,Mul,Rem};
|
||||||
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
|
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
|
||||||
use std::ops::{Sub,SubAssign};
|
use std::ops::{Sub,SubAssign};
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use std::fmt;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use quickcheck::{Arbitrary,Gen};
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
|
||||||
@@ -44,6 +47,7 @@ macro_rules! generate_number
|
|||||||
generate_base!($name, $size);
|
generate_base!($name, $size);
|
||||||
generate_base_conversions!($name);
|
generate_base_conversions!($name);
|
||||||
generate_codec!($name);
|
generate_codec!($name);
|
||||||
|
generate_formatter!($name);
|
||||||
|
|
||||||
cmp_impls!($name);
|
cmp_impls!($name);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user