ppad-bolt7-0.1.0: lib/Lightning/Protocol/BOLT7/CRC32C.hs
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE BangPatterns #-}
-- |
-- Module: Lightning.Protocol.BOLT7.CRC32C
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- CRC-32C (Castagnoli), per RFC 3720, for @channel_update@ checksums.
module Lightning.Protocol.BOLT7.CRC32C (
crc32c
) where
import Data.Bits (complement, shiftL, shiftR, xor, (.&.), (.|.))
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BU
import Data.Word (Word8, Word32)
-- | The CRC-32C of a byte string.
crc32c :: BS.ByteString -> Word32
crc32c = complement . BS.foldl' step 0xFFFFFFFF
where
step !c !b = (c `shiftR` 8) `xor` entry (fromIntegral c `xor` b)
{-# INLINE crc32c #-}
-- the table entry for a byte, read from 'table'
entry :: Word8 -> Word32
entry i =
let !o = 4 * fromIntegral i -- at most 1020, within the 1024-byte table
byte k = fromIntegral (BU.unsafeIndex table (o + k)) :: Word32
in byte 0 .|. (byte 1 `shiftL` 8) .|. (byte 2 `shiftL` 16)
.|. (byte 3 `shiftL` 24)
{-# INLINE entry #-}
-- the 256 table entries, little-endian
table :: BS.ByteString
table = fst (BS.unfoldrN 1024 byte 0)
where
byte :: Int -> Maybe (Word8, Int)
byte k = Just
(fromIntegral (go (8 :: Int) (fromIntegral (k `shiftR` 2))
`shiftR` (8 * (k .&. 3))), k + 1)
-- the Castagnoli polynomial 0x1EDC6F41, bit-reflected
poly = 0x82F63B78 :: Word32
go 0 !c = c
go n !c = go (n - 1) ((c `shiftR` 1) `xor` (poly .&. negate (c .&. 1)))
{-# NOINLINE table #-}