{-# OPTIONS -fno-warn-orphans #-}

module Data.Pairing.BN254
  ( module Data.Pairing
  , module Data.Pairing.Ate
  -- * BN254 curve
  , BN254
  , parameterBin
  , parameterHex
  -- ** Fields
  , Fq
  , Fq2
  , Fq6
  , Fq12
  , Fr
  -- ** Groups
  , G1'
  , G2'
  , GT'
  -- ** Roots of unity
  , getRootOfUnity
  ) where

import Protolude

import Data.Curve.Weierstrass.BN254 as G1
import Data.Curve.Weierstrass.BN254T as G2
import Data.Field.Galois as F

import Data.Pairing
import Data.Pairing.Ate

-------------------------------------------------------------------------------
-- Fields
-------------------------------------------------------------------------------

-- Cubic nonresidue in @Fq2@.
xi :: Fq2
xi = [9, 1]
{-# INLINABLE xi #-}

-- | Field of points of BN254 curve over @Fq6@.
type Fq6 = Extension V Fq2
data V
instance IrreducibleMonic V Fq2 where
  poly _ = [-xi, 0, 0, 1]
  {-# INLINABLE poly #-}

-- | Field of points of BN254 curve over @Fq12@.
type Fq12 = Extension W Fq6
data W
instance IrreducibleMonic W Fq6 where
  poly _ = [[0, -1], 0, 1]
  {-# INLINABLE poly #-}

-------------------------------------------------------------------------------
-- Curves
-------------------------------------------------------------------------------

-- | BN254 curve left group @G1 = E(Fq)@.
type G1' = G1.PA

-- | BN254 curve right group @G2 = E'(Fq2)@.
type G2' = G2.PA

-- | @Fq12@ multiplicative target group @GT@.
type GT' = RootsOfUnity R Fq12
instance CyclicSubgroup (RootsOfUnity R Fq12) where
  gen = toU'
    [ [ [ 0x12c70e90e12b7874510cd1707e8856f71bf7f61d72631e268fca81000db9a1f5
        , 0x84f330485b09e866bc2f2ea2b897394deaf3f12aa31f28cb0552990967d4704
        ]
      , [ 0xe841c2ac18a4003ac9326b9558380e0bc27fdd375e3605f96b819a358d34bde
        , 0x2067586885c3318eeffa1938c754fe3c60224ee5ae15e66af6b5104c47c8c5d8
        ]
      , [ 0x1676555de427abc409c4a394bc5426886302996919d4bf4bdd02236e14b3636
        , 0x2b03614464f04dd772d86df88674c270ffc8747ea13e72da95e3594468f222c4
        ]
      ]
    , [ [ 0x2c53748bcd21a7c038fb30ddc8ac3bf0af25d7859cfbc12c30c866276c565909
        , 0x27ed208e7a0b55ae6e710bbfbd2fd922669c026360e37cc5b2ab862411536104
        ]
      , [ 0x1ad9db1937fd72f4ac462173d31d3d6117411fa48dba8d499d762b47edb3b54a
        , 0x279db296f9d479292532c7c493d8e0722b6efae42158387564889c79fc038ee3
        ]
      , [ 0xdc26f240656bbe2029bd441d77c221f0ba4c70c94b29b5f17f0f6d08745a069
        , 0x108c19d15f9446f744d0f110405d3856d6cc3bda6c4d537663729f5257628417
        ]
      ]
    ]
  {-# INLINABLE gen #-}

-------------------------------------------------------------------------------
-- Pairings
-------------------------------------------------------------------------------

-- | BN254 curve parameter @s = 6t + 2@ in signed binary.
parameterBin :: [Int8]
parameterBin = [ 1, 1, 0, 1, 0, 0,-1, 0, 1, 1, 0, 0, 0,-1, 0, 0, 1
                  , 1, 0, 0,-1, 0, 0, 0, 0, 0, 1, 0, 0,-1, 0, 0, 1
                  , 1, 1, 0, 0, 0, 0,-1, 0, 1, 0, 0,-1, 0, 1, 1, 0
                  , 0, 1, 0, 0,-1, 1, 0, 0,-1, 0, 1, 0, 1, 0, 0, 0
               ]
{-# INLINABLE parameterBin #-}

-- | BN254 curve parameter @t@ in hexadecimal.
parameterHex :: Integer
parameterHex = 0x44e992b44a6909f1
{-# INLINABLE parameterHex #-}

-- BN254 curve is pairing-friendly.
instance Pairing BN254 where

  type instance G1 BN254 = G1'

  type instance G2 BN254 = G2'

  type instance GT BN254 = GT'

  pairing = (.) (finalExponentiationBN parameterHex)
             .    millerAlgorithmBN xi parameterBin
  {-# INLINABLE pairing #-}

-------------------------------------------------------------------------------
-- Roots of unity
-------------------------------------------------------------------------------

-- | Precompute primitive roots of unity for binary powers that divide @r - 1@.
getRootOfUnity :: Int -> Fr
getRootOfUnity 0  = 1
getRootOfUnity 1  = 21888242871839275222246405745257275088548364400416034343698204186575808495616
getRootOfUnity 2  = 21888242871839275217838484774961031246007050428528088939761107053157389710902
getRootOfUnity 3  = 19540430494807482326159819597004422086093766032135589407132600596362845576832
getRootOfUnity 4  = 14940766826517323942636479241147756311199852622225275649687664389641784935947
getRootOfUnity 5  = 4419234939496763621076330863786513495701855246241724391626358375488475697872
getRootOfUnity 6  = 9088801421649573101014283686030284801466796108869023335878462724291607593530
getRootOfUnity 7  = 10359452186428527605436343203440067497552205259388878191021578220384701716497
getRootOfUnity 8  = 3478517300119284901893091970156912948790432420133812234316178878452092729974
getRootOfUnity 9  = 6837567842312086091520287814181175430087169027974246751610506942214842701774
getRootOfUnity 10 = 3161067157621608152362653341354432744960400845131437947728257924963983317266
getRootOfUnity 11 = 1120550406532664055539694724667294622065367841900378087843176726913374367458
getRootOfUnity 12 = 4158865282786404163413953114870269622875596290766033564087307867933865333818
getRootOfUnity 13 = 197302210312744933010843010704445784068657690384188106020011018676818793232
getRootOfUnity 14 = 20619701001583904760601357484951574588621083236087856586626117568842480512645
getRootOfUnity 15 = 20402931748843538985151001264530049874871572933694634836567070693966133783803
getRootOfUnity 16 = 421743594562400382753388642386256516545992082196004333756405989743524594615
getRootOfUnity 17 = 12650941915662020058015862023665998998969191525479888727406889100124684769509
getRootOfUnity 18 = 11699596668367776675346610687704220591435078791727316319397053191800576917728
getRootOfUnity 19 = 15549849457946371566896172786938980432421851627449396898353380550861104573629
getRootOfUnity 20 = 17220337697351015657950521176323262483320249231368149235373741788599650842711
getRootOfUnity 21 = 13536764371732269273912573961853310557438878140379554347802702086337840854307
getRootOfUnity 22 = 12143866164239048021030917283424216263377309185099704096317235600302831912062
getRootOfUnity 23 = 934650972362265999028062457054462628285482693704334323590406443310927365533
getRootOfUnity 24 = 5709868443893258075976348696661355716898495876243883251619397131511003808859
getRootOfUnity 25 = 19200870435978225707111062059747084165650991997241425080699860725083300967194
getRootOfUnity 26 = 7419588552507395652481651088034484897579724952953562618697845598160172257810
getRootOfUnity 27 = 2082940218526944230311718225077035922214683169814847712455127909555749686340
getRootOfUnity 28 = 19103219067921713944291392827692070036145651957329286315305642004821462161904
getRootOfUnity _  = panic "getRootOfUnity: exponent too big for Fr / negative"
{-# INLINABLE getRootOfUnity #-}