{-# LINE 1 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.NMod.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.NMod.FFI (
  -- * Integers mod n (word-size n)
    NMod (..)
  , CNMod (..)
  -- * Memory management
  , newNMod
  , withNMod
  , withNewNMod
  , nmod_init
  -- * Modular reduction and arithmetic
  , _nmod_add
  , nmod_add
  , _nmod_sub
  , nmod_sub
  , nmod_neg
  , nmod_mul
  , _nmod_mul_fullword
  , nmod_inv
  , nmod_div
  , nmod_pow_ui
  -- * Discrete Logarithms via Pohlig-Hellman
  , NModDiscreteLogPohligHellman (..)
  , CNModDiscreteLogPohligHellman (..)
  , nmod_discrete_log_pohlig_hellman_init
  , nmod_discrete_log_pohlig_hellman_clear
  , nmod_discrete_log_pohlig_hellman_precompute_prime
  , nmod_discrete_log_pohlig_hellman_primitive_root
  , nmod_discrete_log_pohlig_hellman_run
) where 

-- integers mod n (word-size n) ------------------------------------------------

import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr ( Ptr, FunPtr, plusPtr, nullPtr )
import Foreign.Storable

import Data.Number.Flint.Flint



-- NMod ------------------------------------------------------------------------

data NMod = NMod {-# UNPACK #-} !(ForeignPtr CNMod)
data CNMod = CNMod CMpLimb CMpLimb CFBitCnt

instance Storable CNMod where
  {-# INLINE sizeOf #-}
  sizeOf :: CNMod -> Int
sizeOf CNMod
_ = (Int
24)
{-# LINE 56 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CNMod -> Int
alignment CNMod
_ = Int
8
{-# LINE 58 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
  peek ptr = return CNMod 
    <*> (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 60 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
    <*> (\hsc_ptr -> peekByteOff hsc_ptr 8) ptr
{-# LINE 61 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
    <*> (\hsc_ptr -> peekByteOff hsc_ptr 16) ptr
{-# LINE 62 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
  poke = error "CNMod.poke: Not defined"

instance Show CNMod where
  show :: CNMod -> [Char]
show (CNMod CMpLimb
n CMpLimb
ninv CMpLimb
norm) = CMpLimb -> [Char]
forall a. Show a => a -> [Char]
show CMpLimb
n

-- NModDiscreteLogPohligHellman ------------------------------------------------

data NModDiscreteLogPohligHellman =
   NModDiscreteLogPohligHellman !(ForeignPtr CNModDiscreteLogPohligHellman)
type CNModDiscreteLogPohligHellman = CFlint NModDiscreteLogPohligHellman

instance Storable CNModDiscreteLogPohligHellman where
  {-# INLINE sizeOf #-}
  sizeOf :: CNModDiscreteLogPohligHellman -> Int
sizeOf CNModDiscreteLogPohligHellman
_ = (Int
56)
{-# LINE 76 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CNModDiscreteLogPohligHellman -> Int
alignment CNModDiscreteLogPohligHellman
_ = Int
8
{-# LINE 78 "src/Data/Number/Flint/NMod/FFI.hsc" #-}
  peek ptr = error "CNModDiscreteLogPohligHellman poke: Not defined"
  poke :: Ptr CNModDiscreteLogPohligHellman
-> CNModDiscreteLogPohligHellman -> IO ()
poke = [Char]
-> Ptr CNModDiscreteLogPohligHellman
-> CNModDiscreteLogPohligHellman
-> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"CNMod.poke: Not defined"

-- Modular reduction and arithmetic --------------------------------------------

-- | Create a new `NMod` structure
newNMod :: CMpLimb -> IO NMod
newNMod CMpLimb
n = do
  ForeignPtr CNMod
x <- IO (ForeignPtr CNMod)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CNMod -> (Ptr CNMod -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CNMod
x ((Ptr CNMod -> IO ()) -> IO ()) -> (Ptr CNMod -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CNMod
x -> Ptr CNMod -> CMpLimb -> IO ()
nmod_init Ptr CNMod
x CMpLimb
n
  NMod -> IO NMod
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (NMod -> IO NMod) -> NMod -> IO NMod
forall a b. (a -> b) -> a -> b
$ ForeignPtr CNMod -> NMod
NMod ForeignPtr CNMod
x

-- | Use `NMod` structure
{-# INLINE withNMod #-}
withNMod :: NMod -> (Ptr CNMod -> IO a) -> IO (NMod, a)
withNMod (NMod ForeignPtr CNMod
x) Ptr CNMod -> IO a
f = do
  ForeignPtr CNMod -> (Ptr CNMod -> IO (NMod, a)) -> IO (NMod, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CNMod
x ((Ptr CNMod -> IO (NMod, a)) -> IO (NMod, a))
-> (Ptr CNMod -> IO (NMod, a)) -> IO (NMod, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CNMod
xp -> Ptr CNMod -> IO a
f Ptr CNMod
xp IO a -> (a -> IO (NMod, a)) -> IO (NMod, a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (NMod, a) -> IO (NMod, a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((NMod, a) -> IO (NMod, a))
-> (a -> (NMod, a)) -> a -> IO (NMod, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ForeignPtr CNMod -> NMod
NMod ForeignPtr CNMod
x,)

withNewNMod :: CMpLimb -> (Ptr CNMod -> IO a) -> IO (NMod, a)
withNewNMod CMpLimb
n Ptr CNMod -> IO a
f = do
  NMod
x <- CMpLimb -> IO NMod
newNMod CMpLimb
n
  NMod -> (Ptr CNMod -> IO a) -> IO (NMod, a)
forall {a}. NMod -> (Ptr CNMod -> IO a) -> IO (NMod, a)
withNMod NMod
x ((Ptr CNMod -> IO a) -> IO (NMod, a))
-> (Ptr CNMod -> IO a) -> IO (NMod, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CNMod
x -> Ptr CNMod -> IO a
f Ptr CNMod
x

--------------------------------------------------------------------------------

-- | /nmod_init/ /mod/ /n/ 
-- 
-- Initialises the given @nmod_t@ structure for reduction modulo \(n\) with
-- a precomputed inverse.
foreign import ccall "nmod.h nmod_init"
  nmod_init :: Ptr CNMod -> CMpLimb -> IO ()

-- | /_nmod_add/ /a/ /b/ /mod/ 
-- 
-- Returns \(a + b\) modulo @mod.n@. It is assumed that @mod@ is no more
-- than @FLINT_BITS - 1@ bits. It is assumed that \(a\) and \(b\) are
-- already reduced modulo @mod.n@.
foreign import ccall "nmod.h _nmod_add"
  _nmod_add :: CMpLimb -> CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /nmod_add/ /a/ /b/ /mod/ 
-- 
-- Returns \(a + b\) modulo @mod.n@. No assumptions are made about @mod.n@.
-- It is assumed that \(a\) and \(b\) are already reduced modulo @mod.n@.
foreign import ccall "nmod.h nmod_add"
  nmod_add :: CMpLimb -> CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /_nmod_sub/ /a/ /b/ /mod/ 
-- 
-- Returns \(a - b\) modulo @mod.n@. It is assumed that @mod@ is no more
-- than @FLINT_BITS - 1@ bits. It is assumed that \(a\) and \(b\) are
-- already reduced modulo @mod.n@.
foreign import ccall "nmod.h _nmod_sub"
  _nmod_sub :: CMpLimb -> CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /nmod_sub/ /a/ /b/ /mod/ 
-- 
-- Returns \(a - b\) modulo @mod.n@. No assumptions are made about @mod.n@.
-- It is assumed that \(a\) and \(b\) are already reduced modulo @mod.n@.
foreign import ccall "nmod.h nmod_sub"
  nmod_sub :: CMpLimb -> CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /nmod_neg/ /a/ /mod/ 
-- 
-- Returns \(-a\) modulo @mod.n@. It is assumed that \(a\) is already
-- reduced modulo @mod.n@, but no assumptions are made about the latter.
foreign import ccall "nmod.h nmod_neg"
  nmod_neg :: CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /nmod_mul/ /a/ /b/ /mod/ 
-- 
-- Returns \(ab\) modulo @mod.n@. No assumptions are made about @mod.n@. It
-- is assumed that \(a\) and \(b\) are already reduced modulo @mod.n@.
foreign import ccall "nmod.h nmod_mul"
  nmod_mul :: CMpLimb -> CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /_nmod_mul_fullword/ /a/ /b/ /mod/ 
-- 
-- Returns \(ab\) modulo @mod.n@. Requires that @mod.n@ is exactly
-- @FLINT_BITS@ large. It is assumed that \(a\) and \(b\) are already
-- reduced modulo @mod.n@.
foreign import ccall "nmod.h _nmod_mul_fullword"
  _nmod_mul_fullword :: CMpLimb -> CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /nmod_inv/ /a/ /mod/ 
-- 
-- Returns \(a^{-1}\) modulo @mod.n@. The inverse is assumed to exist.
foreign import ccall "nmod.h nmod_inv"
  nmod_inv :: CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /nmod_div/ /a/ /b/ /mod/ 
-- 
-- Returns \(ab^{-1}\) modulo @mod.n@. The inverse of \(b\) is assumed to
-- exist. It is assumed that \(a\) is already reduced modulo @mod.n@.
foreign import ccall "nmod.h nmod_div"
  nmod_div :: CMpLimb -> CMpLimb -> Ptr CNMod -> IO CMpLimb

-- | /nmod_pow_ui/ /a/ /e/ /mod/ 
-- 
-- Returns \(a^e\) modulo @mod.n@. No assumptions are made about @mod.n@.
-- It is assumed that \(a\) is already reduced modulo @mod.n@.
foreign import ccall "nmod.h nmod_pow_ui"
  nmod_pow_ui :: CMpLimb -> CULong -> Ptr CNMod -> IO CMpLimb

-- Discrete Logarithms via Pohlig-Hellman --------------------------------------

-- | /nmod_discrete_log_pohlig_hellman_init/ /L/ 
-- 
-- Initialize @L@. Upon initialization @L@ is not ready for computation.
foreign import ccall "nmod.h nmod_discrete_log_pohlig_hellman_init"
  nmod_discrete_log_pohlig_hellman_init :: Ptr CNModDiscreteLogPohligHellman -> IO ()

-- | /nmod_discrete_log_pohlig_hellman_clear/ /L/ 
-- 
-- Free any space used by @L@.
foreign import ccall "nmod.h nmod_discrete_log_pohlig_hellman_clear"
  nmod_discrete_log_pohlig_hellman_clear :: Ptr CNModDiscreteLogPohligHellman -> IO ()

-- | /nmod_discrete_log_pohlig_hellman_precompute_prime/ /L/ /p/ 
-- 
-- Configure @L@ for discrete logarithms modulo @p@ to an internally chosen
-- base. It is assumed that @p@ is prime. The return is an estimate on the
-- number of multiplications needed for one run.
foreign import ccall "nmod.h nmod_discrete_log_pohlig_hellman_precompute_prime"
  nmod_discrete_log_pohlig_hellman_precompute_prime :: Ptr CNModDiscreteLogPohligHellman -> CMpLimb -> IO CDouble

-- | /nmod_discrete_log_pohlig_hellman_primitive_root/ /L/ 
-- 
-- Return the internally stored base.
foreign import ccall "nmod.h nmod_discrete_log_pohlig_hellman_primitive_root"
  nmod_discrete_log_pohlig_hellman_primitive_root :: Ptr CNModDiscreteLogPohligHellman -> IO CMpLimb

-- | /nmod_discrete_log_pohlig_hellman_run/ /L/ /y/ 
-- 
-- Return the logarithm of @y@ with respect to the internally stored base.
-- @y@ is expected to be reduced modulo the @p@. The function is undefined
-- if the logarithm does not exist.
foreign import ccall "nmod.h nmod_discrete_log_pohlig_hellman_run"
  nmod_discrete_log_pohlig_hellman_run :: Ptr CNModDiscreteLogPohligHellman -> CMpLimb -> IO CULong