packages feed

galois-field 0.2.1 → 0.3.0

raw patch · 14 files changed

+611/−468 lines, 14 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- BinaryField: instance Control.DeepSeq.NFData (BinaryField.BinaryField ib)
- BinaryField: instance GHC.Classes.Eq (BinaryField.BinaryField ib)
- BinaryField: instance GHC.Generics.Generic (BinaryField.BinaryField ib)
- BinaryField: instance GHC.Show.Show (BinaryField.BinaryField ib)
- BinaryField: instance GHC.TypeNats.KnownNat ib => GHC.Num.Num (BinaryField.BinaryField ib)
- BinaryField: instance GHC.TypeNats.KnownNat ib => GHC.Real.Fractional (BinaryField.BinaryField ib)
- BinaryField: instance GHC.TypeNats.KnownNat ib => GaloisField.GaloisField (BinaryField.BinaryField ib)
- BinaryField: instance GHC.TypeNats.KnownNat ib => System.Random.Random (BinaryField.BinaryField ib)
- BinaryField: instance GHC.TypeNats.KnownNat ib => Test.QuickCheck.Arbitrary.Arbitrary (BinaryField.BinaryField ib)
- BinaryField: instance GHC.TypeNats.KnownNat ib => Text.PrettyPrint.Leijen.Text.Pretty (BinaryField.BinaryField ib)
+ BinaryField: instance Control.DeepSeq.NFData (BinaryField.BinaryField im)
+ BinaryField: instance GHC.Classes.Eq (BinaryField.BinaryField im)
+ BinaryField: instance GHC.Generics.Generic (BinaryField.BinaryField im)
+ BinaryField: instance GHC.Read.Read (BinaryField.BinaryField im)
+ BinaryField: instance GHC.Show.Show (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => GHC.Num.Num (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => GHC.Real.Fractional (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => GaloisField.GaloisField (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => System.Random.Random (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => Test.QuickCheck.Arbitrary.Arbitrary (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => Text.PrettyPrint.Leijen.Text.Pretty (BinaryField.BinaryField im)
+ ExtensionField: instance Control.DeepSeq.NFData k => Control.DeepSeq.NFData (ExtensionField.Polynomial k)
+ ExtensionField: instance GHC.Classes.Eq k => GHC.Classes.Eq (ExtensionField.Polynomial k)
+ ExtensionField: instance GHC.Generics.Generic (ExtensionField.Polynomial k)
+ ExtensionField: instance GHC.Read.Read k => GHC.Read.Read (ExtensionField.ExtensionField k im)
+ ExtensionField: instance GHC.Read.Read k => GHC.Read.Read (ExtensionField.Polynomial k)
+ ExtensionField: instance GHC.Show.Show k => GHC.Show.Show (ExtensionField.Polynomial k)
+ ExtensionField: instance GaloisField.GaloisField k => GHC.Num.Num (ExtensionField.Polynomial k)
+ GaloisField: quad :: GaloisField k => k -> k -> k -> Maybe k
+ GaloisField: sr :: GaloisField k => k -> Maybe k
+ PrimeField: instance GHC.Read.Read (PrimeField.PrimeField p)
- BinaryField: data BinaryField (ib :: Nat)
+ BinaryField: data BinaryField (im :: Nat)
- GaloisField: class (Arbitrary k, Eq k, Fractional k, Pretty k, Random k, Show k) => GaloisField k
+ GaloisField: class (Arbitrary k, Eq k, Fractional k, Pretty k, Random k, Read k, Show k) => GaloisField k

Files

ChangeLog.md view
@@ -1,22 +1,30 @@ # Change log for galois-field +## 0.3.0++* Add complete implementation of binary fields.+* Add `quad` function for prime fields.+* Add `sr` function for prime fields.+ ## 0.2.1-* Add preliminary implementation of BinaryField.-* Add `frob` function for GaloisField.++* Add preliminary implementation of binary fields.+* Add `frob` function for Galois fields. * Add minor improvements to documentation.  ## 0.2.0 -* Add `deg` function for GaloisField.-* Add `order` function for GaloisField.-* Add `pow` function for GaloisField.-* Add `rnd` function for GaloisField.+* Add `deg` function for Galois fields.+* Add `order` function for Galois fields.+* Add `pow` function for Galois fields.+* Add `rnd` function for Galois fields.+* Add `Random` instances for Galois fields.  ## 0.1.1 -* Add `Arbitrary` instances to PrimeField, PolynomialRing, and ExtensionField.-* Add `Bits` instances to PrimeField.-* Add `Pretty` instances to PrimeField, PolynomialRing, and ExtensionField.+* Add `Arbitrary` instances for Galois fields.+* Add `Bits` instances for prime fields.+* Add `Pretty` instances for Galois fields. * Add minor optimisations to multiplication and inversion with `INLINE`.  ## 0.1.0
README.md view
@@ -4,7 +4,6 @@   </a> </p> - [![CircleCI](https://circleci.com/gh/adjoint-io/galois-field.svg?style=svg)](https://circleci.com/gh/adjoint-io/galois-field) [![Hackage](https://img.shields.io/hackage/v/galois-field.svg)](https://hackage.haskell.org/package/galois-field) @@ -32,6 +31,12 @@  For example, GF(4) has order 2^2 and can be constructed as an extension field GF(2)[X] / \<f(X)\> where f(X) = X^2 + X + 1 is an irreducible monic splitting quadratic polynomial in GF(2)[X]. +### Binary fields++A Galois field of the form GF(2^m) for big positive m is a sum of x^n for a non-empty set of 0 \< n \< m. For computational efficiency in cryptography, an element of a **binary field** can be represented by an integer that represents a bit string.++For example, X^8 + X^4 + X^3 + X + 1 can be represented as the integer 283 that represents the bit string 100011011.+ ## Example usage  Include the following required language extensions.@@ -173,6 +178,26 @@ ```haskell fromList [ fromList [fromList [a, b], fromList [c, d], fromList [e, f]]          , fromList [fromList [g, h], fromList [i, j], fromList [k, l]] ] :: Fq12+```++### Binary fields++The following type declaration creates a binary field modulo a given splitting irreducible binary polynomial.+```haskell+type F2m = BinaryField 0x80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425+```+Note that the splitting polynomial given *must* be irreducible in F2.++Galois field arithmetic can then be performed in this binary field.+```haskell+f2m :: F2m+f2m = 0x303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19++f2m' :: F2m+f2m' = 0x37bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b++arithmeticF2m :: (F2m, F2m, F2m, F2m)+arithmeticF2m = (f2m + f2m', f2m - f2m', f2m * f2m', f2m / f2m') ```  ## License
benchmarks/Main.hs view
@@ -2,8 +2,11 @@  import Protolude +import BinaryField import Criterion.Main import ExtensionField+import GaloisField+import GHC.Base import PrimeField  type Fq = PrimeField 21888242871839275222246405745257275088696311157297823662689037894645226208583@@ -19,55 +22,11 @@   split _ = x ^ (2 :: Int) + 1 type Fq2 = ExtensionField Fq Pu -fq2 :: Fq2-fq2 = fromList-  [ 19908898611787582971615951530393785823319364696376311494770162270472288380562-  , 2444690988583914246674870181013910409542697083717824402984851238236041783759-  ]--fq2' :: Fq2-fq2' = fromList-  [ 176307305890807650390915550856467756101144733976249050387177647283239486934-  , 9913547941088878400547309488585076816688958962210000330808066250849942240036-  ]- data Pv instance IrreducibleMonic Fq2 Pv where-  split _ = x ^ (3 :: Int) - (9 + t x)+  split _ = x ^ (3 :: Int) - 9 - t x type Fq6 = ExtensionField Fq2 Pv -fq6 :: Fq6-fq6 = fromList-  [ fromList-    [ 8727269669017421992537561450387212506711577304101544328736696625792447584819-    , 14548604791762199086915107662335514800873255588931510951007415299299859294564-    ]-  , fromList-    [ 12226353852518517213098257637254082040554292743096797524265221809863992104040-    , 12690801089710533803594523982915673248220237967492611523932652691226365708512-    ]-  , fromList-    [ 18336930404004840796680535059992401039831316705513753839479258873269709495858-    , 21634580953983557175729336703450663797341055784728343534694506874757389871868-    ]-  ]--fq6' :: Fq6-fq6' = fromList-  [ fromList-    [ 21427158918811764040959407626476119248515601360702754918240300689672054041331-    , 12750457256357562507331331307761996193149796736574153338180573114576232473092-    ]-  , fromList-    [ 19307896751125425658868292427117755307914453765471505616446813557567103424424-    , 11511704315039881938763578963465960361806962511008317843374696569679546862720-    ]-  , fromList-    [ 16856354813335682789816416666746807604324955216244680818919639213184967817815-    , 10563739714379631354612735346769824530666877338817980746884577737330686430079-    ]-  ]- data Pw instance IrreducibleMonic Fq6 Pw where   split _ = x ^ (2 :: Int) - t x@@ -137,66 +96,33 @@     ]   ] +type F2m = BinaryField 0x80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425++f2m :: F2m+f2m = 0x303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19++f2m' :: F2m+f2m' = 0x37bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b++benchmark :: GaloisField k => String -> k -> k -> Benchmark+benchmark s a b = bgroup s+  [ bench "Addition" $+    whnf (uncurry (+)) (a, b)+  , bench "Multiplication" $+    whnf (uncurry (*)) (a, b)+  , bench "Negation" $+    whnf negate a+  , bench "Subtraction" $+    whnf (uncurry (-)) (a, b)+  , bench "Inversion" $+    whnf recip a+  , bench "Division" $+    whnf (uncurry (/)) (a, b)+  ]+ main :: IO () main = defaultMain-  [ bgroup "PrimeField"-    [ bgroup "Fq"-      [ bench "Addition"-        $ whnf (uncurry (+)) (fq, fq')-      , bench "Multiplication"-        $ whnf (uncurry (*)) (fq, fq')-      , bench "Negation"-        $ whnf negate fq-      , bench "Subtraction"-        $ whnf (uncurry (-)) (fq, fq')-      , bench "Inversion"-        $ whnf recip fq-      , bench "Division"-        $ whnf (uncurry (/)) (fq, fq')-      ]-    ]-  , bgroup "ExtensionField"-    [ bgroup "Fq2"-      [ bench "Addition"-        $ whnf (uncurry (+)) (fq2, fq2')-      , bench "Multiplication"-        $ whnf (uncurry (*)) (fq2, fq2')-      , bench "Negation"-        $ whnf negate fq2-      , bench "Subtraction"-        $ whnf (uncurry (-)) (fq2, fq2')-      , bench "Inversion"-        $ whnf recip fq2-      , bench "Division"-        $ whnf (uncurry (/)) (fq2, fq2')-      ]-    , bgroup "Fq6"-      [ bench "Addition"-        $ whnf (uncurry (+)) (fq6, fq6')-      , bench "Multiplication"-        $ whnf (uncurry (*)) (fq6, fq6')-      , bench "Negation"-        $ whnf negate fq6-      , bench "Subtraction"-        $ whnf (uncurry (-)) (fq6, fq6')-      , bench "Inversion"-        $ whnf recip fq6-      , bench "Division"-        $ whnf (uncurry (/)) (fq6, fq6')-      ]-    , bgroup "Fq12"-      [ bench "Addition"-        $ whnf (uncurry (+)) (fq12, fq12')-      , bench "Multiplication"-        $ whnf (uncurry (*)) (fq12, fq12')-      , bench "Negation"-        $ whnf negate fq12-      , bench "Subtraction"-        $ whnf (uncurry (-)) (fq12, fq12')-      , bench "Inversion"-        $ whnf recip fq12-      , bench "Division"-        $ whnf (uncurry (/)) (fq12, fq12')-      ]-    ]+  [ benchmark "PrimeField Fq" fq fq'+  , benchmark "ExtensionField Fq12" fq12 fq12'+  , benchmark "BinaryField F2m" f2m f2m'   ]
galois-field.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: c0b59111dcbf4f45abd61925f0a42fbe4a93dce27b89db73519e0e36afc5e8a8+-- hash: 094ec398fd4d7e6719c2a9ba616c6ca5e682b6d55f80d89d64a037adb94e845e  name:           galois-field-version:        0.2.1+version:        0.3.0 synopsis:       Galois field library description:    An efficient implementation of Galois fields used in cryptography research category:       Cryptography@@ -31,7 +31,7 @@       GaloisField       PrimeField   other-modules:-      PolynomialRing+      Paths_galois_field   hs-source-dirs:       src   default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances FlexibleContexts ScopedTypeVariables RankNTypes DataKinds DeriveGeneric GeneralizedNewtypeDeriving KindSignatures MultiParamTypeClasses@@ -49,13 +49,13 @@   type: exitcode-stdio-1.0   main-is: Main.hs   other-modules:+      BinaryFieldTests       ExtensionFieldTests       GaloisFieldTests       PrimeFieldTests       BinaryField       ExtensionField       GaloisField-      PolynomialRing       PrimeField       Paths_galois_field   hs-source-dirs:@@ -80,7 +80,6 @@       BinaryField       ExtensionField       GaloisField-      PolynomialRing       PrimeField       Paths_galois_field   hs-source-dirs:
src/BinaryField.hs view
@@ -10,99 +10,157 @@  import GaloisField (GaloisField(..)) +-------------------------------------------------------------------------------+-- Binary field type+-------------------------------------------------------------------------------+ -- | Binary fields @GF(2^q)[X]/\<f(X)\>@ for @q@ positive and -- @f(X)@ irreducible monic in @GF(2^q)[X]@ encoded as an integer.-newtype BinaryField (ib :: Nat) = BF Integer-  deriving (Eq, Generic, NFData, Show)---- Binary fields are arbitrary.-instance KnownNat ib => Arbitrary (BinaryField ib) where-  arbitrary = BF <$> choose (0, 2 ^ natVal (witness :: BinaryField ib) - 1)---- Binary fields are fields.-instance KnownNat ib => Fractional (BinaryField ib) where-  recip y@(BF x)      = case inv (natVal y) x of-    Just z -> BF z-    _      -> panic "no multiplicative inverse."-  {-# INLINE recip #-}-  fromRational (x:%y) = fromInteger x / fromInteger y-  {-# INLINABLE fromRational #-}+newtype BinaryField (im :: Nat) = BF Integer+  deriving (Eq, Generic, NFData, Read, Show)  -- Binary fields are Galois fields.-instance KnownNat ib => GaloisField (BinaryField ib) where-  char = const 2+instance KnownNat im => GaloisField (BinaryField im) where+  char          = const 2   {-# INLINE char #-}-  deg  = bin . natVal+  deg           = binLog . natVal   {-# INLINE deg #-}-  frob = flip pow 2+  frob          = flip pow 2   {-# INLINE frob #-}-  pow  = (^)+  pow w@(BF y) n+    | n < 0     = pow (recip w) (-n)+    | otherwise = BF (pow' 1 y n)+    where+      mul = (.) (binMod (natVal w)) . binMul+      pow' ws zs m+        | m == 0    = ws+        | m == 1    = mul ws zs+        | even m    = pow' ws (mul zs zs) (div m 2)+        | otherwise = pow' (mul ws zs) (mul zs zs) (div m 2)   {-# INLINE pow #-}-  rnd  = getRandom+  quad a b c+    | b == 0    = sr c+    | otherwise = (* (b / a)) <$> binQuad (a * c / (b * b))+  {-# INLINE quad #-}+  rnd           = getRandom   {-# INLINE rnd #-}+  sr            = panic "not implemented."+  {-# INLINE sr #-} +-------------------------------------------------------------------------------+-- Binary field instances+-------------------------------------------------------------------------------++-- Binary fields are arbitrary.+instance KnownNat im => Arbitrary (BinaryField im) where+  arbitrary = BF <$> choose (0, order (witness :: BinaryField im) - 1)+ -- Binary fields are fields.-instance KnownNat ib => Num (BinaryField ib) where+instance KnownNat im => Fractional (BinaryField im) where+  recip w@(BF x)      = BF (binInv x (natVal w))+  {-# INLINE recip #-}+  fromRational (x:%y) = fromInteger x / fromInteger y+  {-# INLINABLE fromRational #-}++-- Binary fields are rings.+instance KnownNat im => Num (BinaryField im) where   BF x + BF y = BF (xor x y)   {-# INLINE (+) #-}-  BF x * BF y = fromInteger (mul x y)+  BF x * BF y = fromInteger (binMul x y)   {-# INLINE (*) #-}   BF x - BF y = BF (xor x y)   {-# INLINE (-) #-}   negate      = identity   {-# INLINE negate #-}-  fromInteger = BF . red (natVal (witness :: BinaryField ib))+  fromInteger = BF . binMod (natVal (witness :: BinaryField im))   {-# INLINABLE fromInteger #-}   abs         = panic "not implemented."   signum      = panic "not implemented."  -- Binary fields are pretty.-instance KnownNat ib => Pretty (BinaryField ib) where+instance KnownNat im => Pretty (BinaryField im) where   pretty (BF x) = pretty x  -- Binary fields are random.-instance KnownNat ib => Random (BinaryField ib) where-  random  = first BF . randomR (0, 2 ^ natVal (witness :: BinaryField ib) - 1)+instance KnownNat im => Random (BinaryField im) where+  random  = first BF . randomR (0, order (witness :: BinaryField im) - 1)+  {-# INLINE random #-}   randomR = panic "not implemented." +-------------------------------------------------------------------------------+-- Binary field arithmetic+-------------------------------------------------------------------------------+ -- Binary logarithm.-bin :: Integer -> Int-bin = logP 2+binLog :: Integer -> Int+binLog = binLog' 2   where-    logP :: Integer -> Integer -> Int-    logP p x = let l = 2 * logP (p * p) x-               in if x < p then 0 else log' l (quot x (p ^ l))+    binLog' :: Integer -> Integer -> Int+    binLog' p x+      | x < p     = 0+      | otherwise = case binLog' (p * p) x of+        l -> let l' = 2 * l in binLog'' (quot x (p ^ l')) l'       where-        log' :: Int -> Integer -> Int-        log' q y = if y < p then q else log' (q + 1) (quot y p)-{-# INLINE bin #-}+        binLog'' :: Integer -> Int -> Int+        binLog'' y n+          | y < p     = n+          | otherwise = binLog'' (quot y p) (n + 1)+{-# INLINE binLog #-}  -- Binary multiplication.-mul :: Integer -> Integer -> Integer-mul x y = mul' (bin y) (if testBit y 0 then x else 0)+binMul :: Integer -> Integer -> Integer+binMul = binMul' 0   where-    mul' :: Int -> Integer -> Integer-    mul' 0 n = n-    mul' l n = mul' (l - 1) (if testBit y l then xor n (shift x l) else n)-{-# INLINE mul #-}+    binMul' :: Integer -> Integer -> Integer -> Integer+    binMul' n x y+      | y == 0      = n+      | testBit y 0 = binMul' (xor n x) x' y'+      | otherwise   = binMul' n x' y'+      where+        x' = shiftL x 1 :: Integer+        y' = shiftR y 1 :: Integer+{-# INLINE binMul #-} --- Binary reduction.-red :: Integer -> Integer -> Integer-red f = red'+-- Binary modulus.+binMod :: Integer -> Integer -> Integer+binMod f = binMod'   where-    red' :: Integer -> Integer-    red' x = let n = bin x - bin f-             in if n < 0 then x else red' (xor x (shift f n))-{-# INLINE red #-}+    m = binLog f :: Int+    binMod' :: Integer -> Integer+    binMod' x+      | n < 0     = x+      | otherwise = binMod' (xor x (shiftL f n))+      where+        n = binLog x - m :: Int+{-# INLINE binMod #-}  -- Binary inversion.-inv :: Integer -> Integer -> Maybe Integer-inv f x = case inv' 1 x 0 f of-  (y, 1) -> Just y-  _      -> Nothing+binInv :: Integer -> Integer -> Integer+binInv f x = case binInv' 0 1 x f of+  (y, 1) -> y+  _      -> panic "no multiplicative inverse."   where-    inv' :: Integer -> Integer -> Integer -> Integer -> (Integer, Integer)-    inv' t r _  0  = (t, r)-    inv' t r t' r' = let q = max 0 (bin r - bin r')-                     in inv' t' r' (xor t (shift t' q)) (xor r (shift r' q))-{-# INLINE inv #-}+    binInv' :: Integer -> Integer -> Integer -> Integer -> (Integer, Integer)+    binInv' s s' r r'+      | r' == 0   = (s, r)+      | otherwise = binInv' s' (xor s (shift s' q)) r' (xor r (shift r' q))+      where+        q = max 0 (binLog r - binLog r') :: Int+{-# INLINE binInv #-}++-------------------------------------------------------------------------------+-- Binary field quadratics+-------------------------------------------------------------------------------++-- Binary quadratic @y^2+y+x=0@.+binQuad :: forall im . KnownNat im+  => BinaryField im -> Maybe (BinaryField im)+binQuad x+  | sum xs /= 0 = Nothing+  | odd m       = Just (sum h)+  | otherwise   = panic "not implemented."+  where+    m  = deg x :: Int+    xs = take m (iterate (^ (2 :: Int)) x) :: [BinaryField im]+    h  = zipWith ($) (cycle [identity, const 0]) xs :: [BinaryField im]+{-# INLINE binQuad #-}
src/ExtensionField.hs view
@@ -1,6 +1,6 @@ module ExtensionField   ( ExtensionField-  , IrreducibleMonic(..)+  , IrreducibleMonic(split)   , fromField   , fromList   , t@@ -14,108 +14,86 @@ import Text.PrettyPrint.Leijen.Text (Pretty(..))  import GaloisField (GaloisField(..))-import PolynomialRing (Polynomial(..), cut, polyInv, polyMul, polyQR) +-------------------------------------------------------------------------------+-- Extension field type+-------------------------------------------------------------------------------+ -- | Extension fields @GF(p^q)[X]/\<f(X)\>@ for @p@ prime, @q@ positive, and -- @f(X)@ irreducible monic in @GF(p^q)[X]@. newtype ExtensionField k im = EF (Polynomial k)-  deriving (Eq, Generic, NFData, Show)+  deriving (Eq, Generic, NFData, Read, Show)  -- | Irreducible monic splitting polynomial @f(X)@ of extension field. class IrreducibleMonic k im where   {-# MINIMAL split #-}   -- | Splitting polynomial @f(X)@.   split :: ExtensionField k im -> Polynomial k---- Extension fields are arbitrary.-instance (Arbitrary k, GaloisField k, IrreducibleMonic k im)-  => Arbitrary (ExtensionField k im) where-  arbitrary = fromList <$> vector (length xs - 1)-    where-      X xs = split (witness :: ExtensionField k im)---- Extension fields are fields.-instance (GaloisField k, IrreducibleMonic k im)-  => Fractional (ExtensionField k im) where-  recip y@(EF (X ys)) = case polyInv ys xs of-    Just zs -> EF (X zs)-    _       -> panic "no multiplicative inverse."-    where-      X xs = split y-  {-# INLINE recip #-}-  fromRational (y:%z) = fromInteger y / fromInteger z-  {-# INLINABLE fromRational #-}+  -- | Splitting polynomial list.+  plist :: ExtensionField k im -> [k]+  plist = (\(X xs) -> xs) . split  -- Extension fields are Galois fields. instance (GaloisField k, IrreducibleMonic k im)   => GaloisField (ExtensionField k im) where   char          = const (char (witness :: k))   {-# INLINE char #-}-  deg y         = deg (witness :: k) * (length xs - 1)-    where-      X xs = split y+  deg w         = deg (witness :: k) * (length (plist w) - 1)   {-# INLINE deg #-}   frob          = pow <*> char   {-# INLINE frob #-}-  pow y@(EF (X ys)) n-    | n < 0     = pow (recip y) (-n)-    | otherwise = EF (X (pow' [1] ys n))+  pow w@(EF (X y)) n+    | n < 0     = pow (recip w) (-n)+    | otherwise = EF (X (pow' [1] y n))     where-      X xs = split y-      mul = (.) (snd . flip polyQR xs) . polyMul+      mul = (.) (snd . flip polyQR (plist w)) . polyMul       pow' ws zs m         | m == 0    = ws         | m == 1    = mul ws zs         | even m    = pow' ws (mul zs zs) (div m 2)         | otherwise = pow' (mul ws zs) (mul zs zs) (div m 2)   {-# INLINE pow #-}+  quad          = panic "not implemented."+  {-# INLINE quad #-}   rnd           = getRandom   {-# INLINE rnd #-}+  sr            = panic "not implemented."+  {-# INLINE sr #-} --- Extension fields are rings.-instance (GaloisField k, IrreducibleMonic k im)-  => Num (ExtensionField k im) where-  EF y + EF z               = EF (y + z)+-------------------------------------------------------------------------------+-- Extension field conversions+-------------------------------------------------------------------------------++-- Polynomial rings.+newtype Polynomial k = X [k]+  deriving (Eq, Generic, NFData, Read, Show)++-- Polynomial rings are rings.+instance GaloisField k => Num (Polynomial k) where+  X y + X z     = X (polyAdd y z)   {-# INLINE (+) #-}-  y@(EF (X ys)) * EF (X zs) = EF (X (snd (polyQR (polyMul ys zs) xs)))-    where-      X xs = split y+  X y * X z     = X (polyMul y z)   {-# INLINE (*) #-}-  EF y - EF z               = EF (y - z)+  X y - X z     = X (polySub y z)   {-# INLINE (-) #-}-  negate (EF y)             = EF (-y)+  negate (X y)  = X (map negate y)   {-# INLINE negate #-}-  fromInteger               = EF . fromInteger+  fromInteger n = X (let m = fromInteger n in if m == 0 then [] else [m])   {-# INLINABLE fromInteger #-}-  abs                       = panic "not implemented."-  signum                    = panic "not implemented."---- Extension fields are pretty.-instance (GaloisField k, IrreducibleMonic k im)-  => Pretty (ExtensionField k im) where-  pretty (EF y) = pretty y---- Extension fields are random.-instance (GaloisField k, IrreducibleMonic k im)-  => Random (ExtensionField k im) where-  random  = first (EF . X . cut) . unfold (length xs - 1) []-    where-      X xs = split (witness :: ExtensionField k im)-      unfold n ys g = if n <= 0 then (ys, g) else-        let (y, g') = random g in unfold (n - 1) (y : ys) g'-  randomR = panic "not implemented."+  abs           = panic "not implemented."+  signum        = panic "not implemented."  -- | Convert from field element to list representation. fromField :: ExtensionField k im -> [k]-fromField (EF (X xs)) = xs+fromField (EF (X y)) = y {-# INLINABLE fromField #-}  -- | Convert from list representation to field element. fromList :: forall k im . (GaloisField k, IrreducibleMonic k im)   => [k] -> ExtensionField k im-fromList = EF . X . snd . flip polyQR xs . cut+fromList = EF . X . snd . flip polyQR (plist w) . dropZero   where-    X xs = split (witness :: ExtensionField k im)+    w = witness :: ExtensionField k im {-# INLINABLE fromList #-}  -- | Descend tower of indeterminate variables.@@ -127,3 +105,126 @@ x :: GaloisField k => Polynomial k x = X [0, 1] {-# INLINE x #-}++-------------------------------------------------------------------------------+-- Extension field instances+-------------------------------------------------------------------------------++-- Extension fields are arbitrary.+instance (Arbitrary k, GaloisField k, IrreducibleMonic k im)+  => Arbitrary (ExtensionField k im) where+  arbitrary = fromList <$>+    vector (length (plist (witness :: ExtensionField k im)) - 1)++-- Extension fields are fields.+instance (GaloisField k, IrreducibleMonic k im)+  => Fractional (ExtensionField k im) where+  recip w@(EF (X y))  = EF (X (polyInv y (plist w)))+  {-# INLINE recip #-}+  fromRational (y:%z) = fromInteger y / fromInteger z+  {-# INLINABLE fromRational #-}++-- Extension fields are rings.+instance (GaloisField k, IrreducibleMonic k im)+  => Num (ExtensionField k im) where+  EF y + EF z             = EF (y + z)+  {-# INLINE (+) #-}+  w@(EF (X y)) * EF (X z) = EF (X (snd (polyQR (polyMul y z) (plist w))))+  {-# INLINE (*) #-}+  EF y - EF z             = EF (y - z)+  {-# INLINE (-) #-}+  negate (EF y)           = EF (-y)+  {-# INLINE negate #-}+  fromInteger             = EF . fromInteger+  {-# INLINABLE fromInteger #-}+  abs                     = panic "not implemented."+  signum                  = panic "not implemented."++-- Extension fields are pretty.+instance (GaloisField k, IrreducibleMonic k im)+  => Pretty (ExtensionField k im) where+  pretty (EF (X y)) = pretty y++-- Extension fields are random.+instance (GaloisField k, IrreducibleMonic k im)+  => Random (ExtensionField k im) where+  random  = first (EF . X . dropZero) . unfold (length (plist w) - 1) []+    where+      w = witness :: ExtensionField k im+      unfold n ys g+        | n <= 0    = (ys, g)+        | otherwise = case random g of+          (y, g') -> unfold (n - 1) (y : ys) g'+  {-# INLINE random #-}+  randomR = panic "not implemented."++-------------------------------------------------------------------------------+-- Extension field arithmetic+-------------------------------------------------------------------------------++-- Polynomial drop zeroes.+dropZero :: GaloisField k => [k] -> [k]+dropZero = reverse . dropWhile (== 0) . reverse+{-# INLINABLE dropZero #-}++-- Polynomial addition.+polyAdd :: GaloisField k => [k] -> [k] -> [k]+polyAdd ys     []     = ys+polyAdd []     zs     = zs+polyAdd (y:ys) (z:zs) = let w  = y + z+                            ws = polyAdd ys zs+                        in if w == 0 && null ws then [] else w : ws+{-# INLINE polyAdd #-}++-- Polynomial multiplication.+polyMul :: GaloisField k => [k] -> [k] -> [k]+polyMul _      [] = []+polyMul []     _  = []+polyMul (y:ys) zs = let ws  = map (* y) zs+                        ws' = polyMul ys zs+                    in if null ys then ws else polyAdd ws (0 : ws')+{-# INLINE polyMul #-}++-- Polynomial subtraction.+polySub :: GaloisField k => [k] -> [k] -> [k]+polySub ys     []     = ys+polySub []     zs     = map negate zs+polySub (y:ys) (z:zs) = let w  = y - z+                            ws = polySub ys zs+                        in if w == 0 && null ws then [] else w : ws+{-# INLINE polySub #-}++-- Polynomial quotient and remainder.+polyQR :: forall k . GaloisField k => [k] -> [k] -> ([k], [k])+polyQR ys zs = polyGCD ([], ys)+  where+    z = last zs :: k+    m = length zs :: Int+    last :: [k] -> k+    last []     = 0+    last [w]    = w+    last (_:ws) = last ws+    polyGCD :: ([k], [k]) -> ([k], [k])+    polyGCD qr@(qs, rs)+      | n < 0     = qr+      | otherwise = polyGCD (polyAdd qs ts, polySub rs (polyMul ts zs))+      where+        r = last rs :: k+        n = length rs - m :: Int+        ts = replicate n 0 ++ [r / z] :: [k]+{-# INLINE polyQR #-}++-- Polynomial inverse.+polyInv :: forall k . GaloisField k => [k] -> [k] -> [k]+polyInv [y] _ = [recip y]+polyInv ys zs = case extGCD (zs, ys) of+  ([w], (ws, _)) -> map (/ w) ws+  _              -> panic "no multiplicative inverse."+  where+    extGCD :: ([k], [k]) -> ([k], ([k], [k]))+    extGCD (y, []) = (y, ([], [1]))+    extGCD (y, z)  = (g, (polySub v (polyMul u q), u))+      where+        (q, r)      = polyQR y z+        (g, (u, v)) = extGCD (z, r)+{-# INLINE polyInv #-}
src/GaloisField.hs view
@@ -8,10 +8,14 @@ import Test.Tasty.QuickCheck (Arbitrary) import Text.PrettyPrint.Leijen.Text (Pretty) +-------------------------------------------------------------------------------+-- Galois field class+-------------------------------------------------------------------------------+ -- | Galois fields @GF(p^q)@ for @p@ prime and @q@ non-negative.-class (Arbitrary k, Eq k, Fractional k, Pretty k, Random k, Show k)+class (Arbitrary k, Eq k, Fractional k, Pretty k, Random k, Read k, Show k)   => GaloisField k where-  {-# MINIMAL char, deg, frob, pow, rnd #-}+  {-# MINIMAL char, deg, frob, pow, quad, rnd, sr #-}    -- Characteristics @@ -21,18 +25,24 @@   -- | Degree @q@ of field as extension field over prime subfield.   deg :: k -> Int -  -- | Frobenius endomorphism @x->x^p@ of prime subfield.-  frob :: k -> k-   -- | Order @p^q@ of field.   order :: k -> Integer   order = (^) <$> char <*> deg   {-# INLINE order #-} +  -- | Frobenius endomorphism @x->x^p@ of prime subfield.+  frob :: k -> k+   -- Functions -  -- | Exponentiation @x@ to the power of @y@.+  -- | Exponentiation of a field element to an integer.   pow :: k -> Integer -> k -  -- | Randomised element @x@ of field.+  -- | Solve quadratic @ax^2+bx+c=0@ over field.+  quad :: k -> k -> k -> Maybe k++  -- | Randomised field element.   rnd :: MonadRandom m => m k++  -- | Square root of a field element.+  sr :: k -> Maybe k
− src/PolynomialRing.hs
@@ -1,104 +0,0 @@-module PolynomialRing-  ( Polynomial(..)-  , cut-  , polyInv-  , polyMul-  , polyQR-  , toPoly-  ) where--import Protolude--import Test.Tasty.QuickCheck (Arbitrary(..))-import Text.PrettyPrint.Leijen.Text (Pretty(..))--import GaloisField (GaloisField(..))--newtype Polynomial k = X [k]-  deriving (Eq, Generic, NFData, Show)--instance (Arbitrary k, GaloisField k) => Arbitrary (Polynomial k) where-  arbitrary = toPoly <$> arbitrary--instance GaloisField k => Num (Polynomial k) where-  X xs + X ys   = X (polyAdd xs ys)-  {-# INLINE (+) #-}-  X xs * X ys   = X (polyMul xs ys)-  {-# INLINE (*) #-}-  X xs - X ys   = X (polySub xs ys)-  {-# INLINE (-) #-}-  negate (X xs) = X (map negate xs)-  {-# INLINE negate #-}-  fromInteger n = X (let m = fromInteger n in if m == 0 then [] else [m])-  {-# INLINABLE fromInteger #-}-  abs           = panic "not implemented."-  signum        = panic "not implemented."--instance GaloisField k => Pretty (Polynomial k) where-  pretty (X xs) = pretty xs--polyAdd :: GaloisField k => [k] -> [k] -> [k]-polyAdd xs     []     = xs-polyAdd []     ys     = ys-polyAdd (x:xs) (y:ys) = let z  = x + y-                            zs = polyAdd xs ys-                        in if z == 0 && null zs then [] else z : zs-{-# INLINE polyAdd #-}--polyMul :: GaloisField k => [k] -> [k] -> [k]-polyMul _      [] = []-polyMul []     _  = []-polyMul (x:xs) ys = let ws = map (* x) ys-                        zs = polyMul xs ys-                    in if null xs then ws else polyAdd ws (0 : zs)-{-# INLINE polyMul #-}--polySub :: GaloisField k => [k] -> [k] -> [k]-polySub xs     []     = xs-polySub []     ys     = map negate ys-polySub (x:xs) (y:ys) = let z  = x - y-                            zs = polySub xs ys-                        in if z == 0 && null zs then [] else z : zs-{-# INLINE polySub #-}--polyQR :: forall k . GaloisField k => [k] -> [k] -> ([k], [k])-polyQR xs ys = polyGCD ([], xs)-  where-    m :: Int-    m = length ys-    polyGCD :: ([k], [k]) -> ([k], [k])-    polyGCD qr@(qs, rs)-      | n < 0     = qr-      | otherwise = polyGCD (polyAdd qs ts, polySub rs (polyMul ts ys))-      where-        n :: Int-        n = length rs - m-        ts :: [k]-        ts = replicate n 0 ++ [last rs / last ys]-        last :: [k] -> k-        last []     = 0-        last [z]    = z-        last (_:zs) = last zs-{-# INLINE polyQR #-}--polyInv :: forall k . GaloisField k => [k] -> [k] -> Maybe [k]-polyInv [x] _ = Just [recip x]-polyInv xs ps = case extGCD (ps, xs) of-  ([y], (ys, _)) -> Just (map (/ y) ys)-  _              -> Nothing-  where-    extGCD :: ([k], [k]) -> ([k], ([k], [k]))-    extGCD (y, []) = (y, ([], [1]))-    extGCD (y, x)  = (g, (polySub t (polyMul s q), s))-      where-        (q, r)      = polyQR y x-        (g, (s, t)) = extGCD (x, r)-{-# INLINE polyInv #-}--cut :: GaloisField k => [k] -> [k]-cut = reverse . dropWhile (== 0) . reverse-{-# INLINABLE cut #-}--toPoly :: GaloisField k => [k] -> Polynomial k-toPoly = X . cut-{-# INLINABLE toPoly #-}
src/PrimeField.hs view
@@ -12,20 +12,13 @@  import GaloisField (GaloisField(..)) +-------------------------------------------------------------------------------+-- Prime field type+-------------------------------------------------------------------------------+ -- | Prime fields @GF(p)@ for @p@ prime. newtype PrimeField (p :: Nat) = PF Integer-  deriving (Bits, Eq, Generic, NFData, Show)---- Prime fields are arbitrary.-instance KnownNat p => Arbitrary (PrimeField p) where-  arbitrary = fromInteger <$> arbitrary---- Prime fields are fields.-instance KnownNat p => Fractional (PrimeField p) where-  recip y@(PF x)      = PF (recipModInteger x (natVal y))-  {-# INLINE recip #-}-  fromRational (x:%y) = fromInteger x / fromInteger y-  {-# INLINABLE fromRational #-}+  deriving (Bits, Eq, Generic, NFData, Read, Show)  -- Prime fields are Galois fields. instance KnownNat p => GaloisField (PrimeField p) where@@ -35,25 +28,55 @@   {-# INLINE deg #-}   frob           = identity   {-# INLINE frob #-}-  pow y@(PF x) n = PF (powModInteger x n (natVal y))+  pow w@(PF x) n = PF (powModInteger x n (natVal w))   {-# INLINE pow #-}+  quad           = primeQuad+  {-# INLINE quad #-}   rnd            = getRandom   {-# INLINE rnd #-}+  sr w@(PF x)    = let p = natVal w+                   in if p == 2 || x == 0 then Just w else PF <$> primeSqrt p x+  {-# INLINE sr #-} +-------------------------------------------------------------------------------+-- Prime field conversions+-------------------------------------------------------------------------------++-- | Embed field element to integers.+toInt :: PrimeField p -> Integer+toInt (PF x) = x+{-# INLINABLE toInt #-}++-------------------------------------------------------------------------------+-- Prime field instances+-------------------------------------------------------------------------------++-- Prime fields are arbitrary.+instance KnownNat p => Arbitrary (PrimeField p) where+  arbitrary = fromInteger <$> arbitrary++-- Prime fields are fields.+instance KnownNat p => Fractional (PrimeField p) where+  recip w@(PF x)      = PF (if x == 0 then panic "no multiplicative inverse."+                            else recipModInteger x (natVal w))+  {-# INLINE recip #-}+  fromRational (x:%y) = fromInteger x / fromInteger y+  {-# INLINABLE fromRational #-}+ -- Prime fields are rings. instance KnownNat p => Num (PrimeField p) where-  z@(PF x) + PF y = PF (if xyp >= 0 then xyp else xy)+  w@(PF x) + PF y = PF (if xyp >= 0 then xyp else xy)     where       xy  = x + y-      xyp = xy - natVal z+      xyp = xy - natVal w   {-# INLINE (+) #-}-  z@(PF x) * PF y = PF (rem (x * y) (natVal z))+  w@(PF x) * PF y = PF (rem (x * y) (natVal w))   {-# INLINE (*) #-}-  z@(PF x) - PF y = PF (if xy >= 0 then xy else xy + natVal z)+  w@(PF x) - PF y = PF (if xy >= 0 then xy else xy + natVal w)     where       xy = x - y   {-# INLINE (-) #-}-  negate y@(PF x) = PF (if x == 0 then 0 else -x + natVal y)+  negate w@(PF x) = PF (if x == 0 then 0 else -x + natVal w)   {-# INLINE negate #-}   fromInteger x   = PF (if y >= 0 then y else y + p)     where@@ -65,14 +88,76 @@  -- Prime fields are pretty. instance KnownNat p => Pretty (PrimeField p) where-  pretty (PF x) = pretty [x]+  pretty (PF x) = pretty x  -- Prime fields are random. instance KnownNat p => Random (PrimeField p) where   random  = first PF . randomR (0, natVal (witness :: PrimeField p) - 1)+  {-# INLINE random #-}   randomR = panic "not implemented." --- | Embed field element to integers.-toInt :: PrimeField p -> Integer-toInt (PF x) = x-{-# INLINABLE toInt #-}+-------------------------------------------------------------------------------+-- Prime field quadratics+-------------------------------------------------------------------------------++-- Check quadratic nonresidue.+isQNR :: Integer -> Integer -> Bool+isQNR p n = powModInteger n (shiftR (p - 1) 1) p /= 1+{-# INLINE isQNR #-}++-- Factor binary powers.+factor2 :: Integer -> (Integer, Int)+factor2 p = factor 0 (p - 1)+  where+    factor :: Int -> Integer -> (Integer, Int)+    factor s q+      | testBit q 0 = (q, s)+      | otherwise   = factor (s + 1) (shiftR q 1)+{-# INLINE factor2 #-}++-- Get quadratic nonresidue.+getQNR :: Integer -> Integer+getQNR p+  | p7 == 3 || p7 == 5 = 2+  | otherwise          = case find (isQNR p) ps of+    Just q -> q+    _      -> panic "no quadratic nonresidue."+  where+    p7 = p .&. 7+    ps = 3 : 5 : 7 : 11 : 13 : concatMap (\x -> [x - 1, x + 1]) [18, 24 ..]+{-# INLINE getQNR #-}++-- Prime square root.+primeSqrt :: Integer -> Integer -> Maybe Integer+primeSqrt p n+  | isQNR p n = Nothing+  | otherwise = min <*> (-) p <$> case (factor2 p, getQNR p) of+    ((q, s), z) -> let zq  = powModInteger z q p+                       nq  = powModInteger n (quot q 2) p+                       nnq = rem (n * nq) p+                   in loop s zq (rem (nq * nnq) p) nnq+      where+        loop :: Int -> Integer -> Integer -> Integer -> Maybe Integer+        loop m c t r+          | t == 0    = Just 0+          | t == 1    = Just r+          | otherwise = let i  = least t 0+                            b  = powModInteger c (bit (m - i - 1)) p+                            b2 = rem (b * b) p+                        in loop i b2 (rem (t * b2) p) (rem (r * b) p)+          where+            least :: Integer -> Int -> Int+            least 1  j = j+            least ti j = least (rem (ti * ti) p) (j + 1)+{-# INLINE primeSqrt #-}++-- Prime quadratic @ax^2+bx+c=0@.+primeQuad :: KnownNat p+  => PrimeField p -> PrimeField p -> PrimeField p -> Maybe (PrimeField p)+primeQuad a b c+  | a == 0    = Nothing+  | p == 2    = if c == 0 then Just 0 else if b == 0 then Just 1 else Nothing+  | otherwise = (/ (2 * a)) . subtract b <$> sr (b * b - 4 * a * c)+  where+    p = char a :: Integer+{-# INLINE primeQuad #-}
+ tests/BinaryFieldTests.hs view
@@ -0,0 +1,31 @@+module BinaryFieldTests where++import Protolude++import BinaryField+import Test.Tasty++import GaloisFieldTests++type F2A = BinaryField 0x20000000000000000000000000201+type F2B = BinaryField 0x80000000000000000000000000000010d+type F2C = BinaryField 0x800000000000000000000000000000000000000c9+type F2D = BinaryField 0x2000000000000000000000000000000000000000000008001+type F2E = BinaryField 0x20000000000000000000000000000000000000004000000000000000001+type F2F = BinaryField 0x800000000000000000004000000000000000000000000000000000000001+type F2G = BinaryField 0x800000000000000000000000000000000000000000000000000000000000000000010a1+type F2H = BinaryField 0x2000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001+type F2I = BinaryField 0x80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425++testBinaryField :: TestTree+testBinaryField = testGroup "Binary fields"+  [ testBF "F2A" (witness :: F2A)+  , testBF "F2B" (witness :: F2B)+  , testBF "F2C" (witness :: F2C)+  , testBF "F2D" (witness :: F2D)+  , testBF "F2E" (witness :: F2E)+  , testBF "F2F" (witness :: F2F)+  , testBF "F2G" (witness :: F2G)+  , testBF "F2H" (witness :: F2H)+  , testBF "F2I" (witness :: F2I)+  ]
tests/ExtensionFieldTests.hs view
@@ -3,73 +3,72 @@ import Protolude  import ExtensionField-import PolynomialRing import Test.Tasty  import GaloisFieldTests import PrimeFieldTests -data P11-instance IrreducibleMonic FS2 P11 where+data P111+instance IrreducibleMonic FS2 P111 where   split _ = x ^ (2 :: Int) + x + 1-type FS4 = ExtensionField FS2 P11+type FS4 = ExtensionField FS2 P111 -data P110-instance IrreducibleMonic FS2 P110 where+data P1101+instance IrreducibleMonic FS2 P1101 where   split _ = x ^ (3 :: Int) + x + 1-type FS8 = ExtensionField FS2 P110+type FS8 = ExtensionField FS2 P1101 -data P101-instance IrreducibleMonic FS2 P101 where+data P1011+instance IrreducibleMonic FS2 P1011 where   split _ = x ^ (3 :: Int) + x ^ (2 :: Int) + 1-type FS8' = ExtensionField FS2 P101+type FS8' = ExtensionField FS2 P1011 -data P10-instance IrreducibleMonic FS3 P10 where+data P101+instance IrreducibleMonic FS3 P101 where   split _ = x ^ (2 :: Int) + 1-type FS9 = ExtensionField FS3 P10+type FS9 = ExtensionField FS3 P101 -data P21-instance IrreducibleMonic FS3 P21 where+data P211+instance IrreducibleMonic FS3 P211 where   split _ = x ^ (2 :: Int) + x - 1-type FS9' = ExtensionField FS3 P21+type FS9' = ExtensionField FS3 P211 -data P22-instance IrreducibleMonic FS3 P22 where+data P221+instance IrreducibleMonic FS3 P221 where   split _ = x ^ (2 :: Int) - x - 1-type FS9'' = ExtensionField FS3 P22+type FS9'' = ExtensionField FS3 P221 -instance IrreducibleMonic FM0 P10 where+instance IrreducibleMonic FM0 P101 where   split _ = x ^ (2 :: Int) + 1-type FL0 = ExtensionField FM0 P10+type FL0 = ExtensionField FM0 P101 -instance IrreducibleMonic FM1 P10 where+instance IrreducibleMonic FM1 P101 where   split _ = x ^ (2 :: Int) + 1-type FL1 = ExtensionField FM1 P10+type FL1 = ExtensionField FM1 P101 -instance IrreducibleMonic FM2 P10 where+instance IrreducibleMonic FM2 P101 where   split _ = x ^ (2 :: Int) + 1-type FL2 = ExtensionField FM2 P10+type FL2 = ExtensionField FM2 P101 -instance IrreducibleMonic FM3 P10 where+instance IrreducibleMonic FM3 P101 where   split _ = x ^ (2 :: Int) + 1-type FL3 = ExtensionField FM3 P10+type FL3 = ExtensionField FM3 P101 -instance IrreducibleMonic FM4 P10 where+instance IrreducibleMonic FM4 P101 where   split _ = x ^ (2 :: Int) + 1-type FL4 = ExtensionField FM4 P10+type FL4 = ExtensionField FM4 P101 -instance IrreducibleMonic FVL P10 where+instance IrreducibleMonic FVL P101 where   split _ = x ^ (2 :: Int) + 1-type FV2 = ExtensionField FVL P10+type FV2 = ExtensionField FVL P101 -instance IrreducibleMonic FXL P10 where+instance IrreducibleMonic FXL P101 where   split _ = x ^ (2 :: Int) + 1-type FX2 = ExtensionField FXL P10+type FX2 = ExtensionField FXL P101 -instance IrreducibleMonic FZL P10 where+instance IrreducibleMonic FZL P101 where   split _ = x ^ (2 :: Int) + 1-type FZ2 = ExtensionField FZL P10+type FZ2 = ExtensionField FZL P101  data Pu instance IrreducibleMonic Fq Pu where@@ -78,7 +77,7 @@  data Pv instance IrreducibleMonic Fq2 Pv where-  split _ = x ^ (3 :: Int) - (9 + t x)+  split _ = x ^ (3 :: Int) - 9 - t x type Fq6 = ExtensionField Fq2 Pv  data Pw@@ -88,35 +87,21 @@  testExtensionField :: TestTree testExtensionField = testGroup "Extension fields"-  [ testGroup "Polynomial rings"-    [ ringAxioms "FS2[X]" (witness :: Polynomial FS2)-    , ringAxioms "FS3[X]" (witness :: Polynomial FS3)-    , ringAxioms "FS5[X]" (witness :: Polynomial FS5)-    , ringAxioms "FS7[X]" (witness :: Polynomial FS7)-    , ringAxioms "FM0[X]" (witness :: Polynomial FM0)-    , ringAxioms "FM1[X]" (witness :: Polynomial FM1)-    , ringAxioms "FM2[X]" (witness :: Polynomial FM2)-    , ringAxioms "FM3[X]" (witness :: Polynomial FM3)-    , ringAxioms "FM4[X]" (witness :: Polynomial FM4)-    , ringAxioms "FVL[X]" (witness :: Polynomial FVL)-    , ringAxioms "FXL[X]" (witness :: Polynomial FXL)-    , ringAxioms "FZL[X]" (witness :: Polynomial FZL)-    ]-  , fieldAxioms "FS4"   (witness :: FS4  )-  , fieldAxioms "FS8"   (witness :: FS8  )-  , fieldAxioms "FS8'"  (witness :: FS8' )-  , fieldAxioms "FS9"   (witness :: FS9  )-  , fieldAxioms "FS9'"  (witness :: FS9' )-  , fieldAxioms "FS9''" (witness :: FS9'')-  , fieldAxioms "FL0"   (witness :: FL0  )-  , fieldAxioms "FL1"   (witness :: FL1  )-  , fieldAxioms "FL2"   (witness :: FL2  )-  , fieldAxioms "FL3"   (witness :: FL3  )-  , fieldAxioms "FL4"   (witness :: FL4  )-  , fieldAxioms "FV2"   (witness :: FV2  )-  , fieldAxioms "FX2"   (witness :: FX2  )-  , fieldAxioms "FZ2"   (witness :: FZ2  )-  , fieldAxioms "Fq2"   (witness :: Fq2  )-  , fieldAxioms "Fq6"   (witness :: Fq6  )-  , fieldAxioms "Fq12"  (witness :: Fq12 )+  [ testEF "FS4"   (witness :: FS4  )+  , testEF "FS8"   (witness :: FS8  )+  , testEF "FS8'"  (witness :: FS8' )+  , testEF "FS9"   (witness :: FS9  )+  , testEF "FS9'"  (witness :: FS9' )+  , testEF "FS9''" (witness :: FS9'')+  , testEF "FL0"   (witness :: FL0  )+  , testEF "FL1"   (witness :: FL1  )+  , testEF "FL2"   (witness :: FL2  )+  , testEF "FL3"   (witness :: FL3  )+  , testEF "FL4"   (witness :: FL4  )+  , testEF "FV2"   (witness :: FV2  )+  , testEF "FX2"   (witness :: FX2  )+  , testEF "FZ2"   (witness :: FZ2  )+  , testEF "Fq2"   (witness :: Fq2  )+  , testEF "Fq6"   (witness :: Fq6  )+  , testEF "Fq12"  (witness :: Fq12 )   ]
tests/GaloisFieldTests.hs view
@@ -2,6 +2,7 @@  import Protolude +import GaloisField import Test.Tasty import Test.Tasty.QuickCheck @@ -21,31 +22,47 @@ inverses :: Eq a => (a -> a -> a) -> (a -> a) -> a -> a -> Bool inverses op inv e x = op x (inv x) == e && op (inv x) x == e -ringAxioms :: forall r . (Arbitrary r, Eq r, Num r, Show r)-  => TestName -> r -> TestTree-ringAxioms s _ = testGroup ("Ring axioms of " <> s)+fieldAxioms :: forall k . GaloisField k => k -> TestTree+fieldAxioms _ = testGroup ("Field axioms")   [ testProperty "commutativity of addition"-    $ commutativity ((+) :: r -> r -> r)+    $ commutativity ((+) :: k -> k -> k)   , testProperty "commutativity of multiplication"-    $ commutativity ((*) :: r -> r -> r)+    $ commutativity ((*) :: k -> k -> k)   , testProperty "associativity of addition"-    $ associativity ((+) :: r -> r -> r)+    $ associativity ((+) :: k -> k -> k)   , testProperty "associativity of multiplication"-    $ associativity ((*) :: r -> r -> r)+    $ associativity ((*) :: k -> k -> k)   , testProperty "distributivity of multiplication over addition"-    $ distributivity ((*) :: r -> r -> r) (+)+    $ distributivity ((*) :: k -> k -> k) (+)   , testProperty "additive identity"-    $ identities ((+) :: r -> r -> r) 0+    $ identities ((+) :: k -> k -> k) 0   , testProperty "multiplicative identity"-    $ identities ((*) :: r -> r -> r) 1+    $ identities ((*) :: k -> k -> k) 1   , testProperty "additive inverses"-    $ inverses ((+) :: r -> r -> r) negate 0+    $ inverses ((+) :: k -> k -> k) negate 0+  , testProperty "multiplicative inverses"+    $ \x -> x /= 0 ==> inverses ((*) :: k -> k -> k) recip 1 x   ] -fieldAxioms :: forall k . (Arbitrary k, Eq k, Fractional k, Show k)-  => TestName -> k -> TestTree-fieldAxioms s k = testGroup ("Field axioms of " <> s)-  [ ringAxioms s k-  , testProperty "multiplicative inverses"-    $ \n -> n /= 0 ==> inverses ((*) :: k -> k -> k) recip 1 n+squareRoots :: forall k . GaloisField k => k -> TestTree+squareRoots _ = testGroup "Square roots"+  [ testProperty "squares of square roots"+    $ \(x :: k) -> isJust (sr x)+      ==> (((^ (2 :: Int)) <$> sr x) == Just x)   ]++quadraticEquations :: forall k . GaloisField k => k -> TestTree+quadraticEquations _ = testGroup "Quadratic equations"+  [ testProperty "solutions of quadratic equations"+    $ \(a :: k) (b :: k) (c :: k) -> a /= 0 && b /= 0 && isJust (quad a b c)+      ==> (((\x -> a * x * x + b * x + c) <$> quad a b c) == Just 0)+  ]++test :: forall k . GaloisField k => TestName -> k -> TestTree+test s x = testGroup s [fieldAxioms x, squareRoots x, quadraticEquations x]++testEF :: forall k . GaloisField k => TestName -> k -> TestTree+testEF s x = testGroup s [fieldAxioms x]++testBF :: forall k . GaloisField k => TestName -> k -> TestTree+testBF s x = testGroup s [fieldAxioms x]
tests/Main.hs view
@@ -4,8 +4,10 @@  import Test.Tasty +import BinaryFieldTests import ExtensionFieldTests import PrimeFieldTests  main :: IO ()-main = defaultMain $ testGroup "Tests" [testPrimeField, testExtensionField]+main = defaultMain $+  testGroup "Tests" [testPrimeField, testExtensionField, testBinaryField]
tests/PrimeFieldTests.hs view
@@ -26,16 +26,16 @@  testPrimeField :: TestTree testPrimeField = testGroup "Prime fields"-  [ fieldAxioms "FS2" (witness :: FS2)-  , fieldAxioms "FS3" (witness :: FS3)-  , fieldAxioms "FS5" (witness :: FS5)-  , fieldAxioms "FS7" (witness :: FS7)-  , fieldAxioms "FM0" (witness :: FM0)-  , fieldAxioms "FM1" (witness :: FM1)-  , fieldAxioms "FM2" (witness :: FM2)-  , fieldAxioms "FM3" (witness :: FM3)-  , fieldAxioms "FM4" (witness :: FM4)-  , fieldAxioms "FVL" (witness :: FVL)-  , fieldAxioms "FXL" (witness :: FXL)-  , fieldAxioms "FZL" (witness :: FZL)+  [ test "FS2" (witness :: FS2)+  , test "FS3" (witness :: FS3)+  , test "FS5" (witness :: FS5)+  , test "FS7" (witness :: FS7)+  , test "FM0" (witness :: FM0)+  , test "FM1" (witness :: FM1)+  , test "FM2" (witness :: FM2)+  , test "FM3" (witness :: FM3)+  , test "FM4" (witness :: FM4)+  , test "FVL" (witness :: FVL)+  , test "FXL" (witness :: FXL)+  , test "FZL" (witness :: FZL)   ]