packages feed

mcl-1.0.0: src/MCL/Curves/Fp254BNb/G2.hs

{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UnliftedFFITypes #-}
module MCL.Curves.Fp254BNb.G2
  ( G2
  , mkG2
  , mapToG2
  , g2_zero
  , g2_isZero
  , g2_affineCoords
  , g2_getYfromX
  , g2_powFr
  ) where

import Control.DeepSeq
import Data.Binary
import Data.Bits
import Data.Group
import Data.Primitive.ByteArray
import Foreign.C.Types
import GHC.Exts
import GHC.Integer.GMP.Internals

import MCL.Curves.Fp254BNb.Fp
import MCL.Curves.Fp254BNb.Fp2
import MCL.Curves.Fp254BNb.Fr
import MCL.Internal.Utils
import qualified MCL.Internal.Group as I
import qualified MCL.Internal.Prim as I

-- | Subgroup of @E'(Fp2)@ (i.e. curve points with coordinates in Fp2) of order
-- @r@.
data G2 = G2 { unG2 :: I.CC G2 }

instance Binary G2 where
  put = putCurvePoint g2_affineCoords putY
    where
      putY y = put . cintToBool . fromIntegral $ fromFp (fp2_c0 y) .&. 1

  get = getCurvePoint g2_zero $ \x y_lsb ->
    mkG2 x =<< g2_getYfromX y_lsb x

instance NFData G2 where
  rnf = (`seq` ())

instance Eq G2 where
  (==) = I.eqG

instance Show G2 where
  showsPrec = I.showsPrecG

-- | Point addition.
instance Monoid G2 where
  mempty  = I.zero
  mappend = I.plusG

-- | Note: 'pow' uses const-time method, just as 'g2_powFr'.
instance Group G2 where
  invert = I.invertG
  pow    = flip I.scalarMul

instance Abelian G2

-- | Construct non-zero element of G2 from two coordinates in Fp2. If @(X,Y)@
-- does not lie on G2, no result is returned.
{-# INLINABLE mkG2 #-}
mkG2
  :: Fp2 -- ^ X coordinate
  -> Fp2 -- ^ Y coordinate
  -> Maybe G2
mkG2 = I.mkG

-- | Map an element of Fp2 to a curve point.
{-# INLINABLE mapToG2 #-}
mapToG2 :: Fp2 -> G2
mapToG2 = I.mapToG

-- | Neutral element of G2 (point at infinity).
{-# NOINLINE g2_zero #-}
g2_zero :: G2
g2_zero = I.zero

-- | Check if the element of G2 is point at infinity.
{-# INLINABLE g2_isZero #-}
g2_isZero :: G2 -> Bool
g2_isZero = I.isZero

-- | Return affine coordinates of the element @a ∈ G2@. No result is returned if
-- @a@ is the point at inifinity.
{-# INLINABLE g2_affineCoords #-}
g2_affineCoords :: G2 -> Maybe (Fp2, Fp2)
g2_affineCoords = I.affineCoords

-- | Attempt to recover Y coordinate from its least significant bit and X
-- coordinate.
{-# INLINABLE g2_getYfromX #-}
g2_getYfromX
  :: Bool -- ^ Least significant bit of Y coordinate
  -> Fp2  -- ^ X coordinate
  -> Maybe Fp2
g2_getYfromX = I.getYfromX (proxy# :: Proxy# G2)

-- | Multiply the element of G2 by a scalar @x ∈ Fr@. Note: it uses const-time
-- method, i.e. the time it takes to calculate the result depends only on the
-- bitlength of @x@.
{-# INLINABLE g2_powFr #-}
g2_powFr :: G2 -> Fr -> G2
g2_powFr = I.powFr

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

-- | Internal
instance I.Prim G2 where
  prim_size _ = fromIntegral c_mcl_fp254bnb_g2_size
  prim_wrap   = G2
  prim_unwrap = unG2

-- | Internal
instance I.CurveGroup Fp2 G2 where
  c_zero              _ = c_mcl_fp254bnb_g2_zero
  c_construct         _ = c_mcl_fp254bnb_g2_construct
  c_map_to            _ = c_mcl_fp254bnb_g2_map_to
  c_add               _ = c_mcl_fp254bnb_g2_add
  c_invert            _ = c_mcl_fp254bnb_g2_invert
  c_scalar_mul_native _ = c_mcl_fp254bnb_g2_scalar_mul_native
  c_scalar_mul_bignat _ = c_mcl_fp254bnb_g2_scalar_mul
  c_scalar_mul_hsint  _ = c_mcl_fp254bnb_g2_scalar_mul_small
  c_eq                _ = c_mcl_fp254bnb_g2_eq
  c_is_zero           _ = c_mcl_fp254bnb_g2_is_zero
  c_affine_coords     _ = c_mcl_fp254bnb_g2_affine_coords
  c_y_from_x          _ = c_mcl_fp254bnb_g2_y_from_x

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_size"
  c_mcl_fp254bnb_g2_size :: CInt

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_zero"
  c_mcl_fp254bnb_g2_zero :: I.MC G2 -> IO ()

foreign import ccall safe "hs_mcl_fp254bnb_g2_construct"
  c_mcl_fp254bnb_g2_construct :: I.CC Fp2 -> I.CC Fp2 -> I.MC G2 -> IO CInt

foreign import ccall safe "hs_mcl_fp254bnb_g2_map_to"
  c_mcl_fp254bnb_g2_map_to :: I.CC Fp2 -> I.MC G2 -> IO ()

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_add"
  c_mcl_fp254bnb_g2_add :: I.CC G2 -> I.CC G2 -> I.MC G2 -> IO ()

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_invert"
  c_mcl_fp254bnb_g2_invert :: I.CC G2 -> I.MC G2 -> IO ()

foreign import ccall safe "hs_mcl_fp254bnb_g2_scalar_mul_native"
  c_mcl_fp254bnb_g2_scalar_mul_native :: CInt -> I.CC Fr -> I.CC G2 -> I.MC G2 -> IO ()

foreign import ccall safe "hs_mcl_fp254bnb_g2_scalar_mul"
  c_mcl_fp254bnb_g2_scalar_mul :: CInt -> ByteArray# -> GmpSize# -> CInt
                               -> I.CC G2 -> I.MC G2 -> IO ()

foreign import ccall safe "hs_mcl_fp254bnb_g2_scalar_mul_small"
  c_mcl_fp254bnb_g2_scalar_mul_small :: CInt -> Int# -> I.CC G2 -> I.MC G2 -> IO ()

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_eq"
  c_mcl_fp254bnb_g2_eq :: I.CC G2 -> I.CC G2 -> IO CInt

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_is_zero"
  c_mcl_fp254bnb_g2_is_zero :: I.CC G2 -> IO CInt

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_affine_coords"
  c_mcl_fp254bnb_g2_affine_coords :: I.CC G2 -> I.MC Fp2 -> I.MC Fp2 ->  IO ()

foreign import ccall unsafe "hs_mcl_fp254bnb_g2_y_from_x"
  c_mcl_fp254bnb_g2_y_from_x :: CInt -> I.CC Fp2 -> I.MC Fp2 -> IO CInt