-- | This module collects all hGMP functions used by hMPC.

module Hgmp (isPrime, prevPrime, invert) where

import Numeric.GMP.Utils (withInInteger, withOutInteger_)
import Numeric.GMP.Raw.Safe
import System.IO.Unsafe (unsafePerformIO)


-- | Return True if x is probably prime, else False if x is

-- definitely composite

isPrime :: Integer -> Bool
isPrime :: Integer -> Bool
isPrime Integer
x = IO CInt -> CInt
forall a. IO a -> a
unsafePerformIO (Integer -> (Ptr MPZ -> IO CInt) -> IO CInt
forall r. Integer -> (Ptr MPZ -> IO r) -> IO r
withInInteger Integer
x ((Ptr MPZ -> CInt -> IO CInt) -> CInt -> Ptr MPZ -> IO CInt
forall a b c. (a -> b -> c) -> b -> a -> c
flip Ptr MPZ -> CInt -> IO CInt
mpz_probab_prime_p CInt
25)) CInt -> CInt -> Bool
forall a. Ord a => a -> a -> Bool
> CInt
0


-- | Return the greatest probable prime number < x, if any.

prevPrime :: Integer -> Integer
prevPrime :: Integer -> Integer
prevPrime Integer
x
    | Integer
x Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
2 = Integer
0
    | Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
3 = Integer
2
    | Bool
otherwise = Integer -> Integer
_prevPrime (Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- (Integer
1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ (Integer
x Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
2)))
    where
        _prevPrime :: Integer -> Integer
_prevPrime Integer
x
            | Integer -> Bool
isPrime Integer
x = Integer
x
            | Bool
otherwise = Integer -> Integer
_prevPrime (Integer
xInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
2)

-- | Return y such that @x*y == 1 modulo m@.

invert :: Integer -> Integer -> Integer
invert :: Integer -> Integer -> Integer
invert Integer
x Integer
m = IO Integer -> Integer
forall a. IO a -> a
unsafePerformIO (IO Integer -> Integer) -> IO Integer -> Integer
forall a b. (a -> b) -> a -> b
$
                (Ptr MPZ -> IO CInt) -> IO Integer
forall a. (Ptr MPZ -> IO a) -> IO Integer
withOutInteger_ ((Ptr MPZ -> IO CInt) -> IO Integer)
-> (Ptr MPZ -> IO CInt) -> IO Integer
forall a b. (a -> b) -> a -> b
$ \Ptr MPZ
rop ->
                    Integer -> (Ptr MPZ -> IO CInt) -> IO CInt
forall r. Integer -> (Ptr MPZ -> IO r) -> IO r
withInInteger Integer
x ((Ptr MPZ -> IO CInt) -> IO CInt)
-> (Ptr MPZ -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr MPZ
op1 ->
                        Integer -> (Ptr MPZ -> IO CInt) -> IO CInt
forall r. Integer -> (Ptr MPZ -> IO r) -> IO r
withInInteger Integer
m ((Ptr MPZ -> IO CInt) -> IO CInt)
-> (Ptr MPZ -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr MPZ
op2 ->
                            Ptr MPZ -> Ptr MPZ -> Ptr MPZ -> IO CInt
mpz_invert Ptr MPZ
rop Ptr MPZ
op1 Ptr MPZ
op2