Unsigned modular operations.

This commit is contained in:
2020-01-10 09:05:11 -10:00
parent 4b8d0b3f09
commit 4383b67c44
4 changed files with 109 additions and 11 deletions

View File

@@ -5,7 +5,6 @@ module ModOps(modulusOps)
import Data.Map.Strict(Map)
import qualified Data.Map.Strict as Map
import File
import Gen(toLit)
import Generators
import GHC.Integer.GMP.Internals(powModInteger)
import Language.Rust.Data.Ident
@@ -15,7 +14,7 @@ import Language.Rust.Syntax
import System.Random(RandomGen)
numTestCases :: Int
numTestCases = 3000
numTestCases = 1000
modulusOps :: File
modulusOps = File {
@@ -30,9 +29,15 @@ declareModOps :: Word -> [Word] -> SourceFile Span
declareModOps bitsize _ =
let sname = mkIdent ("U" ++ show bitsize)
bname = mkIdent ("U" ++ show (bitsize * 2))
in [sourceFile|
use crate::unsigned::$$sname;
testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty
in [sourceFile|
use core::convert::TryFrom;
use crate::unsigned::{$$sname, $$bname};
use crate::{DivMod, ModularOperations};
#[cfg(test)]
use crate::CryptoNum;
#[cfg(test)]
use crate::testing::{build_test_path,run_test};
impl ModularOperations for $$sname {
fn reduce(&self, m: &$$sname) -> $$sname {
@@ -41,18 +46,69 @@ declareModOps bitsize _ =
}
fn modmul(&self, y: &$$sname, m: &$$sname) -> $$sname {
panic!("modmul")
let r = self * y;
let bigm = $$bname::from(m);
let bigres = r % bigm;
$$sname::try_from(bigres)
.expect("Mathematics is broken?! (mod returned too big result")
}
fn modsq(&self, m: &$$sname) -> $$sname {
panic!("reduce")
let r = self * self;
let bigm = $$bname::from(m);
let bigres = r % bigm;
$$sname::try_from(bigres)
.expect("Mathematics is broken?! (mod returned too big result")
}
fn modexp(&self, e: &$$sname, m: &$$sname) -> $$sname {
panic!("reduce")
let mut r = $$sname::from(1u64);
let bigm = $$bname::from(m);
for digit in e.value.iter().rev() {
for bit in (0..64).rev() {
r = r.modsq(&m);
let big_possible_r = (&r * self) % &bigm;
let possible_r = $$sname::try_from(big_possible_r)
.expect("Math is broken (again)");
let bit = (*digit >> bit) & 1;
r = if bit == 1 { possible_r } else { r };
}
}
r
}
}
|]
#[cfg(test)]
#[allow(non_snake_case)]
#[test]
fn KATs() {
run_test(build_test_path("modops", $$(testFileLit)), 7, |case| {
let (neg0, xbytes) = case.get("x").unwrap();
let (neg1, ybytes) = case.get("y").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
let (neg4, tbytes) = case.get("t").unwrap();
let (neg5, sbytes) = case.get("s").unwrap();
let (neg6, ebytes) = case.get("e").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6);
let x = $$sname::from_bytes(&xbytes);
let y = $$sname::from_bytes(&ybytes);
let m = $$sname::from_bytes(&mbytes);
let r = $$sname::from_bytes(&rbytes);
let t = $$sname::from_bytes(&tbytes);
let s = $$sname::from_bytes(&sbytes);
let e = $$sname::from_bytes(&ebytes);
assert_eq!(r, x.reduce(&m));
assert_eq!(t, x.modmul(&y, &m));
assert_eq!(s, x.modsq(&m));
assert_eq!(e, x.modexp(&y, &m));
});
}
|]
generateModulusTests :: RandomGen g => Word -> g -> [Map String String]
generateModulusTests size g = go g numTestCases