Support modular inverses.

This commit is contained in:
2018-04-14 07:05:57 -07:00
parent b1c659087d
commit c45235473a
4 changed files with 15033 additions and 17 deletions

View File

@@ -220,3 +220,16 @@ fn barrett_reduction_test()
assert_eq!(&result, r); assert_eq!(&result, r);
}); });
} }
#[test]
fn modular_inverse_test()
{
run_test("tests/math/modinv.tests", 3, |scase| {
let case = make_unsigned(scase);
let a = case.get("x").unwrap();
let m = case.get("y").unwrap();
let r = case.get("z").unwrap();
let result = a.modinv(m);
assert_eq!(r, &result);
});
}

View File

@@ -130,23 +130,18 @@ impl UCN {
} }
pub fn modinv(&self, phi: &UCN) -> UCN { pub fn modinv(&self, phi: &UCN) -> UCN {
let (_, mut x, _) = self.extended_euclidean(&phi); let x = SCN::from(self.clone());
let int_phi = SCN::from(phi.clone()); let y = SCN::from(phi.clone());
while x.is_negative() { let (d, a, _b) = x.egcd(y);
x = x + &int_phi;
}
x.into()
}
fn extended_euclidean(&self, b: &UCN) -> (SCN, SCN, SCN) { if d == SCN::from(1 as u8) {
let posinta = SCN::from(self.clone()); if a.is_negative() {
let posintb = SCN::from(b.clone()); (a + SCN::from(phi.clone())).value
let (d, x, y) = posinta.egcd(posintb);
if d.is_negative() {
(d.neg(), x.neg(), y.neg())
} else { } else {
(d, x, y) a.value
}
} else {
UCN::zero()
} }
} }
@@ -1294,5 +1289,9 @@ mod test {
let fast = a.fastmodexp(&b, &cu); let fast = a.fastmodexp(&b, &cu);
slow == fast slow == fast
} }
fn modinv(a: UCN, b: UCN) -> bool {
let i = a.modinv(&b);
i.is_zero() || ( ((a * i) % b) == UCN::from(1 as u64) )
}
} }
} }

View File

@@ -137,7 +137,7 @@ main =
in if m == 0 in if m == 0
then (Nothing, (), g''') then (Nothing, (), g''')
else (Just res, (), g''') else (Just res, (), g''')
_ <- runGenerator g9 "barrett" () $ \ g () -> g10<- runGenerator g9 "barrett" () $ \ g () ->
let (m, g') = randomVal (>= 0) g let (m, g') = randomVal (>= 0) g
(v, g'') = randomVal (>= 0) g' (v, g'') = randomVal (>= 0) g'
barrett = barrett_u m barrett = barrett_u m
@@ -151,7 +151,7 @@ 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 () -> g11<- runGenerator g10 "fastmodexp" () $ \ g () ->
let (a, g') = randomVal (>= 0) g let (a, g') = randomVal (>= 0) g
(b, g'') = randomVal (>= 0) g' (b, g'') = randomVal (>= 0) g'
(m, g''') = randomVal (>= 0) g' (m, g''') = randomVal (>= 0) g'
@@ -164,6 +164,10 @@ main =
("m", m), ("u", bu barrett), ("m", m), ("u", bu barrett),
("k", fromIntegral (bk barrett))] ("k", fromIntegral (bk barrett))]
in (Just res, (), g''') in (Just res, (), g''')
_ <- runGenerator g11 "modinv" Map.empty $
buildBasicLimitingGenerator (>= 0) $ \ a b ->
let res == recipModInteger a b
if b == 0 then Nothing else Just (recipModInteger a b)
return () return ()
-- Implement Barrett reduction using incredibly simplistic implementations, to -- Implement Barrett reduction using incredibly simplistic implementations, to

15000
tests/math/modinv.tests Normal file

File diff suppressed because it is too large Load Diff