ASSERT_MY_TAPROOT removed: one identity assert - #63
Merged
Conversation
0x37 is removed from the vocabulary table and its entry deleted. The self assert family is five conditions at 0x30 to 0x33 and 0x38, and 0x37 joins 0x34 to 0x36 as a visible gap inside the family block, invalid rather than reserved under the section 1 tier rule. The taptree entry now states its agreement fact against ASSERT_MY_SCRIPTPUBKEY over the scriptPubKey its operands derive, and its empty-root contrast against CREATE_OUTPUT_TAPROOT. COSTS.md's generic row covers every self assert, the tweak row prices CREATE_OUTPUT_TAPROOT alone, and VALIDATION.md's charge order and invariants speak of one derivation entry. Ratified as condition-record decision 29 (decision by Evan, 2026-08-23, at the PR 62 review, the venue decision 28 scheduled): ASSERT_MY_TAPTREE subsumes the removed assert on every input base consensus admits, the tweak-collision exemption aside, and PR 62 removed its last caller. The two capabilities removed with it are unreachable, an always-false empty-root form and a collision tolerance behind a discrete log.
The opcode constant, the dataclass, the parse function, the dispatch branch, and the cost row leave python/bitlisp, and the validation assert clause keeps only ASSERT_MY_SCRIPTPUBKEY on the spent-script comparison. The runner's display table, the vector runner's pinned JSON forms, and the compiler's condition-constant list drop the name, the language now 26 condition constants. The taproot derivation helpers stay: CREATE_OUTPUT_TAPROOT owns them. Authorized by spec/CONDITIONS.md sections 1 and 2 as amended in the previous commit, condition-record decision 29.
The removed assert's parse, cost, and validation cases leave the corpus: 11 parse cases, 6 cost cases, and 9 validation cases. gap_0x37_invalid pins the opcode as bad_condition_opcode beside the 0x39 gap vector, so the removal is visible and a revival is a deliberate re-pin. The all-assigned-opcodes total re-pins at 14,405,200 with its boundary twin, exactly the removed 1,300,200 lower, the condition list itself losing only the 0x37 element. The covenant recreation-missing case re-pins on the taptree assert with an honest identity as taptree_covenant_recreation_missing, beside the existing taptree_covenant_recreate, so the missing-recreation failure stays pinned, and the verify-then-recreate acceptance it duplicated is already pinned by that taptree case. Spec citation: CONDITIONS.md sections 1 and 2 as amended, condition-record decision 29. Corpus: 38 files, 1106 cases.
The self-assert suite replaces the taproot-agreement property with agreement between ASSERT_MY_TAPTREE and ASSERT_MY_SCRIPTPUBKEY over the scriptPubKey its operands derive on an honest input: the same oracle chain, the BIP341 tweak derivation still anchoring the identity assert, with the removed assert no longer the intermediate. The duplicate-invariants pool, the cost-invariants menu, the cost-table pins, the runner render pin, and the compiler's transcribed spec table drop the removed entries, the cost menu keeping an identity assert through a taptree entry.
The condition record gains decision 29 and updates divergence C24 and the rule 2 oracle column, the comparison table marks the own-taproot-components row removed, the glossary drops the removed row and restates the taptree row without it, and the execution plan's amendment bullet records the call.
A NUMS-keyed construction has no key path, so every spend is a script-path execution whose authorizations sign BitLisp's outpoint-bound condition digests rather than a BIP341 sighash. Shipping hardware signers refuse arbitrary 32-byte digests, so a hardware-backed wallet cannot sign these spends until firmware understands the digest scheme, even though an xpub-only watcher assembles everything else. Raised while weighing the xpub wallet flow at the PR 62 review, owed to Phase 4.
… tweak site Nine findings from the review pass, all verified. The spec's charge-order sentence and the record's rule 5 row go singular with the removal. The puzzle docs' saving baselines name the removed assert as removed. gap_0x37_invalid moves into the contiguous gap block so an auditor reading the block sees every gap. The self-assert suite derives each honest scriptPubKey once, restoring the derived-once comment's truth. The cost-invariants menu comment counts its generic entries honestly, the dead GOOD_INTERNAL_KEY constant and a vestigial f-string prefix go, and the register's Phase 4 owed list carries the hardware-signer integration note beside its section 5 bullet.
Owner
Author
Review pass (code-review skill, high, Fable finders, adversarial verify)Eight finder angles, nine deduplicated candidates, one verifier each. All nine confirmed at least in substance and all are folded in the review fold-in commit:
Final: 812 tests, 1106 vector cases, lint clean, CI green. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The follow-up PR 62 scheduled: ASSERT_MY_TAPROOT (0x37) leaves the vocabulary, ratified as condition-record decision 29 (decision by Evan, 2026-08-23, at the PR 62 review, the venue decision 28 reserved for this call). The objection register also gains the hardware-signer note from the same review conversation.
Why removal loses nothing. ASSERT_MY_TAPTREE proves the same fact at 200 instead of 1,300,200, and the two capabilities that leave with 0x37 are unreachable: the empty-root form asserts a treeless output on a spend that by definition executes a leaf, and exploiting its tweak-collision tolerance requires a discrete log. PR 62 removed the last caller, so the entry would have carried review burden with no user. CREATE_OUTPUT_TAPROOT and the derivation machinery are untouched.
Read the commits in this order
spec: ASSERT_MY_TAPROOT leaves the vocabulary. The table row and entry go, the self assert family is five conditions, 0x37 joins the 0x34 to 0x36 gap (invalid, not reserved), and the taptree entry restates its agreement fact against ASSERT_MY_SCRIPTPUBKEY over the derived scriptPubKey.conditions: drop the removed assert's implementation. Constant, dataclass, parse function, dispatch branch, cost row, validation branch, display and name tables. The language has 26 condition constants.vectors: 0x37 re-pins as a gap. 26 cases leave,gap_0x37_invalidarrives, the all-opcodes total re-pins at 14,405,200 (exactly 1,300,200 lower), and the covenant recreation-missing case re-pins on the taptree assert with an honest identity.tests: the taptree assert's oracle is the tweak derivation directly. The one substantive test change: the agreement property now pairs ASSERT_MY_TAPTREE with ASSERT_MY_SCRIPTPUBKEY over the scriptPubKey its operands derive, keeping the BIP341 derivation as the identity assert's oracle with no intermediate assert.docs: decision 29 recorded. Record, C24, comparison table, glossary, plan bullet.docs: the register anticipates the hardware-signer objection. In scope by request: this PR was asked to carry the removal and this note together. NUMS-keyed spends sign outpoint-bound condition digests, not a BIP341 sighash, and shipping hardware signers refuse arbitrary digests. An xpub-only watcher assembles everything else. Phase 4 owes the integration note.What a reviewer should scrutinize
gap_0x37_invalidexpectsbad_condition_opcode, the same shape as the 0x39 gap vector, so a future revival of 0x37 is a loud re-pin, never an accident.Verify independently
Confidence
High, 9 of 10. The removal surface was enumerated by grep before editing and re-checked after, every gate is green, and the one deliberate semantic artifact (the gap vector) is pinned. The vendored Bitcoin Core oracle files were touched by a formatter mid-session and restored to main's blobs before any commit,
git diff main -- tools/oracleis empty. Residual risk sits in wording drift across the spec and record, which review reads catch best.