{-# 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