Shift the gold testing infrastructure into its own module, and add the Haskell program I used to generate the tests.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,3 +11,7 @@ Cargo.lock
|
||||
|
||||
# And these are just annoying
|
||||
.DS_Store
|
||||
|
||||
# And some Haskell stuff, because I can't shake it!
|
||||
tests/math/cabal.sandbox.config
|
||||
tests/math/.cabal-sandbox
|
||||
|
||||
205
src/cryptonum/gold_tests.rs
Normal file
205
src/cryptonum/gold_tests.rs
Normal file
@@ -0,0 +1,205 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::str::Lines;
|
||||
|
||||
use cryptonum::unsigned::UCN;
|
||||
use cryptonum::signed::SCN;
|
||||
|
||||
fn next_value_set(line: &str) -> (String, SCN)
|
||||
{
|
||||
assert!(line.is_ascii());
|
||||
assert_eq!(": ", &line[1..3]);
|
||||
let key = String::from(&line[0..1]);
|
||||
let val = SCN::from_str(&line[3..]);
|
||||
(key, val)
|
||||
}
|
||||
|
||||
fn next_test_case(contents: &mut Lines, lines: usize) ->
|
||||
Option<HashMap<String,SCN>>
|
||||
{
|
||||
let mut res = HashMap::new();
|
||||
let mut count = 0;
|
||||
|
||||
while count < lines {
|
||||
let line = contents.next()?;
|
||||
let (key, val) = next_value_set(line);
|
||||
res.insert(key, val);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
Some(res)
|
||||
}
|
||||
|
||||
fn make_unsigned(m: HashMap<String,SCN>) -> HashMap<String,UCN>
|
||||
{
|
||||
let mut res: HashMap<String,UCN> = HashMap::new();
|
||||
|
||||
for (key, sval) in m.iter() {
|
||||
assert!(!sval.is_negative());
|
||||
res.insert(key.clone(), sval.clone().into());
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn run_test<F>(fname: &'static str, i: usize, f: F)
|
||||
where F: Fn(HashMap<String,SCN>)
|
||||
{
|
||||
let mut file = File::open(fname).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let mut iter = contents.lines();
|
||||
|
||||
while let Some(scase) = next_test_case(&mut iter, i) {
|
||||
f(scase);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_sum_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_add.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x + y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_sum_test()
|
||||
{
|
||||
run_test("tests/math/signed_add.tests", 3, |case| {
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x + y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_sub_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_sub.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x - y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_sub_test()
|
||||
{
|
||||
run_test("tests/math/signed_sub.tests", 3, |case| {
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x - y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_mul_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_mul.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x * y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_mul_test()
|
||||
{
|
||||
run_test("tests/math/signed_mul.tests", 3, |case| {
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x * y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_div_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_div.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x / y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_div_test()
|
||||
{
|
||||
run_test("tests/math/signed_div.tests", 3, |case| {
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x / y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_mod_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_mod.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x % y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_mod_test()
|
||||
{
|
||||
run_test("tests/math/signed_mod.tests", 3, |case| {
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x % y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modular_exponentiation_test()
|
||||
{
|
||||
run_test("tests/math/modexp.tests", 4, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let a = case.get("a").unwrap();
|
||||
let b = case.get("b").unwrap();
|
||||
let m = case.get("m").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(a.modexp(&b, &m), *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn barrett_reduction_test()
|
||||
{
|
||||
run_test("tests/math/barrett.tests", 5, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let kbig = case.get("k").unwrap();
|
||||
let m = case.get("m").unwrap();
|
||||
let r = case.get("r").unwrap();
|
||||
let u = case.get("u").unwrap();
|
||||
let v = case.get("v").unwrap();
|
||||
let k = usize::from(kbig);
|
||||
let barrett = m.barrett_u();
|
||||
let result = v.reduce(&barrett);
|
||||
assert_eq!(barrett.k, k);
|
||||
assert_eq!(&barrett.u, u);
|
||||
assert_eq!(&barrett.m, m);
|
||||
assert_eq!(&result, r);
|
||||
});
|
||||
}
|
||||
@@ -4,6 +4,8 @@ mod conversions;
|
||||
mod complete_arith;
|
||||
mod signed;
|
||||
mod unsigned;
|
||||
#[cfg(test)]
|
||||
mod gold_tests;
|
||||
|
||||
pub use self::signed::SCN;
|
||||
pub use self::unsigned::UCN;
|
||||
|
||||
@@ -232,58 +232,8 @@ derive_arithmetic_operators!(SCN, Rem, rem, RemAssign, rem_assign);
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use super::*;
|
||||
|
||||
fn gold_test<F>(name: &str, f: F)
|
||||
where
|
||||
F: Fn(SCN,SCN) -> SCN
|
||||
{
|
||||
let mut file = File::open(name).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let mut iter = contents.lines();
|
||||
|
||||
while let Some(xstr) = iter.next() {
|
||||
let ystr = iter.next().unwrap();
|
||||
let zstr = iter.next().unwrap();
|
||||
|
||||
assert!(xstr.starts_with("x: "));
|
||||
assert!(ystr.starts_with("y: "));
|
||||
assert!(zstr.starts_with("z: "));
|
||||
let x = SCN::from_str(&xstr[3..]);
|
||||
let y = SCN::from_str(&ystr[3..]);
|
||||
let z = SCN::from_str(&zstr[3..]);
|
||||
assert_eq!(f(x,y), z);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_tests() {
|
||||
gold_test("tests/add_tests_signed.txt", |x,y| x + y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_tests() {
|
||||
gold_test("tests/sub_tests_signed.txt", |x,y| x - y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul_tests() {
|
||||
gold_test("tests/mul_tests_signed.txt", |x,y| x * y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn div_tests() {
|
||||
gold_test("tests/div_tests_signed.txt", |x,y| x / y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mod_tests() {
|
||||
gold_test("tests/mod_tests_signed.txt", |x,y| x % y);
|
||||
}
|
||||
|
||||
impl Arbitrary for SCN {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> SCN {
|
||||
let neg = (g.next_u32() & 1) == 1;
|
||||
|
||||
@@ -13,9 +13,9 @@ pub struct UCN {
|
||||
}
|
||||
|
||||
pub struct BarrettUCN {
|
||||
u: UCN,
|
||||
k: usize,
|
||||
m: UCN
|
||||
pub(crate) u: UCN,
|
||||
pub(crate) k: usize,
|
||||
pub(crate) m: UCN
|
||||
}
|
||||
|
||||
static SMALL_PRIMES: [u32; 310] = [
|
||||
@@ -968,8 +968,6 @@ derive_arithmetic_operators!(UCN, Rem, rem, RemAssign, rem_assign);
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@@ -1235,111 +1233,6 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
fn gold_test<F>(name: &str, f: F)
|
||||
where
|
||||
F: Fn(UCN,UCN) -> UCN
|
||||
{
|
||||
let mut file = File::open(name).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let mut iter = contents.lines();
|
||||
|
||||
while let Some(xstr) = iter.next() {
|
||||
let ystr = iter.next().unwrap();
|
||||
let zstr = iter.next().unwrap();
|
||||
|
||||
assert!(xstr.starts_with("x: "));
|
||||
assert!(ystr.starts_with("y: "));
|
||||
assert!(zstr.starts_with("z: "));
|
||||
let x = UCN::from_str(&xstr[3..]);
|
||||
let y = UCN::from_str(&ystr[3..]);
|
||||
let z = UCN::from_str(&zstr[3..]);
|
||||
assert_eq!(f(x,y), z);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_tests() {
|
||||
gold_test("tests/add_tests.txt", |x,y| x + y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_tests() {
|
||||
gold_test("tests/sub_tests.txt", |x,y| x - y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul_tests() {
|
||||
gold_test("tests/mul_tests.txt", |x,y| x * y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn div_tests() {
|
||||
gold_test("tests/div_tests.txt", |x,y| x / y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mod_tests() {
|
||||
gold_test("tests/mod_tests.txt", |x,y| x % y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modexp_tests() {
|
||||
let mut file = File::open("tests/modpow_tests.txt").unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let mut iter = contents.lines();
|
||||
|
||||
while let Some(xstr) = iter.next() {
|
||||
let ystr = iter.next().unwrap();
|
||||
let zstr = iter.next().unwrap();
|
||||
let rstr = iter.next().unwrap();
|
||||
|
||||
assert!(xstr.starts_with("x: "));
|
||||
assert!(ystr.starts_with("y: "));
|
||||
assert!(zstr.starts_with("z: "));
|
||||
assert!(rstr.starts_with("r: "));
|
||||
let x = UCN::from_str(&xstr[3..]);
|
||||
let y = UCN::from_str(&ystr[3..]);
|
||||
let z = UCN::from_str(&zstr[3..]);
|
||||
let r = UCN::from_str(&rstr[3..]);
|
||||
assert_eq!(x.modexp(&y, &z), r);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn barrett_tests() {
|
||||
let mut file = File::open("tests/barrett_tests.txt").unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let mut iter = contents.lines();
|
||||
|
||||
while let Some(mstr) = iter.next() {
|
||||
let kstr = iter.next().unwrap();
|
||||
let ustr = iter.next().unwrap();
|
||||
let vstr = iter.next().unwrap();
|
||||
let rstr = iter.next().unwrap();
|
||||
|
||||
assert!(mstr.starts_with("m: "));
|
||||
assert!(kstr.starts_with("k: "));
|
||||
assert!(ustr.starts_with("u: "));
|
||||
assert!(vstr.starts_with("v: "));
|
||||
assert!(rstr.starts_with("r: "));
|
||||
let m = UCN::from_str(&mstr[3..]);
|
||||
let k = usize::from_str_radix(&kstr[3..], 10).unwrap();
|
||||
let u = UCN::from_str(&ustr[3..]);
|
||||
let v = UCN::from_str(&vstr[3..]);
|
||||
let r = UCN::from_str(&rstr[3..]);
|
||||
let b = m.barrett_u();
|
||||
assert_eq!(b.k, k);
|
||||
println!("");
|
||||
println!("b.u: {:X}", b.u);
|
||||
println!("u: {:X}", u);
|
||||
assert_eq!(b.u, u);
|
||||
assert_eq!(v.reduce(&b), r);
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn and_over_or_distribution(a: UCN, b: UCN, c: UCN) -> bool {
|
||||
(&a & (&b | &c)) == ((&a & &b) | (&a & &c))
|
||||
|
||||
6003
tests/add_tests.txt
6003
tests/add_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
10005
tests/barrett_tests.txt
10005
tests/barrett_tests.txt
File diff suppressed because it is too large
Load Diff
6006
tests/div_tests.txt
6006
tests/div_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
244
tests/math/GenerateMathTests.hs
Normal file
244
tests/math/GenerateMathTests.hs
Normal file
@@ -0,0 +1,244 @@
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
import Control.Monad
|
||||
import Data.Bits
|
||||
import Data.List
|
||||
import qualified Data.Map.Strict as Map
|
||||
import GHC.Integer.GMP.Internals
|
||||
import Numeric
|
||||
import System.IO
|
||||
import System.Random
|
||||
import Debug.Trace
|
||||
|
||||
type Generator a = StdGen -> a -> (Maybe [(String, Integer)], a, StdGen)
|
||||
|
||||
iterations :: Int
|
||||
iterations = 5000
|
||||
|
||||
maxSize :: Int
|
||||
maxSize = 8
|
||||
|
||||
randomVal :: (Integer -> Bool) -> StdGen -> (Integer, StdGen)
|
||||
randomVal filter g =
|
||||
let (mySize, g') = randomR (1, maxSize) g
|
||||
(possible, g'') = go g' mySize
|
||||
in if filter possible
|
||||
then (possible, g'')
|
||||
else randomVal filter g''
|
||||
where
|
||||
go rng 0 = (0, rng)
|
||||
go rng i =
|
||||
let (other, rng') = go rng (i - 1)
|
||||
(self, rng'') = random rng'
|
||||
in ((other `shiftL` 64) + self, rng'')
|
||||
|
||||
buildBasicGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> Maybe Integer) ->
|
||||
Generator ()
|
||||
buildBasicGenerator filter f g () =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y of
|
||||
Nothing ->
|
||||
(Nothing, (), g'')
|
||||
Just z ->
|
||||
(Just [("x", x), ("y", y), ("z", z)], (), g'')
|
||||
|
||||
buildBasicLimitingGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> Maybe Integer) ->
|
||||
Generator (Map.Map Integer Int)
|
||||
buildBasicLimitingGenerator filter f g m =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y of
|
||||
Nothing -> (Nothing, m, g'')
|
||||
Just z ->
|
||||
case Map.lookup z m of
|
||||
Nothing ->
|
||||
(Just [("x",x),("y",y),("z",z)], Map.insert z 1 m, g'')
|
||||
Just c | c >= 100 ->
|
||||
(Nothing, m, g'')
|
||||
Just c ->
|
||||
(Just [("x",x),("y",y),("z",z)], Map.insert z (c + 1) m, g'')
|
||||
|
||||
buildBasicAccGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> a -> Maybe (Integer, a)) ->
|
||||
Generator a
|
||||
buildBasicAccGenerator filter f g acc =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y acc of
|
||||
Nothing ->
|
||||
(Nothing, acc, g'')
|
||||
Just (z, acc') ->
|
||||
(Just [("x", x), ("y", y), ("z", z)], acc', g'')
|
||||
|
||||
runGenerator :: forall a. StdGen -> String -> a -> Generator a -> IO StdGen
|
||||
runGenerator g filename initVal generator =
|
||||
withFile (filename ++ ".tests") WriteMode $ \ hndl ->
|
||||
do putStrLn ("Generating " ++ filename ++ ".tests")
|
||||
go hndl g initVal iterations
|
||||
where
|
||||
go :: Handle -> StdGen -> a -> Int -> IO StdGen
|
||||
go _ g _ 0 = return g
|
||||
go hndl g acc iterations =
|
||||
case generator g acc of
|
||||
(Nothing, acc', g') ->
|
||||
go hndl g' acc' iterations
|
||||
(Just res, acc', g') ->
|
||||
do let sorted = sort res
|
||||
forM_ sorted $ \ (key, val) ->
|
||||
do let neg = if val < 0 then "-" else ""
|
||||
val' = abs val
|
||||
hPutStrLn hndl (key ++ ": " ++ neg ++ showHex val' "")
|
||||
go hndl g' acc' (iterations - 1)
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
do g0 <- newStdGen
|
||||
g1 <- runGenerator g0 "unsigned_add" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b -> Just (a + b)
|
||||
g2 <- runGenerator g1 "signed_add" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a + b)
|
||||
g3 <- runGenerator g2 "unsigned_sub" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b ->
|
||||
if a >= b then Just (a - b) else Nothing
|
||||
g4 <- runGenerator g3 "signed_sub" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a - b)
|
||||
g5 <- runGenerator g4 "unsigned_mul" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b -> Just (a * b)
|
||||
g6 <- runGenerator g5 "signed_mul" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a * b)
|
||||
g7 <- runGenerator g6 "unsigned_div" Map.empty $
|
||||
buildBasicLimitingGenerator (>= 0) $ \ a b ->
|
||||
if b == 0 then Nothing else Just (a `div` b)
|
||||
g8 <- runGenerator g7 "signed_div" Map.empty $
|
||||
buildBasicLimitingGenerator (const True) $ \ a b ->
|
||||
if b == 0 then Nothing else Just (a `div` b)
|
||||
g7 <- runGenerator g6 "unsigned_mod" 0 $
|
||||
buildBasicAccGenerator (>= 0) $ \ a b i ->
|
||||
case a `mod` b of
|
||||
_ | b == 0 -> Nothing
|
||||
x | (a == x) && (i == 100) -> Nothing
|
||||
x | a == x -> Just (x, i + 1)
|
||||
x -> Just (x, i)
|
||||
g8 <- runGenerator g7 "signed_mod" 0 $
|
||||
buildBasicAccGenerator (const True) $ \ a b i ->
|
||||
case a `mod` b of
|
||||
_ | b == 0 -> Nothing
|
||||
x | (a == x) && (i == 100) -> Nothing
|
||||
x | a == x -> Just (x, i + 1)
|
||||
x -> Just (x, i)
|
||||
g9 <- runGenerator g8 "modexp" () $ \ g () ->
|
||||
let (a, g') = randomVal (>= 0) g
|
||||
(b, g'') = randomVal (>= 0) g'
|
||||
(m, g''') = randomVal (>= 0) g''
|
||||
z = powModInteger a b m
|
||||
res = [("a",a),("b",b),("m",m),("z",z)]
|
||||
in if m == 0
|
||||
then (Nothing, (), g''')
|
||||
else (Just res, (), g''')
|
||||
_ <- runGenerator g9 "barrett" () $ \ g () ->
|
||||
let (m, g') = randomVal (>= 0) g
|
||||
(v, g'') = randomVal (>= 0) g'
|
||||
barrett = barrett_u m
|
||||
vk = computeK v
|
||||
in if vk > (2 * (bk barrett))
|
||||
then (Nothing, (), g'')
|
||||
else let me = reduce v barrett
|
||||
standard = v `mod` m
|
||||
res = [("m", m), ("v", v), ("r", me),
|
||||
("u", bu barrett), ("k", fromIntegral (bk barrett))]
|
||||
in if me /= standard
|
||||
then error "Barrett broken"
|
||||
else (Just res, (), g'')
|
||||
|
||||
return ()
|
||||
|
||||
-- Implement Barrett reduction using incredibly simplistic implementations, to
|
||||
-- be sure we got it right.
|
||||
--
|
||||
b :: Integer
|
||||
b = 2 ^ 64
|
||||
|
||||
computeK :: Integer -> Int
|
||||
computeK v = go 0 1
|
||||
where
|
||||
go k acc
|
||||
| v < acc = k
|
||||
| otherwise = go (k + 1) (acc * b)
|
||||
|
||||
data Barrett = Barrett { bm :: Integer, bu :: Integer, bk :: Int }
|
||||
deriving (Show)
|
||||
|
||||
barrett_u :: Integer -> Barrett
|
||||
barrett_u x = Barrett {
|
||||
bm = x,
|
||||
bu = (b ^ (2 * k)) `div` x,
|
||||
bk = k
|
||||
}
|
||||
where k = computeK x
|
||||
|
||||
reduce :: Integer -> Barrett -> Integer
|
||||
reduce x barrett = result
|
||||
where
|
||||
k = bk barrett
|
||||
u = bu barrett
|
||||
m = bm barrett
|
||||
--
|
||||
q1 = x `div` (b ^ (k - 1))
|
||||
q2 = q1 * u
|
||||
q3 = q2 `div` (b ^ (k + 1))
|
||||
r1 = x `mod` (b ^ (k + 1))
|
||||
r2 = (q3 * m) `mod` (b ^ (k + 1))
|
||||
r = r1 - r2
|
||||
r' = if r < 0 then r + (b ^ (k + 1)) else r
|
||||
result = minimize r' m
|
||||
|
||||
minimize :: Integer -> Integer -> Integer
|
||||
minimize r m | r < 0 = error "BLECH"
|
||||
| r >= m = minimize (r - m) m
|
||||
| otherwise = r
|
||||
|
||||
-- runOperation :: Handle -> IO ()
|
||||
-- runOperation hndl =
|
||||
-- do m <- randomVal =<< randomRIO (1,size)
|
||||
-- v <- randomVal =<< randomRIO (1,size)
|
||||
-- let barrett = barrett_u m
|
||||
-- let vk = computeK v
|
||||
-- if vk > (2 * (bk barrett))
|
||||
-- then runOperation hndl
|
||||
-- else do hPutStrLn hndl ("m: " ++ showHex m "")
|
||||
-- hPutStrLn hndl ("k: " ++ show (bk barrett))
|
||||
-- hPutStrLn hndl ("u: " ++ show (bu barrett))
|
||||
-- let me = reduce v barrett
|
||||
-- standard = v `mod` m
|
||||
-- unless (me == standard) $
|
||||
-- fail "Barrett messed up."
|
||||
-- hPutStrLn hndl ("v: " ++ showHex v "")
|
||||
-- hPutStrLn hndl ("r: " ++ showHex me "")
|
||||
-- hFlush hndl
|
||||
--
|
||||
-- generateFile :: String ->
|
||||
-- IO ()
|
||||
-- generateFile file =
|
||||
-- withFile (file ++ "_tests.txt") WriteMode $ \ hndl ->
|
||||
-- forM_ [0..2000] $ \ _ ->
|
||||
-- runOperation hndl
|
||||
--
|
||||
-- main :: IO ()
|
||||
-- main =
|
||||
-- do generateFile "add" $ \ x y ->
|
||||
-- (x, y, x + y)
|
||||
-- generateFile "sub" $ \ x y ->
|
||||
-- let x' = max x y
|
||||
-- y' = min x y
|
||||
-- in (x', y', x' - y')
|
||||
-- generateFile "mul" $ \ x y ->
|
||||
-- (x, y, x * y)
|
||||
-- generateFile "div" $ \ x y ->
|
||||
-- let y' = if y == 0 then 1 else y
|
||||
-- in (x, y', x / y')
|
||||
-- generateFile "mod" $ \ x y ->
|
||||
-- let y' = if y == 0 then 1 else y
|
||||
-- in (x, y', x / y')
|
||||
-- generateFile "barrett"
|
||||
25000
tests/math/barrett.tests
Normal file
25000
tests/math/barrett.tests
Normal file
File diff suppressed because it is too large
Load Diff
20000
tests/math/modexp.tests
Normal file
20000
tests/math/modexp.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_add.tests
Normal file
15000
tests/math/signed_add.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_div.tests
Normal file
15000
tests/math/signed_div.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_mod.tests
Normal file
15000
tests/math/signed_mod.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_mul.tests
Normal file
15000
tests/math/signed_mul.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_sub.tests
Normal file
15000
tests/math/signed_sub.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_add.tests
Normal file
15000
tests/math/unsigned_add.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_div.tests
Normal file
15000
tests/math/unsigned_div.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_mod.tests
Normal file
15000
tests/math/unsigned_mod.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_mul.tests
Normal file
15000
tests/math/unsigned_mul.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_sub.tests
Normal file
15000
tests/math/unsigned_sub.tests
Normal file
File diff suppressed because it is too large
Load Diff
6003
tests/mod_tests.txt
6003
tests/mod_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6003
tests/mul_tests.txt
6003
tests/mul_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6003
tests/sub_tests.txt
6003
tests/sub_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user