Support modular inverses.
This commit is contained in:
@@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
} else {
|
||||||
|
a.value
|
||||||
if d.is_negative() {
|
}
|
||||||
(d.neg(), x.neg(), y.neg())
|
|
||||||
} else {
|
} else {
|
||||||
(d, x, y)
|
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) )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
15000
tests/math/modinv.tests
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user