packages feed

mcl-1.0.0: src/MCL/Internal/Field.hs

{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
module MCL.Internal.Field where

import Data.Ratio
import Data.Typeable
import Foreign.C.Types
import GHC.Exts
import GHC.Integer.GMP.Internals
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BS

import MCL.Internal.Prim
import MCL.Internal.Utils

class Prim fp => BaseField fp where
  c_limbs        :: Proxy# fp -> Int
  c_modulus      :: Proxy# fp -> MC Integer -> CSize -> IO ()
  c_hash_to      :: Proxy# fp -> Ptr CChar -> CSize -> MC fp -> IO ()
  c_from_integer :: Proxy# fp -> CC Integer -> GmpSize# -> MC fp -> IO ()
  c_from_hsint   :: Proxy# fp -> Int# -> MC fp -> IO ()
  c_to_integer   :: Proxy# fp -> CC fp -> MC Integer -> CSize -> IO ()

{-# INLINABLE mkFp #-}
mkFp :: forall fp. (BaseField fp, Typeable fp) => Integer -> fp
mkFp n = unsafeOp0_ $ case n `mod` (modulus fp) of
  Jp# x@(BN# ba) -> c_from_integer fp ba (sizeofBigNat# x)
  Jn# _          -> error $ "mkFp (" ++ fpRep ++ "): n mod p is negative"
  S# k           -> c_from_hsint fp k
  where
    fp    = proxy# :: Proxy# fp
    fpRep = show $ typeRep (Proxy :: Proxy fp)

{-# INLINABLE hashToFp #-}
hashToFp :: forall fp. BaseField fp => BS.ByteString -> fp
hashToFp bs = unsafeOp0 . BS.unsafeUseAsCStringLen bs $ \(ptr, len) ->
  newPrim_ $ c_hash_to (proxy# :: Proxy# fp) ptr (fromIntegral len)

{-# INLINABLE fromFp #-}
fromFp :: forall fp. BaseField fp => fp -> Integer
fromFp = unsafeOp1 (importInteger (c_limbs fp)) (c_to_integer fp)
  where
    fp = proxy# :: Proxy# fp

{-# INLINABLE modulus #-}
modulus :: BaseField fp => Proxy# fp -> Integer
modulus fp = unsafeOp0 $ importInteger (c_limbs fp) (c_modulus fp)

{-# INLINABLE showsPrecFp #-}
showsPrecFp :: BaseField fp => Int -> fp -> ShowS
showsPrecFp p = showsPrec p . fromFp

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

class Prim fp => HasArith fp where
  c_add      :: Proxy# fp -> CC fp -> CC fp -> MC fp -> IO ()
  c_subtract :: Proxy# fp -> CC fp -> CC fp -> MC fp -> IO ()
  c_multiply :: Proxy# fp -> CC fp -> CC fp -> MC fp -> IO ()
  c_negate   :: Proxy# fp -> CC fp          -> MC fp -> IO ()
  c_invert   :: Proxy# fp -> CC fp          -> MC fp -> IO ()
  c_eq       :: Proxy# fp -> CC fp -> CC fp          -> IO CInt
  c_is_zero  :: Proxy# fp -> CC fp                   -> IO CInt

{-# INLINABLE isZero #-}
isZero :: forall fp. HasArith fp => fp -> Bool
isZero = unsafeOp1 (fmap cintToBool) $ c_is_zero (proxy# :: Proxy# fp)

{-# INLINABLE addFp #-}
addFp :: forall fp. HasArith fp => fp -> fp -> fp
addFp = unsafeOp2_ $ c_add (proxy# :: Proxy# fp)

{-# INLINABLE subtractFp #-}
subtractFp :: forall fp. HasArith fp => fp -> fp -> fp
subtractFp = unsafeOp2_ $ c_subtract (proxy# :: Proxy# fp)

{-# INLINABLE multiplyFp #-}
multiplyFp :: forall fp. HasArith fp => fp -> fp -> fp
multiplyFp = unsafeOp2_ $ c_multiply (proxy# :: Proxy# fp)

{-# INLINABLE negateFp #-}
negateFp :: forall fp. HasArith fp => fp -> fp
negateFp = unsafeOp1_ $ c_negate (proxy# :: Proxy# fp)

{-# INLINABLE absFp #-}
absFp :: fp -> fp
absFp = id

{-# INLINABLE signumFp #-}
signumFp :: forall fp. (HasArith fp, Num fp) => fp -> fp
signumFp fp = if isZero fp then fp else 1

{-# INLINABLE recipFp #-}
recipFp :: forall fp. HasArith fp => fp -> fp
recipFp = unsafeOp1_ $ c_invert (proxy# :: Proxy# fp)

{-# INLINABLE fromRationalFp #-}
fromRationalFp :: Fractional fp => Rational -> fp
fromRationalFp r = fromIntegral (numerator r) / fromIntegral (denominator r)

{-# INLINABLE eqFp #-}
eqFp :: forall fp. HasArith fp => fp -> fp -> Bool
eqFp = unsafeOp2 (fmap cintToBool) $ c_eq (proxy# :: Proxy# fp)

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

class HasArith fp => HasSqrt fp where
  c_sqrt :: Proxy# fp -> CC fp -> MC fp -> IO CInt

{-# INLINABLE squareRoot #-}
squareRoot :: forall fp. HasSqrt fp => fp -> Maybe fp
squareRoot = unsafeOp1 maybeNewPrim $ c_sqrt (proxy# :: Proxy# fp)