Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development #15

Merged
merged 11 commits into from
Jul 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
# Change log for galois-field

## 0.2.1
* Add preliminary implementation of BinaryField.
* Add `frob` function for GaloisField.
* Add minor improvements to documentation.

## 0.2.0

* Add `deg` for GaloisField
* Add `order` for GaloisField
* Add `pow` for GaloisField
* Add `rnd` for GaloisField
* Add `deg` function for GaloisField.
* Add `order` function for GaloisField.
* Add `pow` function for GaloisField.
* Add `rnd` function for GaloisField.

## 0.1.1

* Add `Arbitrary` instances to PrimeField, PolynomialRing, and ExtensionField.
* Add `Bits` instances to PrimeField.
* Add `Pretty` instances to PrimeField, PolynomialRing, and ExtensionField.
* Minor optimisations to multiplication and inversion with `INLINE`.
* Add minor optimisations to multiplication and inversion with `INLINE`.

## 0.1.0

Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<p align="center">
<a href="https://www.adjoint.io">
<img width="250" src="./.assets/adjoint.png" alt="Adjoint Logo" />
</a>
<a href="https://www.adjoint.io">
<img width="250" src="./.assets/adjoint.png" alt="Adjoint Logo" />
</a>
</p>


Expand All @@ -14,11 +14,11 @@ An efficient implementation of Galois fields used in cryptography research.

## Technical background

A **Galois field** GF(p<sup>q</sup>), for prime p and positive q, is a *field* (GF(p<sup>q</sup>), +, \*, 0, 1) of finite *order*. Explicitly,
- (GF(p<sup>q</sup>), +, 0) is an abelian group,
- (GF(p<sup>q</sup>) \\ \{0\}, \*, 1) is an abelian group,
A **Galois field** GF(p^q), for prime p and positive q, is a *field* (GF(p^q), +, \*, 0, 1) of finite *order*. Explicitly,
- (GF(p^q), +, 0) is an abelian group,
- (GF(p^q) \\ \{0\}, \*, 1) is an abelian group,
- \* is distributive over +, and
- \#GF(p<sup>q</sup>) is finite.
- \#GF(p^q) is finite.

### Prime fields

Expand All @@ -28,9 +28,9 @@ For example, GF(4) is a Galois field of characteristic 2 that is a two-dimension

### Extension fields

Any Galois field has order a prime power p<sup>q</sup> for prime p and positive q, and there is a Galois field GF(p<sup>q</sup>) of any prime power order p<sup>q</sup> that is *unique up to non-unique isomorphism*. Any Galois field GF(p<sup>q</sup>) can be constructed as an **extension field** over a smaller Galois subfield GF(p<sup>r</sup>), through the identification GF(p<sup>q</sup>) = GF(p<sup>r</sup>)[X] / \<f(X)\> for an *irreducible monic splitting polynomial* f(X) of degree q - r + 1 in the *polynomial ring* GF(p<sup>r</sup>)[X].
Any Galois field has order a prime power p^q for prime p and positive q, and there is a Galois field GF(p^q) of any prime power order p^q that is *unique up to non-unique isomorphism*. Any Galois field GF(p^q) can be constructed as an **extension field** over a smaller Galois subfield GF(p^r), through the identification GF(p^q) = GF(p^r)[X] / \<f(X)\> for an *irreducible monic splitting polynomial* f(X) of degree q - r + 1 in the *polynomial ring* GF(p^r)[X].

For example, GF(4) has order 2<sup>2</sup> and can be constructed as an extension field GF(2)[X] / \<f(X)\> where f(X) = X<sup>2</sup> + X + 1 is an irreducible monic splitting quadratic polynomial in GF(2)[X].
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].

## Example usage

Expand Down
6 changes: 3 additions & 3 deletions benchmarks/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fq' = 10757805228921058098980668000791497318123219899766237205512608761387909753

data Pu
instance IrreducibleMonic Fq Pu where
split _ = x^2 + 1
split _ = x ^ (2 :: Int) + 1
type Fq2 = ExtensionField Fq Pu

fq2 :: Fq2
Expand All @@ -33,7 +33,7 @@ fq2' = fromList

data Pv
instance IrreducibleMonic Fq2 Pv where
split _ = x^3 - (9 + t x)
split _ = x ^ (3 :: Int) - (9 + t x)
type Fq6 = ExtensionField Fq2 Pv

fq6 :: Fq6
Expand Down Expand Up @@ -70,7 +70,7 @@ fq6' = fromList

data Pw
instance IrreducibleMonic Fq6 Pw where
split _ = x^2 - t x
split _ = x ^ (2 :: Int) - t x
type Fq12 = ExtensionField Fq6 Pw

fq12 :: Fq12
Expand Down
19 changes: 8 additions & 11 deletions package.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: galois-field
version: 0.2.0
version: 0.2.1
synopsis: Galois field library
description: Galois field library for cryptography research
description: An efficient implementation of Galois fields used in cryptography research
maintainer: Adjoint Inc ([email protected])
license: MIT
github: adjoint-io/galois-field
Expand Down Expand Up @@ -34,14 +34,16 @@ extra-source-files:
- README.md
- ChangeLog.md

ghc-options:
- -O2
- -Wall

library:
exposed-modules:
- BinaryField
- ExtensionField
- GaloisField
- PrimeField
- ExtensionField
ghc-options:
- -O2
- -Wall
other-modules:
- PolynomialRing
source-dirs:
Expand All @@ -52,9 +54,6 @@ tests:
main: Main
dependencies:
- tasty
- tasty-discover
ghc-options:
- -O2
source-dirs:
- tests
- src
Expand All @@ -64,8 +63,6 @@ benchmarks:
main: Main
dependencies:
- criterion
ghc-options:
- -O2
source-dirs:
- benchmarks
- src
108 changes: 108 additions & 0 deletions src/BinaryField.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
module BinaryField
( BinaryField
) where

import Protolude

import Control.Monad.Random (Random(..), getRandom)
import Test.Tasty.QuickCheck (Arbitrary(..), choose)
import Text.PrettyPrint.Leijen.Text (Pretty(..))

import GaloisField (GaloisField(..))

-- | 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 #-}

-- Binary fields are Galois fields.
instance KnownNat ib => GaloisField (BinaryField ib) where
char = const 2
{-# INLINE char #-}
deg = bin . natVal
{-# INLINE deg #-}
frob = flip pow 2
{-# INLINE frob #-}
pow = (^)
{-# INLINE pow #-}
rnd = getRandom
{-# INLINE rnd #-}

-- Binary fields are fields.
instance KnownNat ib => Num (BinaryField ib) where
BF x + BF y = BF (xor x y)
{-# INLINE (+) #-}
BF x * BF y = fromInteger (mul x y)
{-# INLINE (*) #-}
BF x - BF y = BF (xor x y)
{-# INLINE (-) #-}
negate = identity
{-# INLINE negate #-}
fromInteger = BF . red (natVal (witness :: BinaryField ib))
{-# INLINABLE fromInteger #-}
abs = panic "not implemented."
signum = panic "not implemented."

-- Binary fields are pretty.
instance KnownNat ib => Pretty (BinaryField ib) 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)
randomR = panic "not implemented."

-- Binary logarithm.
bin :: Integer -> Int
bin = logP 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))
where
log' :: Int -> Integer -> Int
log' q y = if y < p then q else log' (q + 1) (quot y p)
{-# INLINE bin #-}

-- Binary multiplication.
mul :: Integer -> Integer -> Integer
mul x y = mul' (bin y) (if testBit y 0 then x else 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 #-}

-- Binary reduction.
red :: Integer -> Integer -> Integer
red f = red'
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 #-}

-- Binary inversion.
inv :: Integer -> Integer -> Maybe Integer
inv f x = case inv' 1 x 0 f of
(y, 1) -> Just y
_ -> Nothing
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 #-}
Loading