module Bitcoin.Script.Integer where
import Data.Int
import Data.Word
import Data.Bits
import Data.List ( unfoldr , splitAt , mapAccumL )
import Data.Maybe
import Control.Monad
import Control.Applicative
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Bitcoin.Misc.BigInt
import Bitcoin.Misc.OctetStream
data Sign = Positive | Negative
signOf :: Integer -> Sign
signOf n = if n<0 then Negative else Positive
toSignAbs :: Integer -> (Sign,Integer)
toSignAbs n = (signOf n, abs n)
fromSignAbs :: (Sign,Integer) -> Integer
fromSignAbs (sign,absn) = case sign of
Positive -> absn
Negative -> negate absn
asInteger :: B.ByteString -> Integer
asInteger bs =
case sign of
Positive -> absn
Negative -> negate absn
where
absn = littleEndianRollInteger ws
(sign,ws) = decodeSign (B.unpack bs)
asByteString :: Integer -> B.ByteString
asByteString 0 = B.empty
asByteString n = B.pack $ encodeSign (signOf n) $ littleEndianUnrollInteger (abs n)
encodeSign :: Sign -> [Word8] -> [Word8]
encodeSign sign = go where
go ws = case ws of
(x:rest@(y:_)) -> x : go rest
[last] -> if last < 0x80
then case sign of { Positive -> [last] ; Negative -> [last + 0x80] }
else last : go []
[] -> [ case sign of { Positive -> 0 ; Negative -> 0x80 } ]
decodeSign :: [Word8] -> (Sign,[Word8])
decodeSign = go where
go ws = case ws of
(x:rest@(y:_)) -> let (sign,xs) = go rest in (sign,x:xs)
[last] -> if last < 0x80
then (Positive, [last ] )
else (Negative, [last0x80] )
[] -> ( Positive , [] )