packages feed

pairing-0.4.2: tests/TestFields.hs

module TestFields where

import Protolude

import GaloisField
import ExtensionField
import Pairing.Fq
import Pairing.Fr
import Pairing.ByteRepr
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import qualified Test.QuickCheck.Monadic as TQM (monadicIO, assert, run)

import TestCommon

-------------------------------------------------------------------------------
-- 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 "associativity of addition"
      $ associates ((+) :: a -> a -> a)
    , testProperty "associativity 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"

-------------------------------------------------------------------------------
-- 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 @=? -1
  where
    u = toField [0, 1] :: Fq2

unit_fq2Pow :: Assertion
unit_fq2Pow = do
  fq2 :: Fq2 <- rnd
  let pow5 = ((fq2 ^ 2) ^ 2) * fq2
  pow5 @=? fq2 ^ 5
  let pow10 = ((((fq2 ^ 2) ^ 2) ^ 2) * fq2) * fq2
  pow10 @=? fq2 ^ 10

unit_fq2Sqrt :: Assertion
unit_fq2Sqrt = do
  fq2 :: Fq2 <- rnd
  let sq = fq2 ^ 2
  let (Just rt) = fq2Sqrt sq
  sq @=? rt ^ 2

-------------------------------------------------------------------------------
-- 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 @=? 9 + u
  where
    v = toField [0, 1] :: Fq6
    u = toField [toField [0, 1]]

-------------------------------------------------------------------------------
-- 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 = toField [0, 1] :: Fq12
    v = toField [toField [0, 1]]

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

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

-------------------------------------------------------------------------------
-- Byte Representation
-------------------------------------------------------------------------------

primeFieldByteRepresentationTest :: Fq -> Assertion
primeFieldByteRepresentationTest f = do
  byteReprTest f MostSignificantFirst 32
  byteReprTest f LeastSignificantFirst 32
  byteReprTest f MostSignificantFirst 64
  byteReprTest f LeastSignificantFirst 64

extensionFieldByteRepresentationTest :: (Show a, Eq a, ByteRepr (ExtensionField a b)) => ExtensionField a b -> Assertion
extensionFieldByteRepresentationTest f = case fromField f of
  [] -> pure ()
  _ -> do
    byteReprTest f MostSignificantFirst 32
    byteReprTest f LeastSignificantFirst 32
    byteReprTest f MostSignificantFirst 64
    byteReprTest f LeastSignificantFirst 64

byteReprTest :: (Show a, Eq a, ByteRepr a) => a -> Pairing.ByteRepr.ByteOrder -> Int -> Assertion
byteReprTest f bo sz = do 
  let t = mkRepr (ByteOrderLength bo sz) f
  assertBool ("mkRepr " <> show f) (isJust t)
  let Just bs = t
  let d = fromRepr (ByteOrderLength bo sz) f bs
  assertBool ("fromRepr " <> show f) (isJust d)
  (Just f) @=? d

prop_fqByteRepr :: Fq -> Property
prop_fqByteRepr a = TQM.monadicIO $ TQM.run $ primeFieldByteRepresentationTest a

prop_fq2ByteRepr :: Fq2 -> Property
prop_fq2ByteRepr a = TQM.monadicIO $ TQM.run $ extensionFieldByteRepresentationTest a

prop_fq6ByteRepr :: Fq6 -> Property
prop_fq6ByteRepr a = TQM.monadicIO $ TQM.run $ extensionFieldByteRepresentationTest a

prop_fq12ByteRepr :: Fq12 -> Property
prop_fq12ByteRepr a = TQM.monadicIO $ TQM.run $ extensionFieldByteRepresentationTest a