    -- CRC24.hs: OpenPGP (RFC4880) CRC24 implementation
    -- Copyright © 2012-2019 Clint Adams
    -- This software is released under the terms of the Expat license.
    -- (See the LICENSE file).

    module Data.Digest.CRC24 (
       crc24
     , crc24Lazy
    ) where

    import Data.Bits (shiftL, (.&.), xor)
    import Data.ByteString.Lazy (ByteString)
    import qualified Data.ByteString as B
    import qualified Data.ByteString.Lazy as BL
    import Data.Word (Word8, Word32)

    crc24Init :: Word32
    crc24Init :: Word32
    crc24Init = Word32
    0xB704CE

    crc24Poly :: Word32
    crc24Poly :: Word32
    crc24Poly = Word32
    0x1864CFB

    crc24Update :: Word32 -> Word8 -> Word32
    crc24Update :: Word32 -> Word8 -> Word32
    crc24Update Word32
    c Word8
    b = ([Word32] -> Word32
    forall a. HasCallStack => [a] -> a
    last ([Word32] -> Word32)
    -> ([Word32] -> [Word32]) -> [Word32] -> Word32
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [Word32] -> [Word32]
    forall a. Int -> [a] -> [a]
    take Int
    9 ([Word32] -> Word32) -> [Word32] -> Word32
    forall a b. (a -> b) -> a -> b
    $ (Word32 -> Word32) -> Word32 -> [Word32]
    forall a. (a -> a) -> a -> [a]
    iterate (\Word32
    x -> if Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    shiftL Word32
    x Int
    1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .&. Word32
    0x1000000 Word32 -> Word32 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word32
    0x1000000 then Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    shiftL Word32
    x Int
    1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` Word32
    crc24Poly else Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    shiftL Word32
    x Int
    1) (Word32
    c Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    shiftL (Word8 -> Word32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    b) Int
    16)) Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .&. Word32
    0xFFFFFF

    crc24 :: B.ByteString -> Word32
    crc24 :: ByteString -> Word32
    crc24 ByteString
    bs = ByteString -> Word32
    crc24Lazy (ByteString -> Word32)
    -> ([ByteString] -> ByteString) -> [ByteString] -> Word32
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ByteString] -> ByteString
    BL.fromChunks ([ByteString] -> Word32) -> [ByteString] -> Word32
    forall a b. (a -> b) -> a -> b
    $ [ByteString
    bs]

    crc24Lazy :: ByteString -> Word32
    crc24Lazy :: ByteString -> Word32
    crc24Lazy = (Word32 -> Word8 -> Word32) -> Word32 -> ByteString -> Word32
    forall a. (a -> Word8 -> a) -> a -> ByteString -> a
    BL.foldl' Word32 -> Word8 -> Word32
    crc24Update Word32
    crc24Init