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:
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))
|
||||
|
||||
Reference in New Issue
Block a user