{-# LANGUAGE Strict #-}
{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}
module Pairing.Fq2 (
Fq2(..),
Pairing.Fq2.new,
fq2scalarMul,
fq2inv,
fq2one,
fq2zero,
fq2conj,
fq2sqr,
fq2sqrt,
fq2pow,
fq2YforX,
mulXi,
divXi,
xi,
Pairing.Fq2.random,
) where
import Protolude
import Crypto.Random (MonadRandom)
import Pairing.Modular
import Pairing.Fq as Fq
import qualified Pairing.Params as Params
import Data.Bits
import Data.ByteString as B (length, splitAt)
import Pairing.CyclicGroup (AsInteger(..), FromX(..))
import Pairing.ByteRepr
data Fq2 = Fq2 { fq2x :: Fq, fq2y :: Fq }
deriving (Eq, Show, Generic, NFData)
new :: Fq -> Fq -> Fq2
new = Fq2
instance Num Fq2 where
(+) = fq2add
(*) = fq2mul
negate = fq2neg
fromInteger = fq2int
abs = panic "abs not defined for fq2"
signum = panic "signum not defined for fq2"
instance Fractional Fq2 where
(/) = fq2div
fromRational (a :% b) = fq2int a / fq2int b
instance Ord Fq2 where
compare (Fq2 x y) (Fq2 a b)
| compare x a == EQ = compare y b
| otherwise = compare x a
instance FromX Fq2 where
yFromX = fq2YforX
isLargestY y = y > negate y
instance ByteRepr Fq2 where
mkRepr (Fq2 x y) = mkRepr x <> mkRepr y
fromRepr (Fq2 x _) bs = do
let (xbs, ybs) = B.splitAt (reprLength x) bs
Just (Fq2 (Fq $ fromBytesToInteger xbs) (Fq $ fromBytesToInteger ybs))
reprLength (Fq2 x y) = reprLength x + reprLength y
xi :: Fq2
xi = Fq2 xiA xiB
where
xiA, xiB :: Fq
xiA = Fq.new Params._xiA
xiB = Fq.new Params._xiB
fq2one :: Fq2
fq2one = fq2int 1
fq2zero :: Fq2
fq2zero = fq2int 0
fq2int :: Integer -> Fq2
fq2int n = Fq2 (fromInteger n) fqZero
fq2neg :: Fq2 -> Fq2
fq2neg (Fq2 x y) = Fq2 (-x) (-y)
fq2add :: Fq2 -> Fq2 -> Fq2
fq2add (Fq2 x y) (Fq2 a b) = Fq2 (x+a) (y+b)
fq2div :: Fq2 -> Fq2 -> Fq2
fq2div a b = fq2mul a (fq2inv b)
fq2mul :: Fq2 -> Fq2 -> Fq2
fq2mul (Fq2 a0 a1) (Fq2 b0 b1) = Fq2 c0 c1
where
aa = a0 * b0
bb = a1 * b1
c0 = bb * fqNqr + aa
c1 = (a0 + a1) * (b0 + b1) - aa - bb
fq2scalarMul :: Fq -> Fq2 -> Fq2
fq2scalarMul a (Fq2 x y) = Fq2 (a*x) (a*y)
mulXi :: Fq2 -> Fq2
mulXi = (* xi)
divXi :: Fq2 -> Fq2
divXi = (/ xi)
fq2sqr :: Fq2 -> Fq2
fq2sqr (Fq2 a0 a1) = Fq2 c0 c1
where
aa = a0 * a0
bb = a1 * a1
c0 = bb * fqNqr + aa
c1 = (a0 + a1) * (a0 + a1) - aa - bb
{-# INLINE fq2pow #-}
fq2pow :: Fq2 -> Integer -> Fq2
fq2pow b 0 = fq2one
fq2pow b e = t * fq2pow (b * b) (shiftR e 1)
where
t = if testBit e 0 then b else fq2one
fq2inv :: Fq2 -> Fq2
fq2inv (Fq2 a0 a1) = Fq2 c0 c1
where
t = fqInv ((a0 ^ 2) - ((a1 ^ 2) * fqNqr))
c0 = a0 * t
c1 = -(a1 * t)
fq2conj :: Fq2 -> Fq2
fq2conj (Fq2 x y) = Fq2 x (negate y)
fq2sqrt :: Fq2 -> Maybe Fq2
fq2sqrt a = do
let a1 = a `fq2pow` qm3by4
let alpha = (fq2sqr a1) * a
let a0 = (alpha `fq2pow` Params._q) * alpha
if a0 == neg1 then Nothing else do
let x0 = a1 * a
if alpha == neg1 then Just (a1 `fq2mul` Pairing.Fq2.new fqZero fqOne) else do
let b = (alpha + fq2one) `fq2pow` qm1by2
Just (b * x0)
where
neg1 = Pairing.Fq2.new (negate fqOne) fqZero
qm3by4 = withQ (modBinOp (Params._q -3) 4 (/))
qm1by2 = withQ (modBinOp (Params._q -1) 2 (/))
random :: MonadRandom m => m Fq2
random = do
x <- Fq.random
y <- Fq.random
pure (Fq2 x y)
fq2YforX :: Fq2 -> Bool -> Maybe Fq2
fq2YforX x ly
| ly = newy
| otherwise = negate <$> newy
where
newy = fq2sqrt (x `fq2pow` 3 + Fq2 (b * inv_xi_a) (b * inv_xi_b))
(Fq2 inv_xi_a inv_xi_b) = fq2inv xi
b = Fq Params._b