PPAD-TX.md (6060B)
1 # ppad-tx 2 3 Minimal Bitcoin transaction primitives for ppad libraries. 4 5 ## Motivation 6 7 Multiple ppad-bolt implementations duplicate core tx-related types: 8 9 | Type | bolt2 | bolt3 | bolt7 | 10 |------------------|-------|-------|-------| 11 | TxId | yes | yes | - | 12 | Outpoint | yes | yes | - | 13 | Sequence | - | yes | - | 14 | Locktime | - | yes | - | 15 | Script | - | yes | - | 16 | Witness | - | yes | - | 17 | Satoshi(s) | yes | yes | - | 18 | MilliSatoshi(s) | yes | yes | - | 19 | Point/Pubkey | yes | yes | yes | 20 | Signature | yes | - | yes | 21 | ChainHash | yes | - | yes | 22 | ShortChannelId | yes | - | yes | 23 24 Common gap across all: no raw Tx structure, no serialisation, no txid 25 computation from raw bytes. 26 27 ppad-tx will provide canonical definitions and allow bolt impls to depend 28 on a single source. 29 30 ## Scope 31 32 ### In scope (v1) 33 34 - Raw transaction types (Tx, TxIn, TxOut) 35 - Outpoint, Sequence, Locktime 36 - Serialisation to/from bytes (legacy and segwit formats) 37 - TxId computation (double SHA256 of non-witness serialisation) 38 - Sighash computation (legacy and BIP143 segwit) 39 - Basic amount types (Satoshi) 40 41 ### Out of scope (v1) 42 43 - Script execution or validation 44 - Signature creation/verification (use ppad-secp256k1) 45 - Transaction building DSL 46 - PSBT support 47 - Taproot/BIP341 sighash (defer to v2) 48 49 ## Module layout 50 51 ``` 52 lib/ 53 Bitcoin/ 54 Prim/ 55 Tx.hs -- core types, serialisation, txid 56 Tx/ 57 Sighash.hs -- sighash computation 58 ``` 59 60 Follow ppad-script conventions: 61 - `Bitcoin.Prim.*` namespace 62 - ByteArray for internal representation where appropriate 63 - base16 conversion utilities 64 - OPTIONS_HADDOCK prune 65 66 ## Core types 67 68 ```haskell 69 -- | Transaction ID (32 bytes, little-endian double-SHA256). 70 newtype TxId = TxId BS.ByteString 71 72 -- | Transaction outpoint. 73 data OutPoint = OutPoint 74 { op_txid :: {-# UNPACK #-} !TxId 75 , op_vout :: {-# UNPACK #-} !Word32 76 } 77 78 -- | Transaction input. 79 data TxIn = TxIn 80 { txin_prevout :: {-# UNPACK #-} !OutPoint 81 , txin_script_sig :: !BS.ByteString 82 , txin_sequence :: {-# UNPACK #-} !Word32 83 } 84 85 -- | Transaction output. 86 data TxOut = TxOut 87 { txout_value :: {-# UNPACK #-} !Word64 -- satoshis 88 , txout_script_pubkey :: !BS.ByteString 89 } 90 91 -- | Witness stack for a single input. 92 newtype Witness = Witness [BS.ByteString] 93 94 -- | Complete transaction. 95 data Tx = Tx 96 { tx_version :: {-# UNPACK #-} !Word32 97 , tx_inputs :: ![TxIn] 98 , tx_outputs :: ![TxOut] 99 , tx_witnesses :: ![Witness] -- empty list for legacy tx 100 , tx_locktime :: {-# UNPACK #-} !Word32 101 } 102 ``` 103 104 ## Serialisation 105 106 ### Format detection 107 108 - Legacy: version || inputs || outputs || locktime 109 - Segwit: version || 0x00 || 0x01 || inputs || outputs || witnesses || locktime 110 111 Detect segwit by marker byte (0x00) after version. If present and followed 112 by flag (0x01), parse as segwit. 113 114 ### Public API 115 116 ```haskell 117 -- Serialisation 118 to_bytes :: Tx -> BS.ByteString -- segwit format if witnesses present 119 from_bytes :: BS.ByteString -> Maybe Tx 120 121 to_base16 :: Tx -> BS.ByteString 122 from_base16 :: BS.ByteString -> Maybe Tx 123 124 -- Legacy serialisation (for txid computation) 125 to_bytes_legacy :: Tx -> BS.ByteString 126 127 -- TxId 128 txid :: Tx -> TxId -- double SHA256 of legacy serialisation 129 ``` 130 131 ### Encoding details 132 133 All integers little-endian. Variable-length integers (compactSize): 134 - 0x00-0xfc: 1 byte 135 - 0xfd: 0xfd || 2 bytes (little-endian) 136 - 0xfe: 0xfe || 4 bytes 137 - 0xff: 0xff || 8 bytes 138 139 ## Sighash 140 141 ### Flags 142 143 ```haskell 144 data SighashType 145 = SIGHASH_ALL 146 | SIGHASH_NONE 147 | SIGHASH_SINGLE 148 | SIGHASH_ALL_ANYONECANPAY 149 | SIGHASH_NONE_ANYONECANPAY 150 | SIGHASH_SINGLE_ANYONECANPAY 151 ``` 152 153 ### Legacy sighash 154 155 Per BIP-143 predecessor. Modify tx copy based on flags, append sighash 156 type as 4-byte LE, double SHA256. 157 158 ### BIP143 segwit sighash 159 160 Required for signing segwit inputs. Precomputed: 161 - hashPrevouts: SHA256(SHA256(all input outpoints)) 162 - hashSequence: SHA256(SHA256(all input sequences)) 163 - hashOutputs: SHA256(SHA256(all outputs)) 164 165 Then: 166 ``` 167 version || hashPrevouts || hashSequence || outpoint || scriptCode || 168 value || sequence || hashOutputs || locktime || sighashType 169 ``` 170 171 ### Public API 172 173 ```haskell 174 -- Legacy 175 sighash_legacy 176 :: Tx 177 -> Int -- input index 178 -> BS.ByteString -- scriptPubKey being spent 179 -> SighashType 180 -> BS.ByteString -- 32-byte hash 181 182 -- BIP143 segwit 183 sighash_segwit 184 :: Tx 185 -> Int -- input index 186 -> BS.ByteString -- scriptCode 187 -> Word64 -- value being spent 188 -> SighashType 189 -> BS.ByteString -- 32-byte hash 190 ``` 191 192 ## Dependencies 193 194 Minimal: 195 - base 196 - bytestring 197 - primitive (for ByteArray if needed) 198 - ppad-sha256 (for txid and sighash) 199 - ppad-base16 (for hex conversion) 200 201 ## Testing 202 203 - Known tx vectors from Bitcoin Core / BIPs 204 - Round-trip: from_bytes . to_bytes == id 205 - TxId computation against known txids 206 - Sighash vectors from BIP143 207 208 Sources: 209 - BIP143 test vectors 210 - Bitcoin Core's tx_valid.json / tx_invalid.json 211 - Manually constructed edge cases (empty witness, max inputs, etc.) 212 213 ## Implementation steps 214 215 ### Step 1: Core types + serialisation (independent) 216 217 - Define Tx, TxIn, TxOut, OutPoint, Witness 218 - Implement compactSize encoding/decoding 219 - Implement to_bytes / from_bytes (both formats) 220 - Implement txid computation 221 222 ### Step 2: Sighash (depends on Step 1) 223 224 - Define SighashType 225 - Implement legacy sighash 226 - Implement BIP143 segwit sighash 227 228 ### Step 3: Tests + benchmarks 229 230 - Add tx serialisation round-trip tests 231 - Add known vector tests for txid 232 - Add BIP143 sighash vectors 233 - Criterion benchmarks for serialisation 234 - Weigh benchmarks for allocations 235 236 ### Step 4: Polish 237 238 - Haddock documentation with examples 239 - Ensure line length < 80 240 - Module headers, OPTIONS_HADDOCK prune 241 242 ## Future (v2) 243 244 - BIP341 taproot sighash 245 - BIP340 schnorr signature integration 246 - Witness program version detection 247 - Transaction weight/vsize calculation