packages feed

mcl-1.0.0: test/Main.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main (main) where

import Data.Binary
import Data.Bits
import Data.Group
import Data.List
import Data.Monoid
import Data.Proxy
import Test.Framework
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck hiding ((.&.))

import MCL.Curves.Fp254BNb

main :: IO ()
main = defaultMain
  [ testGroup "Fr" $ let fr = Proxy :: Proxy Fr in
    [ testProperty "arithmetic"    $ testFieldOps fr
    , testProperty "construction"  $ fr_testFromTo
    , testProperty "square root"   $ fr_testSquareRoot
    , testProperty "serialization" $ testBinary fr
    ]
  , testGroup "Fp" $ let fp = Proxy :: Proxy Fp in
    [ testProperty "arithmetic"    $ testFieldOps fp
    , testProperty "construction"  $ fp_testFromTo
    , testProperty "square root"   $ fp_testSquareRoot
    , testProperty "serialization" $ testBinary fp
    ]
  , testGroup "Fp2" $ let fp2 = Proxy :: Proxy Fp2 in
    [ testProperty "arithmetic"    $ testFieldOps fp2
    , testProperty "construction"  $ fp2_testFromTo
    , testProperty "square root"   $ fp2_testSquareRoot
    , testProperty "serialization" $ testBinary fp2
    ]
  , testGroup "Fp12" $ let fp12 = Proxy :: Proxy Fp12 in
    [ testProperty "arithmetic"    $ testFieldOps fp12
    , testProperty "construction"  $ fp12_testFromTo
    , testProperty "serialization" $ testBinary fp12
    ]
  , testGroup "G1" $ let g1 = Proxy :: Proxy G1 in
    [ testProperty "arithmetic"    $ testGroupOps g1
    , testProperty "serialization" $ testBinary g1
    ]
  , testGroup "G2" $ let g2 = Proxy :: Proxy G2 in
    [ testProperty "arithmetic"    $ testGroupOps g2
    , testProperty "serialization" $ testBinary g2
    ]
  , testGroup "pairing"
    [ testProperty "bilinearity"   $ testPairing
    ]
  ]

----------------------------------------

arbitraryF :: (Integer -> fp) -> Gen fp
arbitraryF mkF = do
  w1 <- (0x1fffffff .&.) <$> arbitrary
  w2 <- arbitrary
  w3 <- arbitrary
  w4 <- arbitrary
  return . mkF $ foldl' assemble 0 [w1, w2, w3, w4]
  where
    assemble :: Integer -> Word64 -> Integer
    assemble acc w = acc `shiftL` 64 .|. fromIntegral w

instance Arbitrary Fr where
  arbitrary = arbitraryF mkFr

instance Arbitrary Fp where
  arbitrary = arbitraryF mkFp

instance Arbitrary Fp2 where
  arbitrary = mkFp2 <$> arbitrary <*> arbitrary

instance Arbitrary Fp12 where
  arbitrary = mkFp12 <$> arbitrary <*> arbitrary <*> arbitrary
                     <*> arbitrary <*> arbitrary <*> arbitrary

instance Arbitrary G1 where
  arbitrary = mapToG1 <$> arbitrary

instance Arbitrary G2 where
  arbitrary = mapToG2 <$> arbitrary

----------------------------------------

testFieldOps
  :: forall proxy fp. (Arbitrary fp, Eq fp, Fractional fp, Show fp)
  => proxy fp
  -> Property
testFieldOps _ = conjoin
  [ property $ \(a::fp) b c -> (a + b) + c == a + (b + c)
  , property $ \(a::fp) b   -> a + b == b + a
  , property $ \(a::fp) b   -> a - b == -(b - a)
  , property $ \(a::fp) b c -> a * (b + c) == a * b + a * c
  , property $ \(a::fp) b c -> (a + b) * c == a * c + b * c
  , property $ \(a::fp)     -> a == -(-a)
  , property $ \(a::fp)     -> recip (recip a) == a
  ]

testGroupOps
  :: forall proxy g. (Arbitrary g, Eq g, Abelian g, Show g)
  => proxy g
  -> Property
testGroupOps _ = conjoin
  [ property $ \(a::g)            -> (a <> mempty) == a
  , property $ \(a::g)            -> (mempty <> a) == a
  , property $ \(a::g) b c        -> (a <> b) <> c == a <> (b <> c)
  , property $ \(a::g) b          -> a <> b == b <> a
  , property $ \(a::g) b          -> a <> invert b == invert (b <> invert a)
  , property $ \(a::g) b (c::Int) -> (a <> b) `pow` c == a `pow` c <> b `pow` c
  , property $ \(a::g)            -> a == invert (invert a)
  ]

testBinary
  :: forall proxy a. (Arbitrary a, Binary a, Eq a, Show a)
  => proxy a
  -> Property
testBinary _ = property $ \(a::a) -> decode (encode a) == a

testPairing :: Property
testPairing = conjoin
  [ property $ \p q r s -> pairing (p <> q) (r <> s) == pairing p r <> pairing p s
                                                     <> pairing q r <> pairing q s
  ]

----------------------------------------

fr_testFromTo :: Fr -> Bool
fr_testFromTo a = a == mkFr (fromFr a)

fp_testFromTo :: Fp -> Bool
fp_testFromTo a = a == mkFp (fromFp a)

fp2_testFromTo :: Fp2 -> Bool
fp2_testFromTo a = a == mkFp2 (fp2_c0 a) (fp2_c1 a)

fp12_testFromTo :: Fp12 -> Bool
fp12_testFromTo a = a == mkFp12 (fp12_c0 a) (fp12_c1 a) (fp12_c2 a)
                                (fp12_c3 a) (fp12_c4 a) (fp12_c5 a)

----------------------------------------

fr_testSquareRoot :: Fr -> Bool
fr_testSquareRoot a = t == Just a || t == Just (-a)
  where
    t = fr_squareRoot (a * a)

fp_testSquareRoot :: Fp -> Bool
fp_testSquareRoot a = t == Just a || t == Just (-a)
  where
    t = fp_squareRoot (a * a)

fp2_testSquareRoot :: Fp2 -> Bool
fp2_testSquareRoot a = t == Just a || t == Just (-a)
  where
    t = fp2_squareRoot (a * a)