Skip to content

nmc(P1c): AuxPow::check_proof parent-coinbase tx-merkle leg (step 3) + witness-stripped txid KAT - #181

Merged
frstrtr merged 1 commit into
nmc/p1b-check-proof-chain-legfrom
nmc/p1c-parent-coinbase-leg
Jun 19, 2026
Merged

nmc(P1c): AuxPow::check_proof parent-coinbase tx-merkle leg (step 3) + witness-stripped txid KAT#181
frstrtr merged 1 commit into
nmc/p1b-check-proof-chain-legfrom
nmc/p1c-parent-coinbase-leg

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Stacked PR — review order P1a (#178) -> P1b (#180) -> P1c (this). Base is the P1b branch so this diff is P1c-only; each leg is independently revertable.

What

Third leg of AuxPow::check_proof(): the parent-coinbase tx-merkle proof (step 3 of 4).

  • New nmc::coin::parent_coinbase_txid()Hash(pack(TX_NO_WITNESS(tx))), byte-identical to the btc tree's compute_txid() (mempool.hpp) but NMC-local per the coin fence (only nmc::coin serializer + core::Hash; no btc include).
  • check_proof step 3: reconstruct the parent block tx-merkle-root from the witness-stripped coinbase txid through parent_coinbase_branch/parent_coinbase_index via aux_merkle_root(). When a parent header is present the reconstructed root MUST equal parent_header.m_merkle_root, else INVALID. Negative/too-wide index => INVALID.

Still INCOMPLETE-never-VALID

Steps 2 (MM-marker commitment + chain_id/slot binding) and 4 (parent PoW vs target, btc tree READ-ONLY) are unbuilt. A structurally-consistent proof returns INCOMPLETE — NMC MUST NOT block-validate off this leaf. No leaf can block-validate until all four legs land, so this carries no merge risk.

Tests — nmc_auxpow_merkle_test 14/14 PASS exit 0 (was 9/9)

  • Load-bearing byte-exactness KAT: txid is hashed over the LEGACY (no-witness) layout — txid, NOT wtxid — re-derived field-by-field WITHOUT SerializeTransaction's witness/marker path (catches a stray marker/flag), and shown to differ from the wtxid for a coinbase carrying the BIP141 reserved value.
  • 4 check_proof boundary KATs: match=>INCOMPLETE, mismatch/negative/too-wide=>INVALID.

Fences

NMC-local (src/impl/nmc/ only), btc tree READ-ONLY, GPG-signed, zero-attribution, test target name unchanged (CI --target allowlist untouched). I do not self-merge.

Next: P1c-step2 (coinbase MM-marker scan + chain_id pin), then step 4 (parent PoW).

…p 3) + witness-stripped txid KAT

Adds nmc::coin::parent_coinbase_txid() (Hash over TX_NO_WITNESS serialization,
byte-identical to btc compute_txid() but NMC-local per the coin fence) and
wires AuxPow::check_proof step 3: reconstruct the parent block tx-merkle-root
from the witness-stripped coinbase txid through parent_coinbase_branch/index
via aux_merkle_root(). When a parent header is present the reconstructed root
MUST equal parent_header.m_merkle_root, else INVALID; malformed legs (negative
index, index wider than branch depth) are INVALID. Steps 2 (MM-marker
commitment) and 4 (parent PoW) remain unbuilt, so a structurally-consistent
proof still returns INCOMPLETE, never VALID -- NMC MUST NOT block-validate off
this leaf.

The load-bearing KAT asserts the exact byte serialization: the txid is hashed
over the LEGACY (no-witness) layout -- txid, NOT wtxid -- re-derived field-by-
field without SerializeTransaction's witness/marker path, and is shown to
differ from the wtxid for a coinbase carrying the BIP141 reserved value. Plus
4 check_proof boundary KATs (match=>INCOMPLETE, mismatch/negative/too-wide=>
INVALID). nmc_auxpow_merkle_test 14/14 PASS exit 0. NMC-local, btc tree
READ-ONLY, test target name unchanged (CI allowlist untouched).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant