Bitcoin Development Mailinglist
 help / color / mirror / Atom feed
* [bitcoindev] [BIP Proposal] Transport Feature Negotiation
@ 2026-09-17 23:23 Liam Gilligan
  0 siblings, 0 replies; only message in thread
From: Liam Gilligan @ 2026-09-17 23:23 UTC (permalink / raw)
  To: Bitcoin Development Mailing List


[-- Attachment #1.1: Type: text/plain, Size: 13126 bytes --]

Hi everyone,

TL;DR (using Terms and Defs below): In order to support encryption upgrades 
and the addition of authentication to P2P, I propose we specify a Transport 
Feature Negotiation protocol, which gives a framework for modifying the 
Transport Layer. This makes use of the version packet BIP-324 left 
unspecified for exactly this purpose, redefining it as a **negotiation 
packet** which carries the features a node supports.

## Terms and Defs

There are some unfortunately similar names, so I'll lay out some 
terminology/definitions in addition to those I made in roasbeef's thread[1].
- **Transport Layer**: The details of how Protocol messages are encoded on 
wire and what security services[2] are provided during transmission.
- The objects the Transport Layer concerns itself with are **packets**, 
which can contain the Protocol Layer's **messages**.
- A **Transport** is a particular version of the Transport Layer; V1 and V2 
are the two that exist today.
- **Protocol Layer**: The layer that defines which Bitcoin P2P messages and 
commands are used.
- The objects the Protocol Layer concerns itself with are **messages**, 
which are contained in Transport Layer's **packets**.
- A **Protocol** is a particular version of the Protocol Layer; these are 
the protocol versions carried in the version message, currently up to 70017.
- **P2P Handshake**: The exchange between two nodes to ensure they are 
using compatible Transports and Protocols. This can simply be called "the 
handshake". It consists of two phases:
- **Transport Phase**: The process in which the Transport is established.
- V1 Transport exchanges no bytes during its Transport Phase.
- V2 Transport's Transport Phase is defined by BIP-324[3].
- The V2 Transport Phase is terminated by a **version packet**, which is a 
Transport Layer packet which contains no Protocol Layer message. The 
version packet will never contain the version message defined below. 
BIP-324 leaves its contents unspecified and sends it empty, making it 
exactly 20 bytes on the wire.
- A **negotiation packet** is that same packet with its contents specified. 
This proposal defines those contents as a list of features; a negotiation 
packet advertising no features is empty, and is therefore a version packet.
- **Protocol Phase**: The process in which the Protocol is established.
- This is done through an exchange of messages contained between a 
**version message** and a **verack message** (or simply verack). The verack 
terminates both the Protocol Phase and the handshake itself.
- As the name suggests, a version message is a Protocol message contained 
within a Transport Layer packet. It will never be contained in the V2 
Transport's version packet.
- Note that nodes not complying with BIP-434[4] may attempt modifying the 
Protocol Layer after the verack.
- **Feature**: a modification to the Transport Layer which can be 
negotiated -- an encryption upgrade or authentication, for example. A 
feature is negotiated when both peers agree to use it, by rules given 
below. A feature exists only within the negotiation packet, whose contents 
are a list of features and nothing else, and is identified by a one-byte 
header. BIP-434 uses "feature" for the Protocol Layer equivalent; the two 
never appear in the same packet.

## Motivation and Rationale

As discussed earlier in roasbeef's thread[1], a PQ upgrade to the Transport 
is needed. The general consensus from that thread was that a CTU solution 
would be best for this, which means we need a mechanism for performing such 
an upgrade. BIP-324 was designed with a future PQ upgrade in mind, and left 
an unspecified version packet specifically to perform it, alongside 
authentication and other Transport upgrades.

The version packet seems like a good fit, but is it the only option? There 
are two main alternatives that come to mind: BIP-434 and defining a V3 
Transport.

BIP-434 is a complete P2P negotiation protocol, but is only used for 
negotiating which messages are sent and how they encode data. In other 
words, BIP-434 is sort of "Protocol Feature Negotiation". But encryption 
and authentication are Transport features, not Protocol features. The 
timing is also an issue -- the Protocol Phase of the handshake will take 
place over two separate Transports.

Defining a V3 Transport by fully replacing the ElligatorSwift ECDH is also 
an option, but there are some issues with this. First, it wouldn't be a CTU 
path that was (loosely) agreed upon in roasbeef's thread, and instead it 
would be an OSH solution. More concretely, it would require committing to 
one specific PQ KEM right off the bat. In the event that this KEM was 
broken or otherwise rejected, it would require a V4 Transport to replace 
it. Negotiating the PQ KEM to use in band allows for modularity and 
backwards-compatibility, which is not offered by a V3.

That leaves in-band negotiation inside V2. Given that a negotiation packet 
is needed in any case, defining an entirely new one instead of redefining 
the version packet adds overhead and potentially round trips. The version 
packet is existent, unused, and positioned ideally and intentionally for 
this purpose.

## Proposed Design

Transport Feature Negotiation specifies what the negotiation packet 
contains:

```
Negotiation Packet Contents:
-------------------------------------
| Feature | Feature | ... | Feature |
-------------------------------------

Feature structure:
------------------------------------------
| CompactSize | Header | Feature Payload |
------------------------------------------
```

The contents of the negotiation packet are a list of features and they are 
not packaged like a message[5], so no message type is prefixed. The 
negotiation packet can carry as many features as can fit in the maximum 
packet size[6]. A node should disconnect if it can't parse a negotiation 
packet.

The CompactSize indicates the size of the Header + Payload in bytes.

The Header is one byte that indicates what feature is being negotiated, and 
nodes should ignore unsupported features. Header values should be recorded 
in a table maintained alongside this specification, as BIP-324 does for its 
one-byte message type IDs[7]. The value zero is reserved so that a later 
revision can introduce a different structure. Because the CompactSize 
covers the Header as well as the Payload, a new Header can take on any 
shape. Until an alternative header format is specified, a zero header 
should be ignored. A node must not send more than one feature with the same 
header, and a node receiving a negotiation packet in which a header repeats 
should act on the first occurrence and ignore[8] the rest.

The Feature Payload contains information relevant to a feature being 
negotiated, and can be empty. How the payload is structured and interpreted 
is defined by that specific feature. A feature may specify that **feature 
packets** can be sent -- additional packets whose contents can be used for 
upgrade. These packets may only be sent if that feature was negotiated, and 
they extend the Transport Phase past the negotiation packet. Their contents 
must begin with the header of their respective feature, and feature packets 
sent with headers that haven't been negotiated should be ignored.

A node supporting no features sends an empty negotiation packet -- which is 
identical to a version packet -- and therefore current V2 nodes are already 
compliant[9], advertising and selecting features correctly and ignoring 
unsupported ones.

One negotiation packet from each side completes negotiation, but each acts 
slightly differently. The first negotiation packet acts as advertisement: 
it should contain every feature a node supports, including those that are 
mutually incompatible. The second negotiation packet acts as selection: it 
responds with a subset of the first packet's features, thus deciding which 
upgrades are performed. A feature is considered to be negotiated if and 
only if it appears in the selecting packet. The two peers are therefore the 
advertiser and the selector.

Features that require payloads should allow the advertiser to omit payloads 
from their advertised feature (for example, to advertise ML-KEM support but 
not send the pubkey). This lets the advertiser avoid computing potentially 
costly setup for a feature which their peer may not support, at the cost of 
a half round-trip. Similarly, these features should require the selector to 
always send payloads, and allow the advertiser to send their payload after 
the fact in a feature packet.

If no negotiated features require feature packets, the Transport Phase ends 
with the second negotiation packet in the same way BIP-324 terminates it. 
Otherwise, it terminates when the last feature packet is sent.

Nodes should accept inbound connections regardless of what features their 
peer supports[10], though a node may disconnect peers based on theirs.

A MitM *can* strip features from the negotiation packet, and a node can't 
tell if its peer doesn't support a feature or had its 
advertisement/selection stripped. An authentication feature can make this 
detectable[11].

## Scope and Open Questions

I can't imagine that there will be any Transport features implemented in 
practice aside from encryption and authentication upgrades. Should we 
restrict the features to just those? This would make ordering feature 
packets and coordinating the encryption upgrades easier. Is there some 
other subset of possible features we want to restrict to? Let me know your 
thoughts.

Should we allow for "staggered negotiation"? Staggered negotiation is what 
I'm calling the process of splitting feature advertisements across separate 
negotiation packets. This could allow nodes to withhold from advertising 
authentication features until after an encryption upgrade is negotiated and 
performed, for example. I haven't described a mechanism for it (because it 
is sort of a headache), but if you all think there is a need, a mechanism 
could be readily designed, and it must be included from the start. There is 
no way to future-proof the protocol to include staggering.

Must the responder be the advertiser? As specified by BIP-324, the 
responder (the node accepting the inbound connection) sends the version 
packet first and thus will always be the advertising peer, meaning the 
initiator gets to choose between mutually incompatible features. Should we 
allow the initiator this privilege? We could choose not to by allowing the 
responder to pass off the obligation of advertisement to the initiator. 
What are your thoughts?

Best,
Liam

---

[1] https://groups.google.com/g/bitcoindev/c/n_5WuKVYqwI/
[2] https://csrc.nist.gov/glossary/term/security_service
[3] https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki
[4] https://github.com/bitcoin/bips/blob/master/bip-0434.md
[5] 
https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#v2-bitcoin-p2p-message-structure
[6] A BIP-324 packet carries a three-byte contents length, so any packet's 
contents are bounded at 2^24 - 1 bytes: 
https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#packet-encryption
[7] https://github.com/bitcoin/bips/blob/master/bip-0324/message_type_ids.md
[8] Note that this is only relevant in the event that the two features 
carry distinct payloads.
[9] BIP-324 specifies this receive behaviour: "Receives a packet, ignores 
its contents. The idea is that features added by future versions get 
negotiated based on what is supported by both parties... we defer 
specifying the encoding for such version content until there is a need for 
it." Core implements it literally -- see VERSION_CONTENTS in src/net.h -- 
and any BIP-324 compliant implementation should do the same.
[10] This is to avoid partitioning. If a peer doesn't support the level of 
desired encryption or authentication, then the connection can be treated 
like a V1. That is, sensitive data can be withheld from unsecure or 
unauthenticated connections.
[11] If every node challenges every peer, there is no signal telling a MitM 
which connections are safe to tamper with, and a node expecting an 
authenticated connection can treat a missing authentication advertisement 
as evidence of interference. The connection need not end and should 
continue unauthenticated, as with any peer lacking some feature -- but the 
interference becomes visible. If CRQCs become a serious threat, an 
authentication feature might go further and treat a connection as authentic 
only where a PQ KEM was also performed: authentication binds to the 
session, and a session established by classical key exchange alone gives a 
quantum attacker everything that binding rests on.

-- 
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/bitcoindev/29174459-1523-4cf8-a20f-5ce1abc302c3n%40googlegroups.com.

[-- Attachment #1.2: Type: text/html, Size: 14264 bytes --]

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-17 23:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 23:23 [bitcoindev] [BIP Proposal] Transport Feature Negotiation Liam Gilligan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox