hashable 1.2.0.2 → 1.2.0.3
raw patch · 5 files changed
+100/−25 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/Hashable.hs +45/−0
- Data/Hashable/Class.hs +25/−16
- benchmarks/Benchmarks.hs +9/−3
- cbits/siphash.c +2/−0
- hashable.cabal +19/−6
Data/Hashable.hs view
@@ -27,6 +27,9 @@ module Data.Hashable (+ -- * Hashing and security+ -- $security+ -- * Computing hash values hash , Hashable(..)@@ -219,3 +222,45 @@ -- > s `hashWithSalt` -- > yr `hashWithSalt` -- > mo `hashWithSalt` dy++-- $security+-- #security#+--+-- Applications that use hash-based data structures to store input+-- from untrusted users can be susceptible to \"hash DoS\", a class of+-- denial-of-service attack that uses deliberately chosen colliding+-- inputs to force an application into unexpectedly behaving with+-- quadratic time complexity.+--+-- This library uses the SipHash algorithm to hash strings. SipHash+-- was designed to be more robust against collision attacks than+-- traditional hash algorithms, while retaining good performance.+--+-- To further mitigate the risk from collision attacks, this library+-- provides an environment variable named @HASHABLE_SALT@ that allows+-- the default salt used by the 'hash' function to be chosen at+-- application startup time.+--+-- * In the normal case, the environment variable is not set, and a+-- fixed salt is used that does not vary between runs. (This choice+-- can be made permanent by building this package with the+-- @-ffixed-salt@ flag.)+--+-- * If the value is the string @random@, the system's cryptographic+-- pseudo-random number generator will be used to supply a salt.+-- While this may offer added security, it can also violate the+-- assumption of some Haskell libraries that expect the results of+-- 'hash' to be stable across application runs. Choose this+-- behaviour with care (and testing)!+--+-- * When the value is an integer (prefixed with @0x@ for hexadecimal),+-- it will be used as the salt.+--+-- If @HASHABLE_SALT@ cannot be parsed, then the first time that a+-- call to 'hash' is made, the application will halt with an+-- informative error message.+--+-- (Implementation note: while SipHash is used for strings, a+-- faster—and almost certainly less secure—algorithm is+-- used for numeric types, on the assumption that strings are much+-- more likely as a hash DoS attack vector.)
Data/Hashable/Class.hs view
@@ -107,8 +107,12 @@ #endif #ifndef FIXED_SALT+import Control.Exception (tryJust)+import Control.Monad (guard) import Data.Hashable.RandomSource (getRandomBytes_) import Foreign.Marshal.Alloc (alloca)+import System.Environment (getEnv)+import System.IO.Error (isDoesNotExistError) #endif #include "MachDeps.h"@@ -121,20 +125,32 @@ -- | A default salt used in the implementation of 'hash'. -- -- To reduce the probability of hash collisions, the value of the--- default salt will vary from one program invocation to the next+-- default salt may vary from one program invocation to the next -- unless this package is compiled with the @fixed-salt@ flag set.-defaultSalt :: Int+defaultSalt, fixedSalt :: Int +fixedSalt = 0xdc36d1615b7400a4+{-# INLINE fixedSalt #-}+ #ifdef FIXED_SALT -defaultSalt = 0xdc36d1615b7400a4+defaultSalt = fixedSalt {-# INLINE defaultSalt #-} #else -defaultSalt = unsafePerformIO . alloca $ \p -> do- getRandomBytes_ "defaultSalt" p (sizeOf (undefined :: Int))- peek p+defaultSalt = unsafePerformIO $ do+ let varName = "HASHABLE_SALT"+ msalt <- tryJust (guard . isDoesNotExistError) $ getEnv varName+ case msalt of+ Right "random" -> alloca $ \p -> do+ getRandomBytes_ "defaultSalt" p (sizeOf (undefined :: Int))+ peek p+ Right s -> case reads s of+ [(salt, "")] -> return salt+ _ -> fail $ "Fatal: cannot parse contents of " +++ varName ++ " environment variable"+ Left _ -> return fixedSalt {-# NOINLINE defaultSalt #-} #endif@@ -182,16 +198,9 @@ -- | Return a hash value for the argument. Defined in terms of -- 'hashWithSalt' and a default salt. ----- At application startup time, the default salt is initialized with a--- new value from the system's cryptographic pseudo-random number--- generator. This means that the result of 'hash' will vary from one--- application run to the next.------ If you need hashes that do not vary from run to run, use--- 'hashWithSalt' instead, and supply a salt of your choosing. (Be--- aware that if you hash untrusted, uncontrolled input data using a--- fixed salt, you may expose your application to hash collision--- attacks.)+-- (See the \"Hashing and security\" section of the+-- "Data.Hashable#security" documentation for an important note on+-- working safely with untrusted user input.) hash :: Hashable a => a -> Int hash = hashWithSalt defaultSalt
benchmarks/Benchmarks.hs view
@@ -78,10 +78,12 @@ fnvHash (PS fp off len) = inlinePerformIO . withForeignPtr fp $ \ptr -> return $! fnv_hash (ptr `plusPtr` off) (fromIntegral len) 2166136261-#ifdef HAVE_SSE+#ifdef HAVE_SSE2 sse2SipHash (PS fp off len) = inlinePerformIO . withForeignPtr fp $ \ptr -> return $! sse2_siphash k0 k1 (ptr `plusPtr` off) (fromIntegral len)+#endif+#ifdef HAVE_SSE41 sse41SipHash (PS fp off len) = inlinePerformIO . withForeignPtr fp $ \ptr -> return $! sse41_siphash k0 k1 (ptr `plusPtr` off) (fromIntegral len)@@ -201,7 +203,7 @@ , bench "512" $ whnf cSipHash24 bs512 , bench "2^20" $ whnf cSipHash24 bs1Mb ]-#ifdef HAVE_SSE+#ifdef HAVE_SSE2 , bgroup "sse2SipHash" [ bench "5" $ whnf sse2SipHash bs5 , bench "8" $ whnf sse2SipHash bs8@@ -211,6 +213,8 @@ , bench "512" $ whnf sse2SipHash bs512 , bench "2^20" $ whnf sse2SipHash bs1Mb ]+#endif+#ifdef HAVE_SSE41 , bgroup "sse41SipHash" [ bench "5" $ whnf sse41SipHash bs5 , bench "8" $ whnf sse41SipHash bs8@@ -261,9 +265,11 @@ :: CInt -> CInt -> Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64 foreign import ccall unsafe "hashable_siphash24" c_siphash24 :: Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64-#ifdef HAVE_SSE+#ifdef HAVE_SSE2 foreign import ccall unsafe "hashable_siphash24_sse2" sse2_siphash :: Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64+#endif+#ifdef HAVE_SSE41 foreign import ccall unsafe "hashable_siphash24_sse41" sse41_siphash :: Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64 #endif
cbits/siphash.c view
@@ -109,8 +109,10 @@ if (edx & (1 << 26)) _siphash24 = hashable_siphash24_sse2;+#if defined(HAVE_SSE41) else if (ecx & (1 << 19)) _siphash24 = hashable_siphash24_sse41;+#endif else _siphash24 = plain_siphash24; }
hashable.cabal view
@@ -1,5 +1,5 @@ Name: hashable-Version: 1.2.0.2+Version: 1.2.0.3 Synopsis: A class for types that can be converted to a hash value Description: This package defines a class, 'Hashable', for types that can be converted to a hash value. This class@@ -31,6 +31,10 @@ Description: Do we use a single fixed salt every time the program runs? Default: False +Flag sse41+ Description: Do we want to assume that a target supports SSE 4.1?+ Default: False+ Library Exposed-modules: Data.Hashable Other-modules: Data.Hashable.Class@@ -53,9 +57,13 @@ cbits/siphash.c if arch(i386) C-sources: cbits/siphash-sse2.c- cbits/siphash-sse41.c- CC-options: -msse2 -msse4.1+ CC-options: -msse2 + if flag(sse41)+ CPP-Options: -DHAVE_SSE41+ CC-options: -msse41+ C-sources: cbits/siphash-sse41.c+ Ghc-options: -Wall if impl(ghc >= 6.8) Ghc-options: -fwarn-tabs@@ -117,11 +125,16 @@ benchmarks/cbits/inthash.c if arch(i386) || arch(x86_64)- cpp-options: -DHAVE_SSE- cc-options: -msse2 -msse4.1+ cpp-options: -DHAVE_SSE2+ cc-options: -msse2 c-sources: cbits/siphash-sse2.c- cbits/siphash-sse41.c++ if flag(sse41)+ cpp-options: -DHAVE_SSE41+ cc-options: -msse4.1+ c-sources:+ cbits/siphash-sse41.c Ghc-options: -Wall -O2 if impl(ghc >= 6.8)