From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Mon, 01 Jun 2026 11:56:34 -0700 Received: from mail-oa1-f58.google.com ([209.85.160.58]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1wU7oM-0003sA-Pv for bitcoindev@gnusha.org; Mon, 01 Jun 2026 11:56:34 -0700 Received: by mail-oa1-f58.google.com with SMTP id 586e51a60fabf-43d2c778510sf161736fac.1 for ; Mon, 01 Jun 2026 11:56:30 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1780340185; cv=pass; d=google.com; s=arc-20240605; b=NfndujpAqFuVmWsMmE41uBOVHvfdMxubJi56+zBKExlHid1EXAJHwhUYodCUw/pn3w mlsOkJdQu5RGp2EXTLZ6113/pe5Y26kYB7tZ/YBIng3anEqlb+wNS5fD7dnWx56/FQyo TSOOfNU5lT/yh6fsWAsPgk7fLg5XRbTE+UG/8R/txTeeJv3tLxOxLLopohIIiOFuvalj hwe4nGK3hYBUeZDwJp47qgZSBf0FAopUTNA+8Xii37le8k6Iz4Jx4np6+qfFZ98QUBrI dOtVxp1LIJYHcEHOypDp+X3/mGIVb8yJf+tSkWurbgZHujY85R3e68RdL524WiGUyWKw /xKQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:mime-version:feedback-id :references:in-reply-to:message-id:subject:cc:from:to:date :dkim-signature; bh=dIDaRCAuBgj3Wxt8RSKfZ244xo3B/9c05cV6f6gcdHk=; fh=0MbZ7JR9MxO7DLa8dEqI/TTuPUGtJfKDFSCqrXPhYNM=; b=DrRR4xd9Kts5aMBgt/YFeMj2VmmI4XPca0kURytk7zqix/VOdZd/jcQsR9OHTil73N uiLWnMiNyKvWvWIgmoyB5F6s3GH0Sm3pp3iZngUCtH1OqBadbeTWaD7Zbt3n0OgIaxee EGm2yqd8+L2pudaVV3j0Nz8HNPvlHnEQsZC2vncAbEIle4hFuiRKYaxsUIsCNCw+X7WI 0RqqH8yDiqsPIkk9sxNIOaCglKloX/q31DTMiA0Mj3vHvb9SnJoZSYZ1HRiW7GXQMKP/ oaPuoMHKOk/Bon0dE+bNmcLerBVTod8xu6ayJMa0Gv/LUa0tx5moM3IsXuB/FtrPF0CD xA8w==; darn=gnusha.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@protonmail.com header.s=protonmail3 header.b="g6kN1E//"; spf=pass (google.com: domain of darosior@protonmail.com designates 185.70.43.103 as permitted sender) smtp.mailfrom=darosior@protonmail.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1780340184; x=1780944984; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :date:from:to:cc:subject:date:message-id:reply-to; bh=dIDaRCAuBgj3Wxt8RSKfZ244xo3B/9c05cV6f6gcdHk=; b=t0RUkTJ5Q+czMeAUmttA15Vet3yAJy9taO4U1egUxpBvTy1knu6MoUw+sGbL2yh7Yl dWX97hxDqTREzRsWaAbSoZY1dYPjCDjzS9DYGaPBR6Hs4Ts85qPE/isUoRdiPqJB0L8p ytRFhWRhluNlTHBP1+207CUPWjoHrES3MPbEZFyYHvGsQqnVtWtArPTDjtKTfcnyb3nT mDvIQPev9bUw0yQp4BscyObJsJR7ebH6dG1VTEtKXxhcQthm5UFt7Fx0whdBDwR04fOL HXx3VxyVrqSQJMQ/Xg9nkjy2kkVY22ACsutMdSLzoUEpcmJcVlrtlV/bzFoT8TTmWUKJ ARcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780340185; x=1780944985; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :date:x-beenthere:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=dIDaRCAuBgj3Wxt8RSKfZ244xo3B/9c05cV6f6gcdHk=; b=fwVKgxswsMGzT/Zr/cGYXlMZHCuKRuC0/CclHw36/te0gBA6e3roHXfWlJa4jypKBp 58nhMcC6n6EcAYWhxHAlj1Tm35m66kUP9F8dWlDYmosNSYywdcqcJg8hmwHZAFEWukEc UfC70vWxESvhFZr9mMz4CgppolduuQFmYFgEw0lLaVPelaDkdFf/Mhmh3XaqQSrIyBJb eaEwTlJY5Ie1GInfZGZoPJvWWlMcMEtQkMw4WND2MNXh7UX1dscCQVbvngg/xiHBiWJi eti6DkRwiYPCoVY4LSC+VDhf0cAn4/pWqcI2OB0RzTdUhpy3y2ial+PYx11VzsqVJtbZ 5dwg== X-Forwarded-Encrypted: i=2; AFNElJ+8FhHuK6EYUCbYAFjQWIbr4qMFI7n5IVz6vCOQzcg3GE1MlvV6L+jOlfdjMtSqPUIGQZUrwSIrgJlU@gnusha.org X-Gm-Message-State: AOJu0YyeH3voQik9FKRvbnITz9r1f7XOxdt7EmdanrakNSQelh/k5VTn HqiYr5quC6Ubu6aBb1CBmWXiFHpCECXGHi1eyyMB6gdoLv2Zy/5x3fJI X-Received: by 2002:a05:6870:9c86:b0:42c:2421:5781 with SMTP id 586e51a60fabf-43ca42cb903mr8793780fac.28.1780340184314; Mon, 01 Jun 2026 11:56:24 -0700 (PDT) X-BeenThere: bitcoindev@googlegroups.com; h="AUV6zMMP9lgmZaQnIgnsg/SfATRDA2AlzlRm0CmvOjE0XUQWQw==" Received: by 2002:a05:6870:8131:b0:43d:8cd:b99f with SMTP id 586e51a60fabf-43d08cde26als814257fac.2.-pod-prod-03-us; Mon, 01 Jun 2026 11:56:19 -0700 (PDT) X-Received: by 2002:a05:6808:6ec3:b0:479:eb19:6e66 with SMTP id 5614622812f47-485fb4c3251mr7063302b6e.38.1780340179800; Mon, 01 Jun 2026 11:56:19 -0700 (PDT) Received: by 2002:ab3:750e:0:b0:302:7afe:cfcd with SMTP id a1c4a302cd1d6-3027afed342msc7a; Mon, 1 Jun 2026 11:49:53 -0700 (PDT) X-Received: by 2002:a05:6512:3182:b0:5aa:7572:a787 with SMTP id 2adb3069b0e04-5aa7572a7d4mr144626e87.22.1780339791698; Mon, 01 Jun 2026 11:49:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1780339791; cv=none; d=google.com; s=arc-20240605; b=lH2IQwUfIA6Zh8GXXN2iaYEjLVBgUOSret0vt1DMqB38sD3o5ZDMH6pHlA57+4rvUe c4dyELq7LnkDibykFVqTZoxaA+nDPn6RNvTWQI+Ap7/T7h+YpMGSs5d4wCzRiYhbFOwH UPcMyIfnNnG9boY6BiYN0bioQFmlfR1Hb8R3XxIX039TYgm2OnMXmUVWDrCkZ97Xl2lh k4EjJ9cdWhsvRT6oOnis1gyuD+B/lMQnYI/QwHgVWgpIIjOBlcqhHxdDpcEFP/vFAmMA 1Ke7o90QeyN0E56yhWuDjBMDF/McwaQhAPUfSp9BwFiZDOrZa2WXBH1Wc79Xq9/9Wd1n 3zbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=mime-version:feedback-id:references:in-reply-to:message-id:subject :cc:from:to:date:dkim-signature; bh=f9g9Tk6X3nQC4nUNxePTNewHgecFdKMOCNEcdjj1vUA=; fh=+Duu3Cp77aXfHDD1ma61XeBuViahPkcQ600hmLognUE=; b=NLGZpFAtbwu4aym7tQDF/uJITBl8pUMbzqjeZR7AqOEZPpQ2PYS5J9+TW3LTffYkQ3 FO3JwIbSez8s1g9fQLLQxA3Y1afvP7uKlr4wbWPgfXr2mfHeai7WCVAqS2fWTT4fwWFe UDbUd2+qJKwZ98GjTkv9BWaH50UCA2VZ39Xi1hiAEyjti3K5AvfKeBhzD6Bi3/+QC10t jqTBKvqOlwoUWsiBOHZHY0gDy2VnR9QplB56RutCnJ1J7RJl1Dc421aGg0LrCj6M3yDr 5oWzoD2m9oy5aEaGfgHAk/uDmOMvGKdp+xy6JrVLK3jRHU4XOq4gXa2tvFfPu88aI3wx ma+Q==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@protonmail.com header.s=protonmail3 header.b="g6kN1E//"; spf=pass (google.com: domain of darosior@protonmail.com designates 185.70.43.103 as permitted sender) smtp.mailfrom=darosior@protonmail.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com Received: from mail-43103.protonmail.ch (mail-43103.protonmail.ch. [185.70.43.103]) by gmr-mx.google.com with ESMTPS id 38308e7fff4ca-39659d69832si1886961fa.3.2026.06.01.11.49.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Jun 2026 11:49:51 -0700 (PDT) Received-SPF: pass (google.com: domain of darosior@protonmail.com designates 185.70.43.103 as permitted sender) client-ip=185.70.43.103; Date: Mon, 01 Jun 2026 18:49:42 +0000 To: jeremy From: "'Antoine Poinsot' via Bitcoin Development Mailing List" Cc: Bitcoin Development Mailing List Subject: Re: [bitcoindev] Prohibit Merkle Internal Node Preimages That Encode Minimal 64-Byte Transactions Message-ID: In-Reply-To: References: Feedback-ID: 7060259:user:proton X-Pm-Message-ID: 7a545d995012531c40e938f207143eaac069f759 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="b1=_XBL4TSruye3KvOySx8A0xnvNxjfqEpY9bLpWUSq6U" X-Original-Sender: darosior@protonmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@protonmail.com header.s=protonmail3 header.b="g6kN1E//"; spf=pass (google.com: domain of darosior@protonmail.com designates 185.70.43.103 as permitted sender) smtp.mailfrom=darosior@protonmail.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com X-Original-From: Antoine Poinsot Reply-To: Antoine Poinsot Precedence: list Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com List-ID: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Score: -1.0 (-) --b1=_XBL4TSruye3KvOySx8A0xnvNxjfqEpY9bLpWUSq6U Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Jeremy, Thanks for sharing the proposal you have been teasing. If requiring a change from SPV verifiers is acceptable, then there are alre= ady mitigations available today that don't need a consensus change. In fact= SPV verifiers could already reject Merkle proofs where any node deserializ= es to a Bitcoin transaction. Introducing a consensus rule to address this issue is interesting if it all= ows to patch the issue "from under" Merkle proofs users. Because despite mi= tigations being available today, we keep seeing new SPV verifiers deployed = without such mitigations in place by implementers who are not aware of this= vulnerability. I don't think we should blame implementers here: this is re= ally a quirk that we should fix at the consensus level if we have the oppor= tunity to. When comparing your proposal to simply invalidating 64-byte transactions, y= ou claim that the latter would also require SPV verifiers to patch their so= ftware: > More generally, a consensus rule invalidating 64-byte transactions does n= ot prevent arbitrary internal node preimages from existing. It only prevent= s those preimages from being valid Bitcoin transactions under upgraded cons= ensus rules. A bridge, wallet, or deposit system that accepts SPV-style pro= ofs but performs incomplete transaction parsing may still be induced to tre= at an internal node preimage as an application-level event. This is incorrect for any bridge, wallet, or deposit system that does not r= eceive funds to a script that either burns the funds or that anyone can spe= nd. Sure, an SPV verifier for a bridge or a wallet that wants to receive funds = into the void would have to be patched to make sure it rejects proofs for 6= 4-byte transactions.. But i don't think this is a meaningful distinction, a= s any system that actually matters and tries to secure value would not have= to be patched. This is why we chose this approach for BIP 54 (see the Rati= onale section). Antoine On Monday, June 1st, 2026 at 2:02 PM, jeremy wro= te: > Esteemed Colleagues, > > As a result of some of my research on 64-byte transactions, I'd like to d= iscuss an alternative soft fork proposal that preserves the ability to enco= de 64-byte transactions while offering protection to SPV users (who must ma= ke a small patch to validate the path property). > > The rule, stated simply, is: > > A block is invalid if any Merkle Tree 64-byte preimage has the exact byte= structure of a minimal one-input, one-output, witness stripped transaction= . > > [With the miracle of GPT,] I've drafted a relatively complete BIP for dis= cussion. > > Happy International Children's Day, > > Jeremy > > p.s. I will later propose potentially a couple other mitigations separate= ly, for discussion as well. > > --------------------------------------------------------------- > > BIP: TBD > Layer: Consensus (soft fork) > Title: Prohibit Merkle Internal Node Preimages That Encode Minimal 64-Byt= e Transactions > Author: TBD > Status: Draft > Type: Standards Track > Created: 2026-06-01 > License: BSD-2-Clause > > Abstract > > This document specifies a consensus rule that invalidates a block if any = transaction Merkle tree internal node preimage encodes a minimal 64-byte tr= ansaction. > > For each internal Merkle node, Bitcoin computes: > > parent =3D SHA256d(left || right) > > where left and right are 32-byte hashes. The 64-byte string left || right= is the internal node preimage. > > After activation, a block is invalid if any such 64-byte preimage has the= exact byte structure of a minimal one-input, one-output, non-witness trans= action. > > This prevents a 64-byte transaction serialization from being malleated in= to an internal Merkle node preimage in SPV transaction inclusion proofs. It= does not make 64-byte transactions invalid in general. > > Motivation > > Bitcoin transaction identifiers and transaction Merkle internal nodes are= both computed with double SHA256: > > txid =3D SHA256d(serialized_transaction) > > parent =3D SHA256d(left_child_hash || right_child_hash) > > If a valid transaction serialization is exactly 64 bytes, the same byte s= tring can also be interpreted as the concatenation of two 32-byte Merkle ch= ild hashes: > > serialized_transaction =3D left_child_hash || right_child_hash > > This creates an ambiguity between a transaction leaf preimage and an inte= rnal node preimage. > > An SPV verifier that accepts a Merkle proof without authenticating the fu= ll tree shape can be made to accept a proof terminating at an internal node= rather than at an actual transaction leaf. > > This proposal removes that ambiguity by forbidding Merkle internal node p= reimages that have the only practical 64-byte transaction encoding shape. > > SegWit and transaction identifiers > > Since SegWit activation, Bitcoin transactions have two related identifier= s: > > txid =3D SHA256d(legacy serialization) > > wtxid =3D SHA256d(witness serialization) > > The distinction is important for understanding this proposal. > > A SegWit transaction is serialized on the wire as: > > nVersion > > marker > > flag > > vin > > vout > > witness > > nLockTime > > where: > > marker =3D 0x00 > > flag =3D 0x01 > > The marker and flag bytes indicate that witness data is present. > > However, the transaction identifier (txid) is not computed from this witn= ess serialization. Instead, the txid is computed from the legacy serializat= ion: > > nVersion > > vin > > vout > > nLockTime > > with the marker, flag, and witness fields omitted. > > Therefore: > > txid =3D SHA256d(non-witness serialization) > > while: > > wtxid =3D SHA256d(full witness serialization) > > The transaction Merkle root committed in the block header is built from t= ransaction identifiers (txids), not witness transaction identifiers (wtxids= ). > > Consequently: > > Merkle root =3D Merkle(txid_0, txid_1, ..., txid_n) > > and not: > > Merkle(wtxid_0, wtxid_1, ..., wtxid_n) > > This means that the marker byte (0x00), flag byte (0x01), and witness dat= a never appear in the transaction Merkle tree committed by the block header= . > > SegWit does define a separate witness Merkle tree whose root is committed= through the coinbase witness commitment, but that witness Merkle tree is d= istinct from the transaction Merkle tree discussed in this proposal. > > As a result, the ambiguity addressed by this proposal concerns only trans= action identifiers (txids) and the transaction Merkle root. The SegWit mark= er and flag bytes are irrelevant to the transaction Merkle root because the= y are excluded from txid serialization. > > Minimal 64-byte transaction shape > > This proposal is concerned with the serialization used to compute a trans= action's txid. > > For legacy transactions, and for SegWit transactions when computing the t= xid, the serialization format is: > > 4 bytes nVersion > > 1 byte vin count =3D 0x01 > > 36 bytes prevout > > 1 byte scriptSig length =3D x > > x bytes scriptSig > > 4 bytes nSequence > > 1 byte vout count =3D 0x01 > > 8 bytes nValue > > 1 byte scriptPubKey length =3D y > > y bytes scriptPubKey > > 4 bytes nLockTime > > Notably, this serialization does not include: > > marker > > flag > > witness stack > > because those fields are excluded from txid computation. > > The fixed overhead is: > > 4 + 1 + 36 + 1 + 4 + 1 + 8 + 1 + 4 =3D 60 bytes > > Therefore, for total serialized size 64: > > x + y =3D 4 > > There are exactly five possible script-length splits: > > scriptSig length scriptPubKey length > > 0 4 > > 1 3 > > 2 2 > > 3 1 > > 4 0 > > This proposal defines a forbidden Merkle internal node preimage as a 64-b= yte byte string satisfying one of those five layouts and whose single outpu= t value is in the consensus money range. > > Specification > > After activation, a block is invalid if any transaction Merkle internal n= ode preimage encodes a minimal 64-byte transaction. > > For every internal Merkle parent computation in the transaction Merkle tr= ee: > > parent =3D SHA256d(left || right) > > where left and right are 32-byte child hashes, define: > > P =3D left || right > > The block is invalid if P satisfies all of the following: > > - > > P[4] =3D=3D 0x01. > > - > > P[41] is one of 0, 1, 2, 3, 4. > > - > > Let x =3D P[41]. > > - > > Let sequence_pos =3D 42 + x. > > - > > Let vout_count_pos =3D sequence_pos + 4. > > - > > Let value_pos =3D vout_count_pos + 1. > > - > > Let scriptpubkey_len_pos =3D value_pos + 8. > > - > > P[vout_count_pos] =3D=3D 0x01. > > - > > P[scriptpubkey_len_pos] =3D=3D 4 - x. > > - > > Let locktime_pos =3D scriptpubkey_len_pos + 1 + (4 - x). > > - > > locktime_pos + 4 =3D=3D 64. > > - > > The 8-byte little-endian integer at P[value_pos..value_pos+7] is in Money= Range. > > Equivalently, the forbidden preimage is a 64-byte serialization of a one-= input, one-output, non-witness transaction with single-byte CompactSize cou= nts and script lengths, where the two script lengths sum to 4 and the outpu= t value is in range. > > For clarity, "non-witness transaction" here refers to the serialization u= sed for txid computation. Even for SegWit transactions, the transaction Mer= kle tree uses txids, so the marker byte, flag byte, and witness data are ex= cluded. > > This rule applies to every transaction Merkle internal node used to compu= te the block header's transaction Merkle root. > > Odd-entry duplication > > If a Merkle level has an odd number of entries, Bitcoin duplicates the fi= nal hash: > > parent =3D SHA256d(last || last) > > The preimage: > > last || last > > MUST be checked by the same rule. > > SPV verification rule > > An SPV verifier relying on this soft fork MUST reject a Merkle proof if a= ny branch preimage in the proof encodes a minimal 64-byte transaction under= the predicate above. > > For each branch step, the verifier knows: > > - > > The current hash. > > - > > The sibling hash. > > - > > The branch direction. > > It reconstructs: > > P =3D left_child_hash || right_child_hash > > The verifier MUST check: > > IsForbiddenMerkleInternalNodePreimage(P) =3D=3D false > > for every branch preimage in the proof. > > If any branch preimage passes the forbidden-preimage predicate, the proof= MUST be rejected. > > The verifier still performs the ordinary Merkle path computation and bloc= k header proof-of-work validation. > > Rationale > > The known 64-byte transaction SPV malleability issue requires a byte stri= ng that is both: > > a valid 64-byte transaction serialization > > and: > > a transaction Merkle internal node preimage > > This proposal forbids that overlap at the Merkle internal node boundary. > > The rule is narrower than invalidating all 64-byte transactions. A 64-byt= e transaction remains valid unless its exact serialization appears as a tra= nsaction Merkle internal node preimage in the same block's transaction Merk= le tree. > > The rule also avoids adding a general transaction validity rule that exis= ts only to protect Merkle proof semantics. > > Why SegWit does not eliminate the ambiguity > > It is sometimes assumed that SegWit automatically removes this ambiguity = because SegWit transactions contain the marker and flag bytes: > > 00 01 > > However, the ambiguity exists at the txid layer, not at the witness-seria= lization layer. > > The transaction Merkle root in the block header is computed from txids, a= nd txids are computed from the serialization that excludes: > > marker > > flag > > witness > > Therefore the relevant byte string remains: > > nVersion > > vin > > vout > > nLockTime > > exactly as before SegWit. > > The witness serialization affects the wtxid, but the block header's trans= action Merkle root does not commit to wtxids. > > As a result, the existence of the SegWit marker and flag bytes does not p= revent a txid preimage from having the same byte structure as a Merkle inte= rnal node preimage. > > The ambiguity addressed by this proposal therefore remains relevant in th= e SegWit era. > > Contrast with a 64-byte transaction invalidity rule > > A direct alternative is: > > A transaction is invalid if its serialized size is exactly 64 bytes. > > That rule has several advantages: > > - > > It is simple to specify. > > - > > It is simple for SPV verifiers to implement. > > - > > It removes the original ambiguity by eliminating all valid 64-byte transa= ction leaves. > > However, it is not correct to describe that rule as automatically fixing = all light clients. > > A 64-byte transaction invalidity rule protects an SPV verifier only if th= e verifier enforces the new rule when interpreting the claimed transaction.= Existing or application-specific SPV verifiers that merely receive a byte = string and a Merkle branch may remain vulnerable if they do not parse the c= laimed transaction and reject exactly-64-byte transaction serializations. > > More generally, a consensus rule invalidating 64-byte transactions does n= ot prevent arbitrary internal node preimages from existing. It only prevent= s those preimages from being valid Bitcoin transactions under upgraded cons= ensus rules. A bridge, wallet, or deposit system that accepts SPV-style pro= ofs but performs incomplete transaction parsing may still be induced to tre= at an internal node preimage as an application-level event. > > For example, suppose an application-level SPV verifier treats a proved by= te string as a "deposit" if some field inside the alleged transaction match= es a registered deposit address, deposit script, or deposit commitment, but= does not fully enforce the upgraded transaction-validity rule. An attacker= may be able to grind child hashes so that: > > left_child_hash || right_child_hash > > has bytes that the application interprets as a deposit transaction or dep= osit commitment. In some systems, the attacker may also be able to choose o= r register deposit data that matches bytes already present in the left-hand= side of an internal node preimage. > > This is not a failure of upgraded full-node consensus. It is a failure of= the assumption that changing full-node transaction validity automatically = upgrades every SPV verifier and every bridge, wallet, or application that c= onsumes SPV-style proofs. > > Therefore, both approaches require light-client changes: > > 64-byte transaction invalidity: > > Light clients must reject claimed 64-byte transaction serializations. > > Merkle-internal-node preimage invalidity: > > Light clients must reject proofs containing forbidden internal branch pre= images. > > The 64-byte transaction invalidity rule is simpler for light clients that= correctly implement it, but it is broader at the transaction layer. This p= roposal places the rule at the Merkle ambiguity boundary and preserves 64-b= yte transactions generally. > > In summary: > > 64-byte transaction invalidity: > > - Simpler SPV rule when implemented correctly. > > - Broader transaction validity change. > > - Invalidates all 64-byte transactions. > > - Does not automatically fix SPV applications that fail to enforce the ne= w rule. > > Merkle-internal-node preimage invalidity: > > - Preserves 64-byte transactions generally. > > - Places the rule at the Merkle ambiguity boundary. > > - Requires SPV verifiers to parse all branch preimages. > > - Directly forbids the ambiguous internal-node preimage condition. > > Minimal C++ implementation sketch > > This implementation checks only the minimal forbidden 64-byte shape. It d= oes not invoke the full transaction deserializer. > > The function returns true if the 64-byte preimage is forbidden. > > static constexpr int64_t COIN =3D 100000000; > > static constexpr int64_t MAX_MONEY =3D 21000000 * COIN; > > static inline bool MoneyRange(int64_t nValue) > > { > > return nValue >=3D 0 && nValue <=3D MAX_MONEY; > > } > > static inline uint64_t ReadLE64(const unsigned char* p) > > { > > return uint64_t{p[0]} > > | (uint64_t{p[1]} << 8) > > | (uint64_t{p[2]} << 16) > > | (uint64_t{p[3]} << 24) > > | (uint64_t{p[4]} << 32) > > | (uint64_t{p[5]} << 40) > > | (uint64_t{p[6]} << 48) > > | (uint64_t{p[7]} << 56); > > } > > static bool IsForbiddenMerkleInternalNodePreimage64(const unsigned char p= [64]) > > { > > // Minimal 64-byte legacy transaction shape: > > // > > // 4 bytes nVersion > > // 1 byte vin count =3D 0x01 > > // 36 bytes prevout > > // 1 byte scriptSig length =3D x > > // x bytes scriptSig > > // 4 bytes nSequence > > // 1 byte vout count =3D 0x01 > > // 8 bytes nValue > > // 1 byte scriptPubKey length =3D y > > // y bytes scriptPubKey > > // 4 bytes nLockTime > > // > > // Since the fixed overhead is 60 bytes, x + y must equal 4. > > if (p[4] !=3D 0x01) { > > return false; > > } > > const unsigned int x =3D p[41]; > > switch (x) { > > case 0: > > if (p[46] !=3D 0x01) return false; > > if (p[55] !=3D 0x04) return false; > > break; > > case 1: > > if (p[47] !=3D 0x01) return false; > > if (p[56] !=3D 0x03) return false; > > break; > > case 2: > > if (p[48] !=3D 0x01) return false; > > if (p[57] !=3D 0x02) return false; > > break; > > case 3: > > if (p[49] !=3D 0x01) return false; > > if (p[58] !=3D 0x01) return false; > > break; > > case 4: > > if (p[50] !=3D 0x01) return false; > > if (p[59] !=3D 0x00) return false; > > break; > > default: > > return false; > > } > > const size_t value_pos =3D 47 + x; > > const uint64_t raw_value =3D ReadLE64(p + value_pos); > > if (raw_value > static_cast(std::numeric_limits::max()= )) { > > return false; > > } > > const int64_t nValue =3D static_cast(raw_value); > > if (!MoneyRange(nValue)) { > > return false; > > } > > return true; > > } > > static bool IsForbiddenMerkleInternalNode( > > const uint256& left, > > const uint256& right) > > { > > unsigned char p[64]; > > std::memcpy(p, left.begin(), 32); > > std::memcpy(p + 32, right.begin(), 32); > > return IsForbiddenMerkleInternalNodePreimage64(p); > > } > > A Merkle parent computation then checks the preimage before hashing: > > static uint256 ComputeMerkleParentChecked( > > const uint256& left, > > const uint256& right, > > bool& invalid) > > { > > if (IsForbiddenMerkleInternalNode(left, right)) { > > invalid =3D true; > > return uint256{}; > > } > > unsigned char p[64]; > > std::memcpy(p, left.begin(), 32); > > std::memcpy(p + 32, right.begin(), 32); > > return Hash(Span(p, 64)); > > } > > This is the intended minimal rule. It checks the five possible 64-byte on= e-input, one-output transaction layouts directly. > > Miner considerations > > Accidental violations by honest miners are expected to be rare. > > Adversarial violations are possible. An attacker may grind transaction id= entifiers so that two transactions, if placed as siblings in the transactio= n Merkle tree, form: > > txid_A || txid_B > > which encodes a forbidden minimal 64-byte transaction. > > An attacker may attempt to influence sibling placement by fee rate, packa= ge construction, direct miner submission, or transaction ordering effects. > > Therefore miners MUST check candidate block templates before mining. Mine= rs MUST NOT rely on accidental violation probability. > > Merkle construction failure recovery > > If a candidate block template violates this rule, the miner usually does = not need to discard the entire template. The violation is local to one or m= ore internal Merkle node preimages: > > left_child_hash || right_child_hash > > A miner can usually repair the candidate block by changing transaction or= der so that the offending pair of child hashes no longer appears as sibling= s at the violating Merkle tree level. > > Recommended recovery procedure > > When Merkle root construction fails because an internal node preimage is = forbidden, mining software SHOULD use the following procedure: > > - > > Record each offending internal node preimage. > > - > > Identify the transaction subtree contributing to each offending child has= h. > > - > > Attempt to repair the block by shuffling transaction order while preservi= ng consensus transaction-order constraints. > > - > > Recompute the Merkle root and re-run the internal-node preimage check. > > - > > If the shuffled template passes, mine the repaired template. > > - > > If shuffling fails repeatedly, remove one or more transactions contributi= ng to the offending subtree and rebuild the template. > > Preserving transaction-order constraints > > A shuffle MUST NOT violate transaction dependency ordering. > > If transaction B spends an output created by transaction A in the same bl= ock, then A MUST appear before B. > > The coinbase transaction MUST remain the first transaction in the block. > > Mining software SHOULD shuffle only transactions whose relative order is = not constrained by in-block dependencies, or use a randomized topological o= rdering of the block's transaction dependency graph. > > Simple shuffle algorithm > > A simple repair algorithm is: > > 1. Keep the coinbase fixed at index 0. > > 2. Build a dependency graph for all non-coinbase transactions. > > 3. Generate a randomized topological ordering of the graph. > > 4. Construct the Merkle tree using that ordering. > > 5. Reject the ordering if any internal node preimage is forbidden. > > 6. Retry with a new randomized topological ordering. > > This changes Merkle sibling relationships without violating in-block tran= saction dependencies. > > Repeated failure > > If randomized repair fails repeatedly, mining software SHOULD remove tran= sactions contributing to the repeated offending subtree. > > A reasonable policy is: > > If Merkle construction fails after 2 independent shuffle attempts, > > remove at least one transaction from each repeatedly offending pair or su= btree. > > For a bottom-level violation, the offending subtree usually corresponds t= o two sibling transaction identifiers: > > txid_A || txid_B > > In that case, the miner may remove either tx_A or tx_B. > > For a higher-level violation, each child hash commits to a subtree contai= ning multiple transactions. In that case, the miner may: > > 1. Try another dependency-preserving shuffle. > > 2. If the same higher-level violation recurs, remove one transaction from= one child subtree. > > 3. Prefer removing the lowest-feerate removable transaction that does not= force removal of higher-feerate descendants. > > This policy does not need to identify a malicious transaction. It only ne= eds to produce a valid block template with minimal fee loss. > > Fee impact > > The expected fee impact for honest block templates should be negligible b= ecause accidental violations are rare. > > If an adversary intentionally creates transactions that cause violations = when paired, shuffling will usually defeat the attempt without fee loss. If= shuffling does not repair the template, removing one or more offending tra= nsactions bounds the miner's exposure. > > The adversary's practical effect is limited to potentially causing some t= ransactions to be omitted from a candidate block template. The rule prevent= s upgraded miners from mining invalid blocks, provided miners check the Mer= kle construction before mining. > > Relation to unupgraded miners > > Because accidental violations are rare, unupgraded miners are unlikely to= encounter the rule during ordinary operation. > > However, an adversary can construct transaction pairs intended to trigger= the rule under specific sibling placement. > > Unupgraded miners that do not enforce this rule may mine a block that upg= raded nodes reject after activation. Low accidental probability improves de= ployment safety but is not a substitute for miner enforcement. > > Probability analysis > > This section estimates accidental violation probability under simplified = randomness assumptions. > > Random left || right > > Assume the 64-byte internal node preimage is uniformly random. > > For the preimage to encode a minimal one-input, one-output 64-byte transa= ction, it must satisfy: > > vin_count =3D 0x01 > > scriptSig_len =3D x, where x =E2=88=88 {0,1,2,3,4} > > vout_count =3D 0x01 at the position determined by x > > scriptPubKey_len =3D 4 - x > > nValue =E2=88=88 [0, MAX_MONEY] > > Ignoring nValue, the structural probability is approximately: > > 5 / 256^3 > > because there are five valid (scriptSig_len, scriptPubKey_len) splits, an= d three one-byte constraints: > > vin_count > > vout_count > > scriptPubKey_len > > Numerically: > > 5 / 256^3 =E2=89=88 2.980232238769531e-7 > > or approximately: > > 1 in 3,355,443 > > Including the output value money range: > > MAX_MONEY =3D 21,000,000 * 100,000,000 > > =3D 2,100,000,000,000,000 > > For a uniformly random unsigned 64-bit output value, the probability of b= eing in range is approximately: > > (MAX_MONEY + 1) / 2^64 > > =E2=89=88 1.1384122811097797e-4 > > Therefore the approximate probability that a random 64-byte preimage is s= tructurally valid and has an in-range output value is: > > (5 / 256^3) * ((MAX_MONEY + 1) / 2^64) > > =E2=89=88 3.392733219831406e-11 > > or approximately: > > 1 in 29,475,000,000 > > Random left || left > > For an odd-entry duplicated Merkle node, the preimage has the form: > > left || left > > where the first 32 bytes equal the last 32 bytes. > > Let the 32-byte half be: > > A[0..31] > > Then: > > P[0..31] =3D A[0..31] > > P[32..63] =3D A[0..31] > > For the same one-input, one-output 64-byte transaction shape: > > P[4] =3D 0x01 > > P[41] =3D scriptSig_len =3D x > > P[vout_count_pos] =3D 0x01 > > P[scriptpubkey_len_pos] =3D 4 - x > > Because positions after byte 31 alias positions in the first half: > > P[i] =3D A[i mod 32] > > The relevant positions are: > > vin_count_pos =3D 4 > > script_len_pos =3D 41 =E2=89=A1 9 mod 32 > > vout_count_pos =3D 46 + x =E2=89=A1 14 + x mod 32 > > scriptpubkey_len_pos =3D 55 + x =E2=89=A1 23 + x mod 32 > > The constraints are: > > A[4] =3D 0x01 > > A[9] =3D x > > A[14 + x] =3D 0x01 > > A[23 + x] =3D 4 - x > > For each fixed x, these are four independent one-byte constraints under t= he random-half model. > > Thus the structural probability is approximately: > > 5 / 256^4 > > =E2=89=88 1.1641532182693481e-9 > > or approximately: > > 1 in 858,993,459 > > The output value begins at: > > value_pos =3D 47 + x > > which aliases to an 8-byte window in the random 32-byte half: > > A[15 + x .. 22 + x] > > Using the same simplified independence approximation, the probability of = being in MoneyRange is approximately: > > (MAX_MONEY + 1) / 2^64 > > =E2=89=88 1.1384122811097797e-4 > > So the approximate probability that a random left || left preimage is str= ucturally valid and has an in-range output value is: > > (5 / 256^4) * ((MAX_MONEY + 1) / 2^64) > > =E2=89=88 1.3252864140005492e-13 > > or approximately: > > 1 in 7,545,600,000,000 > > Block-level accidental probability > > A block with n transactions has approximately n - 1 internal Merkle nodes= , plus duplicated-node cases depending on tree shape. > > Using the rough random left || right estimate: > > p =E2=89=88 3.39e-11 > > A block with 10,000 transactions has approximate accidental violation pro= bability: > > 1 - (1 - p)^9999 =E2=89=88 3.39e-7 > > or roughly: > > 1 in 2,950,000 blocks > > This is a simplified estimate. Actual txids are not perfect independent r= andom samples in all cases, duplicated nodes have lower estimated probabili= ty, and additional implementation details may reduce or alter the rate. > > The deployment-relevant conclusion is: > > Honest accidental violations should be rare. > > Adversarial violations are possible. > > Miners must enforce the rule. > > Backward compatibility > > This is a soft fork. Blocks violating the new rule were previously valid = and become invalid after activation. > > Unupgraded full nodes may accept violating blocks after activation. Activ= ation therefore requires ordinary soft-fork deployment procedures. > > Unupgraded SPV clients remain vulnerable to the legacy proof ambiguity. S= PV clients must update their Merkle proof validation logic to obtain the be= nefit of this rule. > > Test vectors > > Test vectors should include: > > - > > A block whose transaction Merkle internal node preimages do not encode mi= nimal 64-byte transactions. The block is valid. > > - > > A block containing a 64-byte transaction whose serialization does not app= ear as an internal node preimage. The block is valid. > > - > > A block where an internal node preimage encodes a minimal 64-byte transac= tion. The block is invalid. > > - > > A block where an odd-entry duplicated preimage h || h encodes a minimal 6= 4-byte transaction. The block is invalid. > > - > > An SPV proof where one branch preimage encodes a minimal 64-byte transact= ion. The proof is rejected. > > - > > An SPV proof for a 64-byte transaction where no branch preimage encodes a= minimal 64-byte transaction. The proof is accepted if otherwise valid. > > Open questions > > - > > Should the rule include only the explicit minimal 64-byte legacy transact= ion shape above, or should it call the full consensus transaction deseriali= zer? > > - > > Should future transaction serialization changes be required to preserve t= his exact forbidden-preimage invariant? > > - > > Should pre-activation relay policy discourage transaction pairs that can = form forbidden sibling preimages? > > - > > Should mining software standardize a recovery procedure for failed Merkle= construction, or should this remain implementation-specific? > > - > > Should SPV proof formats include an explicit version bit indicating branc= h-preimage checking support? > > -- > You received this message because you are subscribed to the Google Groups= "Bitcoin Development Mailing List" group. > To unsubscribe from this group and stop receiving emails from it, send an= email to bitcoindev+unsubscribe@googlegroups.com. > To view this discussion visit https://groups.google.com/d/msgid/bitcoinde= v/f97afcc5-54ba-4284-8e9b-e8c35c7101f6n%40googlegroups.com. --=20 You received this message because you are subscribed to the Google Groups "= Bitcoin Development Mailing List" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoindev+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/= MuaBBWyHNVBd2i0ppWeXGlhAx8C_UqdUZctkuQ7stQeo8CudqJSWfeJHsmJLYLgXz_XZgRw5i1n= TJ4wAZCsdCyQccR1Xh4IzA4QjBMVUJpU%3D%40protonmail.com. --b1=_XBL4TSruye3KvOySx8A0xnvNxjfqEpY9bLpWUSq6U Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable

Thanks for sharing the proposal you have been teasin= g.

If requiring a change from SPV verifiers is acceptable, the= n there are already mitigations available today that don't need a consensus= change. In fact SPV verifiers could already reject Merkle proofs where any= node deserializes to a Bitcoin transaction.

Introducing a con= sensus rule to address this issue is interesting if it allows to patch the = issue "from under" Merkle proofs users. Because despite mitigations being a= vailable today, we keep seeing new SPV verifiers deployed without such miti= gations in place by implementers who are not aware of this vulnerability. I= don't think we should blame implementers here: this is really a quirk that= we should fix at the consensus level if we have the opportunity to.=

<= /div>
When comparing your proposal to simply invalidating 64-byte transact= ions, you claim that the latter would also require SPV verifiers to patch t= heir software:
More generally, a consensus rule invalidatin= g 64-byte transactions does not prevent arbitrary internal node preimages f= rom existing. It only prevents those preimages from being valid Bitcoin tra= nsactions under upgraded consensus rules. A bridge, wallet, or deposit syst= em that accepts SPV-style proofs but performs incomplete transaction parsin= g may still be induced to treat an internal node preimage as an application= -level event.

This is incorrect for any bridge, wallet, or deposit system that do= es not receive funds to a script that either burns the funds or that anyone= can spend.

Sure, an SPV verifier for a bridge or a wallet that wants to receive fu= nds into the void would have to be patched to make sure it rejects proofs f= or 64-byte transactions.. But i don't think this is a meaningful distinctio= n, as any system that actually matters and tries to secure value would not = have to be patched. This is why we chose this approach for BIP 54 (see the = Rationale section).

<= span style=3D"font-family: Arial, sans-serif; font-size: 10.5pt; line-heigh= t: normal;">Antoine
On Monday, June 1st, 2026 at 2:02 PM, jeremy <jeremy.l.rubin@gma= il.com> wrote:

Esteemed Colleagues,

=

As a result of some of my research on 64-by= te transactions, I'd like to discuss an alternative soft fork proposal that= preserves the ability to encode 64-byte transactions while offering protec= tion to SPV users (who must make a small patch to validate the path propert= y).

The rule, stated simply, is:<= /span>

A block is invalid if any Merkle Tree 64-byte preimag= e has the exact byte structure of a minimal one-input, one-output, witness = stripped transaction.

[With the m= iracle of GPT,] I've drafted a relatively complete BIP for discussion.

Happy International Children's Day,

Jeremy

p.s. I wi= ll later propose potentially a couple other mitigations separately, for dis= cussion as well.


BI= P: TBD
Lay= er: Consensus (soft fork)
Title: Prohibit Merkle Internal Node Preimages That Encode = Minimal 64-Byte Transactions
Author: TBD
Status: Draft
Type: Standards TrackCreated: 2026-06-01
License: BSD-2-Clause

Abstract

This documen= t specifies a consensus rule that invalidates a block if any transaction Me= rkle tree internal node preimage encodes a minimal 64-byte transaction.

For each internal Merkle node, Bitco= in computes:

parent =3D SHA256d(lef= t || right)


where left and right are 32-byt= e hashes. The 64-byte string left || right is the internal node pre= image.

After activation, a block = is invalid if any such 64-byte preimage has the exact byte structure of a m= inimal one-input, one-output, non-witness transaction.

This prevents a 64-byte transaction serialization fro= m being malleated into an internal Merkle node preimage in SPV transaction = inclusion proofs. It does not make 64-byte transactions invalid in general.=

Motivation

Bitc= oin transaction identifiers and transaction Merkle internal nodes are both = computed with double SHA256:

txid = =3D SHA256d(serialized_transaction)


I= f a valid transaction serialization is exactly 64 bytes, the same byte stri= ng can also be interpreted as the concatenation of two 32-byte Merkle child= hashes:

serialized_transaction =3D= left_child_hash || right_child_hash


This creates an ambigu= ity between a transaction leaf preimage and an internal node preimage.

An SPV verifier that accepts a Merkle= proof without authenticating the full tree shape can be made to accept a p= roof terminating at an internal node rather than at an actual transaction l= eaf.

This proposal removes that a= mbiguity by forbidding Merkle internal node preimages that have the only pr= actical 64-byte transaction encoding shape.

SegWit and transaction id= entifiers

Since SegWit= activation, Bitcoin transactions have two related identifiers:

<= p dir=3D"ltr" style=3D"line-height: 1.38; margin-top: 0pt; margin-bottom: 0= pt;">txid =3D SHA256d(legacy serialization)=

wtxid =3D SHA256d(witness serialization)<= /span>


The distinction is important for understanding this proposa= l.

A SegWit transaction is serial= ized on the wire as:

nVersion

marker

flag

vin

vout

witness

nLockTime


where:

marker =3D 0x00

flag =3D 0x01


The marker and flag bytes= indicate that witness data is present.

However, the transaction identifier (txid) is not computed f= rom this witness serialization. Instead, the txid is computed from = the legacy serialization:

nVersion<= /span>

vin

vout

nLockTime

=


with the marker, flag, and witness fields omitted.

Therefore:


while:=

wtxid =3D SHA256d(full witness serializat= ion)


The transaction Merkle root committed in the block hea= der is built from transaction identifiers (txids), not witness tran= saction identifiers (wt= xids).

Consequently:

Merkle root =3D = Merkle(txid_0, txid_1, ..., txid_n)


and not:

Merkle(wtxid_0, wtxid_1, ..., wtxid_n)

=


This means that the marker byte (0x00), flag byte (0x01SegWit does= define a separate witness Merkle tree whose root is committed through the = coinbase witness commitment, but that witness Merkle tree is distinct from = the transaction Merkle tree discussed in this proposal.

<= span style=3D"font-size: 11pt; font-family: Arial, sans-serif; color: rgb(0= , 0, 0); background-color: transparent; font-weight: 400; font-style: norma= l; font-variant: normal; text-decoration: none; vertical-align: baseline; w= hite-space: pre-wrap;">As a result, the ambiguity addressed by this proposa= l concerns only transaction identifiers (txids) and the transaction= Merkle root. The SegWit marker and flag bytes are irrelevant to the transa= ction Merkle root because they are excluded from txid serialization= .

Minimal 64-byte transaction shape

This proposal is concerned with the serialization used = to compute a transaction's txid.

For legacy transactions, and for SegWit transactions when computing= the txid, the serialization format is:

4 bytes nVersion

1 b= yte vin count =3D 0x01

36 bytes = prevout

1 byte scriptSig length= =3D x

x bytes scriptSig

4 bytes nSequence

1 byte vout count =3D 0x01

8 bytes nValue

1 byt= e scriptPubKey length =3D y

y by= tes scriptPubKey

4 bytes nLockT= ime


Notably, this serialization does not include:

marker

flag

witness stack

=

because those fields are excluded from txid computation.<= /p>

The fixed overhead is:

= 4 + 1 + 36 + 1 + 4 + 1 + 8 + 1 + 4 =3D 60 bytes


Therefore, for total serialized size 64:

x + y =3D 4


There are exactly five possi= ble script-length splits:

scriptSig= length scriptPubKey length

0 = 4

1 = 3

2 2

3 1

4 0


This proposal defi= nes a forbidden Merkle internal node preimage as a 64-byte byte string sati= sfying one of those five layouts and whose single output value is in the co= nsensus money range.

Specification

After activation, a block is invalid if any transaction = Merkle internal node preimage encodes a minimal 64-byte transaction.=

For every internal Merkle parent comput= ation in the transaction Merkle tree:

parent =3D SHA256d(left || right)


where left and= right are 32-byte child hashes, define:

P =3D left || right


The block is invalid if <= /span>P satisfies all of the following:

  1. P[4] =3D=3D 0x01.

  2. P[41] is one of 0, 1, 2, 3, 4.

  3. Let x =3D P[41].

  4. Let sequence_pos =3D 42 + x.

  5. Let vout_count_pos =3D= sequence_pos + 4.

  6. Let value_pos =3D vout_count_pos + 1.

  7. Let scriptpubkey_len_pos =3D value_pos + 8.

  8. P[vout_count_pos] =3D=3D 0x01.

  9. P[scriptpubkey_len_pos] =3D=3D 4 - x

    Let locktime_pos =3D scriptpubkey_len_pos = + 1 + (4 - x).

  10. <= span style=3D"font-size: 11pt; font-family: "Roboto Mono", monosp= ace; color: rgb(24, 128, 56); background-color: transparent; font-weight: 4= 00; font-style: normal; font-variant: normal; text-decoration: none; vertic= al-align: baseline; white-space: pre-wrap;">locktime_pos + 4 =3D=3D 64.

  11. The 8-byte little-endian integer at P[value_pos..value_pos+7]= is in MoneyRange.

Equivalently, the forbidden preimage is a 64-byte serialization of a on= e-input, one-output, non-witness transaction with single-byte CompactSize c= ounts and script lengths, where the two script lengths sum to 4 and the out= put value is in range.

For clarit= y, "non-witness transaction" here refers to the serialization used for txid computation. Even for SegWit transactions, the transaction Merkle = tree uses txids<= span style=3D"font-size: 11pt; font-family: Arial, sans-serif; color: rgb(0= , 0, 0); background-color: transparent; font-weight: 400; font-style: norma= l; font-variant: normal; text-decoration: none; vertical-align: baseline; w= hite-space: pre-wrap;">, so the marker byte, flag byte, and witness data ar= e excluded.

This rule applies to = every transaction Merkle internal node used to compute the block header's t= ransaction Merkle root.

Odd-entry duplication

If a Merkle level has an odd number of entrie= s, Bitcoin duplicates the final hash:

parent =3D SHA256d(last || last)


The preimage:

last || last


MUST be checked= by the same rule.

SPV verification rule

An SPV verifier relying on this soft fork MUST re= ject a Merkle proof if any branch preimage in the proof encodes a minimal 6= 4-byte transaction under the predicate above.

For each branch step, the verifier knows:

  1. The current hash.

  2. The sibling hash.

  3. The branch direction.

It reconstructs:

P =3D left_child_hash || right_child_hash


The v= erifier MUST check:

IsForbiddenMerk= leInternalNodePreimage(P) =3D=3D false


for every branch pre= image in the proof.

If any branch= preimage passes the forbidden-preimage predicate, the proof MUST be reject= ed.

The verifier still performs t= he ordinary Merkle path computation and block header proof-of-work validati= on.

Rationale

The known 64-byte transaction SPV malleability issue requires a byte strin= g that is both:

a valid 64-byte tra= nsaction serialization


<= /b>

and:

a transaction Merkle internal node preimage


This = proposal forbids that overlap at the Merkle internal node boundary.<= /p>

The rule is narrower than invalidating a= ll 64-byte transactions. A 64-byte transaction remains valid unless its exa= ct serialization appears as a transaction Merkle internal node preimage in = the same block's transaction Merkle tree.

The rule also avoids adding a general transaction validity rule th= at exists only to protect Merkle proof semantics.

Why SegWit does not= eliminate the ambiguity

It is sometimes assumed that SegWit automatically removes this ambiguity= because SegWit transactions contain the marker and flag bytes:

<= p dir=3D"ltr" style=3D"line-height: 1.38; margin-top: 0pt; margin-bottom: 0= pt;">00 01


However, the ambiguity e= xists at the txid layer, not at the witness-serialization layer.

The transaction Merkle root in the = block header is computed from txids, and txids are computed= from the serialization that excludes:

marker

flag

witness


Therefore the relevant byte st= ring remains:

nVersion

vin

vou= t

nLockTime


exact= ly as before SegWit.

The witness = serialization affects the wtxid, but the block header's transaction= Merkle root does not commit to wtxids.

As a result, the existence of the SegWit marker and flag byt= es does not prevent a t= xid preimage from having the same byte struc= ture as a Merkle internal node preimage.

The ambiguity addressed by this proposal therefore remains relevant= in the SegWit era.

Contrast with a 64-byte transaction invalidity ru= le

A direct alternativ= e is:

A transaction is invalid if i= ts serialized size is exactly 64 bytes.


That rule has sever= al advantages:

  1. It is si= mple to specify.

  2. It is = simple for SPV verifiers to implement.

  3. It removes the original ambiguity by eliminating all valid= 64-byte transaction leaves.

However, it is not correct to describe that rule as automatically fix= ing all light clients.

A 64-byte = transaction invalidity rule protects an SPV verifier only if the verifier e= nforces the new rule when interpreting the claimed transaction. Existing or= application-specific SPV verifiers that merely receive a byte string and a= Merkle branch may remain vulnerable if they do not parse the claimed trans= action and reject exactly-64-byte transaction serializations.

More generally, a consensus rule invalidating = 64-byte transactions does not prevent arbitrary internal node preimages fro= m existing. It only prevents those preimages from being valid Bitcoin trans= actions under upgraded consensus rules. A bridge, wallet, or deposit system= that accepts SPV-style proofs but performs incomplete transaction parsing = may still be induced to treat an internal node preimage as an application-l= evel event.

For example, suppose = an application-level SPV verifier treats a proved byte string as a "deposit= " if some field inside the alleged transaction matches a registered deposit= address, deposit script, or deposit commitment, but does not fully enforce= the upgraded transaction-validity rule. An attacker may be able to grind c= hild hashes so that:

left_child_has= h || right_child_hash


has bytes that the application interp= rets as a deposit transaction or deposit commitment. In some systems, the a= ttacker may also be able to choose or register deposit data that matches by= tes already present in the left-hand side of an internal node preimage.

This is not a failure of upgraded fu= ll-node consensus. It is a failure of the assumption that changing full-nod= e transaction validity automatically upgrades every SPV verifier and every = bridge, wallet, or application that consumes SPV-style proofs.

Therefore, both approaches require light-clie= nt changes:

64-byte transaction inv= alidity:

Light clients must rejec= t claimed 64-byte transaction serializations.


Merkle-internal= -node preimage invalidity:

Light = clients must reject proofs containing forbidden internal branch preimages.<= /span>


The 64-byte transaction invalidity rule is simpler for ligh= t clients that correctly implement it, but it is broader at the transaction= layer. This proposal places the rule at the Merkle ambiguity boundary and = preserves 64-byte transactions generally.

In summary:

64-byte transa= ction invalidity:

- Simpler SPV r= ule when implemented correctly.

-= Broader transaction validity change.

- Invalidates all 64-byte transactions.

- Does not automatically fix SPV applications that fail to enfo= rce the new rule.


Merkle-internal-node preimage invalidity:

- Preserves 64-byte transactions g= enerally.

- Places the rule at th= e Merkle ambiguity boundary.

- Re= quires SPV verifiers to parse all branch preimages.

- Directly forbids the ambiguous internal-node preimage = condition.


Minimal C++ implementation sketch

This implementation checks only the minima= l forbidden 64-byte shape. It does not invoke the full transaction deserial= izer.

The function returns true if the 64-byte preimage is forbidden.

static constexpr int64_t COIN =3D 100000000;

static constexpr int64_t MAX_MONEY =3D 21000000 * COIN;=


static inline bool MoneyRange(int64_t nValue)

{

ret= urn nValue >=3D 0 && nValue <=3D MAX_MONEY;

= }

static inline uint64_t ReadLE64(con= st unsigned char* p)

{

return uint64_t{p[0]}

| (uint64_t{p[1]} << 8)

= | (uint64_t{p[2]} << 16)

| (uint64_t{p[3]} << 24)

| (uint64_t{p[4]} << 32)

| (uint64_t{p[5]} << 40)<= /span>

| (uint64_t{p[6]} << = 48)

| (uint64_t{p[7]} <&= lt; 56);

}


static boo= l IsForbiddenMerkleInternalNodePreimage64(const unsigned char p[64])=

{

// Minimal 64-byte legacy transaction shape:

//

// 4 by= tes nVersion

// 1 byte v= in count =3D 0x01

// 36 bytes= prevout

// 1 byte script= Sig length =3D x

// x bytes = scriptSig

// 4 bytes nSequ= ence

// 1 byte vout count = =3D 0x01

// 8 bytes nValue<= /span>

// 1 byte scriptPubKey len= gth =3D y

// y bytes script= PubKey

// 4 bytes nLockTime=

//

// Since the fixed overhead is 60 bytes, x + y must equal = 4.


if (p[4] !=3D 0x01) {

return false;

= }


const unsigned int x =3D p[41];


swi= tch (x) {

case 0:

if (p[46] !=3D 0x01) return false;

if (p[55] !=3D 0x04) return fals= e;

break;


= case 1:

if (p[47] !=3D 0x0= 1) return false;

if (p[56] = !=3D 0x03) return false;

br= eak;


case 2:

= if (p[48] !=3D 0x01) return false;

if (p[57] !=3D 0x02) return false;

break;

=

case 3:

if (p[49] !=3D 0x01) return false;

if (p[58] !=3D 0x01) return false;

break;


case 4:=

if (p[50] !=3D 0x01) retur= n false;

if (p[59] !=3D 0x0= 0) return false;

break;


default:

r= eturn false;

}


= const size_t value_pos =3D 47 + x;


= if (raw_value > static_cast<uint64_t>(std::numeric_limits<in= t64_t>::max())) {

return= false;

}


con= st int64_t nValue =3D static_cast<int64_t>(raw_value);

<= b style=3D"font-weight: normal;">

= if (!MoneyRange(nValue)) {

= return false;

}

<= p>

return true;

}

=

static bool IsForbiddenMerkleInternalNode(

const uint256& left,

const uint256& right)

{=

unsigned char p[64];


std::memcpy(p, left.begin(), 32);

std::memcpy(p + 32, right.begin(), 32);


ret= urn IsForbiddenMerkleInternalNodePreimage64(p);

}


<= p dir=3D"ltr" style=3D"line-height: 1.38; margin-top: 12pt; margin-bottom: = 12pt;">A Merkle parent computation then checks the = preimage before hashing:

static uin= t256 ComputeMerkleParentChecked(

= const uint256& left,

cons= t uint256& right,

bool&= invalid)

{

if (IsForbiddenMerkleInternalNode(left, right)) {

invalid =3D true;

return uint256{};

}


=

unsigned char p[64];

std::memcpy(p, left.begin(), 32);

std::memcpy(p + 32, right.begin(), 32);<= /span>


return Hash(Span<const unsigned char>(p, 64));

}


This is the intended = minimal rule. It checks the five possible 64-byte one-input, one-output tra= nsaction layouts directly.

<= span dir=3D"ltr" style=3D"line-height: 1.38; margin-top: 24pt; margin-botto= m: 6pt;">Miner considerations

=

Accidental violations by honest miners are = expected to be rare.

Adversarial = violations are possible. An attacker may grind transaction identifiers so t= hat two transactions, if placed as siblings in the transaction Merkle tree,= form:

txid_A || txid_B

<= p>

which encodes a forbidden minimal 64-byte transaction.

An attacker may attempt to influence sibling pla= cement by fee rate, package construction, direct miner submission, or trans= action ordering effects.

Therefor= e miners MUST check candidate block templates before mining. Miners MUST NO= T rely on accidental violation probability.

Merkle construction failu= re recovery

If a candi= date block template violates this rule, the miner usually does not need to = discard the entire template. The violation is local to one or more internal= Merkle node preimages:

left_child_= hash || right_child_hash

A miner can usually repair the can= didate block by changing transaction order so that the offending pair of ch= ild hashes no longer appears as siblings at the violating Merkle tree level= .

Recommended recovery procedure

When Merkle root construction fails because an internal no= de preimage is forbidden, mining software SHOULD use the following procedur= e:

  1. Record each offendin= g internal node preimage.

  2. Identify the transaction subtree contributing to each offending child ha= sh.

  3. Attempt to repair t= he block by shuffling transaction order while preserving consensus transact= ion-order constraints.

  4. = Recompute the Merkle root and re-run the internal-node preimage check.

  5. If the shuffled template pa= sses, mine the repaired template.

  6. If shuffling fails repeatedly, remove one or more transactions= contributing to the offending subtree and rebuild the template.

    =

Preserving transaction-order constraints

A shuffle MUST NOT violate transaction dependency= ordering.

If transaction = BA in the same block, the= n A MUST appear before B.

The coinbase transaction MUST remain the first transaction in = the block.

Mining software SHOULD= shuffle only transactions whose relative order is not constrained by in-bl= ock dependencies, or use a randomized topological ordering of the block's t= ransaction dependency graph.

Simple shuffle algorithm

A simple repair algorithm is:<= /p>

1. Keep the coinbase fixed at index 0.

2. Build a dependency graph for all no= n-coinbase transactions.

3. Generat= e a randomized topological ordering of the graph.

4. Construct the Merkle tree using that ordering.

=

5. Reject the ordering if any internal node p= reimage is forbidden.

6. Retry with= a new randomized topological ordering.


This changes Merkle= sibling relationships without violating in-block transaction dependencies.=

Repeated failure

A reasonable policy is:

If Merkle construction fails after 2 independent shuffle att= empts,

remove at least one transact= ion from each repeatedly offending pair or subtree.


For a= bottom-level violation, the offending subtree usually corresponds to two s= ibling transaction identifiers:

txi= d_A || txid_B


In that case, the miner may remove either tx_A or tx_B.

For a = higher-level violation, each child hash commits to a subtree containing mul= tiple transactions. In that case, the miner may:

1. Try another dependency-preserving shuffle.

2. If the same higher-level violation recurs, remo= ve one transaction from one child subtree.

3. Prefer removing the lowest-feerate removable transaction that = does not force removal of higher-feerate descendants.


This = policy does not need to identify a malicious transaction. It only needs to = produce a valid block template with minimal fee loss.

Fee impact

The expected fee impact fo= r honest block templates should be negligible because accidental violations= are rare.

If an adversary intent= ionally creates transactions that cause violations when paired, shuffling w= ill usually defeat the attempt without fee loss. If shuffling does not repa= ir the template, removing one or more offending transactions bounds the min= er's exposure.

The adversary's pr= actical effect is limited to potentially causing some transactions to be om= itted from a candidate block template. The rule prevents upgraded miners fr= om mining invalid blocks, provided miners check the Merkle construction bef= ore mining.

Relation to unupgraded miners

Because accidental violations are rare, unupgrade= d miners are unlikely to encounter the rule during ordinary operation.

However, an adversary can construct t= ransaction pairs intended to trigger the rule under specific sibling placem= ent.

Unupgraded miners that do no= t enforce this rule may mine a block that upgraded nodes reject after activ= ation. Low accidental probability improves deployment safety but is not a s= ubstitute for miner enforcement.

Probability analysis

This section estimates accidental vio= lation probability under simplified randomness assumptions.

Random left || right

Assume the 64-byte internal node = preimage is uniformly random.

For= the preimage to encode a minimal one-input, one-output 64-byte transaction= , it must satisfy:

vin_count =3D 0x= 01

scriptSig_len =3D x, where x =E2= =88=88 {0,1,2,3,4}

vout_count =3D 0= x01 at the position determined by x

scriptPubKey_len =3D 4 - x

nValue = =E2=88=88 [0, MAX_MONEY]

Ignoring nValue, the struc= tural probability is approximately:

5 / 256^3


because there are five valid (scriptSig_len, scriptPubKey_len)<= span style=3D"font-size: 11pt; font-family: Arial, sans-serif; color: rgb(0= , 0, 0); background-color: transparent; font-weight: 400; font-style: norma= l; font-variant: normal; text-decoration: none; vertical-align: baseline; w= hite-space: pre-wrap;"> splits, and three one-byte constraints:

<= p dir=3D"ltr" style=3D"line-height: 1.38; margin-top: 0pt; margin-bottom: 0= pt;">vin_count

vout_count

scriptPubKey_len


Numerically:

5 / 256^3= =E2=89=88 2.980232238769531e-7


or approximately:

1 in 3,355,443


Including the= output value money range:

MAX_MONE= Y =3D 21,000,000 * 100,000,000

= =3D 2,100,000,000,000,000


For a uniformly random unsi= gned 64-bit output value, the probability of being in range is approximatel= y:

(MAX_MONEY + 1) / 2^64

=E2=89=88 1.1384122811097797e-4


Therefore the approximate probability that a random 64-byte preimage is= structurally valid and has an in-range output value is:

= (5 / 256^3) * ((MAX_MONEY + 1) / 2^64)

=E2=89=88 3.392733219831406e-11


or approximately:

1 in 29,475,000,= 000


Random le= ft || left

For an odd-= entry duplicated Merkle node, the preimage has the form:

= left || left


where the first 32 byt= es equal the last 32 bytes.

Let t= he 32-byte half be:

A[0..31]=


Then:

P[0..31] =3D A[= 0..31]

P[32..63] =3D A[0..31]


For the same one-input, one-output 64-byte transaction shape:<= /span>

P[4] =3D 0x01

P[41] =3D scriptSig_len =3D x

P[vout_count_pos] =3D 0x01

P[scriptpubkey_len_pos] =3D 4 - x


Because positions = after byte 31 alias positions in the first half:

P[i] =3D A[i mod 32]


The relevant positions a= re:

vin_count_pos =3D 4

script_len_pos =3D 41 =E2=89= =A1 9 mod 32

vout_count_pos = =3D 46 + x =E2=89=A1 14 + x mod 32

scriptpubkey_len_pos =3D 55 + x =E2=89=A1 23 + x mod 32


T= he constraints are:

A[4] =3D 0= x01

A[9] =3D x

A[14 + x] =3D 0x01

A[23 + x] =3D 4 - x

For each fixed x, the= se are four independent one-byte constraints under the random-half model.

Thus the structural probability is= approximately:

5 / 256^4

=E2=89=88 1.1641532182693481e-9


or approximately:

1 in 858,993,= 459


The output value begins at:

value_pos =3D 47 + x


which aliases to an 8-byt= e window in the random 32-byte half:


Using the same simplified independenc= e approximation, the probability of being in MoneyRange is approxim= ately:

(MAX_MONEY + 1) / 2^64

=E2=89=88 1.1384122811097797e-4


So the approximate probability that a random left || left p= reimage is structurally valid and has an in-range output value is:

(5 / 256^4) * ((MAX_MONEY + 1) / 2^64)

=E2=89=88 1.3252864140005492e-13=


or approximately:

1 in= 7,545,600,000,000


Block-level accidental probability

A block with n transact= ions has approximately = n - 1 internal Merkle nodes, plus duplicated= -node cases depending on tree shape.

Using the rough random left || right estimate:

= p =E2=89=88 3.39e-11


A block with 1= 0,000 transactions has approximate accidental violation probability:=

1 - (1 - p)^9999 =E2=89=88 3.39e-7=


or roughly:

1 in 2,950= ,000 blocks


This is a simplified estimate. Actual txids are= not perfect independent random samples in all cases, duplicated nodes have= lower estimated probability, and additional implementation details may red= uce or alter the rate.

The deploy= ment-relevant conclusion is:

Honest= accidental violations should be rare.

Adversarial violations are possible.

Miners must enforce the rule.


Backward compatibility=

This is a soft fork. Blocks = violating the new rule were previously valid and become invalid after activ= ation.

Unupgraded full nodes may = accept violating blocks after activation. Activation therefore requires ord= inary soft-fork deployment procedures.

Unupgraded SPV clients remain vulnerable to the legacy proof ambiguit= y. SPV clients must update their Merkle proof validation logic to obtain th= e benefit of this rule.

Test vectors

Test vectors should include:

  1. A block whose transaction Merkle internal node p= reimages do not encode minimal 64-byte transactions. The block is valid.

  2. A block containing a 64-b= yte transaction whose serialization does not appear as an internal node pre= image. The block is valid.

  3. A block where an internal node preimage encodes a minimal 64-byte trans= action. The block is invalid.

  4. A block where an odd-entry duplicated preimage h || h encode= s a minimal 64-byte transaction. The block is invalid.

  5. An SPV proof where one branch preimage enco= des a minimal 64-byte transaction. The proof is rejected.

  6. An SPV proof for a 64-byte transaction = where no branch preimage encodes a minimal 64-byte transaction. The proof i= s accepted if otherwise valid.

Open questions=

  1. Should the rule include o= nly the explicit minimal 64-byte legacy transaction shape above, or should = it call the full consensus transaction deserializer?

  2. Should future transaction serialization cha= nges be required to preserve this exact forbidden-preimage invariant?

  3. Should pre-activation relay = policy discourage transaction pairs that can form forbidden sibling preimag= es?

  4. Should mining softw= are standardize a recovery procedure for failed Merkle construction, or sho= uld this remain implementation-specific?

  5. Should SPV proof formats include an explicit version bit= indicating branch-preimage checking support?

--
You received this message because you are subscribed to the Google Groups "= Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoindev+u= nsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/f97afcc5-54ba-4284-8e= 9b-e8c35c7101f6n%40googlegroups.com.

--
You received this message because you are subscribed to the Google Groups &= quot;Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoind= ev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/= MuaBBWyHNVBd2i0ppWeXGlhAx8C_UqdUZctkuQ7stQeo8CudqJSWfeJHsmJLYLgXz_XZgRw5i1n= TJ4wAZCsdCyQccR1Xh4IzA4QjBMVUJpU%3D%40protonmail.com.
--b1=_XBL4TSruye3KvOySx8A0xnvNxjfqEpY9bLpWUSq6U--