{-# LANGUAGE Strict #-}
{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}
module Pairing.Fq12 (
Fq12(..),
new,
deconstruct,
fq12inv,
fq12one,
fq12zero,
fq12conj,
fq12frobenius,
random
) where
import Protolude
import Crypto.Random (MonadRandom)
import Pairing.Fq (Fq)
import Pairing.Fq6 (Fq6(..))
import qualified Pairing.Fq2 as Fq2
import qualified Pairing.Fq6 as Fq6
import Pairing.CyclicGroup (AsInteger(..), FromX(..))
import Pairing.Params
import Pairing.ByteRepr
import Data.ByteString as B (length, splitAt)
data Fq12 = Fq12 { fq12x :: Fq6, fq12y :: Fq6 }
deriving (Eq, Show, Generic, NFData)
instance Num Fq12 where
(+) = fq12add
(*) = fq12mul
negate = fq12neg
fromInteger = fq12int
abs = panic "abs not defined for fq12"
signum = panic "signum not defined for fq12"
instance Fractional Fq12 where
(/) = fq12div
fromRational (a :% b) = fq12int a / fq12int b
instance ByteRepr Fq12 where
mkRepr (Fq12 x y) = mkRepr x <> mkRepr y
fromRepr (Fq12 x _) bs = do
let (xbs, ybs) = B.splitAt (reprLength x) bs
x <- fromRepr Fq6.fq6one xbs
y <- fromRepr Fq6.fq6one ybs
Just (Fq12 x y)
reprLength (Fq12 x y) = reprLength x + reprLength y
new :: [Fq] -> Fq12
new [a,b,c,d,e,f,g,h,i,j,k,l] = Fq12
(Fq6.new (Fq2.new a b) (Fq2.new c d) (Fq2.new e f))
(Fq6.new (Fq2.new g h) (Fq2.new i j) (Fq2.new k l))
new _ = panic "Invalid arguments to fq12"
deconstruct :: Fq12 -> [Fq]
deconstruct (Fq12
(Fq6.Fq6 (Fq2.Fq2 a b) (Fq2.Fq2 c d) (Fq2.Fq2 e f))
(Fq6.Fq6 (Fq2.Fq2 g h) (Fq2.Fq2 i j) (Fq2.Fq2 k l)))
= [a,b,c,d,e,f,g,h,i,j,k,l]
fq12int :: Integer -> Fq12
fq12int n = new (fromIntegral n : replicate 11 0)
fq12one :: Fq12
fq12one = fq12int 1
fq12zero :: Fq12
fq12zero = fq12int 0
fq12add :: Fq12 -> Fq12 -> Fq12
fq12add (Fq12 x y) (Fq12 a b) = Fq12 (x+a) (y+b)
fq12neg :: Fq12 -> Fq12
fq12neg (Fq12 x y) = Fq12 (negate x) (negate y)
fq12div :: Fq12 -> Fq12 -> Fq12
fq12div a b = a * fq12inv b
fq12mul :: Fq12 -> Fq12 -> Fq12
fq12mul (Fq12 x y) (Fq12 a b) = Fq12 (Fq6.mulXi bb + aa) ((x+y) * (a+b) - aa - bb)
where
aa = x*a
bb = y*b
{-# INLINEABLE fq12inv #-}
fq12inv :: Fq12 -> Fq12
fq12inv (Fq12 a b) = Fq12 (a*t) (-(b*t))
where
t = Fq6.fq6inv (a^2 - Fq6.mulXi (b^2))
fq12conj :: Fq12 -> Fq12
fq12conj (Fq12 x y) = Fq12 x (negate y)
fq12frobenius :: Int -> Fq12 -> Fq12
fq12frobenius i a
| i == 0 = a
| i == 1 = fastFrobenius1 a
| i > 1 = let prev = fq12frobenius (i - 1) a
in fastFrobenius1 prev
| otherwise = panic "fq12frobenius not defined for negative values of i"
fastFrobenius1 :: Fq12 -> Fq12
fastFrobenius1 (Fq12 (Fq6.Fq6 x0 x1 x2) (Fq6.Fq6 y0 y1 y2)) =
let
t1 = Fq2.fq2conj x0
t2 = Fq2.fq2conj y0
t3 = Fq2.fq2conj x1
t4 = Fq2.fq2conj y1
t5 = Fq2.fq2conj x2
t6 = Fq2.fq2conj y2
gamma1 :: Integer -> Fq2.Fq2
gamma1 i = Fq2.xi ^ ((i * (_q - 1)) `div` 6)
t11 = t1
t21 = t2 * gamma1 1
t31 = t3 * gamma1 2
t41 = t4 * gamma1 3
t51 = t5 * gamma1 4
t61 = t6 * gamma1 5
c0 = Fq6 t11 t31 t51
c1 = Fq6 t21 t41 t61
in Fq12 c0 c1
random :: MonadRandom m => m Fq12
random = do
x <- Fq6.random
y <- Fq6.random
pure (Fq12 x y)