bitcoin-hs-0.0.1: Bitcoin/Test/Crypto/Projective.hs
{-# LANGUAGE CPP, BangPatterns, ForeignFunctionInterface #-}
module Bitcoin.Test.Crypto.Projective where
--------------------------------------------------------------------------------
import Test.Tasty
import Test.Tasty.QuickCheck
import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable )
import Bitcoin.Crypto.FiniteField.Fast.Fp hiding ( secp256k1_p )
import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )
import Bitcoin.Crypto.EC.Curve
import Bitcoin.Crypto.EC.Projective
import Bitcoin.Test.Crypto.Curve ()
import Bitcoin.Test.Misc.QuickCheck
--------------------------------------------------------------------------------
testgroup_Projective :: TestTree
testgroup_Projective = testGroup "EC.Projective" [ testgroup_proj , testgroup_ecp ]
testgroup_proj :: TestTree
testgroup_proj = testGroup "proj (projective curve representation)"
[ testProperty "left unit" prop_proj_left_unit
, testProperty "right unit" prop_proj_right_unit
, testProperty "0 + 0 = 0" prop_proj_add_dbl_unit
, testProperty "2*0 = 0" prop_proj_dbl_unit
, testProperty "-0 = 0" prop_proj_inv_unit -- 5
, testProperty "(p+q)-q = p" prop_proj_add_sub
, testProperty "((p+q)-q)-p = 0" prop_proj_add_sub2
, testProperty "2*p - p = p" prop_proj_dbl_sub
, testProperty "2*p - p - p = 0" prop_proj_dbl_sub2
, testProperty "addition is commutative" prop_proj_add_commutative -- 10
, testProperty "addition is associative" prop_proj_add_associative
, testProperty "(p-q)-r = p-(q+r)" prop_proj_add_sub_associative1
, testProperty "(p-q)+r = p-(q-r)" prop_proj_add_sub_associative2
, testProperty "p + (-p) = 0" prop_proj_add_inv
, testProperty "k*p = (k mod n)*p" prop_proj_mul_big -- 15
, testProperty "0*p = 0" prop_proj_mul_0
, testProperty "1*p = p" prop_proj_mul_1
, testProperty "2*p = p + p" prop_proj_mul_2
, testProperty "n*p = 0" prop_proj_mul_n -- 20
, testProperty "(n-1)*p = -p" prop_proj_mul_nminus1
, testProperty "hs add = c add" prop_proj_add_chs
, testProperty "hs dbl = c dbl" prop_proj_dbl_chs
, testProperty "hs mul = c mul" prop_proj_mul_chs
]
testgroup_ecp :: TestTree
testgroup_ecp = testGroup "ecp (projective vs. affine conversions)"
[ testProperty "fromP . toP = id" prop_ecp_from_to
, testProperty "toP (fromP p) ~ p" prop_ecp_to_from
, testProperty "proj. addition" prop_ecp_add
, testProperty "proj. subtraction" prop_ecp_sub
, testProperty "proj. doubling /1" prop_ecp_add_dbl1
, testProperty "proj. doubling /2" prop_ecp_add_dbl2
, testProperty "proj. doubling /3" prop_ecp_add_dbl3
, testProperty "proj. doubling /4" prop_ecp_add_dbl4
, testProperty "proj. doubling /5" prop_ecp_dbl
, testProperty "proj. inverse /1" prop_ecp_inv1
, testProperty "proj. inverse /2" prop_ecp_inv2
, testProperty "proj. inverse /3" prop_ecp_inv3
, testProperty "proj. multiplication" prop_ecp_mul
]
--------------------------------------------------------------------------------
-- * quickcheck
scaleECProj :: Integer -> ECProj -> ECProj
scaleECProj n0 (ECProj x y z) = ECProj (x*n2) (y*n3) (z*n) where
n = toFp n0
n2 = n*n
n3 = n2*n
newtype NonZeroECP = NonZeroECP ECProj deriving (Eq,Show)
data Same = Same ECProj ECProj deriving (Eq,Show)
instance Arbitrary ECProj where
arbitrary = do
ec <- arbitrary
z <- toFp <$> choose (1,secp256k1_p-1)
let z2 = z*z
let z3 = z2*z
return $ case ec of
ECPoint x y -> ECProj (x*z2) (y*z3*2) z
ECInfinity -> ecpInfinity
instance Arbitrary NonZeroECP where
arbitrary = do
n <- choose (1,secp256k1_n-1)
return $ NonZeroECP $ mulECP (secp256k1_G_proj) n
instance Arbitrary Same where
arbitrary = do
ep@(ECProj x y z) <- arbitrary
m <- toFp <$> choose (1,secp256k1_p-1)
return $ Same ep (ECProj (x*m*m) (y*m*m*m) (z*m))
--------------------------------------------------------------------------------
{-
runAllTests_ec_proj :: IO ()
runAllTests_ec_proj = runAllTests_ec_proj' 1000
runAllTests_ec_proj' :: Int -> IO ()
runAllTests_ec_proj' n = do
let args = stdArgs { maxSuccess = n }
let qc :: Testable prop => prop -> IO ()
qc = quickCheckWith args
putStrLn "running all tests in Bitcoin.Crypto.EC.Projective"
putStrLn "================================================="
qc prop_proj_left_unit
qc prop_proj_right_unit
qc prop_proj_add_dbl_unit
qc prop_proj_dbl_unit
qc prop_proj_inv_unit -- 5
qc prop_proj_add_sub
qc prop_proj_add_sub2
qc prop_proj_dbl_sub
qc prop_proj_dbl_sub2
qc prop_proj_add_commutative -- 10
qc prop_proj_add_associative
qc prop_proj_add_sub_associative1
qc prop_proj_add_sub_associative2
qc prop_proj_add_inv
qc prop_proj_mul_big -- 15
qc prop_proj_mul_0
qc prop_proj_mul_1
qc prop_proj_mul_2
qc prop_proj_mul_n -- 20
qc prop_proj_mul_nminus1
qc prop_proj_add_chs
qc prop_proj_dbl_chs
qc prop_proj_mul_chs
putStrLn "-------------------------------------------------"
qc prop_ecp_from_to
qc prop_ecp_to_from
qc prop_ecp_add
qc prop_ecp_add_dbl1
qc prop_ecp_add_dbl2
qc prop_ecp_add_dbl3
qc prop_ecp_add_dbl4
qc prop_ecp_dbl
qc prop_ecp_sub
qc prop_ecp_inv1
qc prop_ecp_inv2
qc prop_ecp_inv3
qc prop_ecp_mul
-}
--------------------------------------------------------------------------------
prop_proj_left_unit :: ECProj -> Bool
prop_proj_left_unit p = addECP p ecpInfinity =~= p
prop_proj_right_unit :: ECProj -> Bool
prop_proj_right_unit q = addECP ecpInfinity q =~= q
prop_proj_add_dbl_unit :: Bool
prop_proj_add_dbl_unit = ecpInfinity + ecpInfinity =~= ecpInfinity
prop_proj_dbl_unit :: Bool
prop_proj_dbl_unit = dblECP ecpInfinity =~= ecpInfinity
prop_proj_inv_unit :: Bool
prop_proj_inv_unit = invECP ecpInfinity =~= ecpInfinity
prop_proj_add_sub :: ECProj -> ECProj -> Bool
prop_proj_add_sub p q = subECP (addECP p q) q =~= p
prop_proj_add_sub2 :: ECProj -> ECProj -> Bool
prop_proj_add_sub2 p q = subECP (subECP (addECP p q) q) p =~= ecpInfinity
prop_proj_dbl_sub :: ECProj -> Bool
prop_proj_dbl_sub p = subECP (dblECP p) p =~= p
prop_proj_dbl_sub2 :: ECProj -> Bool
prop_proj_dbl_sub2 p = subECP (subECP (dblECP p) p) p =~= ecpInfinity
prop_proj_add_commutative :: ECProj -> ECProj -> Bool
prop_proj_add_commutative p q = (addECP p q) =~= (addECP q p)
prop_proj_add_associative :: ECProj -> ECProj -> ECProj -> Bool
prop_proj_add_associative p q r = addECP (addECP p q) r =~= addECP p (addECP q r)
prop_proj_add_sub_associative1 :: ECProj -> ECProj -> ECProj -> Bool
prop_proj_add_sub_associative1 p q r = subECP (subECP p q) r =~= subECP p (addECP q r)
prop_proj_add_sub_associative2 :: ECProj -> ECProj -> ECProj -> Bool
prop_proj_add_sub_associative2 p q r = addECP (subECP p q) r =~= subECP p (subECP q r)
prop_proj_add_inv :: ECProj -> Bool
prop_proj_add_inv p = addECP p (invECP p) =~= ecpInfinity
prop_proj_mul_big :: ECProj -> BigInt -> Bool
prop_proj_mul_big p (BigInt k) = mulECP p k =~= mulECP p (mod k secp256k1_n)
prop_proj_mul_0 :: ECProj -> Bool
prop_proj_mul_0 p = mulECP p 0 =~= ecpInfinity
prop_proj_mul_1 :: ECProj -> Bool
prop_proj_mul_1 p = mulECP p 1 =~= p
prop_proj_mul_2 :: ECProj -> Bool
prop_proj_mul_2 p = mulECP p 2 =~= addECP p p
prop_proj_mul_n :: ECProj -> Bool
prop_proj_mul_n p = mulECP p secp256k1_n =~= ecpInfinity
prop_proj_mul_nminus1 :: ECProj -> Bool
prop_proj_mul_nminus1 p = mulECP p (secp256k1_n - 1) =~= invECP p
prop_proj_dbl_chs :: ECProj -> Bool
prop_proj_dbl_chs p = hs_dblECP p == c_dblECP p
prop_proj_add_chs :: ECProj -> ECProj -> Bool
prop_proj_add_chs p q = hs_addECP p q == c_addECP p q
prop_proj_mul_chs :: ECProj -> BigInt -> Bool
prop_proj_mul_chs p (BigInt n) = c_mulECP p n =~= hs_mulECP p n
--------------------------------------------------------------------------------
prop_ecp_to_from :: ECPoint -> Bool
prop_ecp_to_from p = fromECProj (toECProj p) == p
prop_ecp_from_to :: ECProj -> Bool
prop_ecp_from_to p = toECProj (fromECProj p) =~= p
prop_ecp_add :: ECPoint -> ECPoint -> Bool
prop_ecp_add p q = p + q == fromECProj (toECProj p + toECProj q)
prop_ecp_add_dbl1 :: ECPoint -> Bool
prop_ecp_add_dbl1 p = p + p == fromECProj (toECProj p + toECProj p)
prop_ecp_add_dbl2 :: ECPoint -> Bool
prop_ecp_add_dbl2 p = dblEC p == fromECProj (toECProj p + toECProj p)
prop_ecp_add_dbl3 :: Same -> Bool
prop_ecp_add_dbl3 (Same p q) = fromECProj p + fromECProj q == fromECProj (p+q)
prop_ecp_add_dbl4 :: Same -> Bool
prop_ecp_add_dbl4 (Same p q) = dblEC (fromECProj p) == fromECProj (p+q)
prop_ecp_sub :: ECPoint -> ECPoint -> Bool
prop_ecp_sub p q = p - q == fromECProj (toECProj p - toECProj q)
prop_ecp_dbl :: ECPoint -> Bool
prop_ecp_dbl p = dblEC p == fromECProj (dblECP $ toECProj p)
prop_ecp_inv1 :: ECPoint -> Bool
prop_ecp_inv1 p = invEC p == fromECProj (invECP $ toECProj p)
prop_ecp_inv2 :: ECPoint -> Bool
prop_ecp_inv2 p = ecpInfinity =~= (invECP $ toECProj p) + (toECProj p)
prop_ecp_inv3 :: Same -> Bool
prop_ecp_inv3 (Same p q) = (invECP p =~= invECP q)
prop_ecp_mul :: ECPoint -> BigInt -> Bool
prop_ecp_mul p (BigInt n) = fromECProj (mulECP (toECProj p) n) == mulEC p n
--------------------------------------------------------------------------------