pyrxd.spv — SPV verification¶
Bitcoin SPV primitives for the Radiant-side covenant.
This module is the highest-risk layer of pyrxd: a forged SPV proof
accepted here drains a Maker’s RXD. Every verifier here mirrors the
battle-tested Node.js prototype at gravity-rxd-prototype/ and
incorporates the 12 audit-hardening fixes called out in
docs/audits/02-bitcoin-spv-crypto-correctness.md and
docs/audits/05-spv-data-integrity.md.
- class pyrxd.spv.CovenantParams[source]¶
Bases:
objectFull parameter set committed by the Maker into the covenant.
SpvProofBuildercannot be constructed without all of these. This is the audit 05-F-2 / F-3 fix: every proof is bound to the covenant it satisfies.- __init__(btc_receive_hash, btc_receive_type, btc_satoshis, chain_anchor, anchor_height, merkle_depth)¶
- class pyrxd.spv.SpvProof[source]¶
Bases:
objectA fully-verified SPV proof.
Immutable. The only way to obtain one is via
SpvProofBuilder.build(), which runs every verifier before returning. Carries a reference to itsCovenantParamsso downstream finalize-tx builders can confirm that the proof was built for the right covenant.- __init__(txid, raw_tx, headers, branch, pos, output_offset, covenant_params, _token=None)¶
- covenant_params: CovenantParams¶
- class pyrxd.spv.SpvProofBuilder[source]¶
Bases:
objectBuild and verify an SPV proof against a specific covenant’s parameters.
Construction requires the full
CovenantParams(audit 05-F-2 / F-3 fix). Thebuildmethod runs every verifier and refuses to return partially verified proofs: if any check fails,SpvVerificationErroris raised.- __init__(covenant_params)[source]¶
- Parameters:
covenant_params (CovenantParams)
- Return type:
None
- build(txid_be, raw_tx_hex, headers_hex, merkle_be, pos, output_offset)[source]¶
Verify every SPV-proof component and return an
SpvProof.- Verification order:
Strip witness; stripped raw tx length > 64 (Merkle forgery defense).
hash256(stripped_raw_tx) == txid(tx integrity).PoW + chain link for every header (anchor-bound).
Merkle inclusion (with depth binding + coinbase guard).
Payment output correct (hash + type + value threshold).
- pyrxd.spv.build_branch(merkle_be, pos)[source]¶
Convert a mempool.space / Bitcoin Core Merkle proof into covenant wire format.
- Parameters:
- Returns:
N * 33 bytes of concatenated
[direction][sibling_LE]entries.- Raises:
ValidationError – if
posis negative or any sibling is not 32 bytes.- Return type:
- pyrxd.spv.compute_root(txid_be_hex, branch)[source]¶
Walk a Merkle branch from leaf to root.
- Parameters:
- Returns:
Computed Merkle root in LE (matches what the covenant extracts from the block header at byte offset 36).
- Raises:
ValidationError – if
branchis not a multiple of 33 bytes.- Return type:
- pyrxd.spv.extract_merkle_root(header)[source]¶
Return the 32-byte Merkle root from an 80-byte header (LE, offset 36).
- pyrxd.spv.strip_witness(raw_tx)[source]¶
Strip witness data from a segwit / taproot tx.
Returns the legacy non-witness serialization whose
hash256matches the txid. If the tx already has no segwit marker, returns the input unchanged.- Wire format:
Legacy: version(4) + inputs + outputs + locktime(4) Segwit: version(4) + marker(0x00) + flag(0x01) + inputs + outputs +
witness[] + locktime(4)
- Raises:
ValidationError – if the tx is too short or the serialization is malformed.
- Parameters:
raw_tx (bytes)
- Return type:
- pyrxd.spv.verify_chain(headers, chain_anchor=None)[source]¶
Verify a chain of N consecutive 80-byte Bitcoin block headers.
- Parameters:
- Returns:
List of header hashes in little-endian (32 bytes each).
- Raises:
ValidationError – on malformed input (wrong length, empty list, etc.).
SpvVerificationError – on PoW failure, broken chain link, or anchor mismatch.
- Return type:
- pyrxd.spv.verify_header_pow(header)[source]¶
Verify a single 80-byte Bitcoin block header’s proof of work.
Returns the header hash (little-endian, 32 bytes) on success.
- Raises:
ValidationError – if
headeris not 80 bytes ornBitsis malformed.SpvVerificationError – if the PoW check fails (hash >= target).
- Parameters:
header (bytes)
- Return type:
- pyrxd.spv.verify_payment(raw_tx, output_offset, expected_hash, output_type, min_satoshis)[source]¶
Verify a specific output in
raw_txpaysexpected_hashat leastmin_satoshis.- Parameters:
raw_tx (bytes) – Full raw transaction bytes (witness-stripped if segwit).
output_offset (int) – Byte offset within
raw_txwhere this output begins.expected_hash (bytes) – 20 bytes for P2PKH / P2WPKH / P2SH; 32 bytes for P2TR.
output_type (str) – One of the module constants above.
min_satoshis (int) – Minimum acceptable value (must be > 0 and <= value).
- Raises:
ValidationError – on bad arguments (unknown type, wrong hash length, etc.).
SpvVerificationError – on any verification failure.
- Return type:
None
- pyrxd.spv.verify_tx_in_block(raw_tx, txid_be_hex, branch, pos, header, expected_depth=None)[source]¶
Full Merkle inclusion check for a raw transaction within a block.
- Audit defenses applied here (see docs/audits/02 and docs/audits/05):
Finding 02-F-1:
len(raw_tx) > 64rejects the 64-byte Merkle forgery.Finding 05-F-9:
pos == 0rejects the coinbase as a payment proof.Finding 05-F-8:
expected_depthmust match branch depth when provided.Finding 02-F-1 / parity:
hash256(raw_tx) == txidbound.
- Raises:
ValidationError – on malformed input (wrong lengths, misaligned branch).
SpvVerificationError – on any defense trigger or root mismatch.
- Parameters:
- Return type:
None