{-# LANGUAGE OverloadedStrings #-} import Crypto.Argon2 import Test.QuickCheck import Test.Tasty import Data.Ix import Test.Tasty.QuickCheck import qualified Crypto.Argon2.FFI as FFI import qualified Data.ByteString as BS import qualified Data.Text.Encoding as T import Data.Bits (shiftL) arbitraryVariant :: Gen Argon2Variant arbitraryVariant = arbitraryBoundedEnum -- The hard-coded constants correspond to `decode_string`, but see -- https://github.com/P-H-C/phc-winner-argon2/issues/77 arbitraryHashOptions :: Gen HashOptions arbitraryHashOptions = do p <- arbitraryWithin (max (max FFI.ARGON2_MIN_LANES FFI.ARGON2_MIN_THREADS) 1) (min (min FFI.ARGON2_MAX_LANES FFI.ARGON2_MAX_THREADS) 254) HashOptions <$> arbitraryWithin FFI.ARGON2_MIN_TIME (min FFI.ARGON2_MAX_TIME (2 ^ 32 - 1)) <*> arbitraryWithin (max (max FFI.ARGON2_MIN_MEMORY (8 * p)) (shiftL p 3)) FFI.ARGON2_MAX_MEMORY <*> pure p <*> arbitraryVariant arbitraryWithin lower upper = arbitrary `suchThat` (inRange (lower,upper)) arbitraryBytes :: Gen BS.ByteString arbitraryBytes = fmap BS.pack arbitrary arbitraryPassword :: Gen BS.ByteString arbitraryPassword = arbitraryBytes `suchThat` (\pwd -> (FFI.ARGON2_MIN_PWD_LENGTH ,FFI.ARGON2_MAX_PWD_LENGTH) `inRange` BS.length pwd) arbitrarySalt = arbitraryBytes `suchThat` (\salt -> (FFI.ARGON2_MIN_SALT_LENGTH,FFI.ARGON2_MAX_SALT_LENGTH) `inRange` BS.length salt) main :: IO () main = defaultMain (testGroup "Properties" [testProperty "Round trip" (forAll arbitraryHashOptions $ \hashOptions -> forAll arbitraryPassword $ \password -> forAll arbitrarySalt $ \salt -> verify (hashEncoded hashOptions password salt) password) ,testProperty "Unencoded hashing" (forAll arbitraryHashOptions $ \hashOptions -> forAll arbitraryPassword $ \password -> forAll arbitrarySalt $ \salt -> hash hashOptions password salt /= password) ,testProperty "defaultHashOptions" (forAll arbitraryVariant $ \variant -> (forAll arbitraryPassword $ \password -> forAll arbitrarySalt $ \salt -> verify (hashEncoded (defaultHashOptions {hashVariant = variant}) password salt) password))])