-- | Encoding and decoding of big /natural/ numbers as ByteString or [Word8]

module Bitcoin.Misc.BigInt where

--------------------------------------------------------------------------------

import Data.Word
import Data.Bits
import Data.List ( unfoldr )

--------------------------------------------------------------------------------
-- * encoding/decoding nonnegative integers

bigEndianRollInteger :: [Word8] -> Integer
bigEndianRollInteger = littleEndianRollInteger . reverse

littleEndianRollInteger :: [Word8] -> Integer
littleEndianRollInteger = foldr unstep 0 where
  unstep b a = shiftL a 8 .|. fromIntegral b

bigEndianUnrollInteger :: Integer -> [Word8]
bigEndianUnrollInteger = reverse . littleEndianUnrollInteger

littleEndianUnrollInteger :: Integer -> [Word8]
littleEndianUnrollInteger = unfoldr step where
  step 0 = Nothing
  step i = Just (fromIntegral i, shiftR i 8)

--------------------------------------------------------------------------------

-- | Always 32 byte long (if the integer was less than @2^256@)
bigEndianInteger32 :: Integer -> [Word8]
bigEndianInteger32 = extend32 . bigEndianUnrollInteger where
  extend32 what = replicate (32-n) 0 ++ what where n = length what

littleEndianInteger32 :: Integer -> [Word8]
littleEndianInteger32 = extend32 . littleEndianUnrollInteger where
  extend32 what = what ++ replicate (32-n) 0 where n = length what

--------------------------------------------------------------------------------

-- | Always 20 byte long (if the integer was less than @2^160@)
bigEndianInteger20 :: Integer -> [Word8]
bigEndianInteger20 = extend20 . bigEndianUnrollInteger where
  extend20 what = replicate (20-n) 0 ++ what where n = length what

littleEndianInteger20 :: Integer -> [Word8]
littleEndianInteger20 = extend20 . littleEndianUnrollInteger where
  extend20 what = what ++ replicate (20-n) 0 where n = length what

--------------------------------------------------------------------------------