packages feed

pairing-0.3.0: tests/TestFields.hs

{-# LANGUAGE ScopedTypeVariables #-}

module TestFields where

import Protolude

import Pairing.Fq as Fq
import Pairing.Fr as Fr
import Pairing.Fq2 as Fq2
import Pairing.Fq6 as Fq6
import Pairing.Fq12

import Test.Tasty
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit

import TestCommon

-------------------------------------------------------------------------------
-- Generators
-------------------------------------------------------------------------------

instance Arbitrary Fq where
  arbitrary = Fq.new <$> arbitrary

instance Arbitrary Fr where
  arbitrary = Fr.new <$> arbitrary

instance Arbitrary Fq2 where
  arbitrary = Fq2 <$> arbitrary <*> arbitrary

instance Arbitrary Fq6 where
  arbitrary = Fq6
    <$> arbitrary
    <*> arbitrary
    <*> arbitrary

instance Arbitrary Fq12 where
  arbitrary = Fq12 <$> arbitrary <*> arbitrary

-------------------------------------------------------------------------------
-- Laws of field operations
-------------------------------------------------------------------------------

testFieldLaws
  :: forall a . (Num a, Fractional a, Eq a, Arbitrary a, Show a)
  => Proxy a
  -> TestName
  -> TestTree
testFieldLaws _ descr
  = testGroup ("Test field laws of " <> descr)
    [ testProperty "commutativity of addition"
      $ commutes ((+) :: a -> a -> a)
    , testProperty "commutativity of multiplication"
      $ commutes ((*) :: a -> a -> a)
    , testProperty "associavity of addition"
      $ associates ((+) :: a -> a -> a)
    , testProperty "associavity of multiplication"
      $ associates ((*) :: a -> a -> a)
    , testProperty "additive identity"
      $ isIdentity ((+) :: a -> a -> a) 0
    , testProperty "multiplicative identity"
      $ isIdentity ((*) :: a -> a -> a) 1
    , testProperty "additive inverse"
      $ isInverse ((+) :: a -> a -> a) negate 0
    , testProperty "multiplicative inverse"
      $ \x -> (x /= (0 :: a)) ==> isInverse ((*) :: a -> a -> a) recip 1 x
    , testProperty "multiplication distributes over addition"
      $ distributes ((*) :: a -> a -> a) (+)
    ]

-------------------------------------------------------------------------------
-- Fq
-------------------------------------------------------------------------------

test_fieldLaws_Fq :: TestTree
test_fieldLaws_Fq = testFieldLaws (Proxy :: Proxy Fq) "Fq"

-------------------------------------------------------------------------------
-- Fr
-------------------------------------------------------------------------------

test_fieldLaws_Fr :: TestTree
test_fieldLaws_Fr = testFieldLaws (Proxy :: Proxy Fr) "Fr"

-------------------------------------------------------------------------------
-- Fq2
-------------------------------------------------------------------------------

test_fieldLaws_Fq2 :: TestTree
test_fieldLaws_Fq2 = testFieldLaws (Proxy :: Proxy Fq2) "Fq2"

-- Defining property for Fq2 as an extension over Fq: u^2 = -1
unit_uRoot :: Assertion
unit_uRoot = u^2 @=? minusOne
  where
    u = Fq2.new 0 1
    minusOne = Fq2.new (-1) 0

unit_fq2pow :: Assertion
unit_fq2pow = do
  fq2 <- Fq2.random
  let pow5 = fq2sqr (fq2sqr fq2) * fq2
  pow5 @=?  fq2pow fq2 5
  let pow10 = ((fq2sqr (fq2sqr (fq2sqr fq2))) * fq2) * fq2
  pow10 @=?  fq2pow fq2 10
  where
    u = Fq2.new 0 1
    minusOne = Fq2.new (-1) 0

unit_fq2sqrt :: Assertion
unit_fq2sqrt = do
  fq2 <- Fq2.random
  let sq = fq2sqr fq2
  let (Just rt) = fq2sqrt sq
  sq @=? fq2sqr rt

-------------------------------------------------------------------------------
-- Fq6
-------------------------------------------------------------------------------

test_fieldLaws_Fq6 :: TestTree
test_fieldLaws_Fq6 = testFieldLaws (Proxy :: Proxy Fq6) "Fq6"

-- Defining property for Fq6 as an extension over Fq2: v^3 = 9 + u
unit_vRoot :: Assertion
unit_vRoot = v^3 @=? ninePlusU
  where
    v = Fq6.new 0 1 0
    ninePlusU = Fq6.new (Fq2.new 9 1) 0 0


-------------------------------------------------------------------------------
-- Fq12
-------------------------------------------------------------------------------

test_fieldLaws_Fq12 :: TestTree
test_fieldLaws_Fq12 = testFieldLaws (Proxy :: Proxy Fq12) "Fq12"

-- Defining property for Fq12 as an extension over Fq6: w^2 = v
unit_wRoot :: Assertion
unit_wRoot = w^2 @=? v
  where
    w = Fq12 0 1
    v = Fq12 (Fq6 0 1 0) 0