packages feed

eccrypto-0.1.0: test/Tests.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Tests
-- Copyright   :  (c) Marcel Fourné 20[09..19]
-- License     :  BSD3
-- Maintainer  :  Marcel Fourné (haskell@marcelfourne.de)
--
-- Test module
--
-----------------------------------------------------------------------------
{-# OPTIONS_GHC -O2 -feager-blackholing #-}

module Tests (tests) where
import Distribution.TestSuite
import Crypto.ECC.Weierstrass.Internal.Curvemath
import Crypto.ECC.Weierstrass.StandardCurves
import Crypto.ECC.Weierstrass.ECDSA as N
import Numeric
import qualified Data.ByteString.Char8 as C8
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as BS16
import qualified Crypto.ECC.Ed25519.Sign as ED
import qualified Crypto.ECC.Ed25519.Internal.Ed25519 as EDi

tests :: IO [Test]
tests =  do
  contentP192 <- readFile "test/P192"
  contentP224 <- readFile "test/P224"
  contentP256 <- readFile "test/P256"
  contentP384 <- readFile "test/P384"
  contentP521 <- readFile "test/P521"
  contentEd25519 <- readFile "test/sign.input"
  let nistp192 = Group { groupName = "NIST P192"
                       , concurrently = True
                       , groupTests =
                           map (test "NIST P192" (\x -> affine (ECi (stdc_l p192) (stdc_b p192) (stdc_p p192) (stdc_r p192)) $ pmul (ECi (stdc_l p192) (stdc_b p192) (stdc_p p192) (stdc_r p192)) (ECPp (stdc_xp p192) (stdc_yp p192) 1) x)) $ parse contentP192
                       }
      nistp224 = Group { groupName = "NIST P224"
                       , concurrently = True
                       , groupTests =
                           map (test "NIST P224" (\x -> affine (ECi (stdc_l p224) (stdc_b p224) (stdc_p p224) (stdc_r p224)) $ pmul (ECi (stdc_l p224) (stdc_b p224) (stdc_p p224) (stdc_r p224)) (ECPp (stdc_xp p224) (stdc_yp p224) 1) x)) $ parse contentP224
                       }
      nistp256 = Group { groupName = "NIST P256"
                       , concurrently = True
                       , groupTests =
                           map (test "NIST P256" (\x -> affine (ECi (stdc_l p256) (stdc_b p256) (stdc_p p256) (stdc_r p256)) $ pmul (ECi (stdc_l p256) (stdc_b p256) (stdc_p p256) (stdc_r p256)) (ECPp (stdc_xp p256) (stdc_yp p256) 1) x)) $ parse contentP256
                       }
      nistp384 = Group { groupName = "NIST P384"
                       , concurrently = True
                       , groupTests =
                           map (test "NIST P384" (\x -> affine (ECi (stdc_l p384) (stdc_b p384) (stdc_p p384) (stdc_r p384)) $ pmul (ECi (stdc_l p384) (stdc_b p384) (stdc_p p384) (stdc_r p384)) (ECPp (stdc_xp p384) (stdc_yp p384) 1) x)) $ parse contentP384
                       }
      nistp521 = Group { groupName = "NIST P521"
                       , concurrently = True
                       , groupTests =
                           map (test "NIST P521" (\x -> affine (ECi (stdc_l p521) (stdc_b p521) (stdc_p p521) (stdc_r p521)) $ pmul (ECi (stdc_l p521) (stdc_b p521) (stdc_p p521) (stdc_r p521)) (ECPp (stdc_xp p521) (stdc_yp p521) 1) x)) $ parse contentP521
                       }
      ed25519  = Group { groupName = "Ed25519"
                       , concurrently = True
                       , groupTests = map (testEd25519 . C8.pack) $ lines contentEd25519
                       }
      ecdsa = Group { groupName = "Ed25519"
                    , concurrently = True
                    , groupTests = [testECDSA 6196826090020524094612681716217090709820303001652178894146139893013814408531]
                    }
  return [ nistp192
         , nistp224
         , nistp256
         , nistp384
         , nistp521
         , ed25519
         , ecdsa
         ]

parse :: String -> [(Integer,Integer, Integer)]
parse content = let l = lines content
                    fl = filter (/= "") l
                    ex :: [String] -> [(Integer,Integer, Integer)]
                    ex (k:x:y:ls) = let k' = read (drop 4 k)
                                        x' = fst $ head $ readHex (drop 4 x)
                                        y' = fst $ head $ readHex (drop 4 y)
                                    in (k',x',y'):(ex ls)
                    ex [] = []
                    ex _ = error "parse failed"
                in ex fl

test :: String -> (Integer -> (Integer,Integer)) -> (Integer, Integer, Integer) -> Test
test thename f (k,x,y) = let instanz = TestInstance { run = return $ if f k == (x,y) then Finished Pass else Finished $ Fail "fehlgeschlagen"
                                                    , name = thename ++ " with k = " ++ (show k)
                                                    , tags = []
                                                    , options = []
                                                    , setOption = \_ _ -> Right instanz
                                                    }
                         in Test instanz

testECDSA :: Integer -> Test
testECDSA rand = let c1 = ECi (stdc_l p256) (stdc_b p256) (stdc_p p256) (stdc_r p256)
                     p1 = ECPp  (stdc_xp p256) (stdc_yp p256) 1
                     privk =  93151144317885463729940025875124971369191600717633105593660251066268358953543
                     pub = ECPp 49820351311576200663416054279040683857746363070013834679270516876052449262634 112699216918648906269327207660688102462037435574122213014814143327521473380783 18523244708209522220381629035092551864971849988089188687523906648093563992014
                     sig = N.basicecdsa (BS.pack [0..255]) privk rand 
                     Right (r,s) = sig
                     instanz = TestInstance { run = return $ Finished $ if N.basicecdsaVerify pub (r,s) (BS.pack [0..255]) then Pass else Fail "fehlgeschlagen"
                                            , name = "ECDSAp256 sign+verify" ++ " with k = " ++ (show rand)
                                            , tags = []
                                            , options = []
                                            , setOption = \_ _ -> Right instanz
                                            }
                 in Test instanz


testEd25519 :: BS.ByteString -> Test
testEd25519 line = let x = C8.split ':' line
                       sk = fst $ BS16.decode $ head x
                       m = fst $ BS16.decode $ x !! 2
                       instanz = TestInstance { run = let mytest :: Either String ED.VerifyResult
                                                          mytest = do
                                                            pubkey <- ED.publickey $ EDi.SecKeyBytes sk
                                                            sig <- ED.dsign (EDi.SecKeyBytes $ BS.take 32 sk) m
                                                            res <- ED.dverify pubkey sig m
                                                            pure $ Right res
                                                      in return $ if mytest == Right (Right ED.SigOK) then Finished Pass else Finished $ Fail "fehlgeschlagen"
                                              , name = "Ed25519" ++ " with x = " ++ (show x) ++ " and sk = " ++ (show sk) ++ " and m = " ++ (show m)
                                              , tags = []
                                              , options = []
                                              , setOption = \_ _ -> Right instanz
                                              }
                   in Test instanz