commit 4845706b1c0fc9a2575500c3bd998c730828b0c0
parent 7119cfdd89057702ee86d2467a4890b33eca0a65
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 10 Oct 2026 18:41:01 +0400
docs, meta: readme, changelog and cabal metadata for 0.2.0
Rewrite the README example against the current sighash API (it no
longer typechecked) and mention taproot; update the synopsis and
description, tested-with format and deepseq bounds; drop unused bench
dependencies.
Diffstat:
5 files changed, 72 insertions(+), 32 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
@@ -4,7 +4,7 @@ Minimal Bitcoin transaction primitives for ppad libraries.
## Project Structure
-- `lib/` - library source (Bitcoin.Prim.Tx)
+- `lib/` - library source (Bitcoin.Prim.Tx, Bitcoin.Prim.Tx.Sighash)
- `test/` - tests (tasty + tasty-hunit)
- `bench/` - benchmarks (criterion for timing, weigh for allocations)
- `flake.nix` - nix flake for dependency and build management
diff --git a/CHANGELOG b/CHANGELOG
@@ -9,7 +9,14 @@
* Strips OP_CODESEPARATOR from the script code in legacy sighashes.
* Adds BIP341 taproot sighashes (sighash_taproot_keypath,
sighash_taproot_scriptpath).
- * Adds NFData instances for all transaction types.
+ * Adds NFData instances for all transaction types, an NFData
+ instance for SighashType, and Ord instances for TxId and OutPoint.
+ * Fixes from_bytes, which threw an exception on compactSize lengths
+ of 2^63 or more, and now rejects counts exceeding the remaining
+ input.
+ * Rejects segwit-flagged transactions carrying no witness data, and
+ serialises transactions whose witnesses are all empty in the legacy
+ format, as Bitcoin Core does.
- 0.1.0 (2026-04-18)
* Initial release.
diff --git a/CLAUDE.md b/CLAUDE.md
@@ -4,7 +4,7 @@ Minimal Bitcoin transaction primitives for ppad libraries.
## Project Structure
-- `lib/` - library source (Bitcoin.Prim.Tx)
+- `lib/` - library source (Bitcoin.Prim.Tx, Bitcoin.Prim.Tx.Sighash)
- `test/` - tests (tasty + tasty-hunit)
- `bench/` - benchmarks (criterion for timing, weigh for allocations)
- `flake.nix` - nix flake for dependency and build management
diff --git a/README.md b/README.md
@@ -4,9 +4,10 @@

[](https://docs.ppad.tech/tx)
-Minimal Bitcoin transaction primitives, including raw transaction
-types, serialisation to/from bytes, txid computation, and sighash
-calculation (legacy and BIP143 segwit).
+Minimal Bitcoin transaction primitives in pure Haskell: raw transaction
+types, serialisation to and from bytes (legacy and BIP144 segwit),
+txid computation, and sighash calculation (legacy, [BIP143][bp143]
+segwit and [BIP341][bp341] taproot).
## Usage
@@ -16,42 +17,74 @@ A sample GHCi session:
> :set -XOverloadedStrings
> import qualified Data.ByteString as BS
> import qualified Data.ByteString.Base16 as B16
+ > import qualified Data.List.NonEmpty as NE
> import Bitcoin.Prim.Tx
> import Bitcoin.Prim.Tx.Sighash
>
- > -- parse a raw transaction from hex
- > let raw = "0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000"
+ > -- the Satoshi -> Hal transaction from block 170
+ > :{
+ > let raw = mconcat
+ > [ "0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25"
+ > , "857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f"
+ > , "4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd1290"
+ > , "9d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b0000000043"
+ > , "4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa2"
+ > , "8414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6c"
+ > , "d84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a"
+ > , "382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b"
+ > , "64f9d4c03f999b8643f656b412a3ac00000000"
+ > ]
+ > :}
> let Just tx = from_base16 raw
>
- > -- compute the txid
+ > -- txids are displayed byte-reversed
> let TxId tid = txid tx
> B16.encode (BS.reverse tid)
"f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"
>
- > -- round-trip serialisation
> from_bytes (to_bytes tx) == Just tx
True
>
- > -- compute a legacy sighash
- > let scriptPubKey = BS.pack [0x76, 0xa9, 0x14]
- > let hash = sighash_legacy tx 0 scriptPubKey SIGHASH_ALL
- > BS.length hash
- 32
+ > -- the legacy sighash Satoshi signed: input 0 spends a P2PK output
+ > -- whose scriptPubKey is the same as this tx's change output
+ > let spk = txout_script_pubkey (NE.last (tx_outputs tx))
+ > B16.encode (sighash_legacy tx 0 spk (encode_sighash SIGHASH_ALL))
+ "7a05c6145f10101e9d6325494245adf1297d80f8f38d4d576d57cdba220bcb19"
+ >
+ > -- segwit and taproot sighashes validate their arguments
+ > sighash_segwit tx 1 spk 1000000000 (encode_sighash SIGHASH_ALL)
+ Nothing
```
## Documentation
-Haddocks are hosted at [docs.ppad.tech/tx][hadoc].
+Haddocks (API documentation, etc.) are hosted at
+[docs.ppad.tech/tx][hadoc].
+
+## Performance
+
+The aim is best-in-class performance for pure Haskell code. Run the
+benchmarks (criterion for wall time, weigh for allocation) with:
+
+```
+$ cabal bench
+```
## Security
-This is a pre-release library that, at present, claims no security
-properties whatsoever.
+This library handles no secret material. Parsing is total and
+rejects malformed, non-minimal or trailing-byte encodings, matching
+Bitcoin Core's serialisation rules; it doesn't validate transactions
+against consensus or policy rules (amounts, script validity, etc.).
+Sighash computation follows Bitcoin Core, including its legacy quirks
+(the SIGHASH_SINGLE "bug" value, OP_CODESEPARATOR removal, raw 32-bit
+hashTypes), and is tested against Bitcoin Core's `sighash.json` and
+the BIP143 and BIP341 vectors.
## Development
-You'll require [Nix][nixos] with [flake][flake] support enabled.
-Enter a development shell with:
+You'll require [Nix][nixos] with [flake][flake] support enabled. Enter a
+development shell with:
```
$ nix develop
@@ -60,11 +93,13 @@ $ nix develop
Then do e.g.:
```
-$ cabal build
-$ cabal test
-$ cabal bench
+$ cabal repl ppad-tx
```
+to get a REPL for the main library.
+
+[bp143]: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
+[bp341]: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
[nixos]: https://nixos.org/
[flake]: https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html
[hadoc]: https://docs.ppad.tech/tx
diff --git a/ppad-tx.cabal b/ppad-tx.cabal
@@ -1,19 +1,19 @@
cabal-version: 3.0
name: ppad-tx
version: 0.2.0
-synopsis: Minimal Bitcoin transaction primitives.
+synopsis: Minimal Bitcoin transaction primitives
license: MIT
license-file: LICENSE
author: Jared Tobin
maintainer: jared@ppad.tech
category: Cryptography
build-type: Simple
-tested-with: GHC == 9.10.3
+tested-with: GHC == { 9.10.3 }
extra-doc-files: CHANGELOG
description:
- Minimal Bitcoin transaction primitives for ppad libraries, including
- raw transaction types, serialisation, txid computation, and sighash
- calculation.
+ Minimal Bitcoin transaction primitives: raw transaction types,
+ serialisation, txid computation, and legacy, BIP143 segwit and BIP341
+ taproot sighash calculation.
flag llvm
description: Use GHC's LLVM backend.
@@ -37,7 +37,7 @@ library
build-depends:
base >= 4.9 && < 5
, bytestring >= 0.9 && < 0.13
- , deepseq >= 1.4 && < 2
+ , deepseq >= 1.4 && < 1.6
, ppad-base16 >= 0.3 && < 0.4
, ppad-sha256 >= 0.3 && < 0.4
@@ -48,7 +48,7 @@ test-suite tx-tests
main-is: Main.hs
ghc-options:
- -rtsopts -Wall
+ -rtsopts -Wall -fno-warn-orphans
build-depends:
base
@@ -73,7 +73,6 @@ benchmark tx-bench
base
, bytestring
, criterion
- , deepseq
, ppad-tx
benchmark tx-weigh
@@ -88,6 +87,5 @@ benchmark tx-weigh
build-depends:
base
, bytestring
- , deepseq
, ppad-tx
, weigh