Support fast modular exponentiation for when your base is roughly the same order of magnitude as the modulo.
This commit is contained in:
@@ -3,7 +3,7 @@ use std::fs::File;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::str::Lines;
|
use std::str::Lines;
|
||||||
|
|
||||||
use cryptonum::unsigned::UCN;
|
use cryptonum::unsigned::{UCN,BarrettUCN};
|
||||||
use cryptonum::signed::SCN;
|
use cryptonum::signed::SCN;
|
||||||
|
|
||||||
fn next_value_set(line: &str) -> (String, SCN)
|
fn next_value_set(line: &str) -> (String, SCN)
|
||||||
@@ -184,6 +184,23 @@ fn modular_exponentiation_test()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fast_modular_exponentiation_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/fastmodexp.tests", 6, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let a = case.get("a").unwrap();
|
||||||
|
let b = case.get("b").unwrap();
|
||||||
|
let kbig = case.get("k").unwrap();
|
||||||
|
let k = usize::from(kbig);
|
||||||
|
let m = case.get("m").unwrap();
|
||||||
|
let u = case.get("u").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
let mu = BarrettUCN{ k: k, u: u.clone(), m: m.clone() };
|
||||||
|
assert_eq!(a.fastmodexp(&b, &mu), *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn barrett_reduction_test()
|
fn barrett_reduction_test()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -237,6 +237,25 @@ impl UCN {
|
|||||||
eprime >>= 1;
|
eprime >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fastmodexp(&self, e: &UCN, mu: &BarrettUCN) -> UCN {
|
||||||
|
let mut b = self.reduce(&mu);
|
||||||
|
let mut eprime = e.clone();
|
||||||
|
let mut result = UCN::from(1 as u8);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if eprime.is_zero() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if eprime.is_odd() {
|
||||||
|
result = (result * &b).reduce(&mu);
|
||||||
|
}
|
||||||
|
|
||||||
|
b = (&b * &b).reduce(&mu);
|
||||||
|
eprime >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn miller_rabin<G: Rng>(g: &mut G, n: &UCN, iters: usize) -> bool {
|
fn miller_rabin<G: Rng>(g: &mut G, n: &UCN, iters: usize) -> bool {
|
||||||
@@ -1256,5 +1275,21 @@ mod test {
|
|||||||
let barrett = b.barrett_u();
|
let barrett = b.barrett_u();
|
||||||
(&a % &b) == a.reduce(&barrett)
|
(&a % &b) == a.reduce(&barrett)
|
||||||
}
|
}
|
||||||
|
fn fastmodexp(ina: UCN, b: UCN, c: UCN) -> bool {
|
||||||
|
let mut a = ina.clone();
|
||||||
|
|
||||||
|
if c.contents.len() == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.contents.len() > c.contents.len() {
|
||||||
|
a.contents.resize(c.contents.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cu = c.barrett_u();
|
||||||
|
let slow = a.modexp(&b, &c);
|
||||||
|
let fast = a.fastmodexp(&b, &cu);
|
||||||
|
slow == fast
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,19 @@ main =
|
|||||||
in if me /= standard
|
in if me /= standard
|
||||||
then error "Barrett broken"
|
then error "Barrett broken"
|
||||||
else (Just res, (), g'')
|
else (Just res, (), g'')
|
||||||
|
_ <- runGenerator g9 "fastmodexp" () $ \ g () ->
|
||||||
|
let (a, g') = randomVal (>= 0) g
|
||||||
|
(b, g'') = randomVal (>= 0) g'
|
||||||
|
(m, g''') = randomVal (>= 0) g'
|
||||||
|
z = powModInteger a b m
|
||||||
|
barrett = barrett_u m
|
||||||
|
ak = computeK a
|
||||||
|
in if ak > bk barrett
|
||||||
|
then (Nothing, (), g''')
|
||||||
|
else let res = [("a", a), ("b", b), ("z", z),
|
||||||
|
("m", m), ("u", bu barrett),
|
||||||
|
("k", fromIntegral (bk barrett))]
|
||||||
|
in (Just res, (), g''')
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
-- Implement Barrett reduction using incredibly simplistic implementations, to
|
-- Implement Barrett reduction using incredibly simplistic implementations, to
|
||||||
@@ -198,47 +210,3 @@ minimize :: Integer -> Integer -> Integer
|
|||||||
minimize r m | r < 0 = error "BLECH"
|
minimize r m | r < 0 = error "BLECH"
|
||||||
| r >= m = minimize (r - m) m
|
| r >= m = minimize (r - m) m
|
||||||
| otherwise = r
|
| 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"
|
|
||||||
|
|||||||
30000
tests/math/fastmodexp.tests
Normal file
30000
tests/math/fastmodexp.tests
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user