{-# LANGUAGE OverloadedStrings #-} module KAT_PubKey.ECC (eccTests, eccKatTests) where import Control.Arrow (second) import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.ECC.Prim as ECC import Test.Tasty.KAT import Test.Tasty.KAT.FileLoader import Imports instance Arbitrary ECC.Curve where arbitrary = ECC.getCurveByName <$> elements [ ECC.SEC_p112r1 , ECC.SEC_p112r2 , ECC.SEC_p128r1 , ECC.SEC_p128r2 , ECC.SEC_p160k1 , ECC.SEC_p160r1 , ECC.SEC_p160r2 , ECC.SEC_p192k1 , ECC.SEC_p192r1 , ECC.SEC_p224k1 , ECC.SEC_p224r1 , ECC.SEC_p256k1 , ECC.SEC_p256r1 , ECC.SEC_p384r1 , ECC.SEC_p521r1 , ECC.SEC_t113r1 , ECC.SEC_t113r2 , ECC.SEC_t131r1 , ECC.SEC_t131r2 , ECC.SEC_t163k1 , ECC.SEC_t163r1 , ECC.SEC_t163r2 , ECC.SEC_t193r1 , ECC.SEC_t193r2 , ECC.SEC_t233k1 , ECC.SEC_t233r1 , ECC.SEC_t239k1 , ECC.SEC_t283k1 , ECC.SEC_t283r1 , ECC.SEC_t409k1 , ECC.SEC_t409r1 , ECC.SEC_t571k1 , ECC.SEC_t571r1 ] data VectorPoint = VectorPoint { curve :: ECC.Curve , x :: Integer , y :: Integer , valid :: Bool } vectorsPoint = [ VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x491c0c4761b0a4a147b5e4ce03a531546644f5d1e3d05e57 , y = 0x6fa5addd47c5d6be3933fbff88f57a6c8ca0232c471965de , valid = False -- point not on curve } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x646c22e8aa5f7833390e0399155ac198ae42470bba4fc834 , y = 0x8d4afcfffd80e69a4d180178b37c44572495b7b267ee32a9 , valid = True } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x4c6b9ea0dec92ecfff7799470be6a2277b9169daf45d54bb , y = 0xf0eab42826704f51b26ae98036e83230becb639dd1964627 , valid = False -- point not on curve } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x0673c8bb717b055c3d6f55c06acfcfb7260361ed3ec0f414 , y = 0xba8b172826eb0b854026968d2338a180450a27906f6eddea , valid = True } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x82c949295156192df0b52480e38c810751ac570daec460a3 , y = 0x200057ada615c80b8ff256ce8d47f2562b74a438f1921ac3 , valid = False -- point not on curve } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x284fbaa76ce0faae2ca4867d01092fa1ace5724cd12c8dd0 , y = 0xe42af3dbf3206be3fcbcc3a7ccaf60c73dc29e7bb9b44fca , valid = True } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x1b574acd4fb0f60dde3e3b5f3f0e94211f95112e43cba6fd2 , y = 0xbcc1b8a770f01a22e84d7f14e44932ffe094d8e3b1e6ac26 , valid = False -- x or y out of range } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x16ba109f1f1bb44e0d05b80181c03412ea764a59601d17e9f , y = 0x0569a843dbb4e287db420d6b9fe30cd7b5d578b052315f56 , valid = False -- x or y out of range } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x1333308a7c833ede5189d25ea3525919c9bd16370d904938d , y = 0xb10fd01d67df75ff9b726c700c1b50596c9f0766ea56f80e , valid = False -- x or y out of range } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x9671ec444cff24c8a5be80b018fa505ed6109a731e88c91a , y = 0xfe79dae23008e46bf4230c895aab261a95845a77f06d0655 , valid = True } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0x158e8b6f0b14216bc52fe8897b4305d870ede70436a96741d , y = 0xfb3f970b19a313571a1a23be310923f85acc1cab0a157cbd , valid = False -- x or y out of range } , VectorPoint { curve = ECC.getCurveByName ECC.SEC_p192r1 , x = 0xace95b650c08f73dbb4fa7b4bbdebd6b809a25b28ed135ef , y = 0xe9b8679404166d1329dd539ad52aad9a1b6681f5f26bb9aa , valid = False -- point not on curve } ] doPointValidTest (i, vector) = testCase (show i) (valid vector @=? ECC.isPointValid (curve vector) (ECC.Point (x vector) (y vector))) arbitraryPoint :: ECC.Curve -> Gen ECC.Point arbitraryPoint aCurve = frequency [(5, return ECC.PointO), (95, pointGen)] where n = ECC.ecc_n (ECC.common_curve aCurve) pointGen = ECC.pointBaseMul aCurve <$> choose (1, n - 1) eccTests = testGroup "ECC" [ testGroup "valid-point" $ map doPointValidTest (zip [katZero..] vectorsPoint) , testGroup "property" [ testProperty "point-add" $ \aCurve (QAInteger r1) (QAInteger r2) -> let curveN = ECC.ecc_n . ECC.common_curve $ aCurve curveGen = ECC.ecc_g . ECC.common_curve $ aCurve p1 = ECC.pointMul aCurve r1 curveGen p2 = ECC.pointMul aCurve r2 curveGen pR = ECC.pointMul aCurve ((r1 + r2) `mod` curveN) curveGen in pR `propertyEq` ECC.pointAdd aCurve p1 p2 , localOption (QuickCheckTests 20) $ testProperty "point-mul-mul" $ \aCurve (QAInteger n1) (QAInteger n2) -> do p <- arbitraryPoint aCurve let pRes = ECC.pointMul aCurve (n1 * n2) p let pDef = ECC.pointMul aCurve n1 (ECC.pointMul aCurve n2 p) return $ pRes `propertyEq` pDef , localOption (QuickCheckTests 20) $ testProperty "double-scalar-mult" $ \aCurve (QAInteger n1) (QAInteger n2) -> do p1 <- arbitraryPoint aCurve p2 <- arbitraryPoint aCurve let pRes = ECC.pointAddTwoMuls aCurve n1 p1 n2 p2 let pDef = ECC.pointAdd aCurve (ECC.pointMul aCurve n1 p1) (ECC.pointMul aCurve n2 p2) return $ pRes `propertyEq` pDef ] ] eccKatTests = do res <- testKatLoad "KATs/ECC-PKV.txt" (map (second (map toVector)) . katLoaderSimple) return $ testKatDetailed {-Grouped-} "ECC/valid-point" res (\g vect -> do let mCurve = ECC.getCurveByName <$> case g of "P-192" -> Just ECC.SEC_p192r1 "P-224" -> Just ECC.SEC_p224r1 "P-256" -> Just ECC.SEC_p256r1 "P-384" -> Just ECC.SEC_p384r1 "P-521" -> Just ECC.SEC_p521r1 "B-163" -> Just ECC.SEC_t163r2 "B-233" -> Just ECC.SEC_t233r1 "B-283" -> Just ECC.SEC_t283r1 "B-409" -> Just ECC.SEC_t409r1 "B-571" -> Just ECC.SEC_t571r1 "" -> Nothing _ -> Nothing {- "K-163" -> Just ECC.SEC_t163k1 "K-233" -> Just ECC.SEC_t233k1 "K-283" -> Just ECC.SEC_t283k1 "K-409" -> Just ECC.SEC_t409k1 "K-571" -> Just ECC.SEC_t571k1 -} case mCurve of Nothing -> return True Just c -> do return (ECC.isPointValid c (ECC.Point (x vect) (y vect)) == valid vect) ) where toVector kvs = case sequence $ map (flip lookup kvs) [ "Qx", "Qy", "Result" ] of Just [qx,qy,res] -> VectorPoint undefined (valueHexInteger qx) (valueHexInteger qy) (head res /= 'F') Just _ -> error ("ERROR: " ++ show kvs) Nothing -> error ("ERROR: " ++ show kvs) -- VectorPoint undefined 0 0 True