<p>The goal of decoy packets in general is offering the <strong>option</strong> to implementations of hiding any pattern that can be inferred from the sizes of TCP/IP packets being sent back and forth.</p>
<p>This concern applies to all 3 phases of the protocol. During the <em>key exchange phase</em>, a (limited) form of size pattern hiding can be accomplished through the garbage mechanism. During the <em>application phase</em>, but also during the <em>version negotiation phase</em>, this is done using decoy packets - a much more powerful mechanism than garbage, but only possible after keys have been exchanged.</p>
<p>It is fair to say that right now, with the version negotiation phase just consisting of a single message in both directions, this does not matter. In both directions, instead of a decoy message before the version packet, a decoy message could be sent immediately after it (making it part of the application phase), or garbage could be sent before it instead.</p>
<p>However, in hypothetical extensions, the version negotiation phase could consist of multiple messages too. If there are at least 3, it may not be possible to avoid a recognizable pattern of sizes in the middle ones. Having the decoy mechanism generically available means future extension designers do not have to worry about it.</p>
<p>Furthermore, design wise, I don't believe it complicates implementations much necessarily, but of course that depends on implementation aspects. Think of a BIP324 connection as having a few states it progresses through:</p>
<ul>
<li>Sending/receiving public key</li>
<li>Sending/receiving garbage + garbage terminator</li>
<li>Sending/receiving packets</li>
</ul>
<p>During the 3rd state, all communication is done in the form of packets using the keys negotiated before, decoys and all. The first (non-decoy) packet(s) negotiate the version, and everything after is treated as application layer. I think this makes sense, as version negotiation needs something packet-like anyway, so it might as well use the full packet interface anyway.</p>
<blockquote>
<p>But it does add a bit of complexity to implementations</p>
</blockquote>
<p>Certainly having support for decoy packets as a mechanism in general adds complexity to implementations which cannot be avoided if compatibility with the specification is desired. I don't think having it <em>additionally</em> available during version negotiation adds much complexity on top.</p>
<blockquote>
<p>given the lack of bounds on the decoy packets.</p>
</blockquote>
<p>One cannot avoid supporting packets up to ~4M as that is how large application-layer <code>BLOCK</code> messages are allowed to be. I believe the Bitcoin Core BIP324 implementation uses that as packet size limit for all packets, including decoys.</p>
<blockquote>
<p>I noticed Core has not supported sending decoy packets in the handshake since adding BIP324 support in v26.0, but is this a worthy feature of the protocol that will later be implemented?</p>
</blockquote>
<p>It is not very high on my personal priority list, but I do plan to work at some point on adding support for sending decoys to the Bitcoin Core BIP324 implementation, in particular for transactions (whose relay sizes do reveal some information). It would be great if someone worked on this.</p>
<blockquote>
<p>My guess is to guard against &quot;known plaintext&quot; attack</p>
</blockquote>
<p>A known plaintext would permit an attacker to guess the key stream coming out of the used ChaCha20 cipher, though there are no known ways to exploit that to achieve anything useful (like decrypting other messages, or forging messages). This was not a specific consideration when designing BIP324 or its decoy packet mechanism, as far as I recall.</p>
<hr />
<p>Disclaimer: I am a co-author of BIP324, and am likely biased about the design decisions we made in it.</p>

CC BY-SA 4.0
2024-10-10T16:11:20.853Z
Thanks Pieter, this helped my understanding a ton. The breakdown of how garbage hides the key exchange phase and decoys hide the application phase keeps it simple. I believe my confusion was coming from two things: (1) Since version packets are empty for now, garbage and decoys are kind of the same for them and (2) The handshake spans across the key exchange and application phases. From an implementation perspective, I wrongly assumed the handshake would have a static memory requirement. But since it involves the application phase, its clear now that this isn't the case and for good reason.
yonson
CC BY-SA 4.0
2024-10-07T18:46:15.837Z
2024-10-07T18:53:51.783Z
2024-10-07T18:53:51.783Z
Pieter Wuille
<p>The <a href="https://github.com/bitcoin/bips/blob/22660ad3078ee9bd106e64d44662a59a1967c4bd/bip-0324.mediawiki?plain=1#L126" rel="noreferrer">BIP324 spec</a> allows for any number and any size of decoy packets in the initial handshake of the protocol, right after the materials have been generated and before the version packet is sent.</p>
<p>Are there strong benefits for this complexity in the middle of the handshake? It is not clear to me how much it adds to have that variability on the &quot;left&quot; side of the (currently empty) version packet. But it does add a bit of complexity to implementations given the lack of bounds on the decoy packets. I noticed Core has not supported sending decoy packets in the handshake since adding BIP324 support in <a href="https://github.com/bitcoin/bitcoin/blob/v26.0/src/net.cpp#L1086-L1144" rel="noreferrer">v26.0</a>, but is this a worthy feature of the protocol that will later be implemented?</p>

<bip324-p2p-encryption>
What are the benefits of decoy packets before the version packet in the BIP324 handshake?
yonson
# What are the benefits of decoy packets before the version packet in the BIP324 handshake?

(Asked by: username_0 on 2024-09-20)

The [BIP324 spec](https://github.com/bitcoin/bips/blob/22660ad3078ee9bd106e64d44662a59a1967c4bd/bip-0324.mediawiki?plain=1#L126) allows for any number and any size of decoy packets in the initial handshake of the protocol, right after the materials have been generated and before the version packet is sent.

Are there strong benefits for this complexity in the middle of the handshake? It is not clear to me how much it adds to have that variability on the "left" side of the (currently empty) version packet. But it does add a bit of complexity to implementations given the lack of bounds on the decoy packets. I noticed Core has not supported sending decoy packets in the handshake since adding BIP324 support in [v26.0](https://github.com/bitcoin/bitcoin/blob/v26.0/src/net.cpp#L1086-L1144), but is this a worthy feature of the protocol that will later be implemented?

**Tags:** bip324-p2p-encryption


---

## 1 answers

### Answer by username_1 on 2024-10-07. Score: 3 | Accepted answer

The goal of decoy packets in general is offering the **option** to implementations of hiding any pattern that can be inferred from the sizes of TCP/IP packets being sent back and forth.

This concern applies to all 3 phases of the protocol. During the *key exchange phase*, a (limited) form of size pattern hiding can be accomplished through the garbage mechanism. During the *application phase*, but also during the *version negotiation phase*, this is done using decoy packets - a much more powerful mechanism than garbage, but only possible after keys have been exchanged.

It is fair to say that right now, with the version negotiation phase just consisting of a single message in both directions, this does not matter. In both directions, instead of a decoy message before the version packet, a decoy message could be sent immediately after it (making it part of the application phase), or garbage could be sent before it instead.

However, in hypothetical extensions, the version negotiation phase could consist of multiple messages too. If there are at least 3, it may not be possible to avoid a recognizable pattern of sizes in the middle ones. Having the decoy mechanism generically available means future extension designers do not have to worry about it.

Furthermore, design wise, I don't believe it complicates implementations much necessarily, but of course that depends on implementation aspects. Think of a BIP324 connection as having a few states it progresses through:

* Sending/receiving public key
* Sending/receiving garbage + garbage terminator
* Sending/receiving packets

During the 3rd state, all communication is done in the form of packets using the keys negotiated before, decoys and all. The first (non-decoy) packet(s) negotiate the version, and everything after is treated as application layer. I think this makes sense, as version negotiation needs something packet-like anyway, so it might as well use the full packet interface anyway.

> But it does add a bit of complexity to implementations

Certainly having support for decoy packets as a mechanism in general adds complexity to implementations which cannot be avoided if compatibility with the specification is desired. I don't think having it *additionally* available during version negotiation adds much complexity on top.

> given the lack of bounds on the decoy packets.

One cannot avoid supporting packets up to ~4M as that is how large application-layer `BLOCK` messages are allowed to be. I believe the Bitcoin Core BIP324 implementation uses that as packet size limit for all packets, including decoys.

> I noticed Core has not supported sending decoy packets in the handshake since adding BIP324 support in v26.0, but is this a worthy feature of the protocol that will later be implemented?

It is not very high on my personal priority list, but I do plan to work at some point on adding support for sending decoys to the Bitcoin Core BIP324 implementation, in particular for transactions (whose relay sizes do reveal some information). It would be great if someone worked on this.

> My guess is to guard against "known plaintext" attack

A known plaintext would permit an attacker to guess the key stream coming out of the used ChaCha20 cipher, though there are no known ways to exploit that to achieve anything useful (like decrypting other messages, or forging messages). This was not a specific consideration when designing BIP324 or its decoy packet mechanism, as far as I recall.

---

Disclaimer: I am a co-author of BIP324, and am likely biased about the design decisions we made in it.

> **Comments:**
> **username_0**: Thanks username_1, this helped my understanding a ton. The breakdown of how garbage hides the key exchange phase and decoys hide the application phase keeps it simple. I believe my confusion was coming from two things: (1) Since version packets are empty for now, garbage and decoys are kind of the same for them and (2) The handshake spans across the key exchange and application phases. From an implementation perspective, I wrongly assumed the handshake would have a static memory requirement. But since it involves the application phase, its clear now that this isn't the case and for good reason.  

---

