packages feed

mono-hash (empty) → 0.1.0.0

raw patch · 15 files changed

+2881/−0 lines, 15 filesdep +basedep +bytestringdep +criterion

Dependencies added: base, bytestring, criterion, deepseq, mono-hash, mono-traversable, tasty, tasty-hunit, text, wide-word

Files

+ CHANGELOG.md view
@@ -0,0 +1,7 @@+# Revision history for mono-hash++## 0.1.0.0 -- 2026-10-25++* First release.+* FNV-1 and FNV-1a for monomorphic containers.+* SipHash-c-d and HalfSipHash-c-d for monomorphic containers.
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2025, Philipp Hagenlocher+++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of the copyright holder nor the names of its+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,160 @@+# mono-hash++[![Hackage](https://img.shields.io/hackage/v/mono-hash.svg)](https://hackage.haskell.org/package/mono-hash)+[![Haskell-CI](https://github.com/phagenlocher/mono-hash/actions/workflows/haskell-ci.yml/badge.svg?branch=main)](https://github.com/phagenlocher/mono-hash/actions/workflows/haskell-ci.yml)++Hashing for monomorphic containers: FNV-1/FNV-1a, SipHash, and HalfSipHash for+any [`MonoFoldable`](https://hackage.haskell.org/package/mono-traversable/docs/Data-MonoTraversable.html#t:MonoFoldable),+including `ByteString`, lazy `ByteString`, `Text`, `String`, and lists of+fixed-width words.++## Motivation++This library hashes data in monomorphic containers irrespective of their+structure. Because only the concatenated element bytes matter, changing the+container while keeping the same bytes leaves the hash unchanged. Below, the+`ByteString` and `Vector Word64` hold exactly the same bytes; each formatted+line of the `ByteString` is one `Word64` in the vector:++```haskell+{-# LANGUAGE NumericUnderscores #-}+{-# LANGUAGE TypeApplications #-}++import qualified Data.ByteString as BS+import qualified Data.Vector as V+import Data.Hash.Mono.SipHash (sipHash)+import Data.Tree (Tree (..))+import Data.WideWord.Word128 (Word128)+import Data.Word (Word32, Word64)++key :: Word128+key = 0x000102030405060708090a0b0c0d0e0f++bytes :: BS.ByteString+bytes =+    BS.pack+        [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77+        , 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff+        , 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef+        ]++vector :: V.Vector Word64+vector =+    V.fromList+        [ 0x00_11_22_33_44_55_66_77+        , 0x88_99_aa_bb_cc_dd_ee_ff+        , 0x01_23_45_67_89_ab_cd_ef+        ]++sipHash @Word64 2 4 key bytes+-- 0x6d003ad777121d05++sipHash @Word64 2 4 key vector+-- 0x6d003ad777121d05+```++The same works for any `MonoFoldable`. `Data.Tree.Tree` from `containers`+already has a `MonoFoldable` instance in `mono-traversable`, and it folds in+pre-order:++```haskell+-- Pre-order traversal: the same 24 bytes as six Word32s.+tree :: Tree Word32+tree =+    Node+        0x00_11_22_33+        [ Node 0x44_55_66_77 []+        , Node 0x88_99_aa_bb []+        , Node 0xcc_dd_ee_ff+            [ Node 0x01_23_45_67 []+            , Node 0x89_ab_cd_ef []+            ]+        ]++sipHash @Word64 2 4 key tree+-- 0x6d003ad777121d05+```++## Usage++```haskell+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}++import Data.Hash.Mono.FNV (fnv1a)+import Data.Hash.Mono.HalfSipHash (halfSipHash)+import Data.Hash.Mono.SipHash (sipHash)+import Data.Text (Text)+import Data.WideWord.Word128 (Word128)+import Data.Word (Word32, Word64)++-- FNV-1a with a 64-bit result+fnv1a @Word64 ("hello" :: Text)++-- SipHash-2-4 with a 128-bit key and a 64-bit result+sipHash @Word64 2 4 (0x000102030405060708090a0b0c0d0e0f :: Word128) ("hello" :: Text)++-- HalfSipHash-2-4 with a 64-bit key and a 32-bit result+halfSipHash @Word32 2 4 (0x0001020304050607 :: Word64) ("hello" :: Text)+```++The result type is selected with a type application (or type inference of course):++| Function       | Result type                              |+| -------------- | ---------------------------------------- |+| `fnv1`/`fnv1a` | `Word32`, `Word64`, `Word128`, `Word256` |+| `sipHash`      | `Word64`, `Word128`                      |+| `halfSipHash`  | `Word32`, `Word64`                       |++## Encoding and byte order++Hashing is defined over the concatenation of the elements' byte encodings.+The encoding is not type-tagged, so `[0x01, 0x02 :: Word8]` and+`[0x0102 :: Word16]` hash the same bytes.++`Word8` and `Int8` contribute one byte. Wider integers contribute+their bit pattern most significant byte first; signed integers use two's+complement. `Char` contributes UTF-8; a lone surrogate, which `String` can+contain but UTF-8 cannot represent, uses the 3-byte+[WTF-8](https://wtf-8.codeberg.page) form. `String` and `Text` are+hashed character by character, while `ByteString` contributes its raw bytes.+The library provides instances for `Word8`, `Word16`, `Word32`, `Word64`,+`Word128`, `Word256`, `Int8`, `Int16`, `Int32`, `Int64`, and `Char`.++## Custom element types++Give the element type a `ByteFoldable` instance to hash containers of your+own type:++```haskell+import Data.Hash.Mono.FNV (fnv1a)+import Data.Hash.Mono.Internal.ByteFoldable (ByteFoldable (..))+import Data.Word (Word8, Word64)++data Rgb = Rgb Word8 Word8 Word8++instance ByteFoldable Rgb where+    foldlBytes f z (Rgb r g b) = f (f (f z r) g) b++-- Hashes [Rgb 0x12 0x34 0x56] as the bytes 0x12 0x34 0x56.+fnv1a @Word64 [Rgb 0x12 0x34 0x56]+```++The bytes an instance emits are the bytes hashed, so changing an instance+changes every hash of containers holding that element type.++## Formatting and linting++Sources are formatted with [fourmolu](https://github.com/fourmolu/fourmolu) and+linted with [hlint](https://github.com/ndmitchell/hlint). CI checks both, using+the versions pinned in `.github/workflows/ci.yml`, so run them before opening+a pull request:++```console+fourmolu --mode inplace $(git ls-files '*.hs')+hlint src test bench+```++## License++BSD-3-Clause. See [LICENSE](LICENSE).
+ bench/Main.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++module Main (main) where++import Control.DeepSeq (NFData, force)+import Control.Exception (evaluate)+import Criterion (Benchmark, bench, bgroup, whnf)+import Criterion.Main (defaultMain)+import qualified Data.ByteString as BS+import Data.Hash.Mono.FNV (fnv1, fnv1a)+import Data.Hash.Mono.HalfSipHash (halfSipHash)+import Data.Hash.Mono.SipHash (sipHash)+import qualified Data.Text as T+import Data.WideWord.Word128 (Word128)+import Data.WideWord.Word256 (Word256)+import Data.Word (Word32, Word64)++newtype Sizes a = Sizes [(String, a)]++mkSizes :: (Int -> a) -> Sizes a+mkSizes f =+    Sizes+        [ ("small input", f 10)+        , ("medium input", f 1000)+        , ("large input", f 100000)+        , ("huge input", f 10000000)+        ]++-- | Smaller sizes for element types with a large in-memory footprint.+mkElementSizes :: (Int -> a) -> Sizes a+mkElementSizes f =+    Sizes+        [ ("small input", f 100)+        , ("medium input", f 1000)+        , ("large input", f 10000)+        ]++forceSizes :: (NFData a) => Sizes a -> IO (Sizes a)+forceSizes sizes@(Sizes xs) = do+    _ <- evaluate $ force xs+    pure sizes++mkBench :: (a -> b) -> Sizes a -> [Benchmark]+mkBench fun (Sizes xs) = [bench name (whnf fun x) | (name, x) <- xs]++main :: IO ()+main = do+    strings <- forceSizes $ mkSizes (`replicate` 'a')+    bytes <- forceSizes $ mkSizes (`BS.replicate` 97)+    texts <- forceSizes $ mkSizes (\n -> T.replicate n (T.singleton 'a'))+    word128s <- forceSizes $ mkElementSizes (\n -> [fromIntegral i :: Word128 | i <- [0 .. n - 1]])+    word256s <- forceSizes $ mkElementSizes (\n -> [fromIntegral i :: Word256 | i <- [0 .. n - 1]])++    boundaryInputs <-+        evaluate $+            force+                [ (n, BS.replicate n 97)+                | n <- [254, 255, 256, 257, 258, 511, 512, 513]+                ]++    defaultMain+        [ bgroup "FNV1 Word32" $ mkBench (fnv1 @Word32) strings+        , bgroup "FNV1a Word32" $ mkBench (fnv1a @Word32) strings+        , bgroup "FNV1 Word64" $ mkBench (fnv1 @Word64) strings+        , bgroup "FNV1a Word64" $ mkBench (fnv1a @Word64) strings+        , bgroup "FNV1 Word128" $ mkBench (fnv1 @Word128) strings+        , bgroup "FNV1a Word128" $ mkBench (fnv1a @Word128) strings+        , bgroup "FNV1 Word256" $ mkBench (fnv1 @Word256) strings+        , bgroup "FNV1a Word256" $ mkBench (fnv1a @Word256) strings+        , bgroup "SipHash-2-4 Word64" $ mkBench (sipHash @Word64 2 4 0xc0ffee) strings+        , bgroup "SipHash-2-4 Word128" $ mkBench (sipHash @Word128 2 4 0xc0ffee) strings+        , bgroup "HalfSipHash-2-4 Word32" $ mkBench (halfSipHash @Word32 2 4 0xc0ffee) strings+        , bgroup "HalfSipHash-2-4 Word64" $ mkBench (halfSipHash @Word64 2 4 0xc0ffee) strings+        , bgroup "FNV1a Word64/ByteString" $ mkBench (fnv1a @Word64) bytes+        , bgroup "FNV1a Word64/Text" $ mkBench (fnv1a @Word64) texts+        , bgroup "SipHash-2-4 Word64/ByteString" $ mkBench (sipHash @Word64 2 4 0xc0ffee) bytes+        , bgroup "SipHash-2-4 Word64/Text" $ mkBench (sipHash @Word64 2 4 0xc0ffee) texts+        , bgroup "HalfSipHash-2-4 Word32/ByteString" $ mkBench (halfSipHash @Word32 2 4 0xc0ffee) bytes+        , bgroup "HalfSipHash-2-4 Word32/Text" $ mkBench (halfSipHash @Word32 2 4 0xc0ffee) texts+        , bgroup+            "SipHash-2-4 Word64 length boundary"+            [ bench (show n) $ whnf (sipHash @Word64 2 4 0xc0ffee) input+            | (n, input) <- boundaryInputs+            ]+        , bgroup "FNV1a Word64/[Word128]" $ mkBench (fnv1a @Word64) word128s+        , bgroup "FNV1a Word256/[Word128]" $ mkBench (fnv1a @Word256) word128s+        , bgroup "SipHash-2-4 Word64/[Word128]" $ mkBench (sipHash @Word64 2 4 0xc0ffee) word128s+        , bgroup "FNV1a Word64/[Word256]" $ mkBench (fnv1a @Word64) word256s+        , bgroup "FNV1a Word256/[Word256]" $ mkBench (fnv1a @Word256) word256s+        , bgroup "SipHash-2-4 Word64/[Word256]" $ mkBench (sipHash @Word64 2 4 0xc0ffee) word256s+        ]
+ mono-hash.cabal view
@@ -0,0 +1,102 @@+cabal-version: 3.0+name: mono-hash+version: 0.1.0.0+synopsis: Hashing for monomorphic containers.+description:+  FNV, SipHash, and HalfSipHash hashing for monomorphic containers.+license: BSD-3-Clause+license-file: LICENSE+author: Philipp Hagenlocher+maintainer: me@philipphagenlocher.de+category: Data+build-type: Simple+homepage: https://github.com/phagenlocher/mono-hash#readme+bug-reports: https://github.com/phagenlocher/mono-hash/issues+extra-doc-files:+  CHANGELOG.md+  README.md+tested-with:+  ghc ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.7+    || ==9.8.4 || ==9.10.3 || ==9.12.4 || ==9.14.1++source-repository head+  type: git+  location: https://github.com/phagenlocher/mono-hash++common warnings+  ghc-options: -Wall++library+  import: warnings+  ghc-options: -O2++  exposed-modules:+    Data.Hash.Mono.FNV+    Data.Hash.Mono.HalfSipHash+    Data.Hash.Mono.Internal.ByteFoldable+    Data.Hash.Mono.SipHash++  other-modules:+    Data.Hash.Mono.Internal++  build-depends:+    base >=4.14.3.0 && <5,+    mono-traversable >=1.0.21 && <1.1,+    wide-word >=0.1.7 && <0.2++  hs-source-dirs: src++  default-language: Haskell2010++  default-extensions:+    ConstraintKinds+    FlexibleContexts+    ImportQualifiedPost+    InstanceSigs+    ScopedTypeVariables++test-suite mono-hash-test+  import: warnings++  default-language: Haskell2010++  other-modules:+    Test.Data.ByteFoldable+    Test.Data.FNV+    Test.Data.SipHash+    Test.Data.HalfSipHash++  type: exitcode-stdio-1.0++  hs-source-dirs: test++  main-is: Main.hs++  build-depends:+    base >=4.14.3.0 && <5,+    bytestring >=0.10 && <0.13,+    mono-hash,+    tasty >=1.4 && <1.6,+    tasty-hunit >=0.10 && <0.11,+    text >=1.2 && <2.2,+    wide-word >=0.1.7 && <0.2,++benchmark mono-hash-bench+  type: exitcode-stdio-1.0++  hs-source-dirs: bench++  default-language: Haskell2010++  ghc-options: -O2++  main-is: Main.hs++  build-depends:+    base >=4.14.3.0 && <5,+    bytestring >=0.10 && <0.13,+    criterion >=1.5 && <1.7,+    deepseq >=1.4 && <1.6,+    mono-hash,+    text >=1.2 && <2.2,+    wide-word >=0.1.7 && <0.2,
+ src/Data/Hash/Mono/FNV.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE BangPatterns #-}++-- | FNV-1 and FNV-1a hashes for any 'MonoFoldable' container.+module Data.Hash.Mono.FNV (+    FNVData,+    FNVResult,+    HasFNVBasis,+    fnv1,+    fnv1a,+)+where++import Data.Bits (Bits (xor))+import Data.Hash.Mono.Internal.ByteFoldable (ByteFoldable (..))+import Data.MonoTraversable (Element, MonoFoldable (ofoldl'))+import Data.WideWord.Word128 (Word128)+import Data.WideWord.Word256 (Word256)+import Data.Word (Word32, Word64, Word8)++-- | Offset basis and prime for an FNV result width.+class HasFNVBasis a where+    -- | Offset basis used to seed the hash.+    fnvOffsetBasis :: a++    -- | Prime applied once per input byte.+    fnvPrime :: a++instance HasFNVBasis Word32 where+    fnvOffsetBasis :: Word32+    fnvOffsetBasis = 2166136261++    fnvPrime :: Word32+    fnvPrime = 16777619++instance HasFNVBasis Word64 where+    fnvOffsetBasis :: Word64+    fnvOffsetBasis = 14695981039346656037++    fnvPrime :: Word64+    fnvPrime = 1099511628211++instance HasFNVBasis Word128 where+    fnvOffsetBasis :: Word128+    fnvOffsetBasis = 144066263297769815596495629667062367629++    fnvPrime :: Word128+    fnvPrime = 309485009821345068724781371++instance HasFNVBasis Word256 where+    fnvOffsetBasis :: Word256+    fnvOffsetBasis = 100029257958052580907070968620625704837092796014241193945225284501741471925557++    fnvPrime :: Word256+    fnvPrime = 374144419156711147060143317175368453031918731002211++-- | Constraint for types that can be used as an FNV result.+type FNVResult a = (HasFNVBasis a, Bits a, Num a)++-- | Constraint for containers hashed with FNV.+type FNVData a = (MonoFoldable a, ByteFoldable (Element a))++fnvGeneric :: forall result mono. (FNVData mono, FNVResult result) => (result -> Word8 -> result) -> mono -> result+fnvGeneric fnvRound = ofoldl' (foldlBytes fnvRound) fnvOffsetBasis+{-# INLINE fnvGeneric #-}++{- | FNV-1 hash of a monomorphic container.++Example:+@+fnv1 \@'Word64' \"hello\"+@+-}+fnv1 :: forall result mono. (FNVData mono, FNVResult result) => mono -> result+fnv1 = fnvGeneric fnvRound+  where+    fnvRound :: result -> Word8 -> result+    fnvRound !acc !octet = (acc * fnvPrime) `xor` fromIntegral octet+{-# INLINEABLE fnv1 #-}++{- | FNV-1a hash of a monomorphic container.++Example:+@+fnv1a \@'Word64' \"hello\"+@+-}+fnv1a :: forall result mono. (FNVData mono, FNVResult result) => mono -> result+fnv1a = fnvGeneric fnvRound+  where+    fnvRound :: result -> Word8 -> result+    fnvRound !acc !octet = (acc `xor` fromIntegral octet) * fnvPrime+{-# INLINEABLE fnv1a #-}
+ src/Data/Hash/Mono/HalfSipHash.hs view
@@ -0,0 +1,170 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE StrictData #-}+{-# LANGUAGE TypeApplications #-}++-- | HalfSipHash-@c@-@d@ for any 'MonoFoldable' container.+module Data.Hash.Mono.HalfSipHash (+    HalfSipHashData,+    HalfSipHashResult,+    halfSipHash,+)+where++import Data.Bits (Bits (rotateL, shiftL, shiftR, xor, (.&.), (.|.)))+import Data.Hash.Mono.Internal (byteSwap32)+import Data.Hash.Mono.Internal.ByteFoldable (ByteFoldable (..))+import Data.MonoTraversable (Element, MonoFoldable (ofoldl'))+import Data.Word (Word32, Word64, Word8)++-- | Result types that 'halfSipHash' can produce.+class HalfSipHashResult a where+    -- | Adjust the initial state for the selected result type.+    initialize :: HalfSipData -> HalfSipData++    -- | Run the finalization rounds and return the hash.+    finalization :: Word -> HalfSipData -> a++instance HalfSipHashResult Word32 where+    initialize :: HalfSipData -> HalfSipData+    initialize = id++    finalization :: Word -> HalfSipData -> Word32+    finalization d (HalfSipData !v0 !v1 !v2 !v3) =+        let v2' = v2 `xor` 0xff+            (HalfSipData !_ v1' _ !v3') = halfSipRounds d (HalfSipData v0 v1 v2' v3)+         in v1' `xor` v3'++instance HalfSipHashResult Word64 where+    initialize :: HalfSipData -> HalfSipData+    initialize (HalfSipData !v0 !v1 !v2 !v3) = HalfSipData v0 (v1 `xor` 0xee) v2 v3++    finalization :: Word -> HalfSipData -> Word64+    finalization d (HalfSipData !v0 !v1 !v2 !v3) =+        let v2' = v2 `xor` 0xee+            (HalfSipData !v0' !v1' !v2'' !v3') = halfSipRounds d (HalfSipData v0 v1 v2' v3)+            word0 = v1' `xor` v3'+            v1'' = v1' `xor` 0xdd+            (HalfSipData _ !v1''' _ !v3'') = halfSipRounds d (HalfSipData v0' v1'' v2'' v3')+            word1 = v1''' `xor` v3''+         in (fromIntegral word1 `shiftL` 32) + fromIntegral word0++-- | Constraint for containers hashed with HalfSipHash.+type HalfSipHashData a = (MonoFoldable a, ByteFoldable (Element a))++-- | HalfSipHash internal state, consisting of four 32-bit words.+data HalfSipData = HalfSipData+    { hv0 :: {-# UNPACK #-} !Word32+    , hv1 :: {-# UNPACK #-} !Word32+    , hv2 :: {-# UNPACK #-} !Word32+    , hv3 :: {-# UNPACK #-} !Word32+    }++-- | Internal HalfSipHash accumulator.+data HalfSipStream = HalfSipStream+    { hsData :: {-# UNPACK #-} !HalfSipData+    -- ^ HalfSipHash state.+    , hsWord :: {-# UNPACK #-} !Word32+    -- ^ Input bytes buffered so far, in little-endian order.+    , hsCount :: {-# UNPACK #-} !Int+    -- ^ Number of bytes buffered in 'hsWord' (0-3).+    , hsLen :: {-# UNPACK #-} !Word8+    -- ^ Total number of input bytes, modulo 256.+    }++{- | Compute HalfSipHash-@c@-@d@ of a monomorphic container.++@c@ and @d@ are the compression and finalization round counts;+HalfSipHash-2-4 is the standard variant.++Byte order: the 'Word64' key holds the 8 reference key bytes in+big-endian order, and each 32-bit half is then read as a little-endian+word. The result is the reference implementation's output word: a+'Word32' result is the 32-bit tag. A 'Word64' result packs the first+32-bit tag word in the low half and the second in the high half; its+little-endian serialization is the 8-byte reference digest.++Example:+@+halfSipHash \@'Word32' 2 4 0xc0ffee \"hello\"+@+-}+halfSipHash :: forall result mono. (HalfSipHashData mono, HalfSipHashResult result) => Word -> Word -> Word64 -> mono -> result+halfSipHash c d key mono =+    case ofoldl' (foldlBytes (step c)) initStream mono of+        HalfSipStream{hsData = state, hsWord = word, hsLen = len} ->+            finalization d (compress c state (word .|. (fromIntegral len `shiftL` 24)))+  where+    initData :: HalfSipData+    initData =+        HalfSipData+            { hv0 = k0+            , hv1 = k1+            , hv2 = k0 `xor` 0x6c796765+            , hv3 = k1 `xor` 0x74656462+            }+      where+        k0 :: Word32+        k0 = byteSwap32 . fromIntegral $ key `shiftR` 32++        k1 :: Word32+        k1 = byteSwap32 . fromIntegral $ key .&. 0xffffffff++    initStream :: HalfSipStream+    initStream =+        HalfSipStream+            { hsData = initialize @result initData+            , hsWord = 0+            , hsCount = 0+            , hsLen = 0+            }+{-# INLINEABLE halfSipHash #-}++step :: Word -> HalfSipStream -> Word8 -> HalfSipStream+step c HalfSipStream{hsData = d, hsWord = word, hsCount = n, hsLen = len} !b =+    let word' = word .|. (fromIntegral b `shiftL` (8 * n))+        len' = len + 1+     in if n == 3+            then HalfSipStream{hsData = compress c d word', hsWord = 0, hsCount = 0, hsLen = len'}+            else HalfSipStream{hsData = d, hsWord = word', hsCount = n + 1, hsLen = len'}+{-# INLINE step #-}++compress :: Word -> HalfSipData -> Word32 -> HalfSipData+compress c (HalfSipData !v0 !v1 !v2 !v3) m =+    let v3' = v3 `xor` m+        (HalfSipData !v0' !v1' !v2' !v3'') = halfSipRounds c (HalfSipData v0 v1 v2 v3')+        v0'' = v0' `xor` m+     in HalfSipData v0'' v1' v2' v3''+{-# INLINE compress #-}++halfSipRound :: HalfSipData -> HalfSipData+halfSipRound (HalfSipData !v0 !v1 !v2 !v3) =+    let v0' = v0 + v1+        v1' = v1 `rotateL` 5+        v1'' = v1' `xor` v0'+        v0'' = v0' `rotateL` 16+        v2' = v2 + v3+        v3' = v3 `rotateL` 8+        v3'' = v3' `xor` v2'+        v0''' = v0'' + v3''+        v3''' = v3'' `rotateL` 7+        v3'''' = v3''' `xor` v0'''+        v2'' = v2' + v1''+        v1''' = v1'' `rotateL` 13+        v1'''' = v1''' `xor` v2''+        v2''' = v2'' `rotateL` 16+     in HalfSipData v0''' v1'''' v2''' v3''''+{-# INLINE halfSipRound #-}++halfSipRoundN :: Word -> HalfSipData -> HalfSipData+halfSipRoundN 0 !x = x+halfSipRoundN n !x = halfSipRoundN (n - 1) $! halfSipRound x++-- | Unrolled variant of 'halfSipRoundN' for the small counts used in practice.+halfSipRounds :: Word -> HalfSipData -> HalfSipData+halfSipRounds 1 !x = halfSipRound x+halfSipRounds 2 !x = halfSipRound (halfSipRound x)+halfSipRounds 3 !x = halfSipRound (halfSipRound (halfSipRound x))+halfSipRounds 4 !x = halfSipRound (halfSipRound (halfSipRound (halfSipRound x)))+halfSipRounds n !x = halfSipRoundN n x+{-# INLINE halfSipRounds #-}
+ src/Data/Hash/Mono/Internal.hs view
@@ -0,0 +1,43 @@+-- | Internal helpers shared by the hash implementations.+module Data.Hash.Mono.Internal (+    byteSwap64,+    byteSwap32,+)+where++import Data.Bits (Bits (shiftL, shiftR, (.&.)))+import Data.Word (Word32, Word64)++-- | Byte-swap a 'Word64'.+byteSwap64 :: Word64 -> Word64+byteSwap64 w =+    let c0 = (w `shiftR` 56) .&. 0xff+        c1 = (w `shiftR` 48) .&. 0xff+        c2 = (w `shiftR` 40) .&. 0xff+        c3 = (w `shiftR` 32) .&. 0xff+        c4 = (w `shiftR` 24) .&. 0xff+        c5 = (w `shiftR` 16) .&. 0xff+        c6 = (w `shiftR` 8) .&. 0xff+        c7 = w .&. 0xff+     in c0+            + (c1 `shiftL` 8)+            + (c2 `shiftL` 16)+            + (c3 `shiftL` 24)+            + (c4 `shiftL` 32)+            + (c5 `shiftL` 40)+            + (c6 `shiftL` 48)+            + (c7 `shiftL` 56)+{-# INLINEABLE byteSwap64 #-}++-- | Byte-swap a 'Word32'.+byteSwap32 :: Word32 -> Word32+byteSwap32 w =+    let c0 = (w `shiftR` 24) .&. 0xff+        c1 = (w `shiftR` 16) .&. 0xff+        c2 = (w `shiftR` 8) .&. 0xff+        c3 = w .&. 0xff+     in c0+            + (c1 `shiftL` 8)+            + (c2 `shiftL` 16)+            + (c3 `shiftL` 24)+{-# INLINEABLE byteSwap32 #-}
+ src/Data/Hash/Mono/Internal/ByteFoldable.hs view
@@ -0,0 +1,163 @@+{-# LANGUAGE InstanceSigs #-}++-- | Byte encoding for types.+module Data.Hash.Mono.Internal.ByteFoldable (+    ByteFoldable (..),+)+where++import Data.Bits (Bits (shiftR, (.&.)))+import Data.Char qualified as Char+import Data.Int (Int16, Int32, Int64, Int8)+import Data.WideWord.Word128 (Word128 (..))+import Data.WideWord.Word256 (Word256 (..))+import Data.Word (Word16, Word32, Word64, Word8)++{- | Types with a fixed byte encoding.++An instance must define a fixed order for the bytes to be folded.+-}+class ByteFoldable a where+    -- | Fold over the bytes of a value.+    foldlBytes :: (b -> Word8 -> b) -> b -> a -> b++{- | 'Char' is encoded as+<https://wtf-8.codeberg.page WTF-8>, the UTF-8 encoding extended to+lone surrogates. For all other code points the bytes are ordinary UTF-8.++'Char' can represent lone surrogates, which strict UTF-8 cannot encode.+Replacing them, as @Text@ does with @U+FFFD@, would be lossy and would let+distinct strings produce the same bytes. WTF-8 instead uses the ordinary+three-byte shape for them, so every 'Char' has an encoding, the encoding+stays injective, and valid text remains plain UTF-8. A 'String' and a+@Text@ containing a lone surrogate therefore encode differently.+-}+instance ByteFoldable Char where+    foldlBytes f z c+        | n < 0x80 = f z (fromIntegral n)+        | n < 0x800 =+            f+                (f z (fromIntegral (0xc0 + (n `shiftR` 6))))+                (fromIntegral (0x80 + (n .&. 0x3f)))+        | n < 0x10000 =+            f+                ( f+                    (f z (fromIntegral (0xe0 + (n `shiftR` 12))))+                    (fromIntegral (0x80 + ((n `shiftR` 6) .&. 0x3f)))+                )+                (fromIntegral (0x80 + (n .&. 0x3f)))+        | otherwise =+            f+                ( f+                    ( f+                        (f z (fromIntegral (0xf0 + (n `shiftR` 18))))+                        (fromIntegral (0x80 + ((n `shiftR` 12) .&. 0x3f)))+                    )+                    (fromIntegral (0x80 + ((n `shiftR` 6) .&. 0x3f)))+                )+                (fromIntegral (0x80 + (n .&. 0x3f)))+      where+        n :: Int+        n = Char.ord c+    {-# INLINE foldlBytes #-}++instance ByteFoldable Word8 where+    foldlBytes f = f+    {-# INLINE foldlBytes #-}++{- | Encoded as its two's-complement bit pattern, the same bytes as the+corresponding 'Word8'.+-}+instance ByteFoldable Int8 where+    foldlBytes f z i = foldlBytes f z (fromIntegral i :: Word8)+    {-# INLINE foldlBytes #-}++-- | Encoded as two bytes, most significant first.+instance ByteFoldable Word16 where+    foldlBytes f z w =+        f (f z (fromIntegral (w `shiftR` 8))) (fromIntegral w)+    {-# INLINE foldlBytes #-}++{- | Encoded as its two's-complement bit pattern, the same bytes as the+corresponding 'Word16'.+-}+instance ByteFoldable Int16 where+    foldlBytes f z i = foldlBytes f z (fromIntegral i :: Word16)+    {-# INLINE foldlBytes #-}++-- | Encoded as four bytes, most significant first.+instance ByteFoldable Word32 where+    foldlBytes f z w =+        f+            ( f+                ( f+                    (f z (fromIntegral (w `shiftR` 24)))+                    (fromIntegral (w `shiftR` 16))+                )+                (fromIntegral (w `shiftR` 8))+            )+            (fromIntegral w)+    {-# INLINE foldlBytes #-}++{- | Encoded as its two's-complement bit pattern, the same bytes as the+corresponding 'Word32'.+-}+instance ByteFoldable Int32 where+    foldlBytes f z i = foldlBytes f z (fromIntegral i :: Word32)+    {-# INLINE foldlBytes #-}++-- | Encoded as eight bytes, most significant first.+instance ByteFoldable Word64 where+    foldlBytes f z w =+        f+            ( f+                ( f+                    ( f+                        ( f+                            ( f+                                ( f+                                    (f z (fromIntegral (w `shiftR` 56)))+                                    (fromIntegral (w `shiftR` 48))+                                )+                                (fromIntegral (w `shiftR` 40))+                            )+                            (fromIntegral (w `shiftR` 32))+                        )+                        (fromIntegral (w `shiftR` 24))+                    )+                    (fromIntegral (w `shiftR` 16))+                )+                (fromIntegral (w `shiftR` 8))+            )+            (fromIntegral w)+    {-# INLINE foldlBytes #-}++{- | Encoded as its two's-complement bit pattern, the same bytes as the+corresponding 'Word64'.+-}+instance ByteFoldable Int64 where+    foldlBytes f z i = foldlBytes f z (fromIntegral i :: Word64)+    {-# INLINE foldlBytes #-}++-- | Encoded as sixteen bytes, most significant first.+instance ByteFoldable Word128 where+    foldlBytes f z w =+        foldlBytes f (foldlBytes f z (word128Hi64 w)) (word128Lo64 w)+    {-# INLINE foldlBytes #-}++-- | Encoded as thirty-two bytes, most significant first.+instance ByteFoldable Word256 where+    foldlBytes f z w =+        foldlBytes+            f+            ( foldlBytes+                f+                ( foldlBytes+                    f+                    (foldlBytes f z (word256hi w))+                    (word256m1 w)+                )+                (word256m0 w)+            )+            (word256lo w)+    {-# INLINE foldlBytes #-}
+ src/Data/Hash/Mono/SipHash.hs view
@@ -0,0 +1,171 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE StrictData #-}+{-# LANGUAGE TypeApplications #-}++-- | SipHash-@c@-@d@ for any 'MonoFoldable' container.+module Data.Hash.Mono.SipHash (+    SipHashData,+    SipHashResult,+    sipHash,+)+where++import Data.Bits (Bits (rotateL, shiftL, xor, (.|.)))+import Data.Hash.Mono.Internal (byteSwap64)+import Data.Hash.Mono.Internal.ByteFoldable (ByteFoldable (..))+import Data.MonoTraversable (Element, MonoFoldable (ofoldl'))+import Data.WideWord.Word128 (Word128 (..))+import Data.Word (Word64, Word8)++-- | Result types that 'sipHash' can produce.+class SipHashResult a where+    -- | Adjust the initial state for the selected result type.+    initialize :: SipData -> SipData++    -- | Run the finalization rounds and return the hash.+    finalization :: Word -> SipData -> a++instance SipHashResult Word64 where+    initialize :: SipData -> SipData+    initialize = id++    finalization :: Word -> SipData -> Word64+    finalization d (SipData !v0 !v1 !v2 !v3) =+        let v2' = v2 `xor` 0xff+            (SipData !v0' !v1' !v2'' !v3') = sipRounds d (SipData v0 v1 v2' v3)+         in v0' `xor` v1' `xor` v2'' `xor` v3'++instance SipHashResult Word128 where+    initialize :: SipData -> SipData+    initialize (SipData !v0 !v1 !v2 !v3) = SipData v0 (v1 `xor` 0xee) v2 v3++    finalization :: Word -> SipData -> Word128+    finalization d (SipData !v0 !v1 !v2 !v3) =+        let v2' = v2 `xor` 0xee+            (SipData !v0' !v1' !v2'' !v3') = sipRounds d (SipData v0 v1 v2' v3)+            word0 = v0' `xor` v1' `xor` v2'' `xor` v3'+            v1'' = v1' `xor` 0xdd+            (SipData !v0'' !v1''' !v2''' !v3'') = sipRounds d (SipData v0' v1'' v2'' v3')+            word1 = v0'' `xor` v1''' `xor` v2''' `xor` v3''+         in Word128 word1 word0++-- | Constraint for containers hashable with SipHash.+type SipHashData a = (MonoFoldable a, ByteFoldable (Element a))++-- | SipHash internal state.+data SipData = SipData+    { sv0 :: {-# UNPACK #-} !Word64+    , sv1 :: {-# UNPACK #-} !Word64+    , sv2 :: {-# UNPACK #-} !Word64+    , sv3 :: {-# UNPACK #-} !Word64+    }++-- | Internal SipHash accumulator.+data SipStream = SipStream+    { ssData :: {-# UNPACK #-} !SipData+    -- ^ SipHash state.+    , ssWord :: {-# UNPACK #-} !Word64+    -- ^ Input bytes buffered so far, in little-endian order.+    , ssCount :: {-# UNPACK #-} !Int+    -- ^ Number of bytes buffered in 'ssWord'.+    , ssLen :: {-# UNPACK #-} !Word8+    -- ^ Total number of input bytes, modulo 256.+    }++{- | Compute SipHash-@c@-@d@ of a monomorphic container.++@c@ and @d@ are the compression and finalization round counts;+SipHash-2-4 is the standard variant.++Byte order: the @Word128@ key holds the 16 reference key bytes in+big-endian order, and each 64-bit half is then read as a little-endian+word. The result is the reference implementation's output word: a+'Word64' result is the 64-bit tag. A @Word128@ result packs the first+64-bit tag word in the low half and the second in the high half; its+little-endian serialization is the 16-byte reference digest.++Example:+@+sipHash \@'Word64' 2 4 0xc0ffee \"hello\"+@+-}+sipHash :: forall result mono. (SipHashData mono, SipHashResult result) => Word -> Word -> Word128 -> mono -> result+sipHash c d key mono =+    case ofoldl' (foldlBytes (step c)) initStream mono of+        SipStream{ssData = state, ssWord = word, ssLen = len} ->+            finalization d (compress c state (word .|. (fromIntegral len `shiftL` 56)))+  where+    initData :: SipData+    initData =+        SipData+            { sv0 = k0 `xor` 0x736f6d6570736575+            , sv1 = k1 `xor` 0x646f72616e646f6d+            , sv2 = k0 `xor` 0x6c7967656e657261+            , sv3 = k1 `xor` 0x7465646279746573+            }+      where+        k0 :: Word64+        k0 = byteSwap64 $ word128Hi64 key++        k1 :: Word64+        k1 = byteSwap64 $ word128Lo64 key++    initStream :: SipStream+    initStream =+        SipStream+            { ssData = initialize @result initData+            , ssWord = 0+            , ssCount = 0+            , ssLen = 0+            }+{-# INLINEABLE sipHash #-}++step :: Word -> SipStream -> Word8 -> SipStream+step c SipStream{ssData = d, ssWord = word, ssCount = n, ssLen = len} !b =+    let word' = word .|. (fromIntegral b `shiftL` (8 * n))+        len' = len + 1+     in if n == 7+            then SipStream{ssData = compress c d word', ssWord = 0, ssCount = 0, ssLen = len'}+            else SipStream{ssData = d, ssWord = word', ssCount = n + 1, ssLen = len'}+{-# INLINE step #-}++compress :: Word -> SipData -> Word64 -> SipData+compress c (SipData !v0 !v1 !v2 !v3) m =+    let v3' = v3 `xor` m+        (SipData !v0' !v1' !v2' !v3'') = sipRounds c (SipData v0 v1 v2 v3')+        v0'' = v0' `xor` m+     in SipData v0'' v1' v2' v3''+{-# INLINE compress #-}++sipRound :: SipData -> SipData+sipRound (SipData !v0 !v1 !v2 !v3) =+    let v0' = v0 + v1+        v1' = v1 `rotateL` 13+        v1'' = v1' `xor` v0'+        v0'' = v0' `rotateL` 32+        v2' = v2 + v3+        v3' = v3 `rotateL` 16+        v3'' = v3' `xor` v2'+        v0''' = v0'' + v3''+        v3''' = v3'' `rotateL` 21+        v3'''' = v3''' `xor` v0'''+        v2'' = v2' + v1''+        v1''' = v1'' `rotateL` 17+        v1'''' = v1''' `xor` v2''+        v2''' = v2'' `rotateL` 32+     in SipData v0''' v1'''' v2''' v3''''+{-# INLINE sipRound #-}++sipRoundN :: Word -> SipData -> SipData+sipRoundN 0 !x = x+sipRoundN n !x = sipRoundN (n - 1) $! sipRound x++-- | Unrolled variant of 'sipRoundN' for the small counts used in practice.+sipRounds :: Word -> SipData -> SipData+sipRounds 1 !x = sipRound x+sipRounds 2 !x = sipRound (sipRound x)+sipRounds 3 !x = sipRound (sipRound (sipRound x))+sipRounds 4 !x = sipRound (sipRound (sipRound (sipRound x)))+sipRounds n !x = sipRoundN n x+{-# INLINE sipRounds #-}
+ test/Main.hs view
@@ -0,0 +1,362 @@+{-# LANGUAGE TypeApplications #-}++module Main (main) where++import Data.Bits (Bits, shiftL, shiftR, (.&.))+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BSC+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Lazy.Char8 as BSLC+import Data.Hash.Mono.FNV (fnv1, fnv1a)+import Data.Hash.Mono.HalfSipHash+import Data.Hash.Mono.SipHash+import Data.Int (Int16, Int32, Int64, Int8)+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import Data.WideWord.Word128 (Word128)+import Data.WideWord.Word256 (Word256)+import Data.Word (Word16, Word32, Word64, Word8)+import qualified Test.Data.ByteFoldable+import qualified Test.Data.FNV+import qualified Test.Data.HalfSipHash+import qualified Test.Data.SipHash+import Test.Tasty (TestTree, defaultMain, testGroup)+import Test.Tasty.HUnit (assertBool, testCase, (@?=))++main :: IO ()+main = defaultMain tests++{- | Code points spanning the one- to four-byte UTF-8 ranges, including the+boundaries between them.+-}+charEncodingInput :: String+charEncodingInput = "\x00\x7f\x80\x7ff\x800\xffff\x10000\x1234\x1F600\x10FFFF"++-- | UTF-8 bytes of a 'Char'; lone surrogates use the 3-byte WTF-8 form.+charBytes :: Char -> [Word8]+charBytes c+    | n < 0x80 = [fromIntegral n]+    | n < 0x800 = [byte 0xc0 6, byte 0x80 0]+    | n < 0x10000 = [byte 0xe0 12, byte 0x80 6, byte 0x80 0]+    | otherwise = [byte 0xf0 18, byte 0x80 12, byte 0x80 6, byte 0x80 0]+  where+    n = fromEnum c+    byte mask shift = fromIntegral (mask + ((n `shiftR` shift) .&. 0x3f))++-- | UTF-8 bytes of a 'String'.+utf8 :: String -> BS.ByteString+utf8 = TE.encodeUtf8 . T.pack++-- | Big-endian bytes of a fixed-width word.+wordBytes :: (Bits a, Integral a) => Int -> a -> [Word8]+wordBytes width w =+    [fromIntegral (w `shiftR` (8 * i)) | i <- [width - 1, width - 2 .. 0]]++packWords :: (Bits a, Integral a) => Int -> [a] -> BS.ByteString+packWords width = BS.pack . concatMap (wordBytes width)++word16Samples :: [Word16]+word16Samples = [0x0102, 0x0304, 0xfffe]++word32Samples :: [Word32]+word32Samples = [0x01020304, 0x05060708, 0xdeadbeef]++word64Samples :: [Word64]+word64Samples = [0x0102030405060708, 0x1112131415161718, 0xdeadbeefcafed00d]++-- | Boundary values for the signed element types.+int8Samples :: [Int8]+int8Samples = [minBound, -1, 0, 1, maxBound]++int16Samples :: [Int16]+int16Samples = [minBound, -1, 0, 1, maxBound]++int32Samples :: [Int32]+int32Samples = [minBound, -1, 0, 1, maxBound]++int64Samples :: [Int64]+int64Samples = [minBound, -1, 0, 1, maxBound]++-- | Big-endian two's-complement encoding of the signed sample lists.+int8SampleBytes :: BS.ByteString+int8SampleBytes = BS.pack [0x80, 0xff, 0x00, 0x01, 0x7f]++int16SampleBytes :: BS.ByteString+int16SampleBytes =+    BS.pack [0x80, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x7f, 0xff]++int32SampleBytes :: BS.ByteString+int32SampleBytes =+    BS.pack+        [ 0x80+        , 0x00+        , 0x00+        , 0x00+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x01+        , 0x7f+        , 0xff+        , 0xff+        , 0xff+        ]++int64SampleBytes :: BS.ByteString+int64SampleBytes =+    BS.pack+        [ 0x80+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x00+        , 0x01+        , 0x7f+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        , 0xff+        ]++word128Sample :: Word128+word128Sample =+    (fromIntegral (0x0102030405060708 :: Word64) `shiftL` 64)+        + fromIntegral (0x1112131415161718 :: Word64)++word256Sample :: Word256+word256Sample =+    (fromIntegral (0x2122232425262728 :: Word64) `shiftL` 192)+        + (fromIntegral (0x3132333435363738 :: Word64) `shiftL` 128)+        + (fromIntegral (0x4142434445464748 :: Word64) `shiftL` 64)+        + fromIntegral (0x5152535455565758 :: Word64)++tests :: TestTree+tests =+    testGroup+        "Tests"+        [ goldenSamples+        , inputEncoding+        , encodingCollisions+        , Test.Data.ByteFoldable.tests+        ]++{- | Hashes must match the reference vectors in 'Test.Data.SipHash',+'Test.Data.HalfSipHash', and 'Test.Data.FNV'.+-}+goldenSamples :: TestTree+goldenSamples =+    testGroup+        "Golden Samples"+        [ testGroup+            "FNV"+            [ testCase "FNV1  Word32 String matches UTF-8 bytes" $ fmap (fnv1 @Word32) (Test.Data.FNV.inputs @String) @?= fmap (fnv1 @Word32 . utf8) (Test.Data.FNV.inputs @String)+            , testCase "FNV1a Word32 String matches UTF-8 bytes" $ fmap (fnv1a @Word32) (Test.Data.FNV.inputs @String) @?= fmap (fnv1a @Word32 . utf8) (Test.Data.FNV.inputs @String)+            , testCase "FNV1  Word64 String matches UTF-8 bytes" $ fmap (fnv1 @Word64) (Test.Data.FNV.inputs @String) @?= fmap (fnv1 @Word64 . utf8) (Test.Data.FNV.inputs @String)+            , testCase "FNV1a Word64 String matches UTF-8 bytes" $ fmap (fnv1a @Word64) (Test.Data.FNV.inputs @String) @?= fmap (fnv1a @Word64 . utf8) (Test.Data.FNV.inputs @String)+            , testCase "FNV1  Word32 Text matches UTF-8 bytes" $ fmap (fnv1 @Word32) (Test.Data.FNV.inputs @Text) @?= fmap (fnv1 @Word32 . TE.encodeUtf8) (Test.Data.FNV.inputs @Text)+            , testCase "FNV1a Word32 Text matches UTF-8 bytes" $ fmap (fnv1a @Word32) (Test.Data.FNV.inputs @Text) @?= fmap (fnv1a @Word32 . TE.encodeUtf8) (Test.Data.FNV.inputs @Text)+            , testCase "FNV1  Word64 Text matches UTF-8 bytes" $ fmap (fnv1 @Word64) (Test.Data.FNV.inputs @Text) @?= fmap (fnv1 @Word64 . TE.encodeUtf8) (Test.Data.FNV.inputs @Text)+            , testCase "FNV1a Word64 Text matches UTF-8 bytes" $ fmap (fnv1a @Word64) (Test.Data.FNV.inputs @Text) @?= fmap (fnv1a @Word64 . TE.encodeUtf8) (Test.Data.FNV.inputs @Text)+            , testCase "FNV1a Word32 non-ASCII String" $ fmap (fnv1a @Word32) Test.Data.FNV.utf8Inputs @?= Test.Data.FNV.fnv1aVectorsForWord32Utf8+            , testCase "FNV1a Word32 non-ASCII Text" $ fmap ((fnv1a @Word32) . T.pack) Test.Data.FNV.utf8Inputs @?= Test.Data.FNV.fnv1aVectorsForWord32Utf8+            , testCase "FNV1a Word64 non-ASCII String" $ fmap (fnv1a @Word64) Test.Data.FNV.utf8Inputs @?= Test.Data.FNV.fnv1aVectorsForWord64Utf8+            , testCase "FNV1a Word64 non-ASCII Text" $ fmap ((fnv1a @Word64) . T.pack) Test.Data.FNV.utf8Inputs @?= Test.Data.FNV.fnv1aVectorsForWord64Utf8+            , testCase "FNV1  Word32 ByteString" $ fmap (fnv1 @Word32) (Test.Data.FNV.inputs @BS.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord32+            , testCase "FNV1a Word32 ByteString" $ fmap (fnv1a @Word32) (Test.Data.FNV.inputs @BS.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord32+            , testCase "FNV1  Word64 ByteString" $ fmap (fnv1 @Word64) (Test.Data.FNV.inputs @BS.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord64+            , testCase "FNV1a Word64 ByteString" $ fmap (fnv1a @Word64) (Test.Data.FNV.inputs @BS.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord64+            , testCase "FNV1  Word32 Lazy ByteString" $ fmap (fnv1 @Word32) (Test.Data.FNV.inputs @BSL.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord32+            , testCase "FNV1a Word32 Lazy ByteString" $ fmap (fnv1a @Word32) (Test.Data.FNV.inputs @BSL.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord32+            , testCase "FNV1  Word64 Lazy ByteString" $ fmap (fnv1 @Word64) (Test.Data.FNV.inputs @BSL.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord64+            , testCase "FNV1a Word64 Lazy ByteString" $ fmap (fnv1a @Word64) (Test.Data.FNV.inputs @BSL.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord64+            , testCase "FNV1  Word32 ByteString Char8" $ fmap (fnv1 @Word32) (Test.Data.FNV.inputs @BSC.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord32+            , testCase "FNV1a Word32 ByteString Char8" $ fmap (fnv1a @Word32) (Test.Data.FNV.inputs @BSC.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord32+            , testCase "FNV1  Word64 ByteString Char8" $ fmap (fnv1 @Word64) (Test.Data.FNV.inputs @BSC.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord64+            , testCase "FNV1a Word64 ByteString Char8" $ fmap (fnv1a @Word64) (Test.Data.FNV.inputs @BSC.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord64+            , testCase "FNV1  Word32 Lazy ByteString Char8" $ fmap (fnv1 @Word32) (Test.Data.FNV.inputs @BSLC.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord32+            , testCase "FNV1a Word32 Lazy ByteString Char8" $ fmap (fnv1a @Word32) (Test.Data.FNV.inputs @BSLC.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord32+            , testCase "FNV1  Word64 Lazy ByteString Char8" $ fmap (fnv1 @Word64) (Test.Data.FNV.inputs @BSLC.ByteString) @?= Test.Data.FNV.fnv1VectorsForWord64+            , testCase "FNV1a Word64 Lazy ByteString Char8" $ fmap (fnv1a @Word64) (Test.Data.FNV.inputs @BSLC.ByteString) @?= Test.Data.FNV.fnv1aVectorsForWord64+            ]+        , testGroup+            "SipHash"+            [ testCase "SipHash-2-4 Word64 String" $ fmap (sipHash @Word64 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @String) @?= Test.Data.SipHash.sipHash24VectorsForWord64+            , testCase "SipHash-2-4 Word64 Text" $ fmap (sipHash @Word64 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @Text) @?= Test.Data.SipHash.sipHash24VectorsForWord64+            , testCase "SipHash-2-4 Word64 ByteString" $ fmap (sipHash @Word64 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BS.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord64+            , testCase "SipHash-2-4 Word64 Lazy ByteString" $ fmap (sipHash @Word64 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BSL.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord64+            , testCase "SipHash-2-4 Word64 ByteString Char8" $ fmap (sipHash @Word64 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BSC.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord64+            , testCase "SipHash-2-4 Word64 Lazy ByteString Char8" $ fmap (sipHash @Word64 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BSLC.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord64+            , testCase "SipHash-2-4 Word128 String" $ fmap (sipHash @Word128 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @String) @?= Test.Data.SipHash.sipHash24VectorsForWord128+            , testCase "SipHash-2-4 Word128 Text" $ fmap (sipHash @Word128 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @Text) @?= Test.Data.SipHash.sipHash24VectorsForWord128+            , testCase "SipHash-2-4 Word128 ByteString" $ fmap (sipHash @Word128 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BS.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord128+            , testCase "SipHash-2-4 Word128 Lazy ByteString" $ fmap (sipHash @Word128 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BSL.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord128+            , testCase "SipHash-2-4 Word128 ByteString Char8" $ fmap (sipHash @Word128 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BSC.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord128+            , testCase "SipHash-2-4 Word128 Lazy ByteString Char8" $ fmap (sipHash @Word128 2 4 Test.Data.SipHash.key) (Test.Data.SipHash.inputs @BSLC.ByteString) @?= Test.Data.SipHash.sipHash24VectorsForWord128+            , testCase "SipHash-2-4 Word64 boundary lengths" $ fmap (sipHash @Word64 2 4 Test.Data.SipHash.key) Test.Data.SipHash.boundaryInputs @?= Test.Data.SipHash.boundaryVectorsForWord64+            ]+        , testGroup+            "HalfSipHash"+            [ testCase "HalfSipHash-2-4 Word32 String" $ fmap (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @String) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord32+            , testCase "HalfSipHash-2-4 Word32 Text" $ fmap (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @Text) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord32+            , testCase "HalfSipHash-2-4 Word32 ByteString" $ fmap (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BS.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord32+            , testCase "HalfSipHash-2-4 Word32 Lazy ByteString" $ fmap (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BSL.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord32+            , testCase "HalfSipHash-2-4 Word32 ByteString Char8" $ fmap (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BSC.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord32+            , testCase "HalfSipHash-2-4 Word32 Lazy ByteString Char8" $ fmap (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BSLC.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord32+            , testCase "HalfSipHash-2-4 Word64 String" $ fmap (halfSipHash @Word64 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @String) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord64+            , testCase "HalfSipHash-2-4 Word64 Text" $ fmap (halfSipHash @Word64 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @Text) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord64+            , testCase "HalfSipHash-2-4 Word64 ByteString" $ fmap (halfSipHash @Word64 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BS.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord64+            , testCase "HalfSipHash-2-4 Word64 Lazy ByteString" $ fmap (halfSipHash @Word64 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BSL.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord64+            , testCase "HalfSipHash-2-4 Word64 ByteString Char8" $ fmap (halfSipHash @Word64 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BSC.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord64+            , testCase "HalfSipHash-2-4 Word64 Lazy ByteString Char8" $ fmap (halfSipHash @Word64 2 4 Test.Data.HalfSipHash.key) (Test.Data.HalfSipHash.inputs @BSLC.ByteString) @?= Test.Data.HalfSipHash.halfSipHash24VectorsForWord64+            , testCase "HalfSipHash-2-4 Word32 boundary lengths" $ fmap (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) Test.Data.HalfSipHash.boundaryInputs @?= Test.Data.HalfSipHash.boundaryVectorsForWord32+            ]+        ]++{- | Every element type must feed the hash the same bytes its explicit+byte encoding does, so typed inputs and byte inputs agree.+-}+inputEncoding :: TestTree+inputEncoding =+    testGroup+        "Input Encoding"+        [ testGroup+            "FNV"+            [ testCase "FNV1a Word64 Char encoding matches bytes" $ do+                let bytes = BS.pack (concatMap charBytes charEncodingInput)+                bytes @?= TE.encodeUtf8 (T.pack charEncodingInput)+                fnv1a @Word64 charEncodingInput @?= fnv1a @Word64 bytes+                fnv1a @Word64 (T.pack charEncodingInput) @?= fnv1a @Word64 bytes+                fnv1a @Word64 "\xD800" @?= fnv1a @Word64 (BS.pack [0xed, 0xa0, 0x80])+            , testCase "FNV1a Word64 word elements match bytes" $ do+                fnv1a @Word64 [word128Sample] @?= fnv1a @Word64 (BS.pack (wordBytes 16 word128Sample))+                fnv1a @Word64 [word256Sample] @?= fnv1a @Word64 (BS.pack (wordBytes 32 word256Sample))+            , testCase "FNV1 Word64 small word elements match bytes" $ do+                fnv1 @Word64 word16Samples @?= fnv1 @Word64 (packWords 2 word16Samples)+                fnv1 @Word64 word32Samples @?= fnv1 @Word64 (packWords 4 word32Samples)+                fnv1 @Word64 word64Samples @?= fnv1 @Word64 (packWords 8 word64Samples)+            , testCase "FNV1a Word64 small word elements match bytes" $ do+                fnv1a @Word64 word16Samples @?= fnv1a @Word64 (packWords 2 word16Samples)+                fnv1a @Word64 word32Samples @?= fnv1a @Word64 (packWords 4 word32Samples)+                fnv1a @Word64 word64Samples @?= fnv1a @Word64 (packWords 8 word64Samples)+            , testCase "FNV1a Word64 signed elements match two's complement bytes" $ do+                fnv1a @Word64 int8Samples @?= fnv1a @Word64 int8SampleBytes+                fnv1a @Word64 int16Samples @?= fnv1a @Word64 int16SampleBytes+                fnv1a @Word64 int32Samples @?= fnv1a @Word64 int32SampleBytes+                fnv1a @Word64 int64Samples @?= fnv1a @Word64 int64SampleBytes+            ]+        , testGroup+            "SipHash"+            [ testCase "SipHash-2-4 Word64 Char encoding matches bytes" $ do+                let bytes = BS.pack (concatMap charBytes charEncodingInput)+                bytes @?= TE.encodeUtf8 (T.pack charEncodingInput)+                sipHash @Word64 2 4 Test.Data.SipHash.key charEncodingInput @?= sipHash @Word64 2 4 Test.Data.SipHash.key bytes+                sipHash @Word64 2 4 Test.Data.SipHash.key (T.pack charEncodingInput) @?= sipHash @Word64 2 4 Test.Data.SipHash.key bytes+            , testCase "SipHash-2-4 Word64 word elements match bytes" $ do+                sipHash @Word64 2 4 Test.Data.SipHash.key [word128Sample] @?= sipHash @Word64 2 4 Test.Data.SipHash.key (BS.pack (wordBytes 16 word128Sample))+                sipHash @Word64 2 4 Test.Data.SipHash.key [word256Sample] @?= sipHash @Word64 2 4 Test.Data.SipHash.key (BS.pack (wordBytes 32 word256Sample))+            , testCase "SipHash-2-4 Word64 small word elements match bytes" $ do+                sipHash @Word64 2 4 Test.Data.SipHash.key word16Samples @?= sipHash @Word64 2 4 Test.Data.SipHash.key (packWords 2 word16Samples)+                sipHash @Word64 2 4 Test.Data.SipHash.key word32Samples @?= sipHash @Word64 2 4 Test.Data.SipHash.key (packWords 4 word32Samples)+                sipHash @Word64 2 4 Test.Data.SipHash.key word64Samples @?= sipHash @Word64 2 4 Test.Data.SipHash.key (packWords 8 word64Samples)+            , testCase "SipHash-2-4 Word64 signed elements match two's complement bytes" $ do+                sipHash @Word64 2 4 Test.Data.SipHash.key int8Samples @?= sipHash @Word64 2 4 Test.Data.SipHash.key int8SampleBytes+                sipHash @Word64 2 4 Test.Data.SipHash.key int16Samples @?= sipHash @Word64 2 4 Test.Data.SipHash.key int16SampleBytes+                sipHash @Word64 2 4 Test.Data.SipHash.key int32Samples @?= sipHash @Word64 2 4 Test.Data.SipHash.key int32SampleBytes+                sipHash @Word64 2 4 Test.Data.SipHash.key int64Samples @?= sipHash @Word64 2 4 Test.Data.SipHash.key int64SampleBytes+            ]+        , testGroup+            "HalfSipHash"+            [ testCase "HalfSipHash-2-4 Word32 Char encoding matches bytes" $ do+                let bytes = BS.pack (concatMap charBytes charEncodingInput)+                bytes @?= TE.encodeUtf8 (T.pack charEncodingInput)+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key charEncodingInput @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key bytes+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key (T.pack charEncodingInput) @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key bytes+            , testCase "HalfSipHash-2-4 Word32 word elements match bytes" $ do+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key [word128Sample] @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key (BS.pack (wordBytes 16 word128Sample))+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key [word256Sample] @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key (BS.pack (wordBytes 32 word256Sample))+            , testCase "HalfSipHash-2-4 Word32 small word elements match bytes" $ do+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key word16Samples @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key (packWords 2 word16Samples)+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key word32Samples @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key (packWords 4 word32Samples)+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key word64Samples @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key (packWords 8 word64Samples)+            , testCase "HalfSipHash-2-4 Word32 signed elements match two's complement bytes" $ do+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int8Samples @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int8SampleBytes+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int16Samples @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int16SampleBytes+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int32Samples @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int32SampleBytes+                halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int64Samples @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key int64SampleBytes+            ]+        ]++{- | Distinct texts that the old, non-prefix-free 'Char' encoding mapped to+the same bytes must hash differently.+-}+encodingCollisions :: TestTree+encodingCollisions =+    testGroup+        "Encoding Collisions"+        [ testGroup+            "FNV"+            [ testCase "FNV1a Word64 String" $ checkCollisions (fnv1a @Word64) id+            , testCase "FNV1a Word64 Text" $ checkCollisions (fnv1a @Word64) T.pack+            ]+        , testGroup+            "SipHash"+            [ testCase "SipHash-2-4 Word64 String" $ checkCollisions (sipHash @Word64 2 4 Test.Data.SipHash.key) id+            , testCase "SipHash-2-4 Word64 Text" $ checkCollisions (sipHash @Word64 2 4 Test.Data.SipHash.key) T.pack+            ]+        , testGroup+            "HalfSipHash"+            [ testCase "HalfSipHash-2-4 Word32 String" $ checkCollisions (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) id+            , testCase "HalfSipHash-2-4 Word32 Text" $ checkCollisions (halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key) T.pack+            ]+        ]++checkCollisions :: (Eq a, Show a) => (t -> a) -> (String -> t) -> IO ()+checkCollisions h mk =+    mapM_+        (\(label, x, y) -> assertBool label (h (mk x) /= h (mk y)))+        collisionPairs++collisionPairs :: [(String, String, String)]+collisionPairs =+    [ ("U+0100 and U+0001 U+0000 must not collide", "\x0100", "\x01\x00")+    , ("U+1234 and U+0012 U+0034 must not collide", "\x1234", "\x12\x34")+    , ("U+1F600 and U+0001 U+00F6 U+0000 must not collide", "\x1F600", "\x01\xF6\x00")+    ]
+ test/Test/Data/ByteFoldable.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE TypeApplications #-}++{- | Tests for the public 'ByteFoldable' extension point: an element type+defined outside the library must be hashable via its own instance, and must+produce exactly the hash of the bytes it emits.+-}+module Test.Data.ByteFoldable (tests) where++import qualified Data.ByteString as BS+import Data.Hash.Mono.FNV (fnv1a)+import Data.Hash.Mono.HalfSipHash (halfSipHash)+import Data.Hash.Mono.Internal.ByteFoldable (ByteFoldable (..))+import Data.Hash.Mono.SipHash (sipHash)+import Data.Word (Word32, Word64, Word8)+import qualified Test.Data.HalfSipHash+import qualified Test.Data.SipHash+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase, (@?=))++-- | A user-defined element with a two-byte encoding, high byte first.+data TwoBytes = TwoBytes !Word8 !Word8++instance ByteFoldable TwoBytes where+    foldlBytes f z (TwoBytes hi lo) = f (f z hi) lo++-- | The bytes the instance above emits.+sampleBytes :: BS.ByteString+sampleBytes = BS.pack [0x01, 0x02]++sample :: TwoBytes+sample = TwoBytes 0x01 0x02++samples :: [TwoBytes]+samples = [sample]++tests :: TestTree+tests =+    testGroup+        "ByteFoldable"+        [ testCase "custom instance matches raw bytes (FNV-1a)" $+            fnv1a @Word64 samples @?= fnv1a @Word64 sampleBytes+        , testCase "custom instance matches raw bytes (SipHash-2-4)" $+            sipHash @Word64 2 4 Test.Data.SipHash.key samples+                @?= sipHash @Word64 2 4 Test.Data.SipHash.key sampleBytes+        , testCase "custom instance matches raw bytes (HalfSipHash-2-4)" $+            halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key samples+                @?= halfSipHash @Word32 2 4 Test.Data.HalfSipHash.key sampleBytes+        ]
+ test/Test/Data/FNV.hs view
@@ -0,0 +1,1078 @@+{-# LANGUAGE OverloadedStrings #-}++module Test.Data.FNV where++import Data.String (IsString)+import Data.Word (Word32, Word64)++inputs :: (IsString a, Monoid a) => [a]+inputs =+    [ ""+    , "a"+    , "b"+    , "c"+    , "d"+    , "e"+    , "f"+    , "fo"+    , "foo"+    , "foob"+    , "fooba"+    , "foobar"+    , "\x00"+    , "a\x00"+    , "b\x00"+    , "c\x00"+    , "d\x00"+    , "e\x00"+    , "f\x00"+    , "fo\x00"+    , "foo\x00"+    , "foob\x00"+    , "fooba\x00"+    , "foobar\x00"+    , "ch"+    , "cho"+    , "chon"+    , "chong"+    , "chongo"+    , "chongo "+    , "chongo w"+    , "chongo wa"+    , "chongo was"+    , "chongo was "+    , "chongo was h"+    , "chongo was he"+    , "chongo was her"+    , "chongo was here"+    , "chongo was here!"+    , "chongo was here!\n"+    , "ch\x00"+    , "cho\x00"+    , "chon\x00"+    , "chong\x00"+    , "chongo\x00"+    , "chongo \x00"+    , "chongo w\x00"+    , "chongo wa\x00"+    , "chongo was\x00"+    , "chongo was \x00"+    , "chongo was h\x00"+    , "chongo was he\x00"+    , "chongo was her\x00"+    , "chongo was here\x00"+    , "chongo was here!\x00"+    , "chongo was here!\n\x00"+    , "cu"+    , "cur"+    , "curd"+    , "curds"+    , "curds "+    , "curds a"+    , "curds an"+    , "curds and"+    , "curds and "+    , "curds and w"+    , "curds and wh"+    , "curds and whe"+    , "curds and whey"+    , "curds and whey\n"+    , "cu\x00"+    , "cur\x00"+    , "curd\x00"+    , "curds\x00"+    , "curds \x00"+    , "curds a\x00"+    , "curds an\x00"+    , "curds and\x00"+    , "curds and \x00"+    , "curds and w\x00"+    , "curds and wh\x00"+    , "curds and whe\x00"+    , "curds and whey\x00"+    , "curds and whey\n\x00"+    , "hi"+    , "hi\x00"+    , "hello"+    , "hello\x00"+    , "\xff\x00\x00\x01"+    , "\x01\x00\x00\xff"+    , "\xff\x00\x00\x02"+    , "\x02\x00\x00\xff"+    , "\xff\x00\x00\x03"+    , "\x03\x00\x00\xff"+    , "\xff\x00\x00\x04"+    , "\x04\x00\x00\xff"+    , "\x40\x51\x4e\x44"+    , "\x44\x4e\x51\x40"+    , "\x40\x51\x4e\x4a"+    , "\x4a\x4e\x51\x40"+    , "\x40\x51\x4e\x54"+    , "\x54\x4e\x51\x40"+    , "127.0.0.1"+    , "127.0.0.1\x00"+    , "127.0.0.2"+    , "127.0.0.2\x00"+    , "127.0.0.3"+    , "127.0.0.3\x00"+    , "64.81.78.68"+    , "64.81.78.68\x00"+    , "64.81.78.74"+    , "64.81.78.74\x00"+    , "64.81.78.84"+    , "64.81.78.84\x00"+    , "feedface"+    , "feedface\x00"+    , "feedfacedaffdeed"+    , "feedfacedaffdeed\x00"+    , "feedfacedeadbeef"+    , "feedfacedeadbeef\x00"+    , "line 1\nline 2\nline 3"+    , "chongo <Landon Curt Noll> /\\../\\"+    , "chongo <Landon Curt Noll> /\\../\\\x00"+    , "chongo (Landon Curt Noll) /\\../\\"+    , "chongo (Landon Curt Noll) /\\../\\\x00"+    , "http://antwrp.gsfc.nasa.gov/apod/astropix.html"+    , "http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash"+    , "http://epod.usra.edu/"+    , "http://exoplanet.eu/"+    , "http://hvo.wr.usgs.gov/cam3/"+    , "http://hvo.wr.usgs.gov/cams/HMcam/"+    , "http://hvo.wr.usgs.gov/kilauea/update/deformation.html"+    , "http://hvo.wr.usgs.gov/kilauea/update/images.html"+    , "http://hvo.wr.usgs.gov/kilauea/update/maps.html"+    , "http://hvo.wr.usgs.gov/volcanowatch/current_issue.html"+    , "http://neo.jpl.nasa.gov/risk/"+    , "http://norvig.com/21-days.html"+    , "http://primes.utm.edu/curios/home.php"+    , "http://slashdot.org/"+    , "http://tux.wr.usgs.gov/Maps/155.25-19.5.html"+    , "http://volcano.wr.usgs.gov/kilaueastatus.php"+    , "http://www.avo.alaska.edu/activity/Redoubt.php"+    , "http://www.dilbert.com/fast/"+    , "http://www.fourmilab.ch/gravitation/orbits/"+    , "http://www.fpoa.net/"+    , "http://www.ioccc.org/index.html"+    , "http://www.isthe.com/cgi-bin/number.cgi"+    , "http://www.isthe.com/chongo/bio.html"+    , "http://www.isthe.com/chongo/index.html"+    , "http://www.isthe.com/chongo/src/calc/lucas-calc"+    , "http://www.isthe.com/chongo/tech/astro/venus2004.html"+    , "http://www.isthe.com/chongo/tech/astro/vita.html"+    , "http://www.isthe.com/chongo/tech/comp/c/expert.html"+    , "http://www.isthe.com/chongo/tech/comp/calc/index.html"+    , "http://www.isthe.com/chongo/tech/comp/fnv/index.html"+    , "http://www.isthe.com/chongo/tech/math/number/howhigh.html"+    , "http://www.isthe.com/chongo/tech/math/number/number.html"+    , "http://www.isthe.com/chongo/tech/math/prime/mersenne.html"+    , "http://www.isthe.com/chongo/tech/math/prime/mersenne.html#largest"+    , "http://www.lavarnd.org/cgi-bin/corpspeak.cgi"+    , "http://www.lavarnd.org/cgi-bin/haiku.cgi"+    , "http://www.lavarnd.org/cgi-bin/rand-none.cgi"+    , "http://www.lavarnd.org/cgi-bin/randdist.cgi"+    , "http://www.lavarnd.org/index.html"+    , "http://www.lavarnd.org/what/nist-test.html"+    , "http://www.macosxhints.com/"+    , "http://www.mellis.com/"+    , "http://www.nature.nps.gov/air/webcams/parks/havoso2alert/havoalert.cfm"+    , "http://www.nature.nps.gov/air/webcams/parks/havoso2alert/timelines_24.cfm"+    , "http://www.paulnoll.com/"+    , "http://www.pepysdiary.com/"+    , "http://www.sciencenews.org/index/home/activity/view"+    , "http://www.skyandtelescope.com/"+    , "http://www.sput.nl/~rob/sirius.html"+    , "http://www.systemexperts.com/"+    , "http://www.tq-international.com/phpBB3/index.php"+    , "http://www.travelquesttours.com/index.htm"+    , "http://www.wunderground.com/global/stations/89606.html"+    , mconcat $ replicate 10 "21701"+    , mconcat $ replicate 10 "M21701"+    , mconcat $ replicate 10 "2^21701-1"+    , mconcat $ replicate 10 "\x54\xc5"+    , mconcat $ replicate 10 "\xc5\x54"+    , mconcat $ replicate 10 "23209"+    , mconcat $ replicate 10 "M23209"+    , mconcat $ replicate 10 "2^23209-1"+    , mconcat $ replicate 10 "\x5a\xa9"+    , mconcat $ replicate 10 "\xa9\x5a"+    , mconcat $ replicate 10 "391581216093"+    , mconcat $ replicate 10 "391581*2^216093-1"+    , mconcat $ replicate 10 "\x05\xf9\x9d\x03\x4c\x81"+    , mconcat $ replicate 10 "FEDCBA9876543210"+    , mconcat $ replicate 10 "\xfe\xdc\xba\x98\x76\x54\x32\x10"+    , mconcat $ replicate 10 "EFCDAB8967452301"+    , mconcat $ replicate 10 "\xef\xcd\xab\x89\x67\x45\x23\x01"+    , mconcat $ replicate 10 "0123456789ABCDEF"+    , mconcat $ replicate 10 "\x01\x23\x45\x67\x89\xab\xcd\xef"+    , mconcat $ replicate 10 "1032547698BADCFE"+    , mconcat $ replicate 10 "\x10\x32\x54\x76\x98\xba\xdc\xfe"+    , mconcat $ replicate 500 "\x00"+    , mconcat $ replicate 500 "\x07"+    , mconcat $ replicate 500 "~"+    , mconcat $ replicate 500 "\x7f"+    ]++{- | Non-ASCII inputs for the UTF-8 golden vectors: @é@, @café@, @naïve@,+@U+0100@, @U+1F600@, and @U+10FFFF@.+-}+utf8Inputs :: [String]+utf8Inputs =+    [ "\xe9"+    , "caf\xe9"+    , "na\xefve"+    , "\x0100"+    , "\x1F600"+    , "\x10FFFF"+    ]++{- | FNV-1a over the UTF-8 bytes of 'utf8Inputs'. With a 32-bit result the+values wrap modulo @2^32@.+-}+fnv1aVectorsForWord32Utf8 :: [Word32]+fnv1aVectorsForWord32Utf8 =+    [ 0x1e9de8c1+    , 0xa82b5049+    , 0x999a082b+    , 0x779015e9+    , 0x33a29608+    , 0x41c1bc3a+    ]++-- | FNV-1a over the UTF-8 bytes of 'utf8Inputs'.+fnv1aVectorsForWord64Utf8 :: [Word64]+fnv1aVectorsForWord64Utf8 =+    [ 0x0ac21707b7181e01+    , 0x48e8823acfa40d89+    , 0x1e858bc68a6332ab+    , 0x0ab1f007b70b1b89+    , 0xfeff073875020288+    , 0x6eb1861c2c1fff5a+    ]++fnv1VectorsForWord32 :: [Word32]+fnv1VectorsForWord32 =+    [ 0x811c9dc5+    , 0x050c5d7e+    , 0x050c5d7d+    , 0x050c5d7c+    , 0x050c5d7b+    , 0x050c5d7a+    , 0x050c5d79+    , 0x6b772514+    , 0x408f5e13+    , 0xb4b1178b+    , 0xfdc80fb0+    , 0x31f0b262+    , 0x050c5d1f+    , 0x70772d5a+    , 0x6f772bc7+    , 0x6e772a34+    , 0x6d7728a1+    , 0x6c77270e+    , 0x6b77257b+    , 0x408f5e7c+    , 0xb4b117e9+    , 0xfdc80fd1+    , 0x31f0b210+    , 0xffe8d046+    , 0x6e772a5c+    , 0x4197aebb+    , 0xfcc8100f+    , 0xfdf147fa+    , 0xbcd44ee1+    , 0x23382c13+    , 0x846d619e+    , 0x1630abdb+    , 0xc99e89b2+    , 0x1692c316+    , 0x9f091bca+    , 0x2556be9b+    , 0x628e0e73+    , 0x98a0bf6c+    , 0xb10d5725+    , 0xdd002f35+    , 0x4197aed4+    , 0xfcc81061+    , 0xfdf1479d+    , 0xbcd44e8e+    , 0x23382c33+    , 0x846d61e9+    , 0x1630abba+    , 0xc99e89c1+    , 0x1692c336+    , 0x9f091ba2+    , 0x2556befe+    , 0x628e0e01+    , 0x98a0bf09+    , 0xb10d5704+    , 0xdd002f3f+    , 0x1c4a506f+    , 0x6e772a41+    , 0x26978421+    , 0xe184ff97+    , 0x9b5e5ac6+    , 0x5b88e592+    , 0xaa8164b7+    , 0x20b18c7b+    , 0xf28025c5+    , 0x84bb753f+    , 0x3219925a+    , 0x384163c6+    , 0x54f010d7+    , 0x8cea820c+    , 0xe12ab8ee+    , 0x26978453+    , 0xe184fff3+    , 0x9b5e5ab5+    , 0x5b88e5b2+    , 0xaa8164d6+    , 0x20b18c15+    , 0xf28025a1+    , 0x84bb751f+    , 0x3219922d+    , 0x384163ae+    , 0x54f010b2+    , 0x8cea8275+    , 0xe12ab8e4+    , 0x64411eaa+    , 0x6977223c+    , 0x428ae474+    , 0xb6fa7167+    , 0x73408525+    , 0xb78320a1+    , 0x0caf4135+    , 0xb78320a2+    , 0xcdc88e80+    , 0xb78320a3+    , 0x8ee1dbcb+    , 0xb78320a4+    , 0x4ffb2716+    , 0x860632aa+    , 0xcc2c5c64+    , 0x860632a4+    , 0x2a7ec4a6+    , 0x860632ba+    , 0xfefe8e14+    , 0x0a3cffd8+    , 0xf606c108+    , 0x0a3cffdb+    , 0xf906c5c1+    , 0x0a3cffda+    , 0xf806c42e+    , 0xc07167d7+    , 0xc9867775+    , 0xbf716668+    , 0xc78435b8+    , 0xc6717155+    , 0xb99568cf+    , 0x7662e0d6+    , 0x33a7f0e2+    , 0xc2732f95+    , 0xb053e78f+    , 0x3a19c02a+    , 0xa089821e+    , 0x31ae8f83+    , 0x995fa9c4+    , 0x35983f8c+    , 0x5036a251+    , 0x97018583+    , 0xb4448d60+    , 0x025dfe59+    , 0xc5eab3af+    , 0x7d21ba1e+    , 0x7704cddb+    , 0xd0071bfe+    , 0x0ff3774c+    , 0xb0fea0ea+    , 0x58177303+    , 0x4f599cda+    , 0x3e590a47+    , 0x965595f8+    , 0xc37f178d+    , 0x9711dd26+    , 0x23c99b7f+    , 0x6e568b17+    , 0x43f0245b+    , 0xbcb7a001+    , 0x12e6dffe+    , 0x0792f2d6+    , 0xb966936b+    , 0x46439ac5+    , 0x728d49af+    , 0xd33745c9+    , 0xbc382a57+    , 0x4bda1d31+    , 0xce35ccae+    , 0x3b6eed94+    , 0x445c9c58+    , 0x3db8bf9d+    , 0x2dee116d+    , 0xc18738da+    , 0x5b156176+    , 0x2aa7d593+    , 0xb2409658+    , 0xe1489528+    , 0xfe1ee07e+    , 0xe8842315+    , 0x3a6a63a2+    , 0x06d2c18c+    , 0xf8ef7225+    , 0x843d3300+    , 0xbb24f7ae+    , 0x878c0ec9+    , 0xb557810f+    , 0x57423246+    , 0x87f7505e+    , 0xbb809f20+    , 0x8932abb5+    , 0x0a9b3aa0+    , 0xb8682a24+    , 0xa7ac1c56+    , 0x11409252+    , 0xa987f517+    , 0xf309e7ed+    , 0xc9e8f417+    , 0x7f447bdd+    , 0xb929adc5+    , 0x57022879+    , 0xdcfd2c49+    , 0x6edafff5+    , 0xf04fb1f1+    , 0xfb7de8b9+    , 0xc5f1d7e9+    , 0x32c1f439+    , 0x7fd3eb7d+    , 0x81597da5+    , 0x05eb7a25+    , 0x9c0fa1b5+    , 0x53ccb1c5+    , 0xfabece15+    , 0x4ad745a5+    , 0xe5bdc495+    , 0x23b3c0a5+    , 0xfa823dd5+    , 0x0c6c58b9+    , 0xe2dbccd5+    , 0xdb7f50f9+    ]++fnv1aVectorsForWord32 :: [Word32]+fnv1aVectorsForWord32 =+    [ 0x811c9dc5+    , 0xe40c292c+    , 0xe70c2de5+    , 0xe60c2c52+    , 0xe10c2473+    , 0xe00c22e0+    , 0xe30c2799+    , 0x6222e842+    , 0xa9f37ed7+    , 0x3f5076ef+    , 0x39aaa18a+    , 0xbf9cf968+    , 0x050c5d1f+    , 0x2b24d044+    , 0x9d2c3f7f+    , 0x7729c516+    , 0xb91d6109+    , 0x931ae6a0+    , 0x052255db+    , 0xbef39fe6+    , 0x6150ac75+    , 0x9aab3a3d+    , 0x519c4c3e+    , 0x0c1c9eb8+    , 0x5f299f4e+    , 0xef8580f3+    , 0xac297727+    , 0x4546b9c0+    , 0xbd564e7d+    , 0x6bdd5c67+    , 0xdd77ed30+    , 0xf4ca9683+    , 0x4aeb9bd0+    , 0xe0e67ad0+    , 0xc2d32fa8+    , 0x7f743fb7+    , 0x6900631f+    , 0xc59c990e+    , 0x448524fd+    , 0xd49930d5+    , 0x1c85c7ca+    , 0x0229fe89+    , 0x2c469265+    , 0xce566940+    , 0x8bdd8ec7+    , 0x34787625+    , 0xd3ca6290+    , 0xddeaf039+    , 0xc0e64870+    , 0xdad35570+    , 0x5a740578+    , 0x5b004d15+    , 0x6a9c09cd+    , 0x2384f10a+    , 0xda993a47+    , 0x8227df4f+    , 0x4c298165+    , 0xfc563735+    , 0x8cb91483+    , 0x775bf5d0+    , 0xd5c428d0+    , 0x34cc0ea3+    , 0xea3b4cb7+    , 0x8e59f029+    , 0x2094de2b+    , 0xa65a0ad4+    , 0x9bbee5f4+    , 0xbe836343+    , 0x22d5344e+    , 0x19a1470c+    , 0x4a56b1ff+    , 0x70b8e86f+    , 0x0a5b4a39+    , 0xb5c3f670+    , 0x53cc3f70+    , 0xc03b0a99+    , 0x7259c415+    , 0x4095108b+    , 0x7559bdb1+    , 0xb3bf0bbc+    , 0x2183ff1c+    , 0x2bd54279+    , 0x23a156ca+    , 0x64e2d7e4+    , 0x683af69a+    , 0xaed2346e+    , 0x4f9f2cab+    , 0x02935131+    , 0xc48fb86d+    , 0x2269f369+    , 0xc18fb3b4+    , 0x50ef1236+    , 0xc28fb547+    , 0x96c3bf47+    , 0xbf8fb08e+    , 0xf3e4d49c+    , 0x32179058+    , 0x280bfee6+    , 0x30178d32+    , 0x21addaf8+    , 0x4217a988+    , 0x772633d6+    , 0x08a3d11e+    , 0xb7e2323a+    , 0x07a3cf8b+    , 0x91dfb7d1+    , 0x06a3cdf8+    , 0x6bdd3d68+    , 0x1d5636a7+    , 0xd5b808e5+    , 0x1353e852+    , 0xbf16b916+    , 0xa55b89ed+    , 0x3c1a2017+    , 0x0588b13c+    , 0xf22f0174+    , 0xe83641e1+    , 0x6e69b533+    , 0xf1760448+    , 0x64c8bd58+    , 0x97b4ea23+    , 0x9a4e92e6+    , 0xcfb14012+    , 0xf01b2511+    , 0x0bbb59c3+    , 0xce524afa+    , 0xdd16ef45+    , 0x60648bb3+    , 0x7fa4bcfc+    , 0x5053ae17+    , 0xc9302890+    , 0x956ded32+    , 0x9136db84+    , 0xdf9d3323+    , 0x32bb6cd0+    , 0xc8f8385b+    , 0xeb08bfba+    , 0x62cc8e3d+    , 0xc3e20f5c+    , 0x39e97f17+    , 0x7837b203+    , 0x319e877b+    , 0xd3e63f89+    , 0x29b50b38+    , 0x5ed678b8+    , 0xb0d5b793+    , 0x52450be5+    , 0xfa72d767+    , 0x95066709+    , 0x7f52e123+    , 0x76966481+    , 0x063258b0+    , 0x2ded6e8a+    , 0xb07d7c52+    , 0xd0c71b71+    , 0xf684f1bd+    , 0x868ecfa8+    , 0xf794f684+    , 0xd19701c3+    , 0x346e171e+    , 0x91f8f676+    , 0x0bf58848+    , 0x6317b6d1+    , 0xafad4c54+    , 0x0f25681e+    , 0x91b18d49+    , 0x7d61c12e+    , 0x5147d25c+    , 0x9a8b6805+    , 0x4cd2a447+    , 0x1e549b14+    , 0x2fe1b574+    , 0xcf0cd31e+    , 0x6c471669+    , 0x0e5eef1e+    , 0x2bed3602+    , 0xb26249e0+    , 0x2c9b86a4+    , 0xe415e2bb+    , 0x18a98d1d+    , 0xb7df8b7b+    , 0x241e9075+    , 0x063f70dd+    , 0x0295aed9+    , 0x56a7f781+    , 0x253bc645+    , 0x46610921+    , 0x7c1577f9+    , 0x512b2851+    , 0x76823999+    , 0xc0586935+    , 0xf3415c85+    , 0x0ae4ff65+    , 0x58b79725+    , 0xdea43aa5+    , 0x2bb3be35+    , 0xea777a45+    , 0x8f21c305+    , 0x5c9d0865+    , 0xfa823dd5+    , 0x21a27271+    , 0x83c5c6d5+    , 0x813b0881+    ]++fnv1VectorsForWord64 :: [Word64]+fnv1VectorsForWord64 =+    [ 0xcbf29ce484222325+    , 0xaf63bd4c8601b7be+    , 0xaf63bd4c8601b7bd+    , 0xaf63bd4c8601b7bc+    , 0xaf63bd4c8601b7bb+    , 0xaf63bd4c8601b7ba+    , 0xaf63bd4c8601b7b9+    , 0x08326207b4eb2f34+    , 0xd8cbc7186ba13533+    , 0x0378817ee2ed65cb+    , 0xd329d59b9963f790+    , 0x340d8765a4dda9c2+    , 0xaf63bd4c8601b7df+    , 0x08326707b4eb37da+    , 0x08326607b4eb3627+    , 0x08326507b4eb3474+    , 0x08326407b4eb32c1+    , 0x08326307b4eb310e+    , 0x08326207b4eb2f5b+    , 0xd8cbc7186ba1355c+    , 0x0378817ee2ed65a9+    , 0xd329d59b9963f7f1+    , 0x340d8765a4dda9b0+    , 0x50a6d3b724a774a6+    , 0x08326507b4eb341c+    , 0xd8d5c8186ba98bfb+    , 0x1ccefc7ef118dbef+    , 0x0c92fab3ad3db77a+    , 0x9b77794f5fdec421+    , 0x0ac742dfe7874433+    , 0xd7dad5766ad8e2de+    , 0xa1bb96378e897f5b+    , 0x5b3f9b6733a367d2+    , 0xb07ce25cbea969f6+    , 0x8d9e9997f9df0d6a+    , 0x838c673d9603cb7b+    , 0x8b5ee8a5e872c273+    , 0x4507c4e9fb00690c+    , 0x4c9ca59581b27f45+    , 0xe0aca20b624e4235+    , 0xd8d5c8186ba98b94+    , 0x1ccefc7ef118db81+    , 0x0c92fab3ad3db71d+    , 0x9b77794f5fdec44e+    , 0x0ac742dfe7874413+    , 0xd7dad5766ad8e2a9+    , 0xa1bb96378e897f3a+    , 0x5b3f9b6733a367a1+    , 0xb07ce25cbea969d6+    , 0x8d9e9997f9df0d02+    , 0x838c673d9603cb1e+    , 0x8b5ee8a5e872c201+    , 0x4507c4e9fb006969+    , 0x4c9ca59581b27f64+    , 0xe0aca20b624e423f+    , 0x13998e580afa800f+    , 0x08326507b4eb3401+    , 0xd8d5ad186ba95dc1+    , 0x1c72e17ef0ca4e97+    , 0x2183c1b327c38ae6+    , 0xb66d096c914504f2+    , 0x404bf57ad8476757+    , 0x887976bd815498bb+    , 0x3afd7f02c2bf85a5+    , 0xfc4476b0eb70177f+    , 0x186d2da00f77ecba+    , 0xf97140fa48c74066+    , 0xa2b1cf49aa926d37+    , 0x0690712cd6cf940c+    , 0xf7045b3102b8906e+    , 0xd8d5ad186ba95db3+    , 0x1c72e17ef0ca4ef3+    , 0x2183c1b327c38a95+    , 0xb66d096c914504d2+    , 0x404bf57ad8476736+    , 0x887976bd815498d5+    , 0x3afd7f02c2bf85c1+    , 0xfc4476b0eb70175f+    , 0x186d2da00f77eccd+    , 0xf97140fa48c7400e+    , 0xa2b1cf49aa926d52+    , 0x0690712cd6cf9475+    , 0xf7045b3102b89064+    , 0x74f762479f9d6aea+    , 0x08326007b4eb2b9c+    , 0xd8c4c9186b9b1a14+    , 0x7b495389bdbdd4c7+    , 0x3b6dba0d69908e25+    , 0xd6b2b17bf4b71261+    , 0x447bfb7f98e615b5+    , 0xd6b2b17bf4b71262+    , 0x3bd2807f93fe1660+    , 0xd6b2b17bf4b71263+    , 0x3329057f8f16170b+    , 0xd6b2b17bf4b71264+    , 0x2a7f8a7f8a2e19b6+    , 0x23d3767e64b2f98a+    , 0xff768d7e4f9d86a4+    , 0x23d3767e64b2f984+    , 0xccd1837e334e4aa6+    , 0x23d3767e64b2f99a+    , 0x7691fd7e028f6754+    , 0x34ad3b1041204318+    , 0xa29e749ea9d201c8+    , 0x34ad3b104120431b+    , 0xa29e779ea9d206e1+    , 0x34ad3b104120431a+    , 0xa29e769ea9d2052e+    , 0x02a17ebca4aa3497+    , 0x229ef18bcd375c95+    , 0x02a17dbca4aa32c8+    , 0x229b6f8bcd3449d8+    , 0x02a184bca4aa3ed5+    , 0x22b3618bcd48c3ef+    , 0x5c2c346706186f36+    , 0xb78c410f5b84f8c2+    , 0xed9478212b267395+    , 0xd9bbb55c5256662f+    , 0x8c54f0203249438a+    , 0xbd9790b5727dc37e+    , 0xa64e5f36c9e2b0e3+    , 0x8fd0680da3088a04+    , 0x67aad32c078284cc+    , 0xb37d55d81c57b331+    , 0x55ac0f3829057c43+    , 0xcb27f4b8e1b6cc20+    , 0x26caf88bcbef2d19+    , 0x8e6e063b97e61b8f+    , 0xb42750f7f3b7c37e+    , 0xf3c6ba64cf7ca99b+    , 0xebfb69b427ea80fe+    , 0x39b50c3ed970f46c+    , 0x5b9b177aa3eb3e8a+    , 0x6510063ecf4ec903+    , 0x2b3bbd2c00797c7a+    , 0xf1d6204ff5cb4aa7+    , 0x4836e27ccf099f38+    , 0x82efbb0dd073b44d+    , 0x4a80c282ffd7d4c6+    , 0x305d1a9c9ee43bdf+    , 0x15c366948ffc6997+    , 0x80153ae218916e7b+    , 0xfa23e2bdf9e2a9e1+    , 0xd47e8d8a2333c6de+    , 0x7e128095f688b056+    , 0x2f5356890efcedab+    , 0x95c2b383014f55c5+    , 0x4727a5339ce6070f+    , 0xb0555ecd575108e9+    , 0x48d785770bb4af37+    , 0x09d4701c12af02b1+    , 0x79f031e78f3cf62e+    , 0x52a1ee85db1b5a94+    , 0x6bd95b2eb37fa6b8+    , 0x74971b7077aef85d+    , 0xb4e4fae2ffcc1aad+    , 0x2bd48bd898b8f63a+    , 0xe9966ac1556257f6+    , 0x92a3d1cd078ba293+    , 0xf81175a482e20ab8+    , 0x5bbb3de722e73048+    , 0x6b4f363492b9f2be+    , 0xc2d559df73d59875+    , 0xf75f62284bc7a8c2+    , 0xda8dd8e116a9f1cc+    , 0xbdc1e6ab76057885+    , 0xfec6a4238a1224a0+    , 0xc03f40f3223e290e+    , 0x1ed21673466ffda9+    , 0xdf70f906bb0dd2af+    , 0xf3dcda369f2af666+    , 0x9ebb11573cdcebde+    , 0x81c72d9077fedca0+    , 0x0ec074a31be5fb15+    , 0x2a8b3280b6c48f20+    , 0xfd31777513309344+    , 0x194534a86ad006b6+    , 0x3be6fdf46e0cfe12+    , 0x017cc137a07eb057+    , 0x9428fc6e7d26b54d+    , 0x9aaa2e3603ef8ad7+    , 0x82c6d3f3a0ccdf7d+    , 0xc86eeea00cf09b65+    , 0x705f8189dbb58299+    , 0x415a7f554391ca69+    , 0xcfe3d49fa2bdc555+    , 0xf0f9c56039b25191+    , 0x7075cb6abd1d32d9+    , 0x43c94e2c8b277509+    , 0x3cbfd4e4ea670359+    , 0xc05887810f4d019d+    , 0x14468ff93ac22dc5+    , 0xebed699589d99c05+    , 0x6d99f6df321ca5d5+    , 0x0cd410d08c36d625+    , 0xef1b2a2c86831d35+    , 0x3b349c4d69ee5f05+    , 0x55248ce88f45f035+    , 0xaa69ca6a18a4c885+    , 0x1fe3fce62bd816b5+    , 0x0289a488a8df69d9+    , 0x15e96e1613df98b5+    , 0xe6be57375ad89b99+    ]++fnv1aVectorsForWord64 :: [Word64]+fnv1aVectorsForWord64 =+    [ 0xcbf29ce484222325+    , 0xaf63dc4c8601ec8c+    , 0xaf63df4c8601f1a5+    , 0xaf63de4c8601eff2+    , 0xaf63d94c8601e773+    , 0xaf63d84c8601e5c0+    , 0xaf63db4c8601ead9+    , 0x08985907b541d342+    , 0xdcb27518fed9d577+    , 0xdd120e790c2512af+    , 0xcac165afa2fef40a+    , 0x85944171f73967e8+    , 0xaf63bd4c8601b7df+    , 0x089be207b544f1e4+    , 0x08a61407b54d9b5f+    , 0x08a2ae07b54ab836+    , 0x0891b007b53c4869+    , 0x088e4a07b5396540+    , 0x08987c07b5420ebb+    , 0xdcb28a18fed9f926+    , 0xdd1270790c25b935+    , 0xcac146afa2febf5d+    , 0x8593d371f738acfe+    , 0x34531ca7168b8f38+    , 0x08a25607b54a22ae+    , 0xf5faf0190cf90df3+    , 0xf27397910b3221c7+    , 0x2c8c2b76062f22e0+    , 0xe150688c8217b8fd+    , 0xf35a83c10e4f1f87+    , 0xd1edd10b507344d0+    , 0x2a5ee739b3ddb8c3+    , 0xdcfb970ca1c0d310+    , 0x4054da76daa6da90+    , 0xf70a2ff589861368+    , 0x4c628b38aed25f17+    , 0x9dd1f6510f78189f+    , 0xa3de85bd491270ce+    , 0x858e2fa32a55e61d+    , 0x46810940eff5f915+    , 0xf5fadd190cf8edaa+    , 0xf273ed910b32b3e9+    , 0x2c8c5276062f6525+    , 0xe150b98c821842a0+    , 0xf35aa3c10e4f55e7+    , 0xd1ed680b50729265+    , 0x2a5f0639b3dded70+    , 0xdcfbaa0ca1c0f359+    , 0x4054ba76daa6a430+    , 0xf709c7f5898562b0+    , 0x4c62e638aed2f9b8+    , 0x9dd1a8510f779415+    , 0xa3de2abd4911d62d+    , 0x858e0ea32a55ae0a+    , 0x46810f40eff60347+    , 0xc33bce57bef63eaf+    , 0x08a24307b54a0265+    , 0xf5b9fd190cc18d15+    , 0x4c968290ace35703+    , 0x07174bd5c64d9350+    , 0x5a294c3ff5d18750+    , 0x05b3c1aeb308b843+    , 0xb92a48da37d0f477+    , 0x73cdddccd80ebc49+    , 0xd58c4c13210a266b+    , 0xe78b6081243ec194+    , 0xb096f77096a39f34+    , 0xb425c54ff807b6a3+    , 0x23e520e2751bb46e+    , 0x1a0b44ccfe1385ec+    , 0xf5ba4b190cc2119f+    , 0x4c962690ace2baaf+    , 0x0716ded5c64cda19+    , 0x5a292c3ff5d150f0+    , 0x05b3e0aeb308ecf0+    , 0xb92a5eda37d119d9+    , 0x73ce41ccd80f6635+    , 0xd58c2c132109f00b+    , 0xe78baf81243f47d1+    , 0xb0968f7096a2ee7c+    , 0xb425a84ff807855c+    , 0x23e4e9e2751b56f9+    , 0x1a0b4eccfe1396ea+    , 0x54abd453bb2c9004+    , 0x08ba5f07b55ec3da+    , 0x337354193006cb6e+    , 0xa430d84680aabd0b+    , 0xa9bc8acca21f39b1+    , 0x6961196491cc682d+    , 0xad2bb1774799dfe9+    , 0x6961166491cc6314+    , 0x8d1bb3904a3b1236+    , 0x6961176491cc64c7+    , 0xed205d87f40434c7+    , 0x6961146491cc5fae+    , 0xcd3baf5e44f8ad9c+    , 0xe3b36596127cd6d8+    , 0xf77f1072c8e8a646+    , 0xe3b36396127cd372+    , 0x6067dce9932ad458+    , 0xe3b37596127cf208+    , 0x4b7b10fa9fe83936+    , 0xaabafe7104d914be+    , 0xf4d3180b3cde3eda+    , 0xaabafd7104d9130b+    , 0xf4cfb20b3cdb5bb1+    , 0xaabafc7104d91158+    , 0xf4cc4c0b3cd87888+    , 0xe729bac5d2a8d3a7+    , 0x74bc0524f4dfa4c5+    , 0xe72630c5d2a5b352+    , 0x6b983224ef8fb456+    , 0xe73042c5d2ae266d+    , 0x8527e324fdeb4b37+    , 0x0a83c86fee952abc+    , 0x7318523267779d74+    , 0x3e66d3d56b8caca1+    , 0x956694a5c0095593+    , 0xcac54572bb1a6fc8+    , 0xa7a4c9f3edebf0d8+    , 0x7829851fac17b143+    , 0x2c8f4c9af81bcf06+    , 0xd34e31539740c732+    , 0x3605a2ac253d2db1+    , 0x08c11b8346f4a3c3+    , 0x6be396289ce8a6da+    , 0xd9b957fb7fe794c5+    , 0x05be33da04560a93+    , 0x0957f1577ba9747c+    , 0xda2cc3acc24fba57+    , 0x74136f185b29e7f0+    , 0xb2f2b4590edb93b2+    , 0xb3608fce8b86ae04+    , 0x4a3a865079359063+    , 0x5b3a7ef496880a50+    , 0x48fae3163854c23b+    , 0x07aaa640476e0b9a+    , 0x2f653656383a687d+    , 0xa1031f8e7599d79c+    , 0xa31908178ff92477+    , 0x097edf3c14c3fb83+    , 0xb51ca83feaa0971b+    , 0xdd3c0d96d784f2e9+    , 0x86cd26a9ea767d78+    , 0xe6b215ff54a30c18+    , 0xec5b06a1c5531093+    , 0x45665a929f9ec5e5+    , 0x8c7609b4a9f10907+    , 0x89aac3a491f0d729+    , 0x32ce6b26e0f4a403+    , 0x614ab44e02b53e01+    , 0xfa6472eb6eef3290+    , 0x9e5d75eb1948eb6a+    , 0xb6d12ad4a8671852+    , 0x88826f56eba07af1+    , 0x44535bf2645bc0fd+    , 0x169388ffc21e3728+    , 0xf68aac9e396d8224+    , 0x8e87d7e7472b3883+    , 0x295c26caa8b423de+    , 0x322c814292e72176+    , 0x8a06550eb8af7268+    , 0xef86d60e661bcf71+    , 0x9e5426c87f30ee54+    , 0xf1ea8aa826fd047e+    , 0x0babaf9a642cb769+    , 0x4b3341d4068d012e+    , 0xd15605cbc30a335c+    , 0x5b21060aed8412e5+    , 0x45e2cda1ce6f4227+    , 0x50ae3745033ad7d4+    , 0xaa4588ced46bf414+    , 0xc1b0056c4a95467e+    , 0x56576a71de8b4089+    , 0xbf20965fa6dc927e+    , 0x569f8383c2040882+    , 0xe1e772fba08feca0+    , 0x4ced94af97138ac4+    , 0xc4112ffb337a82fb+    , 0xd64a4fd41de38b7d+    , 0x4cfc32329edebcbb+    , 0x0803564445050395+    , 0xaa1574ecf4642ffd+    , 0x694bc4e54cc315f9+    , 0xa3d7cb273b011721+    , 0x577c2f8b6115bfa5+    , 0xb7ec8c1a769fb4c1+    , 0x5d5cfce63359ab19+    , 0x33b96c3cd65b5f71+    , 0xd845097780602bb9+    , 0x84d47645d02da3d5+    , 0x83544f33b58773a5+    , 0x9175cbb2160836c5+    , 0xc71b3bc175e72bc5+    , 0x636806ac222ec985+    , 0xb6ef0e6950f52ed5+    , 0xead3d8a0f3dfdaa5+    , 0x922908fe9a861ba5+    , 0x6d4821de275fd5c5+    , 0x1fe3fce62bd816b5+    , 0xc23e9fccd6f70591+    , 0xc1af12bdfe16b5b5+    , 0x39e9f18f2f85e221+    ]
+ test/Test/Data/HalfSipHash.hs view
@@ -0,0 +1,182 @@+{- | Reference HalfSipHash-2-4 vectors.++The values are the reference implementation's output words, i.e. the+little-endian reading of the byte arrays in+<https://github.com/veorq/SipHash/blob/master/vectors.h>. The key bytes+are @00 01 .. 07@.+-}+module Test.Data.HalfSipHash where++import qualified Data.ByteString as BS+import Data.Char (chr)+import Data.String (IsString, fromString)+import Data.Word (Word32, Word64)++key :: Word64+key = 0x0001020304050607++inputs :: (IsString a, Monoid a) => [a]+inputs = fmap (\n -> fromString $ fmap chr [0 .. n - 1]) [0 .. 64 - 1]++-- | Inputs around the 256-byte length-byte wrap (254-513 bytes).+boundaryInputs :: [BS.ByteString]+boundaryInputs = [BS.replicate n 97 | n <- [254, 255, 256, 257, 258, 511, 512, 513]]++{- | HalfSipHash-2-4-32 reference output words for the empty input and+the prefixes of @00 01 ..@.+-}+halfSipHash24VectorsForWord32 :: [Word32]+halfSipHash24VectorsForWord32 =+    [ 0x5b9f35a9+    , 0xb85a4727+    , 0x03a662fa+    , 0x04e7fe8a+    , 0x89466e2a+    , 0x69b6fac5+    , 0x23fc6358+    , 0xc563cf8b+    , 0x8f84b8d0+    , 0x79e706f8+    , 0x3479b094+    , 0x50300808+    , 0x2f87f057+    , 0xff63e677+    , 0x7cf8ffd6+    , 0x972bfe74+    , 0x84acb5d9+    , 0x5b6474c4+    , 0x9b8d5b46+    , 0x87e3ef7b+    , 0x45104de3+    , 0xb3623f61+    , 0xfe67f370+    , 0xbdb8ade6+    , 0x630c4027+    , 0x75787826+    , 0x5f7b564f+    , 0x69e6b03a+    , 0x004064b0+    , 0xb40f67ff+    , 0x8b339e50+    , 0x1a9f585d+    , 0x1221e7fe+    , 0x59327533+    , 0x8c4f436a+    , 0x29b728fe+    , 0xecc65ce7+    , 0x548d7e69+    , 0x0f8b6863+    , 0xb4620b65+    , 0x4018bcb6+    , 0x0545075d+    , 0x2efd4224+    , 0x3a86b77b+    , 0x48d50577+    , 0xb10852d7+    , 0xc899d4b6+    , 0x2e209208+    , 0xe32ce169+    , 0xe580b58d+    , 0xc6649736+    , 0x04026e01+    , 0xd4f3853b+    , 0xbe66dbfe+    , 0x3a2a691e+    , 0xc08489c6+    , 0x40b9c5a5+    , 0x8ce8e99b+    , 0x4081bc7d+    , 0xc58e077c+    , 0x736ce7d4+    , 0xb9cb8f42+    , 0x7a9983bd+    , 0x744aea59+    ]++{- | HalfSipHash-2-4-64 reference output words. Each result is the+little-endian reading of an 8-byte @vectors_hsip64@ entry: the first+32-bit output word is the low half and the second is the high half.+-}+halfSipHash24VectorsForWord64 :: [Word64]+halfSipHash24VectorsForWord64 =+    [ 0xc83cb8b9591f8d21+    , 0x157338f8122455be+    , 0x57eb507cef394f06+    , 0x790606f7451a0fce+    , 0xa12ee55b178ae7d5+    , 0x80b53d2f3f7c9dcb+    , 0x25bca28a35913ece+    , 0x84c67bb0282720ff+    , 0x8c85e4bc20e8feed+    , 0x07838813cccc515b+    , 0xeef2a6069f46b095+    , 0x48cddd94393326ae+    , 0x99c7f5ae9f1fc77b+    , 0x44370c5ad752235a+    , 0x58e6e8ea70a8b13b+    , 0x02c9814ecb0b7d21+    , 0xb5f37b5fd2aa3673+    , 0x6a4f4c1c64c0ad37+    , 0xf9423e9a2bdbb2c9+    , 0x3c36ab2080e410f9+    , 0xdba7ee6f0a2bf51b+    , 0xefb3e869c21d7400+    , 0xef76a71bfa0301e2+    , 0x731d684be510224c+    , 0xf1a63fae45107470+    , 0x384071393740860c+    , 0xf0232911d89e890d+    , 0xb8e11eb8faf56b22+    , 0xb516001efb5f922d+    , 0xf110ee2cd5581936+    , 0x9d17984886af1a29+    , 0x7c11345c157f3c86+    , 0x6c6211d8469d7028+    , 0x9cf8281d68778424+    , 0x30988f52d7e42483+    , 0xd86bea3ae1d4eff9+    , 0xdc7642ec407ad686+    , 0x357ea9ccec92623f+    , 0x0921d424e72ed9cb+    , 0x793d408d80f68d36+    , 0x4caec8671cc8385b+    , 0xb3ac39d48971ab95+    , 0x24703225c0521aa9+    , 0xeaac2895c687005b+    , 0x5ab1dc27adf3301e+    , 0xd44e32909a5c7f69+    , 0x38dc5755990f5c49+    , 0x4df9293c2a202794+    , 0x3e3ea94bc0a8eaa9+    , 0x1812017d73c1a4ee+    , 0x495af6d88f562d91+    , 0x975cffb096959156+    , 0xe150f598795a4402+    , 0xb21f1de76c46ec86+    , 0xbce389d2e7699535+    , 0x967cbb62ca051b87+    , 0x1d5ff142f992a4a1+    , 0x6e5b09f67f26ec12+    , 0x9dd831b2a15e1b5d+    , 0x54ee923f45b4cfd8+    , 0x60e426bf902876d6+    , 0xf35cedb7a4633531+    , 0x9366d472b53a0bf9+    , 0x876032bf713ca62e+    ]++{- | Reference HalfSipHash-2-4-32 output words for 'boundaryInputs'.+The values use the same byte order as+'halfSipHash24VectorsForWord32'.+-}+boundaryVectorsForWord32 :: [Word32]+boundaryVectorsForWord32 =+    [ 0x8bafb24d+    , 0x80debc4f+    , 0xccc21763+    , 0x74aae63c+    , 0xc110387a+    , 0x8d238996+    , 0xea25986f+    , 0x79711faa+    ]
+ test/Test/Data/SipHash.hs view
@@ -0,0 +1,182 @@+{- | Reference SipHash-2-4 vectors.++The values are the reference implementation's output words, i.e. the+little-endian reading of the byte arrays in+<https://github.com/veorq/SipHash/blob/master/vectors.h>. The key bytes+are @00 01 .. 0f@.+-}+module Test.Data.SipHash where++import qualified Data.ByteString as BS+import Data.Char (chr)+import Data.String (IsString, fromString)+import Data.WideWord.Word128 (Word128)+import Data.Word (Word64)++key :: Word128+key = 0x000102030405060708090a0b0c0d0e0f++inputs :: (IsString a, Monoid a) => [a]+inputs = fmap (\n -> fromString $ fmap chr [0 .. n - 1]) [0 .. 64 - 1]++-- | Inputs around the 256-byte length-byte wrap (254-513 bytes).+boundaryInputs :: [BS.ByteString]+boundaryInputs = [BS.replicate n 97 | n <- [254, 255, 256, 257, 258, 511, 512, 513]]++{- | SipHash-2-4-64 reference output words for the empty input and the+prefixes of @00 01 ..@.+-}+sipHash24VectorsForWord64 :: [Word64]+sipHash24VectorsForWord64 =+    [ 0x726fdb47dd0e0e31+    , 0x74f839c593dc67fd+    , 0x0d6c8009d9a94f5a+    , 0x85676696d7fb7e2d+    , 0xcf2794e0277187b7+    , 0x18765564cd99a68d+    , 0xcbc9466e58fee3ce+    , 0xab0200f58b01d137+    , 0x93f5f5799a932462+    , 0x9e0082df0ba9e4b0+    , 0x7a5dbbc594ddb9f3+    , 0xf4b32f46226bada7+    , 0x751e8fbc860ee5fb+    , 0x14ea5627c0843d90+    , 0xf723ca908e7af2ee+    , 0xa129ca6149be45e5+    , 0x3f2acc7f57c29bdb+    , 0x699ae9f52cbe4794+    , 0x4bc1b3f0968dd39c+    , 0xbb6dc91da77961bd+    , 0xbed65cf21aa2ee98+    , 0xd0f2cbb02e3b67c7+    , 0x93536795e3a33e88+    , 0xa80c038ccd5ccec8+    , 0xb8ad50c6f649af94+    , 0xbce192de8a85b8ea+    , 0x17d835b85bbb15f3+    , 0x2f2e6163076bcfad+    , 0xde4daaaca71dc9a5+    , 0xa6a2506687956571+    , 0xad87a3535c49ef28+    , 0x32d892fad841c342+    , 0x7127512f72f27cce+    , 0xa7f32346f95978e3+    , 0x12e0b01abb051238+    , 0x15e034d40fa197ae+    , 0x314dffbe0815a3b4+    , 0x027990f029623981+    , 0xcadcd4e59ef40c4d+    , 0x9abfd8766a33735c+    , 0x0e3ea96b5304a7d0+    , 0xad0c42d6fc585992+    , 0x187306c89bc215a9+    , 0xd4a60abcf3792b95+    , 0xf935451de4f21df2+    , 0xa9538f0419755787+    , 0xdb9acddff56ca510+    , 0xd06c98cd5c0975eb+    , 0xe612a3cb9ecba951+    , 0xc766e62cfcadaf96+    , 0xee64435a9752fe72+    , 0xa192d576b245165a+    , 0x0a8787bf8ecb74b2+    , 0x81b3e73d20b49b6f+    , 0x7fa8220ba3b2ecea+    , 0x245731c13ca42499+    , 0xb78dbfaf3a8d83bd+    , 0xea1ad565322a1a0b+    , 0x60e61c23a3795013+    , 0x6606d7e446282b93+    , 0x6ca4ecb15c5f91e1+    , 0x9f626da15c9625f3+    , 0xe51b38608ef25f57+    , 0x958a324ceb064572+    ]++{- | SipHash-2-4-128 reference output words. Each result is the+little-endian reading of a 16-byte @vectors_sip128@ entry: the first+64-bit output word is the low half and the second is the high half.+-}+sipHash24VectorsForWord128 :: [Word128]+sipHash24VectorsForWord128 =+    [ 0x930255c71472f66de6a825ba047f81a3+    , 0x45fc229b1159763444af996bd8c187da+    , 0xe4ff0af6de8ba3fcc75da4a48d227781+    , 0x51ed8529b0b6335f4ea967520cb6709c+    , 0x7955cd7b7c6e0f7daf8f9c2dc16481f8+    , 0x27960e69077a5254886f778059876813+    , 0x5ea1d78f30a05e481386208b33caee14+    , 0x3982f01fa64ab8c053c1dbd8beebf1a1+    , 0xb49714f364e2830f61f55862baa9623b+    , 0xed716dbb028b7fc4abbad90a06994426+    , 0xbafbd0f3d34754c956691478c30d1100+    , 0x18dce5816fdcb4a277666b3868c55101+    , 0x25c13285f64d638258f35e9066b226d6+    , 0xf752b9c44f9329d0108bc0e947e26998+    , 0x024949e45f48c77e9cded766aceffc31+    , 0xd9c3cf970fec087e11a8b03399e99354+    , 0x77052385bf1533fdbb54b067caa4e26e+    , 0x4077e47ac466c05498b88d73e8063d47+    , 0x23f7aefe81a44d298548bf23e4e526a4+    , 0xb12e51528920d574b0fa65cf31770178+    , 0xeb3938e8a544933e7390223f83fc259e+    , 0x121d073ecd14228a215a52be5a498e56+    , 0xae0aff8e52109c469a6bd15245b5294a+    , 0x1c69bf9a9ae28ccfe0f5a9d5dd84d1c9+    , 0xad32618a178a2a88d850bd78ae79b42d+    , 0x6f8f8dcbeab951507b445e2d045fce8e+    , 0x661f147886e0ae7ee807c3b3b4530b9c+    , 0x94eb9e122febd3bfe4eaa669af48f2ab+    , 0xf4ae587302f335b9884b576816da6406+    , 0xb76a7c463cfdd40ce97d33bfc49d4baa+    , 0x87226d68d4d71a2bde6baf1f477f5cea+    , 0x353dc4524fde2317fcfa233218b03929+    , 0x68eb4665559d3e363efcea5eca56397c+    , 0xcfffa94e5f9db6b6321cf0467107c677+    , 0xde549b30f1f02509df7e84b86c98a637+    , 0xc88c3c922e1a2407f9a8a99de6f005a7+    , 0x11674f90ed769e1e4648c4291f7dc43d+    , 0x2b69d3c551473c0d1a0efce601bf620d+    , 0xb5e7be4b085efde49e667cca8b46038c+    , 0xd92bd2d0e5cc73449c2caf3bb95b8a52+    , 0xd83b91c6c80cae97ad5dc9951e306adf+    , 0xdbb6705e289135e7397f852c90891180+    , 0x5b0ccacc34ae5036bb31c2c96a3417e6+    , 0x89df5aecdc211840aa21b7ef3734d927+    , 0x4273cc66b1c9b1d8785e9ced9d7d2389+    , 0x4cb150a294fa8911657d5ebf91806d4a+    , 0x022949cf3d0efc3f89aee75560f9330e+    , 0x1b1563dc4bd8c88ed1190b722b431ce6+    , 0x169b2608a6559037cf82f749f5aee5f7+    , 0x03641a20adf237a84fa5b7d00f038d43+    , 0x3f4286f2270d7e24e304bf4feed390a5+    , 0x38f5f9ae7cd35cb1c493fe72a1c1e25f+    , 0x7c013a8bd03d13b26eb306bd5c32972c+    , 0x9ed32a009f65f09f94ca6b7a2214c892+    , 0x871d91d64108d5fb8c32d80b1150e8dc+    , 0xda832592b52be3481279dac78449f167+    , 0x362a1da96f16947ee94ed572cff23819+    , 0x8e6904163024620ffe49ed46961e4874+    , 0x1d8a3d58d0386400d8d6a998dea5fc57+    , 0x595357d9743676d4be1cdcef1cdeec9f+    , 0x40e772d8cb73ca6653f128eb000c04e3+    , 0x7a0f6793591ca9ccfe1d836a9a009776+    , 0xbd5947f0a447d505a067f52123545358+    , 0x7cbd3f979a063e504a83502f77d15051+    ]++{- | Reference SipHash-2-4-64 output words for 'boundaryInputs'. The+values use the same byte order as 'sipHash24VectorsForWord64'.+-}+boundaryVectorsForWord64 :: [Word64]+boundaryVectorsForWord64 =+    [ 0x0028c1ded1b851e5+    , 0xe987ca4ff9f8404d+    , 0x03413138de48340e+    , 0xa5d0d8d2d9378001+    , 0xde306f78d586b010+    , 0xb2b283a137aa8552+    , 0x9cb7322fb06c14a2+    , 0xbad61d3a1333d25b+    ]