module Test.Curve where import Protolude import Data.Curve import Data.Group import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Test.Field doubleIdentities :: (Eq a, Eq b) => (a -> b) -> (b -> a) -> a -> b -> Bool doubleIdentities f t e e' = f e == e' && t e' == e doubleDefined :: (a -> Bool) -> (b -> Bool) -> (b -> a) -> b -> Bool doubleDefined d d' t x = d' x && d (t x) doubleInverses :: (Eq a, Eq b) => (a -> b) -> (b -> a) -> b -> Bool doubleInverses f t x = f (t x) == x && t (f (t x)) == t x doubleHomeomorphism :: (Eq a, Eq b) => (a -> a) -> (b -> b) -> (a -> b) -> (b -> a) -> b -> Bool doubleHomeomorphism op op' f t x = t (op' x) == op (t x) && f (op (t x)) == op' x curveAxioms :: forall f c e q r . (Curve f 'Affine e q r, Curve f c e q r) => Point f c e q r -> TestTree curveAxioms g = testGroup "Curve axioms" [ testCase "identity closure" $ def (mempty :: Point f c e q r) @?= True , testProperty "point closure" $ (def :: Point f c e q r -> Bool) , testProperty "inversion closure" $ def . (inv :: Point f c e q r -> Point f c e q r) , testProperty "addition closure" $ (.) def . ((<>) :: Point f c e q r -> Point f c e q r -> Point f c e q r) , testProperty "doubling closure" $ def . (join (<>) :: Point f c e q r -> Point f c e q r) , testProperty "multiplication closure" $ def . (flip mul' (-3 :: Int) :: Point f c e q r -> Point f c e q r) , testCase "discriminant is nonzero" $ disc g /= 0 @?= True , testCase "generator is well-defined" $ def g @?= True , testCase "affine transformation is doubly identity-preserving" $ doubleIdentities fromA (toA :: Point f c e q r -> Point f 'Affine e q r) mempty mempty @?= True , testProperty "affine transformation is doubly well-defined" $ doubleDefined def def (toA :: Point f c e q r -> Point f 'Affine e q r) , testProperty "affine transformation is doubly invertible" $ doubleInverses fromA (toA :: Point f c e q r -> Point f 'Affine e q r) , testProperty "affine transformation is doubly homeomorphic" $ doubleHomeomorphism (flip mul 3) (flip mul 3) fromA (toA :: Point f c e q r -> Point f 'Affine e q r) ] testCurve :: forall f c e q r . (Curve f c e q r, Curve f 'Affine e q r) => TestName -> Point f c e q r -> TestTree testCurve s g = testGroup s [ testGroup "Group axioms" $ groupAxioms (<>) invert (mempty :: Point f c e q r) (const True) , curveAxioms g ]