From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Sun, 28 Jun 2026 22:32:39 -0700 Received: from mail-oo1-f59.google.com ([209.85.161.59]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1we4bm-00037L-Gv for bitcoindev@gnusha.org; Sun, 28 Jun 2026 22:32:39 -0700 Received: by mail-oo1-f59.google.com with SMTP id 006d021491bc7-6a0e8ca12b5sf2545096eaf.0 for ; Sun, 28 Jun 2026 22:32:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1782711152; x=1783315952; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:sender:from :to:cc:subject:date:message-id:reply-to; bh=19G5a1svOOKL9OcsxNu0LDeH2MOZRe0BD+sFWqobsWo=; b=eziHD8dXPPttfwYmwlwAweF5NRAJiu8ohUBJ9gwKOWk9UMWVc20BmT8AWuysR9kxG1 qd1la77fjaReLvj8UpcdQcA0WYcMAH5VPnUKyXsJGMyNopleVQWdIN+lDRIQB+/AnCkz UjyJyhQF2WOMzf+Ic6aEAhDOer8pZmcG+YkMl8dL4u30PVcCMlHYJz5/4QSrEZHckCZG dbyF60VPNwb1M1cHND3u/4NQ9Yaed9AzEIZd6uScdkO5Cqk+bbdRbWCbBjZX39R+NPfg w3BwEXEvhm5pOo5FUUCyfZvpGVCG+lrnkcZfB574yNzh3zxUJRi0lQpZ6HZ9M32FhJr/ jdeg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1782711152; x=1783315952; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:from:to:cc :subject:date:message-id:reply-to; bh=19G5a1svOOKL9OcsxNu0LDeH2MOZRe0BD+sFWqobsWo=; b=PHT9PxWSimGNE+jKSiY+wmwyXz8LdY41hZUviLISMQ35mtGdfG3I1gedyBe/V8BL6x pJB7oKRVW+IR9CyO/hJ9Ikc/pUGkth9KctM1hIMI5AM/wRAb6kZ0odPjGPtwpbQtdk6L JAI2pAIHUk5mnmGP4OduQmNE7NZjhJf/Fm/0xlOSWFWujA56fbVSOgqCEzDIdGGVwT+R qkTg0zY3xrbVcplNEs5oy/zNn6j8hogPh80Ye5Y/VF0GYSeHGdiZkpN+xG1IAyT1UR69 +K3JJxyNkQ+riJ2KviiEnSuC0CYy/G02LP5sypqhuDdmcA8H1CL3/38vbMmFkNrzYDBl vu5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782711152; x=1783315952; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:x-beenthere :x-gm-message-state:sender:from:to:cc:subject:date:message-id :reply-to; bh=19G5a1svOOKL9OcsxNu0LDeH2MOZRe0BD+sFWqobsWo=; b=UnhV48JxetgPTi3dUUKnuKu0kE9H2f0qjrNe/BB+bnPWgy+3o+SRhWvzeQE28m0ZbI CZIRJhBtiCZrsr06DPv08ha3QGGCZ38hjJxr5kB97kg2pcTrVHwsoCetI2hvkV6uVTqK jeiPsZx1YZkfexwz3aGYW/HfO6pxM/FOziEwS//aSQuBkuiNlt6AZQW2Rq4q9bz4/AFY B2zGzgsHhNIB2KCopdFZIhpg9YL0kLjz8ziTMZHbv0rTZe2rxSuaTDQtibislIG9tKZJ 88rpy8LLEFQf3geeV8KYV6GnSjWrAP9O+i8qLZMXDa7jEomGaN5L3g6OO5mKHV+w2RD+ 4JzA== Sender: bitcoindev@googlegroups.com X-Forwarded-Encrypted: i=1; AFNElJ9yoGleWgFGfhevkNmNkYQyWXLjIT5p0is1+GgfNvDnJduLPkLlFpcKM0YWHLrvFOAyKVGOY3rZY+1I@gnusha.org X-Gm-Message-State: AOJu0YwrenDDBp39l+NKFjrFum3kb6nJ6hmEElPfgTC8i/4jvQe5ptQL zco6FyVcgqwn4sqZH+w1jYZSqiGNIlWRZ2PSiOu9wzpOoXZ+OpjyctY8 X-Received: by 2002:a05:6820:20a:b0:6a1:7e36:e87a with SMTP id 006d021491bc7-6a17e36fab1mr436412eaf.66.1782711152048; Sun, 28 Jun 2026 22:32:32 -0700 (PDT) X-BeenThere: bitcoindev@googlegroups.com; h="AX0PUUfaH7BrYC/Rb1SSxOtpVw6Fhm5OOfaCg0XM9QCeFAKLZw==" Received: by 2002:a05:6820:2905:b0:6a1:3eb9:9181 with SMTP id 006d021491bc7-6a13eb9932cls2498511eaf.1.-pod-prod-05-us; Sun, 28 Jun 2026 22:32:27 -0700 (PDT) X-Received: by 2002:a05:6808:1b23:b0:484:b678:6c55 with SMTP id 5614622812f47-4921b23436cmr11340163b6e.38.1782711147423; Sun, 28 Jun 2026 22:32:27 -0700 (PDT) Received: by 2002:a05:690c:c6c8:b0:7ba:f5aa:4ab8 with SMTP id 00721157ae682-80b9edeca59ms7b3; Sun, 28 Jun 2026 20:40:08 -0700 (PDT) X-Received: by 2002:a05:690c:4c05:b0:80e:54a:83df with SMTP id 00721157ae682-80e054a84ddmr44500577b3.47.1782704408016; Sun, 28 Jun 2026 20:40:08 -0700 (PDT) Date: Sun, 28 Jun 2026 20:40:07 -0700 (PDT) From: Antoine Riard To: Bitcoin Development Mailing List Message-Id: <6c02cc0f-13c0-4670-8689-9ad39cd8a203n@googlegroups.com> In-Reply-To: <8FEEF72A-92A3-48A9-AC49-43107D17B090@sprovoost.nl> References: <8FEEF72A-92A3-48A9-AC49-43107D17B090@sprovoost.nl> Subject: Re: [bitcoindev] Prohibit Merkle Internal Node Preimages That Encode Minimal 64-Byte Transactions MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_14774_191265418.1782704407626" X-Original-Sender: antoine.riard@gmail.com 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: -0.5 (/) ------=_Part_14774_191265418.1782704407626 Content-Type: multipart/alternative; boundary="----=_Part_14775_1231445375.1782704407626" ------=_Part_14775_1231445375.1782704407626 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Jeremy, Okay, so the main intuition is only a reduction of the "seam" to a specific structure, by checking that all txid merkle has a specific 1-input,=20 1-output, tx. Would be good if you have benchmark for iterating on a=20 max-depth-tree-min -size tx on a i5 or i7 to have an idea of the perf measurement. Somehow,=20 without more information, I can only echo my protocol colleagues that your solution is naively coming with more CPU cycles consumption. On another point, from your discussion with the other Antoine, what is=20 observed is very interesting. It's not only a SPV proof for e.g let's say a bridge= =20 protocol using connector output, thar your consideration can be intereesting. It's= =20 also that the whole merkle tree can be seen a *scriptable surface*. Assuming tha= t all the other txn ids are fixed points (easy fulfilled assumption if you're= =20 a miner and you can choose the template), a remaining txid slot can be used t= o convey *information* from a fixed spent UTXO (where the prover would grind= =20 on the remaining entropy bits to get a satisfying solution). Somehow allowing to build interesting cryptographic puzzles, giving=20 zero-knowledge properties to a simple merkle branch. What theoretically you could do with= =20 it ? Super compact proof that a UTXO has been spent and a 1-bit of information= =20 has been exchanged. Of course, the current BIP54 fix ruling out 64 bytes tx=20 would still allow to build that kind of proofs, you would just have to special=20 case this in the prover structure. Anyway, about BIP54, I'm +1 to have a long validation block cost and timewarp fixes, I'm shrug about getting a better fix for coinbase id=20 collision, we have more time to come with one, ruling out 64 byte tx to make secure SP= V verifier, I've been always less interested by it, personally. Best, Antoine OTS: 62a4928f9aaa678a225f6ca55564049d6ba19ae4d006b890cdfc945248aebb9e Le Monday, June 22, 2026 =C3=A0 3:27:54=E2=80=AFPM UTC+1, Sjors Provoost a = =C3=A9crit : > > > > Op 1 jun 2026, om 19:46 heeft jeremy het=20 > volgende geschreven: > >=20 > > Esteemed Colleagues, > > As a result of some of my research on 64-byte transactions, I'd like to= =20 > discuss an alternative soft fork proposal that preserves the ability to= =20 > encode 64-byte transactions while offering protection to SPV users (who= =20 > must make 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=20 > byte structure of a minimal one-input, one-output, witness stripped=20 > transaction. > > [With the miracle of GPT,] I've drafted a relatively complete BIP for= =20 > discussion. > > I like the idea of fixing the problem as close to the (merkle, haha) root= =20 > of the problem. But is there a more elegant and succinct way to implement= =20 > IsForbiddenMerkleInternalNodePreimage64? > > Otherwise I prefer to wait 80 years for a proper fix, rather than add thi= s=20 > complexity to consensus code. Even if we can't have the 64 byte exception= =20 > (which I still prefer). > > After 2106, the fix can be a simple tweak to the leaf hash calculation: > > if (!hardfork) return tx.getHash().ToUint256(); > > // Fix Merkle tree, and drop the separate witness commitment by committin= g > // witness data directly in the transaction Merkle tree. > return (HashWriter{TaggedHash("TaggedWtxid")} <<=20 > TX_WITH_WITNESS(tx)).GetSHA256(); > > Here's a rough sketch: > https://github.com/Sjors/bitcoin/tree/2026/06/merkle > > > The upgrade mechanism isn't important in this context, but I implemented= =20 > the following rules: > > 1. a new header format, growing timestamp from 32 to 64 bits > - mask one byte to use for nonce space, if we think two billion years is= =20 > enough > > 2. the block version must be negative, if and only if it uses the new=20 > header format > - let's the header/block deserialiser know in the first 4 bytes how long= =20 > the header is=20 > - current nodes will reject such blocks, because BIP34 deployment burned= =20 > nVersion < 2 > - therefore it's not used for signalling or nonce grinding > - no historical blocks have a negative version > > 3. new headers must have timestamp >=3D 2^32=20 > - makes it a clean break both ways > - maybe require old headers can't connect to a new header > > - Sjors > > > static bool IsForbiddenMerkleInternalNodePreimage64(const unsigned char= =20 > 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. > >=20 > > if (p[4] !=3D 0x01) { > > return false; > > } > >=20 > > const unsigned int x =3D p[41]; > >=20 > > switch (x) { > > case 0: > > if (p[46] !=3D 0x01) return false; > > if (p[55] !=3D 0x04) return false; > > break; > >=20 > > case 1: > > if (p[47] !=3D 0x01) return false; > > if (p[56] !=3D 0x03) return false; > > break; > >=20 > > case 2: > > if (p[48] !=3D 0x01) return false; > > if (p[57] !=3D 0x02) return false; > > break; > >=20 > > case 3: > > if (p[49] !=3D 0x01) return false; > > if (p[58] !=3D 0x01) return false; > > break; > >=20 > > case 4: > > if (p[50] !=3D 0x01) return false; > > if (p[59] !=3D 0x00) return false; > > break; > >=20 > > default: > > return false; > > } > >=20 > > const size_t value_pos =3D 47 + x; > > const uint64_t raw_value =3D ReadLE64(p + value_pos); > >=20 > > if (raw_value >=20 > static_cast(std::numeric_limits::max())) { > > return false; > > } > >=20 > > const int64_t nValue =3D static_cast(raw_value); > >=20 > > if (!MoneyRange(nValue)) { > > return false; > > } > >=20 > > return true; > > } > >=20 > >=20 > > --=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/= 6c02cc0f-13c0-4670-8689-9ad39cd8a203n%40googlegroups.com. ------=_Part_14775_1231445375.1782704407626 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Jeremy,

Okay, so the main intuition is only a reduction of th= e "seam" to a specific
structure, by checking that all txid merkle has= a specific 1-input, 1-output,
tx. Would be good if you have benchmark= for iterating on a max-depth-tree-min
-size tx on a i5 or i7 to have = an idea of the perf measurement. Somehow, without
more information, I = can only echo my protocol colleagues that your solution
is naively com= ing with more CPU cycles consumption.

On another point, from you= r discussion with the other Antoine, what is observed
is very interest= ing. It's not only a SPV proof for e.g let's say a bridge protocol
usi= ng connector output, thar your consideration can be intereesting. It's also=
that the whole merkle tree can be seen a *scriptable surface*. Assumi= ng that
all the other txn ids are fixed points (easy fulfilled assumpt= ion if you're a
miner and you can choose the template), a remaining tx= id slot can be used to
convey *information* from a fixed spent UTXO (w= here the prover would grind on
the remaining entropy bits to get a sat= isfying solution).

Somehow allowing to build interesting cryptog= raphic puzzles, giving zero-knowledge
properties to a simple merkle br= anch. What theoretically you could do with it ?
Super compact proof th= at a UTXO has been spent and a 1-bit of information has
been exchanged= . Of course, the current BIP54 fix ruling out 64 bytes tx would
still = allow to build that kind of proofs, you would just have to special case
this in the prover structure.

Anyway, about BIP54, I'm +1 to h= ave a long validation block cost and
timewarp fixes, I'm shrug about g= etting a better fix for coinbase id collision,
we have more time to co= me with one, ruling out 64 byte tx to make secure SPV
verifier, I've b= een always less interested by it, personally.

Best,
Antoine=
OTS: 62a4928f9aaa678a225f6ca55564049d6ba19ae4d006b890cdfc945248aebb9e=

Le Monday, June 22, 2026 =C3=A0 3:27:54=E2=80=AFPM UTC+1, Sjors Provoost= a =C3=A9crit=C2=A0:


> Op 1 jun 2026, om 19:46 heeft jeremy <jeremy....@gmail.com> het volgende geschreven:
>=20
> Esteemed Colleagues,
> As a result of some of my research on 64-byte transactions, I'= d like to discuss an alternative soft fork proposal that preserves the abil= ity to encode 64-byte transactions while offering protection to SPV users (= who must make 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 exa= ct byte structure of a minimal one-input, one-output, witness stripped tran= saction.
> [With the miracle of GPT,] I've drafted a relatively complete = BIP for discussion.

I like the idea of fixing the problem as close to the (merkle, haha) ro= ot of the problem. But is there a more elegant and succinct way to implemen= t IsForbiddenMerkleInternalNodePreimage64?

Otherwise I prefer to wait 80 years for a proper fix, rather than add t= his complexity to consensus code. Even if we can't have the 64 byte exc= eption (which I still prefer).

After 2106, the fix can be a simple tweak to the leaf hash calculation:

if (!hardfork) return tx.getHash().ToUint256();

// Fix Merkle tree, and drop the separate witness commitment by committ= ing
// witness data directly in the transaction Merkle tree.
return (HashWriter{TaggedHash("TaggedWtxid")} << TX_WIT= H_WITNESS(tx)).GetSHA256();

Here's a rough sketch:
https://github.com/Sjors/bitcoin/tree/2026/06/merkle


The upgrade mechanism isn't important in this context, but I implem= ented the following rules:

1. a new header format, growing timestamp from 32 to 64 bits
- mask one byte to use for nonce space, if we think two billion years= is enough

2. the block version must be negative, if and only if it uses the new h= eader format
- let's the header/block deserialiser know in the first 4 bytes h= ow long the header is=20
- current nodes will reject such blocks, because BIP34 deployment bur= ned nVersion < 2
- therefore it's not used for signalling or nonce grinding
- no historical blocks have a negative version

3. new headers must have timestamp >=3D 2^32=20
- makes it a clean break both ways
- maybe require old headers can't connect to a new header

- Sjors

> 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.
>=20
> if (p[4] !=3D 0x01) {
> return false;
> }
>=20
> const unsigned int x =3D p[41];
>=20
> switch (x) {
> case 0:
> if (p[46] !=3D 0x01) return false;
> if (p[55] !=3D 0x04) return false;
> break;
>=20
> case 1:
> if (p[47] !=3D 0x01) return false;
> if (p[56] !=3D 0x03) return false;
> break;
>=20
> case 2:
> if (p[48] !=3D 0x01) return false;
> if (p[57] !=3D 0x02) return false;
> break;
>=20
> case 3:
> if (p[49] !=3D 0x01) return false;
> if (p[58] !=3D 0x01) return false;
> break;
>=20
> case 4:
> if (p[50] !=3D 0x01) return false;
> if (p[59] !=3D 0x00) return false;
> break;
>=20
> default:
> return false;
> }
>=20
> const size_t value_pos =3D 47 + x;
> const uint64_t raw_value =3D ReadLE64(p + value_pos);
>=20
> if (raw_value > static_cast<uint64_t>(std::numeric_li= mits<int64_t>::max())) {
> return false;
> }
>=20
> const int64_t nValue =3D static_cast<int64_t>(raw_value)= ;
>=20
> if (!MoneyRange(nValue)) {
> return false;
> }
>=20
> return true;
> }
>=20
>=20

--
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/bitcoind= ev/6c02cc0f-13c0-4670-8689-9ad39cd8a203n%40googlegroups.com.
------=_Part_14775_1231445375.1782704407626-- ------=_Part_14774_191265418.1782704407626--