module Data.Field.Galois.Frobenius
  ( frobenius
  ) where

import Protolude

import Data.Vector (Vector)

import Data.Field.Galois.Base (GaloisField(..))

-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------

-- | Frobenius endomorphism precomputation.
frobenius :: GaloisField k => Vector k -> Vector k -> Maybe (Vector k)
frobenius [ ] _ = Just []
frobenius [a] _ = Just [frob a]
frobenius [a, b] [x, 0, 1]
  | deg x == 2  = Just [a, negate b]
  | char x == 2 = Just [frob a - frob b * x]
  | otherwise   = Just [frob a, frob b * nxq]
  where
    nxq = negate x ^ shiftR (char x) 1
frobenius [a, b] [x, 0, 0, 1]
  | char x == 3 = Just [frob a - frob b * x]
  | r == 1      = Just [frob a, frob b * nxq]
  | otherwise   = Just [frob a, 0, frob b * nxq]
  where
    (q, r) = quotRem (char x) 3
    nxq    = negate x ^ q
frobenius [a, b, c] [x, 0, 0, 1]
  | char x == 3 = Just [frob a - (frob b - frob c * x) * x]
  | r == 1      = Just [frob a, frob b * nxq, frob c * nxq * nxq]
  | otherwise   = Just [frob a, frob c * nx * nxq * nxq, frob b * nxq]
  where
    (q, r) = quotRem (char x) 3
    nx     = negate x
    nxq    = nx ^ q
frobenius _ _   = Nothing
{-# INLINABLE frobenius #-}