File: runtests.hs

package info (click to toggle)
haskell-skein 0.1.0.7-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 708 kB
  • sloc: ansic: 2,591; haskell: 408; makefile: 8
file content (174 lines) | stat: -rw-r--r-- 6,434 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
-- from base
import Control.Applicative ((<$>))
import Control.Monad (forM_, unless)
import Data.Char (isNumber)
import Data.Maybe (catMaybes)
import Text.Printf

-- from bytestring
import qualified Data.ByteString as B
--import qualified Data.ByteString.Lazy as L

-- from cereal
import Data.Serialize (encode)

-- from tagged
import Data.Tagged (Tagged(..))

-- from crypto-api
import Crypto.Classes


-- from filepath
import System.FilePath ((</>))

-- from transformers
import Control.Monad.Trans.Writer.Lazy (Writer)

-- from hspec
import Test.Hspec.Monadic
--import Test.Hspec.QuickCheck
import Test.Hspec.HUnit ()


-- from this package
import Paths_skein (getDataFileName)
import Crypto.Skein




main :: IO ()
main = do
  skein_golden_kat_txt <- getDataFileName ("tests" </> "skein_golden_kat.txt")
  kats <- parseKats <$> readFile skein_golden_kat_txt
  putStrLn $ "Parsed " ++ show (length kats) ++ " known answer tests"
  hspecX $ do
         describe "Skein golden known answer tests" $ do
           skeinKats kats (undefined :: Skein_512_512)
           skeinKats kats (undefined :: Skein_1024_1024)
           skeinKats kats (undefined :: Skein_256_256)
           skeinKats kats (undefined :: Skein_256_128)
           skeinKats kats (undefined :: Skein_256_160)
           skeinKats kats (undefined :: Skein_256_224)
           skeinKats kats (undefined :: Skein_512_128)
           skeinKats kats (undefined :: Skein_512_160)
           skeinKats kats (undefined :: Skein_512_224)
           skeinKats kats (undefined :: Skein_512_256)
           skeinKats kats (undefined :: Skein_512_384)
           skeinKats kats (undefined :: Skein_1024_384)
           skeinKats kats (undefined :: Skein_1024_512)

readMsg :: Read a => String -> String -> a
readMsg msg str = case readsPrec 0 str of
                    [(r, "")] -> r
                    _ -> error msg

----------------------------------------------------------------------

data Kat = Kat { skeinType :: SkeinType
               , message   :: B.ByteString
               , macKey    :: Maybe B.ByteString
               , result    :: B.ByteString
               }

data SkeinType = Skein !Int !Int deriving (Eq)

instance Show SkeinType where
    show (Skein s o) = printf "Skein-%d-%d" s o

parseKats :: String -> [Kat]
parseKats = catMaybes . map parseKat . groupKats . lines . filter (/= '\r')

groupKats :: [String] -> [[String]]
groupKats = go []
    where
      sep = "--------------------------------"
      go acc (x:xs) | x == sep  = reverse acc : go [] xs
                    | otherwise = go (x:acc) xs
      go []    []               = []
      go (_:_) []               = error "groupKats: didn't find last separator"

parseKat :: [String] -> Maybe Kat
parseKat ("":xs) = parseKat xs
parseKat (header:"":rest) =
    case (isTree header, parseMsgLen header, parseBlocks rest) of
      (_, msgLen, _) | msgLen `mod` 8 /= 0 -> Nothing
      (False, _, [Message msg,             Result ret]) -> kat msg Nothing    ret
      (False, _, [Message msg, MACKey mac, Result ret]) -> kat msg (Just mac) ret
      _ -> Nothing
    where kat msg mac ret = Just $ Kat (parseSkeinType header) msg mac ret
parseKat _ = Nothing

isTree :: String -> Bool
isTree ('T':'r':'e':'e':':':_) = True
isTree (_:xs) = isTree xs
isTree []     = False

parseMsgLen :: String -> Int
parseMsgLen ('m':'s':'g':'L':'e':'n':' ':'=':xs) = readMsg "parseMsgLen" $ take 6 xs
parseMsgLen (_:xs) = parseMsgLen xs
parseMsgLen []     = error "parseMsgLen: didn't find msgLen"

parseSkeinType :: String -> SkeinType
parseSkeinType xs0 =
    let (":Skein", '-':xs1) = break (== '-') xs0
        (stateS,   xs2)     = span isNumber xs1
        (':':_,    xs3)     = break isNumber xs2
        (outputS,  _)       = span isNumber xs3
    in Skein (readMsg "stateS" stateS) (readMsg "outputS" outputS)

data Block = Message B.ByteString | MACKey B.ByteString | Result B.ByteString

block :: String -> B.ByteString -> Block
block "Message data:" = Message
block "Result:"       = Result
block ('M':'A':'C':_) = MACKey
block x               = error $ "block: unknown block type " ++ x

parseBlocks :: [String] -> [Block]
parseBlocks [] = []
parseBlocks (header:rest)
    | last header /= ':' = error "parseBlocks: something went wrong"
    | otherwise          = let (data_, rest') = span ((== ' ') . head) rest
                           in block header (parseData data_) : parseBlocks rest'

parseData :: [String] -> B.ByteString
parseData [' ':' ':' ':' ':'(':'n':'o':'n':'e':')':_] = B.empty
parseData xs = B.pack $ map (readMsg "parseData" . ("0x"++)) $ concatMap words xs

----------------------------------------------------------------------

skeinKats :: (SkeinMAC skeinCtx, Hash skeinCtx digest) =>
             [Kat] -> digest -> Writer [Spec] ()
skeinKats kats digest =
  let get t@(Tagged x) = x
          where
            f :: Tagged d a -> d
            f = undefined

            p = f t `asTypeOf` digest
      skeinType = Skein (get blockLength) (get outputLength)
      myHashKats  = [(msg,         ret) | Kat t msg Nothing       ret <- kats, t == skeinType]
      myMacKats   = [(msg, macKey, ret) | Kat t msg (Just macKey) ret <- kats, t == skeinType]
      lenHashKats = length myHashKats
      lenMacKats  = length myMacKats
      testName =
          if lenHashKats + lenMacKats == 0
          then printf "has no tests for %s =(" (show skeinType)
          else printf "works for %s (%d hash tests, %d MAC tests)"
                      (show skeinType) lenHashKats lenMacKats
  in it testName $ do
       putStrLn "Testing hashes..."
       forM_ myHashKats $ \(msg, ret) -> do
         let myHash = hash' msg `asTypeOf` digest
         unless (encode myHash == ret) $ fail $ concat ["Message: ", show msg,
                                                        "\nExpected: ", show ret,
                                                        "\nCalculated: ", show (encode myHash)]
       putStrLn "Testing MACs..."
       forM_ myMacKats $ \(msg, macKey, ret) -> do
         let myMAC = skeinMAC' macKey msg `asTypeOf` digest
         unless (encode myMAC == ret) $ fail $ concat ["Message: ", show msg,
                                                       "MAC Key: ", show macKey,
                                                       "\nExpected: ", show ret,
                                                       "\nCalculated: ", show (encode myMAC)]