Barrett reduction! And number formatting.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
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!(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]
|
||||
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user