pairing-0.1.0: src/Pairing/Fq12.hs
{-# LANGUAGE Strict #-}
-- | Final quadratic extension of the tower:
--
-- * Fq
-- * Fq2 := Fq[u]/u^2 + 1
-- * Fq6 := Fq2[v]/v^3 - (9 + u)
-- * Fq12 := Fq6[w]/w^2 - v
--
-- Implementation follows "Multiplication and Squaring on
-- Pairing-Friendly Fields" by Devigili, hEigeartaigh, Scott and
-- Dahab.
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.Params
-- | Field extension defined as Fq6[w]/w^2 - v
data Fq12 = Fq12 { fq12x :: Fq6, fq12y :: Fq6 } -- ^ Use @new@ instead
-- of this constructor
deriving (Eq, Show)
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
-- | Create a new value in @Fq12@ by providing a list of twelve
-- coefficients in @Fq@, should be used instead of the @Fq12@
-- constructor.
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 a value in @Fq12@ into a list of twelve coefficients in @Fq@.
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)
-- | Multiplicative identity
fq12one :: Fq12
fq12one = fq12int 1
-- | Additive identity
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
-- | Multiplicative inverse
{-# INLINEABLE fq12inv #-}
fq12inv :: Fq12 -> Fq12
fq12inv (Fq12 a b) = Fq12 (a*t) (-(b*t))
where
t = Fq6.fq6inv (a^2 - Fq6.mulXi (b^2))
-- | Conjugation
fq12conj :: Fq12 -> Fq12
fq12conj (Fq12 x y) = Fq12 x (negate y)
-- | Iterated Frobenius automorphism
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)