{-# LANGUAGE OverloadedStrings #-} module Salsa (tests) where import qualified Data.ByteString as B import qualified Crypto.Cipher.Salsa as Salsa import Imports type Vector = (Int, B.ByteString, B.ByteString, [(Int, B.ByteString)]) vectors :: [Vector] vectors = [ (20, key, iv , [ (0, "\x99\xA8\xCC\xEC\x6C\x5B\x2A\x0B\x6E\x33\x6C\xB2\x06\x52\x24\x1C\x32\xB2\x4D\x34\xAC\xC0\x45\x7E\xF6\x79\x17\x8E\xDE\x7C\xF8\x05\x80\x5A\x93\x05\xC7\xC4\x99\x09\x68\x3B\xD1\xA8\x03\x32\x78\x17\x62\x7C\xA4\x6F\xE8\xB9\x29\xB6\xDF\x00\x12\xBD\x86\x41\x83\xBE") , (192, "\x2D\x22\x6C\x11\xF4\x7B\x3C\x0C\xCD\x09\x59\xB6\x1F\x59\xD5\xCC\x30\xFC\xEF\x6D\xBB\x8C\xBB\x3D\xCC\x1C\xC2\x52\x04\xFC\xD4\x49\x8C\x37\x42\x6A\x63\xBE\xA3\x28\x2B\x1A\x8A\x0D\x60\xE1\x3E\xB2\xFE\x59\x24\x1A\x9F\x6A\xF4\x26\x68\x98\x66\xED\xC7\x69\xE1\xE6\x48\x2F\xE1\xC1\x28\xA1\x5C\x11\x23\xB5\x65\x5E\xD5\x46\xDF\x01\x4C\xE0\xC4\x55\xDB\xF5\xD3\xA1\x3D\x9C\xD4\xF0\xE2\xD1\xDA\xB9\xF1\x2F\xB6\x8C\x54\x42\x61\xD7\xF8\x8E\xAC\x1C\x6C\xBF\x99\x3F\xBB\xB8\xE0\xAA\x85\x10\xBF\xF8\xE7\x38\x35\xA1\xE8\x6E\xAD\xBB") , (448, "\x05\x97\x18\x8A\x1C\x19\x25\x57\x69\xBE\x1C\x21\x03\x99\xAD\x17\x2E\xB4\x6C\x52\xF9\x2F\xD5\x41\xDF\x2E\xAD\x71\xB1\xFF\x8E\xA7\xAD\xD3\x80\xEC\x71\xA5\xFD\x7A\xDB\x51\x81\xEA\xDD\x18\x25\xEC\x02\x77\x9A\x45\x09\xBE\x58\x32\x70\x8C\xA2\x83\x6C\x16\x93\xA5") ]) , (20 , "\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD\x30\x83\xD6\x29\x7C\xCF\x22\x75\xC8\x1B\x6E\xC1\x14\x67\xBA\x0D" , "\x0D\x74\xDB\x42\xA9\x10\x77\xDE" , [ (0, "\xF5\xFA\xD5\x3F\x79\xF9\xDF\x58\xC4\xAE\xA0\xD0\xED\x9A\x96\x01\xF2\x78\x11\x2C\xA7\x18\x0D\x56\x5B\x42\x0A\x48\x01\x96\x70\xEA\xF2\x4C\xE4\x93\xA8\x62\x63\xF6\x77\xB4\x6A\xCE\x19\x24\x77\x3D\x2B\xB2\x55\x71\xE1\xAA\x85\x93\x75\x8F\xC3\x82\xB1\x28\x0B\x71") , (65472, "\xB7\x0C\x50\x13\x9C\x63\x33\x2E\xF6\xE7\x7A\xC5\x43\x38\xA4\x07\x9B\x82\xBE\xC9\xF9\xA4\x03\xDF\xEA\x82\x1B\x83\xF7\x86\x07\x91\x65\x0E\xF1\xB2\x48\x9D\x05\x90\xB1\xDE\x77\x2E\xED\xA4\xE3\xBC\xD6\x0F\xA7\xCE\x9C\xD6\x23\xD9\xD2\xFD\x57\x58\xB8\x65\x3E\x70\x81\x58\x2C\x65\xD7\x56\x2B\x80\xAE\xC2\xF1\xA6\x73\xA9\xD0\x1C\x9F\x89\x2A\x23\xD4\x91\x9F\x6A\xB4\x7B\x91\x54\xE0\x8E\x69\x9B\x41\x17\xD7\xC6\x66\x47\x7B\x60\xF8\x39\x14\x81\x68\x2F\x5D\x95\xD9\x66\x23\xDB\xC4\x89\xD8\x8D\xAA\x69\x56\xB9\xF0\x64\x6B\x6E") , (131008, "\xA1\x3F\xFA\x12\x08\xF8\xBF\x50\x90\x08\x86\xFA\xAB\x40\xFD\x10\xE8\xCA\xA3\x06\xE6\x3D\xF3\x95\x36\xA1\x56\x4F\xB7\x60\xB2\x42\xA9\xD6\xA4\x62\x8C\xDC\x87\x87\x62\x83\x4E\x27\xA5\x41\xDA\x2A\x5E\x3B\x34\x45\x98\x9C\x76\xF6\x11\xE0\xFE\xC6\xD9\x1A\xCA\xCC") ]) ] where key :: B.ByteString key = "\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" iv = B.replicate 8 0 newtype RandomVector = RandomVector Vector deriving (Show,Eq) instance Arbitrary RandomVector where arbitrary = RandomVector <$> elements vectors tests = testGroup "Salsa" [ testGroup "KAT" $ map (\(i,f) -> testCase (show (i :: Int)) f) $ zip [1..] $ map (\(r, k,i,e) -> salsaRunSimple e r k i) vectors , testProperty "generate-combine" salsaGenerateCombine , testProperty "chunking-generate" salsaGenerateChunks , testProperty "chunking-combine" salsaCombineChunks ] where salsaRunSimple expected rounds key nonce = let salsa = Salsa.initialize rounds key nonce in map snd expected @=? salsaLoop 0 salsa expected salsaLoop _ _ [] = [] salsaLoop current salsa (r@(ofs,expectBs):rs) | current < ofs = let (_, salsaNext) = Salsa.generate salsa (ofs - current) :: (ByteString, Salsa.State) in salsaLoop ofs salsaNext (r:rs) | current == ofs = let (e, salsaNext) = Salsa.generate salsa (B.length expectBs) in e : salsaLoop (current + B.length expectBs) salsaNext rs | otherwise = error "internal error in salsaLoop" salsaGenerateCombine :: ChunkingLen0_127 -> RandomVector -> Int0_2901 -> Bool salsaGenerateCombine (ChunkingLen0_127 ckLen) (RandomVector (rounds, key, iv, _)) (Int0_2901 nbBytes) = let initSalsa = Salsa.initialize rounds key iv in loop nbBytes ckLen initSalsa where loop n [] salsa = loop n ckLen salsa loop 0 _ _ = True loop n (x:xs) salsa = let len = min x n (c1, next) = Salsa.generate salsa len (c2, _) = Salsa.combine salsa (B.replicate len 0) in if c1 == c2 then loop (n - len) xs next else False salsaGenerateChunks :: ChunkingLen -> RandomVector -> Bool salsaGenerateChunks (ChunkingLen ckLen) (RandomVector (rounds, key, iv, _)) = let initSalsa = Salsa.initialize rounds key iv nbBytes = 1048 (expected,_) = Salsa.generate initSalsa nbBytes chunks = loop nbBytes ckLen (Salsa.initialize rounds key iv) in expected == B.concat chunks where loop n [] salsa = loop n ckLen salsa loop 0 _ _ = [] loop n (x:xs) salsa = let len = min x n (c, next) = Salsa.generate salsa len in c : loop (n - len) xs next salsaCombineChunks :: ChunkingLen -> RandomVector -> ArbitraryBS0_2901 -> Bool salsaCombineChunks (ChunkingLen ckLen) (RandomVector (rounds, key, iv, _)) (ArbitraryBS0_2901 wholebs) = let initSalsa = Salsa.initialize rounds key iv (expected,_) = Salsa.combine initSalsa wholebs chunks = loop wholebs ckLen initSalsa in expected `propertyEq` B.concat chunks where loop bs [] salsa = loop bs ckLen salsa loop bs (x:xs) salsa | B.null bs = [] | otherwise = let (bs1, bs2) = B.splitAt (min x (B.length bs)) bs (c, next) = Salsa.combine salsa bs1 in c : loop bs2 xs next