packages feed

galois-field 0.3.0 → 0.4.0

raw patch · 15 files changed

+688/−547 lines, 15 filesdep +polydep +semiringsdep +vectordep ~basedep ~protoludePVP ok

version bump matches the API change (PVP)

Dependencies added: poly, semirings, vector

Dependency ranges changed: base, protolude

API changes (from Hackage documentation)

- BinaryField: instance Control.DeepSeq.NFData (BinaryField.BinaryField im)
- BinaryField: instance GHC.Read.Read (BinaryField.BinaryField im)
- ExtensionField: fromList :: forall k im. (GaloisField k, IrreducibleMonic k im) => [k] -> ExtensionField k im
- ExtensionField: instance (GaloisField.GaloisField k, ExtensionField.IrreducibleMonic k im) => GHC.Num.Num (ExtensionField.ExtensionField k im)
- ExtensionField: instance (GaloisField.GaloisField k, ExtensionField.IrreducibleMonic k im) => GHC.Real.Fractional (ExtensionField.ExtensionField k im)
- ExtensionField: instance (GaloisField.GaloisField k, ExtensionField.IrreducibleMonic k im) => GaloisField.GaloisField (ExtensionField.ExtensionField k im)
- ExtensionField: instance (GaloisField.GaloisField k, ExtensionField.IrreducibleMonic k im) => System.Random.Random (ExtensionField.ExtensionField k im)
- ExtensionField: instance (GaloisField.GaloisField k, ExtensionField.IrreducibleMonic k im) => Text.PrettyPrint.Leijen.Text.Pretty (ExtensionField.ExtensionField k im)
- ExtensionField: instance (Test.QuickCheck.Arbitrary.Arbitrary k, GaloisField.GaloisField k, ExtensionField.IrreducibleMonic k im) => Test.QuickCheck.Arbitrary.Arbitrary (ExtensionField.ExtensionField k im)
- ExtensionField: instance Control.DeepSeq.NFData k => Control.DeepSeq.NFData (ExtensionField.ExtensionField k 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)
- ExtensionField: t :: Polynomial k -> Polynomial (ExtensionField k im)
- ExtensionField: x :: GaloisField k => Polynomial k
- PrimeField: instance Control.DeepSeq.NFData (PrimeField.PrimeField p)
- PrimeField: instance GHC.Read.Read (PrimeField.PrimeField p)
+ BinaryField: instance GHC.Classes.Ord (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => Data.Euclidean.Euclidean (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => Data.Euclidean.GcdDomain (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => Data.Semiring.Ring (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => Data.Semiring.Semiring (BinaryField.BinaryField im)
+ BinaryField: instance GHC.TypeNats.KnownNat im => GaloisField.Field (BinaryField.BinaryField im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => Data.Euclidean.Euclidean (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => Data.Euclidean.GcdDomain (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => Data.Semiring.Ring (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => Data.Semiring.Semiring (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => GHC.Num.Num (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => GHC.Real.Fractional (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => GaloisField.Field (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => GaloisField.GaloisField (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => System.Random.Random (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => Test.QuickCheck.Arbitrary.Arbitrary (ExtensionField.ExtensionField k im)
+ ExtensionField: instance ExtensionField.IrreducibleMonic k im => Text.PrettyPrint.Leijen.Text.Pretty (ExtensionField.ExtensionField k im)
+ ExtensionField: instance GHC.Classes.Ord k => GHC.Classes.Ord (ExtensionField.ExtensionField k im)
+ ExtensionField: pattern X :: forall a (v :: Type -> Type). (Eq a, Semiring a, Vector v a, Eq (v a)) => () => Poly v a
+ ExtensionField: pattern Y :: IrreducibleMonic k im => VPoly k -> VPoly (ExtensionField k im)
+ ExtensionField: toField :: forall k im. IrreducibleMonic k im => [k] -> ExtensionField k im
+ ExtensionField: type PolynomialRing = VPoly
+ GaloisField: class (Euclidean k, Ring k) => Field k
+ GaloisField: divide :: Field k => k -> k -> k
+ GaloisField: invert :: Field k => k -> k
+ GaloisField: minus :: Field k => k -> k -> k
+ GaloisField: qnr :: GaloisField k => k
+ GaloisField: qr :: GaloisField k => k -> Bool
+ PrimeField: instance GHC.Classes.Ord (PrimeField.PrimeField p)
+ PrimeField: instance GHC.TypeNats.KnownNat p => Data.Euclidean.Euclidean (PrimeField.PrimeField p)
+ PrimeField: instance GHC.TypeNats.KnownNat p => Data.Euclidean.GcdDomain (PrimeField.PrimeField p)
+ PrimeField: instance GHC.TypeNats.KnownNat p => Data.Semiring.Ring (PrimeField.PrimeField p)
+ PrimeField: instance GHC.TypeNats.KnownNat p => Data.Semiring.Semiring (PrimeField.PrimeField p)
+ PrimeField: instance GHC.TypeNats.KnownNat p => GaloisField.Field (PrimeField.PrimeField p)
- ExtensionField: class IrreducibleMonic k im
+ ExtensionField: class GaloisField k => IrreducibleMonic k im
- ExtensionField: split :: IrreducibleMonic k im => ExtensionField k im -> Polynomial k
+ ExtensionField: split :: IrreducibleMonic k im => ExtensionField k im -> VPoly k
- GaloisField: class (Arbitrary k, Eq k, Fractional k, Pretty k, Random k, Read k, Show k) => GaloisField k
+ GaloisField: class (Arbitrary k, Field k, Fractional k, Generic k, Ord k, Pretty k, Random k, Show k) => GaloisField k

Files

ChangeLog.md view
@@ -1,5 +1,16 @@ # Change log for galois-field +## 0.4.0++* Add `Vector` implementation of extension fields.+* Add `qnr` function for Galois fields.+* Add `qr` function for Galois fields.+* Add `quad` function for extension fields and binary fields.+* Add `sr` function for extension fields and binary fields.+* Add `Semiring` instances for Galois fields.+* Add `Ord` instances for Galois fields.+* Add minor optimisations to exponentiation with `RULES`.+ ## 0.3.0  * Add complete implementation of binary fields.
README.md view
@@ -33,7 +33,7 @@  ### 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.+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. It should always be used when the field characteristic is 2.  For example, X^8 + X^4 + X^3 + X + 1 can be represented as the integer 283 that represents the bit string 100011011. @@ -44,11 +44,14 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-} ``` Import the following functions at minimum. ```haskell import PrimeField (PrimeField)-import ExtensionField (ExtensionField, IrreducibleMonic(split), fromList, t, x)+import ExtensionField (ExtensionField, IrreducibleMonic(split), toField,+                       pattern X, pattern X2, pattern X3, pattern Y)+import BinaryField (BinaryField) ```  ### Prime fields@@ -77,7 +80,7 @@ ```haskell data P2 instance IrreducibleMonic Fq P2 where-  split _ = x^2 + 1+  split _ = X2 + 1 ``` The following type declaration then creates an extension field with this splitting polynomial. ```haskell@@ -89,46 +92,46 @@ ```haskell data P6 instance IrreducibleMonic Fq2 P6 where-  split _ = x^3 - (9 + t x)+  split _ = X3 - (9 + Y X)  type Fq6 = ExtensionField Fq2 P6  data P12 instance IrreducibleMonic Fq6 P12 where-  split _ = x^2 - t x+  split _ = X2 - Y X  type Fq12 = ExtensionField Fq6 P12 ```-Note that `x` accesses the current indeterminate variable and `t` descends the tower of indeterminate variables.+Note that `X, X2, X3` accesses the current indeterminate variables and `Y` descends the tower of indeterminate variables.  Galois field arithmetic can then be performed in this extension field. ```haskell fq12 :: Fq12-fq12 = fromList-  [ fromList-    [ fromList+fq12 = toField+  [ toField+    [ toField       [ 4025484419428246835913352650763180341703148406593523188761836807196412398582       , 5087667423921547416057913184603782240965080921431854177822601074227980319916       ]-    , fromList+    , toField       [ 8868355606921194740459469119392835913522089996670570126495590065213716724895       , 12102922015173003259571598121107256676524158824223867520503152166796819430680       ]-    , fromList+    , toField       [ 92336131326695228787620679552727214674825150151172467042221065081506740785       , 5482141053831906120660063289735740072497978400199436576451083698548025220729       ]     ]-  , fromList-    [ fromList+  , toField+    [ toField       [ 7642691434343136168639899684817459509291669149586986497725240920715691142493       , 1211355239100959901694672926661748059183573115580181831221700974591509515378       ]-    , fromList+    , toField       [ 20725578899076721876257429467489710434807801418821512117896292558010284413176       , 17642016461759614884877567642064231230128683506116557502360384546280794322728       ]-    , fromList+    , toField       [ 17449282511578147452934743657918270744212677919657988500433959352763226500950       , 1205855382909824928004884982625565310515751070464736233368671939944606335817       ]@@ -136,31 +139,31 @@   ]  fq12' :: Fq12-fq12' = fromList-  [ fromList-    [ fromList+fq12' = toField+  [ toField+    [ toField       [ 495492586688946756331205475947141303903957329539236899715542920513774223311       , 9283314577619389303419433707421707208215462819919253486023883680690371740600       ]-    , fromList+    , toField       [ 11142072730721162663710262820927009044232748085260948776285443777221023820448       , 1275691922864139043351956162286567343365697673070760209966772441869205291758       ]-    , fromList+    , toField       [ 20007029371545157738471875537558122753684185825574273033359718514421878893242       , 9839139739201376418106411333971304469387172772449235880774992683057627654905       ]     ]-  , fromList-    [ fromList+  , toField+    [ toField       [ 9503058454919356208294350412959497499007919434690988218543143506584310390240       , 19236630380322614936323642336645412102299542253751028194541390082750834966816       ]-    , fromList+    , toField       [ 18019769232924676175188431592335242333439728011993142930089933693043738917983       , 11549213142100201239212924317641009159759841794532519457441596987622070613872       ]-    , fromList+    , toField       [ 9656683724785441232932664175488314398614795173462019188529258009817332577664       , 20666848762667934776817320505559846916719041700736383328805334359135638079015       ]@@ -172,12 +175,12 @@ ``` Note that ```-a + bx + (c + dx)y + (e + fx)y^2 + (g + hx + (i + jx)y + (k + lx)y^2)z+a + bX + (c + dX)Y + (e + fX)Y^2 + (g + hX + (i + jX)Y + (k + lX)Y^2)Z ```-where `x, y, z` is a tower of indeterminate variables is constructed by+where `X, Y, Z` is a tower of indeterminate variables, is constructed by ```haskell-fromList [ fromList [fromList [a, b], fromList [c, d], fromList [e, f]]-         , fromList [fromList [g, h], fromList [i, j], fromList [k, l]] ] :: Fq12+toField [ toField [toField [a, b], toField [c, d], toField [e, f]]+        , toField [toField [g, h], toField [i, j], toField [k, l]] ] :: Fq12 ```  ### Binary fields
+ benchmarks/BinaryFieldBenchmarks.hs view
@@ -0,0 +1,17 @@+module BinaryFieldBenchmarks where++import BinaryField+import Criterion.Main++import GaloisFieldBenchmarks++type F2m = BinaryField 0x80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425++f2m :: F2m+f2m = 0x303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19++f2m' :: F2m+f2m' = 0x37bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b++benchmarkBinaryField :: Benchmark+benchmarkBinaryField = benchmark "BinaryField F2m" f2m f2m'
+ benchmarks/ExtensionFieldBenchmarks.hs view
@@ -0,0 +1,91 @@+module ExtensionFieldBenchmarks where++import Protolude++import Criterion.Main+import ExtensionField++import GaloisFieldBenchmarks+import PrimeFieldBenchmarks++data Pu+instance IrreducibleMonic Fq Pu where+  split _ = X2 + 1+type Fq2 = ExtensionField Fq Pu++data Pv+instance IrreducibleMonic Fq2 Pv where+  split _ = X3 - 9 - Y X+type Fq6 = ExtensionField Fq2 Pv++data Pw+instance IrreducibleMonic Fq6 Pw where+  split _ = X2 - Y X+type Fq12 = ExtensionField Fq6 Pw++fq12 :: Fq12+fq12 = toField+  [ toField+    [ toField+      [ 4025484419428246835913352650763180341703148406593523188761836807196412398582+      , 5087667423921547416057913184603782240965080921431854177822601074227980319916+      ]+    , toField+      [ 8868355606921194740459469119392835913522089996670570126495590065213716724895+      , 12102922015173003259571598121107256676524158824223867520503152166796819430680+      ]+    , toField+      [ 92336131326695228787620679552727214674825150151172467042221065081506740785+      , 5482141053831906120660063289735740072497978400199436576451083698548025220729+      ]+    ]+  , toField+    [ toField+      [ 7642691434343136168639899684817459509291669149586986497725240920715691142493+      , 1211355239100959901694672926661748059183573115580181831221700974591509515378+      ]+    , toField+      [ 20725578899076721876257429467489710434807801418821512117896292558010284413176+      , 17642016461759614884877567642064231230128683506116557502360384546280794322728+      ]+    , toField+      [ 17449282511578147452934743657918270744212677919657988500433959352763226500950+      , 1205855382909824928004884982625565310515751070464736233368671939944606335817+      ]+    ]+  ]++fq12' :: Fq12+fq12' = toField+  [ toField+    [ toField+      [ 495492586688946756331205475947141303903957329539236899715542920513774223311+      , 9283314577619389303419433707421707208215462819919253486023883680690371740600+      ]+    , toField+      [ 11142072730721162663710262820927009044232748085260948776285443777221023820448+      , 1275691922864139043351956162286567343365697673070760209966772441869205291758+      ]+    , toField+      [ 20007029371545157738471875537558122753684185825574273033359718514421878893242+      , 9839139739201376418106411333971304469387172772449235880774992683057627654905+      ]+    ]+  , toField+    [ toField+      [ 9503058454919356208294350412959497499007919434690988218543143506584310390240+      , 19236630380322614936323642336645412102299542253751028194541390082750834966816+      ]+    , toField+      [ 18019769232924676175188431592335242333439728011993142930089933693043738917983+      , 11549213142100201239212924317641009159759841794532519457441596987622070613872+      ]+    , toField+      [ 9656683724785441232932664175488314398614795173462019188529258009817332577664+      , 20666848762667934776817320505559846916719041700736383328805334359135638079015+      ]+    ]+  ]++benchmarkExtensionField :: Benchmark+benchmarkExtensionField = benchmark "ExtensionField Fq12" fq12 fq12'
+ benchmarks/GaloisFieldBenchmarks.hs view
@@ -0,0 +1,23 @@+module GaloisFieldBenchmarks where++import Protolude++import Criterion.Main+import GaloisField+import GHC.Base++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)+  ]
benchmarks/Main.hs view
@@ -2,127 +2,12 @@  import Protolude -import BinaryField import Criterion.Main-import ExtensionField-import GaloisField-import GHC.Base-import PrimeField -type Fq = PrimeField 21888242871839275222246405745257275088696311157297823662689037894645226208583--fq :: Fq-fq = 5216004179354450092383934373463611881445186046129513844852096383579774061693--fq' :: Fq-fq' = 10757805228921058098980668000791497318123219899766237205512608761387909753942--data Pu-instance IrreducibleMonic Fq Pu where-  split _ = x ^ (2 :: Int) + 1-type Fq2 = ExtensionField Fq Pu--data Pv-instance IrreducibleMonic Fq2 Pv where-  split _ = x ^ (3 :: Int) - 9 - t x-type Fq6 = ExtensionField Fq2 Pv--data Pw-instance IrreducibleMonic Fq6 Pw where-  split _ = x ^ (2 :: Int) - t x-type Fq12 = ExtensionField Fq6 Pw--fq12 :: Fq12-fq12 = fromList-  [ fromList-    [ fromList-      [ 4025484419428246835913352650763180341703148406593523188761836807196412398582-      , 5087667423921547416057913184603782240965080921431854177822601074227980319916-      ]-    , fromList-      [ 8868355606921194740459469119392835913522089996670570126495590065213716724895-      , 12102922015173003259571598121107256676524158824223867520503152166796819430680-      ]-    , fromList-      [ 92336131326695228787620679552727214674825150151172467042221065081506740785-      , 5482141053831906120660063289735740072497978400199436576451083698548025220729-      ]-    ]-  , fromList-    [ fromList-      [ 7642691434343136168639899684817459509291669149586986497725240920715691142493-      , 1211355239100959901694672926661748059183573115580181831221700974591509515378-      ]-    , fromList-      [ 20725578899076721876257429467489710434807801418821512117896292558010284413176-      , 17642016461759614884877567642064231230128683506116557502360384546280794322728-      ]-    , fromList-      [ 17449282511578147452934743657918270744212677919657988500433959352763226500950-      , 1205855382909824928004884982625565310515751070464736233368671939944606335817-      ]-    ]-  ]--fq12' :: Fq12-fq12' = fromList-  [ fromList-    [ fromList-      [ 495492586688946756331205475947141303903957329539236899715542920513774223311-      , 9283314577619389303419433707421707208215462819919253486023883680690371740600-      ]-    , fromList-      [ 11142072730721162663710262820927009044232748085260948776285443777221023820448-      , 1275691922864139043351956162286567343365697673070760209966772441869205291758-      ]-    , fromList-      [ 20007029371545157738471875537558122753684185825574273033359718514421878893242-      , 9839139739201376418106411333971304469387172772449235880774992683057627654905-      ]-    ]-  , fromList-    [ fromList-      [ 9503058454919356208294350412959497499007919434690988218543143506584310390240-      , 19236630380322614936323642336645412102299542253751028194541390082750834966816-      ]-    , fromList-      [ 18019769232924676175188431592335242333439728011993142930089933693043738917983-      , 11549213142100201239212924317641009159759841794532519457441596987622070613872-      ]-    , fromList-      [ 9656683724785441232932664175488314398614795173462019188529258009817332577664-      , 20666848762667934776817320505559846916719041700736383328805334359135638079015-      ]-    ]-  ]--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)-  ]+import BinaryFieldBenchmarks+import ExtensionFieldBenchmarks+import PrimeFieldBenchmarks  main :: IO () main = defaultMain-  [ benchmark "PrimeField Fq" fq fq'-  , benchmark "ExtensionField Fq12" fq12 fq12'-  , benchmark "BinaryField F2m" f2m f2m'-  ]+  [benchmarkBinaryField, benchmarkExtensionField, benchmarkPrimeField]
+ benchmarks/PrimeFieldBenchmarks.hs view
@@ -0,0 +1,17 @@+module PrimeFieldBenchmarks where++import Criterion.Main+import PrimeField++import GaloisFieldBenchmarks++type Fq = PrimeField 21888242871839275222246405745257275088696311157297823662689037894645226208583++fq :: Fq+fq = 5216004179354450092383934373463611881445186046129513844852096383579774061693++fq' :: Fq+fq' = 10757805228921058098980668000791497318123219899766237205512608761387909753942++benchmarkPrimeField :: Benchmark+benchmarkPrimeField = benchmark "PrimeField Fq" fq fq'
galois-field.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 094ec398fd4d7e6719c2a9ba616c6ca5e682b6d55f80d89d64a037adb94e845e+-- hash: 033214ea0f37604de3c3e831efac36ce0278f2f57df82216bf93635ec31dc830  name:           galois-field-version:        0.3.0+version:        0.4.0 synopsis:       Galois field library description:    An efficient implementation of Galois fields used in cryptography research category:       Cryptography@@ -34,14 +34,17 @@       Paths_galois_field   hs-source-dirs:       src-  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances FlexibleContexts ScopedTypeVariables RankNTypes DataKinds DeriveGeneric GeneralizedNewtypeDeriving KindSignatures MultiParamTypeClasses+  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances FlexibleContexts ScopedTypeVariables RankNTypes DataKinds DeriveGeneric GeneralizedNewtypeDeriving KindSignatures MultiParamTypeClasses PatternSynonyms   ghc-options: -O2 -Wall   build-depends:       MonadRandom-    , base >=4.7 && <5+    , base >=4.10 && <5     , integer-gmp-    , protolude >=0.2+    , poly+    , protolude+    , semirings     , tasty-quickcheck+    , vector     , wl-pprint-text   default-language: Haskell2010 @@ -61,15 +64,18 @@   hs-source-dirs:       tests       src-  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances FlexibleContexts ScopedTypeVariables RankNTypes DataKinds DeriveGeneric GeneralizedNewtypeDeriving KindSignatures MultiParamTypeClasses+  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances FlexibleContexts ScopedTypeVariables RankNTypes DataKinds DeriveGeneric GeneralizedNewtypeDeriving KindSignatures MultiParamTypeClasses PatternSynonyms   ghc-options: -O2 -Wall -main-is Main   build-depends:       MonadRandom-    , base >=4.7 && <5+    , base >=4.10 && <5     , integer-gmp-    , protolude >=0.2+    , poly+    , protolude+    , semirings     , tasty     , tasty-quickcheck+    , vector     , wl-pprint-text   default-language: Haskell2010 @@ -77,6 +83,10 @@   type: exitcode-stdio-1.0   main-is: Main.hs   other-modules:+      BinaryFieldBenchmarks+      ExtensionFieldBenchmarks+      GaloisFieldBenchmarks+      PrimeFieldBenchmarks       BinaryField       ExtensionField       GaloisField@@ -85,14 +95,17 @@   hs-source-dirs:       benchmarks       src-  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances FlexibleContexts ScopedTypeVariables RankNTypes DataKinds DeriveGeneric GeneralizedNewtypeDeriving KindSignatures MultiParamTypeClasses+  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances FlexibleContexts ScopedTypeVariables RankNTypes DataKinds DeriveGeneric GeneralizedNewtypeDeriving KindSignatures MultiParamTypeClasses PatternSynonyms   ghc-options: -O2 -Wall -main-is Main   build-depends:       MonadRandom-    , base >=4.7 && <5+    , base >=4.10 && <5     , criterion     , integer-gmp-    , protolude >=0.2+    , poly+    , protolude+    , semirings     , tasty-quickcheck+    , vector     , wl-pprint-text   default-language: Haskell2010
src/BinaryField.hs view
@@ -2,22 +2,24 @@   ( BinaryField   ) where -import Protolude+import Protolude as P hiding (Semiring) -import Control.Monad.Random (Random(..), getRandom)+import Control.Monad.Random (Random(..))+import Data.Euclidean (Euclidean(..), GcdDomain(..))+import Data.Semiring (Ring(..), Semiring(..)) import Test.Tasty.QuickCheck (Arbitrary(..), choose) import Text.PrettyPrint.Leijen.Text (Pretty(..)) -import GaloisField (GaloisField(..))+import GaloisField (Field(..), GaloisField(..))  ---------------------------------------------------------------------------------- Binary field type+-- Data types -------------------------------------------------------------------------------  -- | 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 (im :: Nat) = BF Integer-  deriving (Eq, Generic, NFData, Read, Show)+  deriving (Eq, Generic, Ord, Show)  -- Binary fields are Galois fields. instance KnownNat im => GaloisField (BinaryField im) where@@ -27,46 +29,27 @@   {-# INLINE deg #-}   frob          = flip pow 2   {-# INLINE frob #-}-  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 #-}-  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 #-} +{-# RULES "BinaryField/pow"+  forall (k :: KnownNat im => BinaryField im) n . (^) k n = pow k n+  #-}+ ---------------------------------------------------------------------------------- Binary field instances+-- Numeric 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.+-- Binary fields are fractional. instance KnownNat im => Fractional (BinaryField im) where-  recip w@(BF x)      = BF (binInv x (natVal w))+  recip (BF x)        = BF (binInv x (natVal (witness :: BinaryField im)))   {-# INLINE recip #-}   fromRational (x:%y) = fromInteger x / fromInteger y   {-# INLINABLE fromRational #-} --- Binary fields are rings.+-- Binary fields are numeric. instance KnownNat im => Num (BinaryField im) where   BF x + BF y = BF (xor x y)   {-# INLINE (+) #-}-  BF x * BF y = fromInteger (binMul x y)+  BF x * BF y = BF (binMul (natVal (witness :: BinaryField im)) x y)   {-# INLINE (*) #-}   BF x - BF y = BF (xor x y)   {-# INLINE (-) #-}@@ -77,6 +60,53 @@   abs         = panic "not implemented."   signum      = panic "not implemented." +-------------------------------------------------------------------------------+-- Semiring instances+-------------------------------------------------------------------------------++-- Binary fields are Euclidean domains.+instance KnownNat im => Euclidean (BinaryField im) where+  quotRem = (flip (,) 0 .) . (/)+  {-# INLINE quotRem #-}+  degree  = panic "not implemented."+  {-# INLINE degree #-}++-- Binary fields are fields.+instance KnownNat im => Field (BinaryField im) where+  invert = recip+  {-# INLINE invert #-}+  minus  = (-)+  {-# INLINE minus #-}++-- Binary fields are GCD domains.+instance KnownNat im => GcdDomain (BinaryField im)++-- Binary fields are rings.+instance KnownNat im => Ring (BinaryField im) where+  negate = P.negate+  {-# INLINE negate #-}++-- Binary fields are semirings.+instance KnownNat im => Semiring (BinaryField im) where+  zero        = 0+  {-# INLINE zero #-}+  plus        = (+)+  {-# INLINE plus #-}+  one         = 1+  {-# INLINE one #-}+  times       = (*)+  {-# INLINE times #-}+  fromNatural = fromIntegral+  {-# INLINE fromNatural #-}++-------------------------------------------------------------------------------+-- Other instances+-------------------------------------------------------------------------------++-- Binary fields are arbitrary.+instance KnownNat im => Arbitrary (BinaryField im) where+  arbitrary = BF <$> choose (0, order (witness :: BinaryField im) - 1)+ -- Binary fields are pretty. instance KnownNat im => Pretty (BinaryField im) where   pretty (BF x) = pretty x@@ -88,7 +118,7 @@   randomR = panic "not implemented."  ---------------------------------------------------------------------------------- Binary field arithmetic+-- Binary arithmetic -------------------------------------------------------------------------------  -- Binary logarithm.@@ -99,17 +129,17 @@     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'+        l -> let l' = 2 * l in binLog'' (P.quot x (p ^ l')) l'       where         binLog'' :: Integer -> Int -> Int         binLog'' y n           | y < p     = n-          | otherwise = binLog'' (quot y p) (n + 1)+          | otherwise = binLog'' (P.quot y p) (n + 1) {-# INLINE binLog #-}  -- Binary multiplication.-binMul :: Integer -> Integer -> Integer-binMul = binMul' 0+binMul :: Integer -> Integer -> Integer -> Integer+binMul = (. binMul' 0) . (.) . binMod   where     binMul' :: Integer -> Integer -> Integer -> Integer     binMul' n x y@@ -147,20 +177,3 @@       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,230 +1,192 @@ module ExtensionField   ( ExtensionField+  , PolynomialRing   , IrreducibleMonic(split)   , fromField-  , fromList-  , t-  , x+  , toField+  , pattern X+  , pattern X2+  , pattern X3+  , pattern Y   ) where -import Protolude+import Protolude as P hiding (Semiring, quot, quotRem, rem) -import Control.Monad.Random (Random(..), getRandom)+import Control.Monad.Random (Random(..))+import Data.Euclidean (Euclidean(..), GcdDomain(..))+import Data.Poly.Semiring (VPoly, leading, monomial, scale, toPoly, unPoly, pattern X)+import Data.Semiring as S (Ring(..), Semiring(..))+import Data.Vector (fromList) import Test.Tasty.QuickCheck (Arbitrary(..), vector) import Text.PrettyPrint.Leijen.Text (Pretty(..)) -import GaloisField (GaloisField(..))+import GaloisField (Field(..), GaloisField(..))  ---------------------------------------------------------------------------------- Extension field type+-- Data types -------------------------------------------------------------------------------  -- | 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, Read, Show)+newtype ExtensionField k im = EF (VPoly k)+  deriving (Eq, Generic, Ord, Show) +-- | Polynomial rings.+type PolynomialRing = VPoly+ -- | Irreducible monic splitting polynomial @f(X)@ of extension field.-class IrreducibleMonic k im where+class GaloisField k => IrreducibleMonic k im where   {-# MINIMAL split #-}   -- | Splitting polynomial @f(X)@.-  split :: ExtensionField k im -> Polynomial k-  -- | Splitting polynomial list.-  plist :: ExtensionField k im -> [k]-  plist = (\(X xs) -> xs) . split+  split :: ExtensionField k im -> VPoly k+  -- | Splitting polynomial degree.+  deg' :: ExtensionField k im -> Int+  deg' = pred . fromIntegral . degree . split  -- Extension fields are Galois fields.-instance (GaloisField k, IrreducibleMonic k im)-  => GaloisField (ExtensionField k im) where+instance IrreducibleMonic k im => GaloisField (ExtensionField k im) where   char          = const (char (witness :: k))   {-# INLINE char #-}-  deg w         = deg (witness :: k) * (length (plist w) - 1)+  deg           = (deg (witness :: k) *) . deg'   {-# INLINE deg #-}   frob          = pow <*> char   {-# INLINE frob #-}-  pow w@(EF (X y)) n-    | n < 0     = pow (recip w) (-n)-    | otherwise = EF (X (pow' [1] y n))-    where-      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 #-} +{-# RULES "ExtensionField/pow"+  forall (k :: IrreducibleMonic k im => ExtensionField k im) n . (^) k n = pow k n+  #-}+ ---------------------------------------------------------------------------------- Extension field conversions+-- Numeric instances ------------------------------------------------------------------------------- --- Polynomial rings.-newtype Polynomial k = X [k]-  deriving (Eq, Generic, NFData, Read, Show)+-- Extension fields are fractional.+instance IrreducibleMonic k im => Fractional (ExtensionField k im) where+  recip (EF x)        = EF (polyInv x (split (witness :: ExtensionField k im)))+  {-# INLINE recip #-}+  fromRational (x:%y) = fromInteger x / fromInteger y+  {-# INLINABLE fromRational #-} --- Polynomial rings are rings.-instance GaloisField k => Num (Polynomial k) where-  X y + X z     = X (polyAdd y z)+-- Extension fields are numeric.+instance IrreducibleMonic k im => Num (ExtensionField k im) where+  EF x + EF y   = EF (plus x y)   {-# INLINE (+) #-}-  X y * X z     = X (polyMul y z)+  EF x * EF y   = EF (rem (times x y) (split (witness :: ExtensionField k im)))   {-# INLINE (*) #-}-  X y - X z     = X (polySub y z)+  EF x - EF y   = EF (x - y)   {-# INLINE (-) #-}-  negate (X y)  = X (map negate y)+  negate (EF x) = EF (S.negate x)   {-# INLINE negate #-}-  fromInteger n = X (let m = fromInteger n in if m == 0 then [] else [m])+  fromInteger   = EF . fromInteger   {-# INLINABLE fromInteger #-}   abs           = panic "not implemented."   signum        = panic "not implemented." --- | Convert from field element to list representation.-fromField :: ExtensionField k im -> [k]-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 (plist w) . dropZero-  where-    w = witness :: ExtensionField k im-{-# INLINABLE fromList #-}---- | Descend tower of indeterminate variables.-t :: Polynomial k -> Polynomial (ExtensionField k im)-t = X . return . EF-{-# INLINE t #-}---- | Current indeterminate variable.-x :: GaloisField k => Polynomial k-x = X [0, 1]-{-# INLINE x #-}- ---------------------------------------------------------------------------------- Extension field instances+-- Semiring 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 Euclidean domains.+instance IrreducibleMonic k im => Euclidean (ExtensionField k im) where+  quotRem = (flip (,) 0 .) . (/)+  {-# INLINE quotRem #-}+  degree  = panic "not implemented."+  {-# INLINE degree #-}  -- 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 #-}+instance IrreducibleMonic k im => Field (ExtensionField k im) where+  invert = recip+  {-# INLINE invert #-}+  minus  = (-)+  {-# INLINE minus #-} +-- Extension fields are GCD domains.+instance IrreducibleMonic k im => GcdDomain (ExtensionField k im)+ -- 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)+instance IrreducibleMonic k im => Ring (ExtensionField k im) where+  negate = P.negate   {-# INLINE negate #-}-  fromInteger             = EF . fromInteger-  {-# INLINABLE fromInteger #-}-  abs                     = panic "not implemented."-  signum                  = panic "not implemented." +-- Extension fields are semirings.+instance IrreducibleMonic k im => Semiring (ExtensionField k im) where+  zero        = 0+  {-# INLINE zero #-}+  plus        = (+)+  {-# INLINE plus #-}+  one         = 1+  {-# INLINE one #-}+  times       = (*)+  {-# INLINE times #-}+  fromNatural = fromIntegral+  {-# INLINE fromNatural #-}++-------------------------------------------------------------------------------+-- Other instances+-------------------------------------------------------------------------------++-- Extension fields are arbitrary.+instance IrreducibleMonic k im => Arbitrary (ExtensionField k im) where+  arbitrary = toField <$> vector (deg' (witness :: ExtensionField k im))+ -- Extension fields are pretty.-instance (GaloisField k, IrreducibleMonic k im)-  => Pretty (ExtensionField k im) where-  pretty (EF (X y)) = pretty y+instance IrreducibleMonic k im => Pretty (ExtensionField k im) where+  pretty (EF x) = pretty (toList (unPoly x))  -- 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) []+instance IrreducibleMonic k im => Random (ExtensionField k im) where+  random  = first toField . unfold (deg' (witness :: ExtensionField k im)) []     where-      w = witness :: ExtensionField k im-      unfold n ys g-        | n <= 0    = (ys, g)+      unfold n xs g+        | n <= 0    = (xs, g)         | otherwise = case random g of-          (y, g') -> unfold (n - 1) (y : ys) g'+        (x, g') -> unfold (n - 1) (x : xs) g'   {-# INLINE random #-}   randomR = panic "not implemented."  ---------------------------------------------------------------------------------- Extension field arithmetic+-- Type conversions ------------------------------------------------------------------------------- --- Polynomial drop zeroes.-dropZero :: GaloisField k => [k] -> [k]-dropZero = reverse . dropWhile (== 0) . reverse-{-# INLINABLE dropZero #-}+-- | Convert from field element to list representation.+fromField :: ExtensionField k im -> [k]+fromField (EF x) = toList (unPoly x)+{-# INLINABLE fromField #-} --- 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 #-}+-- | Convert from list representation to field element.+toField :: forall k im . IrreducibleMonic k im => [k] -> ExtensionField k im+toField = EF . flip rem (split (witness :: ExtensionField k im)) . toPoly . fromList+{-# INLINABLE toField #-} --- 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 #-}+-- | Pattern for @X^2@.+pattern X2 :: GaloisField k => VPoly k+pattern X2 <- _ where X2 = toPoly (fromList [0, 0, 1]) --- 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 #-}+-- | Pattern for @X^3@.+pattern X3 :: GaloisField k => VPoly k+pattern X3 <- _ where X3 = toPoly (fromList [0, 0, 0, 1]) --- 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 #-}+-- | Pattern for descending tower of indeterminate variables.+pattern Y :: IrreducibleMonic k im => VPoly k -> VPoly (ExtensionField k im)+pattern Y <- _ where Y = monomial 0 . EF --- 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)+-------------------------------------------------------------------------------+-- Polynomial arithmetic+-------------------------------------------------------------------------------++-- Polynomial inversion algorithm.+polyInv :: GaloisField k => VPoly k -> VPoly k -> VPoly k+polyInv xs ps = case first leading (polyGCD xs ps) of+  (Just (0, x), ys) -> scale 0 (recip x) ys+  _                 -> panic "no multiplicative inverse." {-# INLINE polyInv #-}++-- Polynomial extended greatest common divisor algorithm.+polyGCD :: forall k . GaloisField k => VPoly k -> VPoly k -> (VPoly k, VPoly k)+polyGCD x y = polyGCD' 0 1 y x+  where+    polyGCD' :: VPoly k -> VPoly k -> VPoly k -> VPoly k -> (VPoly k, VPoly k)+    polyGCD' s _  r 0  = (r, s)+    polyGCD' s s' r r' = case quot r r' of+      q -> polyGCD' s' (s - times q s') r' (r - times q r')+{-# INLINE polyGCD #-}
src/GaloisField.hs view
@@ -1,21 +1,45 @@ module GaloisField-  ( GaloisField(..)+  ( Field(..)+  , GaloisField(..)   ) where -import Protolude+import Protolude hiding ((-), one, quot) -import Control.Monad.Random (MonadRandom, Random)+import Control.Monad.Random (MonadRandom, Random, StdGen,+                             getRandom, mkStdGen, runRand)+import Data.Euclidean (Euclidean(..))+import Data.Semiring (Ring, (-), one) import Test.Tasty.QuickCheck (Arbitrary) import Text.PrettyPrint.Leijen.Text (Pretty)  ---------------------------------------------------------------------------------- Galois field class+-- Classes ------------------------------------------------------------------------------- +-- | Fields.+class (Euclidean k, Ring k) => Field k where++  -- Operations++  -- | Division.+  divide :: k -> k -> k+  divide = quot+  {-# INLINE divide #-}++  -- | Inversion.+  invert :: k -> k+  invert = quot one+  {-# INLINE invert #-}++  -- | Subtraction.+  minus :: k -> k -> k+  minus = (-)+  {-# INLINE minus #-}+ -- | Galois fields @GF(p^q)@ for @p@ prime and @q@ non-negative.-class (Arbitrary k, Eq k, Fractional k, Pretty k, Random k, Read k, Show k)-  => GaloisField k where-  {-# MINIMAL char, deg, frob, pow, quad, rnd, sr #-}+class (Arbitrary k, Field k, Fractional k,+       Generic k, Ord k, Pretty k, Random k, Show k) => GaloisField k where+  {-# MINIMAL char, deg, frob #-}    -- Characteristics @@ -35,14 +59,126 @@    -- Functions -  -- | Exponentiation of a field element to an integer.+  -- | Exponentiation of field element to integer.   pow :: k -> Integer -> k+  pow x n+    | n < 0     = pow (recip x) (negate n)+    | otherwise = pow' 1 x n+    where+      pow' z y m+        | m == 0    = z+        | m == 1    = z'+        | even m    = pow' z  y' m'+        | otherwise = pow' z' y' m'+        where+          z' = z * y+          y' = y * y+          m' = div m 2+  {-# INLINE pow #-} -  -- | Solve quadratic @ax^2+bx+c=0@ over field.+  -- | Get randomised quadratic nonresidue.+  qnr :: k+  qnr = getQNR+  {-# INLINE qnr #-}++  -- | Check if quadratic residue.+  qr :: k -> Bool+  qr = not . isQNR+  {-# INLINE qr #-}++  -- | Solve quadratic @ax^2 + bx + c = 0@ over field.   quad :: k -> k -> k -> Maybe k+  quad = solveQuadratic+  {-# INLINE quad #-}    -- | Randomised field element.   rnd :: MonadRandom m => m k+  rnd = getRandom+  {-# INLINE rnd #-} -  -- | Square root of a field element.+  -- | Square root of field element.   sr :: k -> Maybe k+  sr = squareRoot+  {-# INLINE sr #-}++-------------------------------------------------------------------------------+-- Square roots+-------------------------------------------------------------------------------++-- Check if an element is a quadratic nonresidue.+isQNR :: GaloisField k => k -> Bool+isQNR n = pow n (shiftR (order n) 1) /= 1+{-# INLINE isQNR #-}++-- Factor the order @p - 1@ to get @q@ and @s@ such that @p - 1 = q2^s@.+factorOrder :: GaloisField k => k -> (Integer, Int)+factorOrder w = factorOrder' (order w - 1, 0)+  where+    factorOrder' :: (Integer, Int) -> (Integer, Int)+    factorOrder' qs@(q, s)+      | testBit q 0 = qs+      | otherwise   = factorOrder' (shiftR q 1, s + 1)+{-# INLINE factorOrder #-}++-- Get a random quadratic nonresidue.+getQNR :: forall k . GaloisField k => k+getQNR = getQNR' (runRand rnd (mkStdGen 0))+  where+    getQNR' :: (k, StdGen) -> k+    getQNR' (x, g)+      | x /= 0 && isQNR x = x+      | otherwise         = getQNR' (runRand rnd g)+{-# INLINE getQNR #-}++-- Get a square root of @n@ with the Tonelli-Shanks algorithm.+squareRoot :: forall k . GaloisField k => k -> Maybe k+squareRoot 0    = Just 0+squareRoot n+  | char n == 2 = Just (power n)+  | isQNR n     = Nothing+  | otherwise   = case (factorOrder n, getQNR) of+  ((q, s), z) -> let zq  = pow z q+                     nq  = pow n (shiftR q 1)+                     nnq = n * nq+                 in loop s zq (nq * nnq) nnq+  where+    power :: k -> k+    power = next (deg n)+      where+       next :: Int -> k -> k+       next 1 m = m+       next i m = next (i - 1) (m * m)+    loop :: Int -> k -> k -> k -> Maybe k+    loop _ _ 0 _ = Just 0+    loop _ _ 1 r = Just r+    loop m c t r = let i  = least t 0+                       b  = pow c (bit (m - i - 1))+                       b2 = b * b+                   in loop i b2 (t * b2) (r * b)+      where+        least :: k -> Int -> Int+        least 1  j = j+        least ti j = least (ti * ti) (j + 1)+{-# INLINE squareRoot #-}++-- Solve a quadratic equation @ax^2 + bx + c = 0@.+solveQuadratic :: forall k . GaloisField k => k -> k -> k -> Maybe k+solveQuadratic 0 _ _ = Nothing+solveQuadratic _ _ 0 = Just 0+solveQuadratic a 0 c = squareRoot (-c / a)+solveQuadratic a b c+  | char a == 2      = (* (b / a)) <$> solveQuadratic' (ac / bb)+  | otherwise        = (/ (2 * a)) . subtract b <$> squareRoot (bb - 4 * ac)+  where+    ac = a * c+    bb = b * b+    solveQuadratic' :: k -> Maybe k+    solveQuadratic' x+      | sum xs /= 0 = Nothing+      | odd m       = Just (sum h)+      | otherwise   = panic "not implemented."+      where+        m  = deg x+        xs = take m (iterate (join (*)) x)+        h  = zipWith ($) (cycle [identity, const 0]) xs+{-# INLINE solveQuadratic #-}
src/PrimeField.hs view
@@ -3,89 +3,123 @@   , toInt   ) where -import Protolude+import Protolude as P hiding (Semiring) -import Control.Monad.Random (Random(..), getRandom)+import Control.Monad.Random (Random(..))+import Data.Euclidean (Euclidean(..), GcdDomain(..))+import Data.Semiring (Ring(..), Semiring(..)) import GHC.Integer.GMP.Internals (powModInteger, recipModInteger)-import Test.Tasty.QuickCheck (Arbitrary(..))+import Test.Tasty.QuickCheck (Arbitrary(..), choose) import Text.PrettyPrint.Leijen.Text (Pretty(..)) -import GaloisField (GaloisField(..))+import GaloisField (Field(..), GaloisField(..))  ---------------------------------------------------------------------------------- Prime field type+-- Data types -------------------------------------------------------------------------------  -- | Prime fields @GF(p)@ for @p@ prime. newtype PrimeField (p :: Nat) = PF Integer-  deriving (Bits, Eq, Generic, NFData, Read, Show)+  deriving (Bits, Eq, Generic, Ord, Show)  -- Prime fields are Galois fields. instance KnownNat p => GaloisField (PrimeField p) where-  char           = natVal+  char         = natVal   {-# INLINE char #-}-  deg            = const 1+  deg          = const 1   {-# INLINE deg #-}-  frob           = identity+  frob         = identity   {-# INLINE frob #-}-  pow w@(PF x) n = PF (powModInteger x n (natVal w))+  pow (PF x) n = PF (powModInteger x n (natVal (witness :: PrimeField p)))   {-# 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 #-}+{-# RULES "PrimeField/pow"+  forall (k :: KnownNat p => PrimeField p) (n :: Integer) . (^) k n = pow k n+  #-}  ---------------------------------------------------------------------------------- Prime field instances+-- Numeric instances ------------------------------------------------------------------------------- --- Prime fields are arbitrary.-instance KnownNat p => Arbitrary (PrimeField p) where-  arbitrary = fromInteger <$> arbitrary---- Prime fields are fields.+-- Prime fields are fractional. 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))+  recip (PF 0)        = panic "no multiplicative inverse."+  recip (PF x)        = PF (recipModInteger x (natVal (witness :: PrimeField p)))   {-# INLINE recip #-}   fromRational (x:%y) = fromInteger x / fromInteger y   {-# INLINABLE fromRational #-} --- Prime fields are rings.+-- Prime fields are numeric. instance KnownNat p => Num (PrimeField p) where-  w@(PF x) + PF y = PF (if xyp >= 0 then xyp else xy)+  PF x + PF y   = PF (if xyp >= 0 then xyp else xy)     where       xy  = x + y-      xyp = xy - natVal w+      xyp = xy - natVal (witness :: PrimeField p)   {-# INLINE (+) #-}-  w@(PF x) * PF y = PF (rem (x * y) (natVal w))+  PF x * PF y   = PF (P.rem (x * y) (natVal (witness :: PrimeField p)))   {-# INLINE (*) #-}-  w@(PF x) - PF y = PF (if xy >= 0 then xy else xy + natVal w)+  PF x - PF y   = PF (if xy >= 0 then xy else xy + natVal (witness :: PrimeField p))     where       xy = x - y   {-# INLINE (-) #-}-  negate w@(PF x) = PF (if x == 0 then 0 else -x + natVal w)+  negate (PF 0) = PF 0+  negate (PF x) = PF (natVal (witness :: PrimeField p) - x)   {-# INLINE negate #-}-  fromInteger x   = PF (if y >= 0 then y else y + p)+  fromInteger x = PF (if y >= 0 then y else y + p)     where-      y = rem x p+      y = P.rem x p       p = natVal (witness :: PrimeField p)   {-# INLINABLE fromInteger #-}-  abs             = panic "not implemented."-  signum          = panic "not implemented."+  abs           = panic "not implemented."+  signum        = panic "not implemented." +-------------------------------------------------------------------------------+-- Semiring instances+-------------------------------------------------------------------------------++-- Prime fields are Euclidean domains.+instance KnownNat p => Euclidean (PrimeField p) where+  quotRem = (flip (,) 0 .) . (/)+  {-# INLINE quotRem #-}+  degree  = panic "not implemented."+  {-# INLINE degree #-}++-- Prime fields are fields.+instance KnownNat p => Field (PrimeField p) where+  invert = recip+  {-# INLINE invert #-}+  minus  = (-)+  {-# INLINE minus #-}++-- Prime fields are GCD domains.+instance KnownNat p => GcdDomain (PrimeField p)++-- Prime fields are rings.+instance KnownNat p => Ring (PrimeField p) where+  negate = P.negate+  {-# INLINE negate #-}++-- Prime fields are semirings.+instance KnownNat p => Semiring (PrimeField p) where+  zero        = 0+  {-# INLINE zero #-}+  plus        = (+)+  {-# INLINE plus #-}+  one         = 1+  {-# INLINE one #-}+  times       = (*)+  {-# INLINE times #-}+  fromNatural = fromIntegral+  {-# INLINE fromNatural #-}++-------------------------------------------------------------------------------+-- Other instances+-------------------------------------------------------------------------------++-- Prime fields are arbitrary.+instance KnownNat p => Arbitrary (PrimeField p) where+  arbitrary = PF <$> choose (0, natVal (witness :: PrimeField p) - 1)+ -- Prime fields are pretty. instance KnownNat p => Pretty (PrimeField p) where   pretty (PF x) = pretty x@@ -97,67 +131,10 @@   randomR = panic "not implemented."  ---------------------------------------------------------------------------------- Prime field quadratics+-- Type conversions ------------------------------------------------------------------------------- --- 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 #-}+-- | Embed field element to integers.+toInt :: PrimeField p -> Integer+toInt (PF x) = x+{-# INLINABLE toInt #-}
tests/BinaryFieldTests.hs view
@@ -19,13 +19,13 @@  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)+  [ test "F2A" (witness :: F2A)+  , test "F2B" (witness :: F2B)+  , test "F2C" (witness :: F2C)+  , test "F2D" (witness :: F2D)+  , test "F2E" (witness :: F2E)+  , test "F2F" (witness :: F2F)+  , test "F2G" (witness :: F2G)+  , test "F2H" (witness :: F2H)+  , test "F2I" (witness :: F2I)   ]
tests/ExtensionFieldTests.hs view
@@ -10,98 +10,98 @@  data P111 instance IrreducibleMonic FS2 P111 where-  split _ = x ^ (2 :: Int) + x + 1+  split _ = X2 + X + 1 type FS4 = ExtensionField FS2 P111  data P1101 instance IrreducibleMonic FS2 P1101 where-  split _ = x ^ (3 :: Int) + x + 1+  split _ = X3 + X + 1 type FS8 = ExtensionField FS2 P1101  data P1011 instance IrreducibleMonic FS2 P1011 where-  split _ = x ^ (3 :: Int) + x ^ (2 :: Int) + 1+  split _ = X3 + X2 + 1 type FS8' = ExtensionField FS2 P1011  data P101 instance IrreducibleMonic FS3 P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 1 type FS9 = ExtensionField FS3 P101  data P211 instance IrreducibleMonic FS3 P211 where-  split _ = x ^ (2 :: Int) + x - 1+  split _ = X2 + X - 1 type FS9' = ExtensionField FS3 P211  data P221 instance IrreducibleMonic FS3 P221 where-  split _ = x ^ (2 :: Int) - x - 1+  split _ = X2 - X - 1 type FS9'' = ExtensionField FS3 P221  instance IrreducibleMonic FM0 P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 1 type FL0 = ExtensionField FM0 P101  instance IrreducibleMonic FM1 P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 1 type FL1 = ExtensionField FM1 P101  instance IrreducibleMonic FM2 P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 1 type FL2 = ExtensionField FM2 P101  instance IrreducibleMonic FM3 P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 1 type FL3 = ExtensionField FM3 P101  instance IrreducibleMonic FM4 P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 1 type FL4 = ExtensionField FM4 P101  instance IrreducibleMonic FVL P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 17 type FV2 = ExtensionField FVL P101  instance IrreducibleMonic FXL P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 17 type FX2 = ExtensionField FXL P101  instance IrreducibleMonic FZL P101 where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 17 type FZ2 = ExtensionField FZL P101  data Pu instance IrreducibleMonic Fq Pu where-  split _ = x ^ (2 :: Int) + 1+  split _ = X2 + 1 type Fq2 = ExtensionField Fq Pu  data Pv instance IrreducibleMonic Fq2 Pv where-  split _ = x ^ (3 :: Int) - 9 - t x+  split _ = X3 - 9 - Y X type Fq6 = ExtensionField Fq2 Pv  data Pw instance IrreducibleMonic Fq6 Pw where-  split _ = x ^ (2 :: Int) - t x+  split _ = X2 - Y X type Fq12 = ExtensionField Fq6 Pw  testExtensionField :: TestTree testExtensionField = testGroup "Extension fields"-  [ 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 )+  [ test' "FS4"   (witness :: FS4  ) -- not implemented.+  , test  "FS8"   (witness :: FS8  )+  , test  "FS8'"  (witness :: FS8' )+  , test  "FS9"   (witness :: FS9  )+  , test  "FS9'"  (witness :: FS9' )+  , test  "FS9''" (witness :: FS9'')+  , test  "FL0"   (witness :: FL0  )+  , test  "FL1"   (witness :: FL1  )+  , test  "FL2"   (witness :: FL2  )+  , test  "FL3"   (witness :: FL3  )+  , test  "FL4"   (witness :: FL4  )+  , test  "FV2"   (witness :: FV2  )+  , test  "FX2"   (witness :: FX2  )+  , test  "FZ2"   (witness :: FZ2  )+  , test  "Fq2"   (witness :: Fq2  )+  , test' "Fq6"   (witness :: Fq6  ) -- time out.+  , test' "Fq12"  (witness :: Fq12 ) -- time out.   ]
tests/GaloisFieldTests.hs view
@@ -45,24 +45,17 @@   ]  squareRoots :: forall k . GaloisField k => k -> TestTree-squareRoots _ = testGroup "Square roots"+squareRoots _ = localOption (QuickCheckTests 10) $ 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"+  , 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]+test s x = testGroup s [fieldAxioms x, squareRoots x] -testBF :: forall k . GaloisField k => TestName -> k -> TestTree-testBF s x = testGroup s [fieldAxioms x]+test' :: forall k . GaloisField k => TestName -> k -> TestTree+test' s x = testGroup s [fieldAxioms x]