script

A Script library.
git clone git://git.ppad.tech/script.git
Log | Files | Refs | LICENSE

commit d01ad0caf0f32fcfa3a0219ea163925691426b5f
parent c21f3525360110f5e96c50f5f95f35e55763c989
Author: Jared Tobin <jared@jtobin.io>
Date:   Mon, 13 Jan 2025 02:18:35 +0400

lib: nicer base16 decoding

Diffstat:
Mlib/Bitcoin/Prim/Script.hs | 67++++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 34 insertions(+), 33 deletions(-)

diff --git a/lib/Bitcoin/Prim/Script.hs b/lib/Bitcoin/Prim/Script.hs @@ -7,14 +7,16 @@ module Bitcoin.Prim.Script where -import Control.Monad (when, unless) +import Control.Monad (unless) import Control.Monad.ST import qualified Crypto.Hash.RIPEMD160 as RIPEMD160 import qualified Crypto.Hash.SHA256 as SHA256 import qualified Data.Bits as B import Data.Bits ((.&.), (.|.)) import qualified Data.ByteString as BS +import qualified Data.ByteString.Internal as BI import qualified Data.ByteString.Builder as BSB +import qualified Data.ByteString.Unsafe as BU import qualified Data.Char as C import qualified Data.Primitive.ByteArray as PB import Data.STRef @@ -42,12 +44,14 @@ newtype Script = Script PB.ByteArray newtype ScriptHash = ScriptHash BS.ByteString deriving Eq +hex_charset :: BS.ByteString +hex_charset = "0123456789abcdef" + -- split a word8 into a pair of its high and low bits hilo :: Word8 -> (Word8, Word8) hilo b = - let bet = "0123456789abcdef" - hi = BS.index bet (fi b `B.shiftR` 4) - lo = BS.index bet (fi b .&. 0b00001111) + let hi = BU.unsafeIndex hex_charset (fi b `B.shiftR` 4) + lo = BU.unsafeIndex hex_charset (fi b .&. 0b00001111) in (hi, lo) instance Show ScriptHash where @@ -82,32 +86,36 @@ to_base16 (Script bs) = toStrict (go 0) where .|. lo in BSB.word16BE w16 <> go (succ j) --- adapted from emilypi's 'base16' package +word4 :: Word8 -> Maybe Word8 +word4 w8 = fmap fi (BS.elemIndex w8 hex_charset) + from_base16 :: BS.ByteString -> Maybe Script -from_base16 bs - | B.testBit l 0 = Nothing +from_base16 b16@(BI.PS _ _ b16_l) + | B.testBit b16_l 0 = Nothing | otherwise = runST $ do - arr <- PB.newByteArray (l `quot` 2) + arr <- PB.newByteArray (b16_l `quot` 2) ear <- newSTRef False - let loop i o - | i == l = pure () - | otherwise = do - let x = BS.index bs i - y = BS.index bs (i + 1) - - a = look hi x - b = look lo y - - when (a == 0xff) $ writeSTRef ear True - when (b == 0xff) $ writeSTRef ear True - - err <- readSTRef ear - unless err $ do - PB.writeByteArray arr o (a .|. b) - loop (i + 2) (o + 1) - - loop 0 0 + let loop j bs@(BI.PS _ _ l) + | l == 0 = pure () + | otherwise = case BS.splitAt 2 bs of + (chunk, etc) -> do + let ws = do + hi <- word4 (BU.unsafeIndex chunk 0) + lo <- word4 (BU.unsafeIndex chunk 1) + pure (hi, lo) + + case ws of + Nothing -> writeSTRef ear True + Just (hi, lo) -> do + err <- readSTRef ear + unless err $ do + let b = hi `B.shiftL` 4 + .|. lo + PB.writeByteArray arr j b + loop (succ j) etc + + loop 0 b16 err <- readSTRef ear if err @@ -115,13 +123,6 @@ from_base16 bs else do ray <- PB.unsafeFreezeByteArray arr pure (Just (Script ray)) - where - l = BS.length bs - look bet = BS.index bet . fi - - lo = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" - - hi = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xff\xff\xff\xff\xff\xff\xff\xa0\xb0\xc0\xd0\xe0\xf0\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xa0\xb0\xc0\xd0\xe0\xf0\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" data Term = OPCODE Opcode