Skip to content
BIP ATLAS

BIP 0324

What changes when nodes encrypt their traffic?

BIP 324 wraps the peer-to-peer protocol in opportunistic encryption that looks like random bytes on the wire. It does not tell a node who is on the other end, and it changes nothing about blocks or transactions.

Everything Bitcoin nodes relay is public: blocks, transactions, addresses. Before BIP 324, every connection carried it in the clear (v1 connections still do), over connections that were neither encrypted nor authenticated. The authors point out what that costs. A global passive eavesdropper can trivially identify the source and timing of a transaction; bytes can be altered on the fly at low cost; and every connection begins with the same magic bytes, so deep packet inspection can spot and block it.12

BIP 324, assigned in 2019 and recorded as Deployed, defines version 2 of the transport. It adds opportunistic encryption, makes the bytes on the wire look uniformly random to a passive observer, trims a little bandwidth, and leaves room to negotiate future upgrades. Only the framing changes: the messages inside are the same ones v1 carries.3456

Source revision
bitcoin/bips @ 3a10b5b
Source checked
1 October 2026
Review state
Draft — independent technical review applied; awaiting human sign-off
Source details

This chapter is an independent explanation, not the proposals themselves. Preamble fields are shown as recorded in the pinned files, with author e-mail addresses omitted. Status is the proposal’s own field, not an endorsement or a sign of consensus.

BIP 324: Version 2 P2P Encrypted Transport Protocol

BIP
324
Layer
Peer Services
Title
Version 2 P2P Encrypted Transport Protocol
Authors
Dhruv Mehta
Tim Ruffing
Jonas Schnelli
Pieter Wuille
Status
Deployed
Type
Specification
Assigned
2019-03-08
License
BSD-3-Clause
Version
1.0.2
Replaces
151

Pinned source · Reader view on bips.dev
SHA-256 14de484a709946348effa8264991cf124a34ecdaf0a3f9d68a42313287625ad8
Git blob 2b3caff37f5b589d7d42eba0eaf36c42eab332c5

FIG. A17.1 Framing, v1 and v2

v1: 24 bytes besides the payload

  1. network magic4 B
  2. command, 12 ASCII bytes12 B
  3. payload length4 B
  4. checksum4 B

Sent in the clear. Every v1 message begins with the network’s 4 magic bytes, and every connection opens with the command “version”.

v2: 21 bytes besides the payload

  1. encrypted length3 B
  2. header (ignore bit)1 B
  3. message type ID 181 B
  4. Poly1305 tag16 B

Everything is encrypted or random-looking. A ping message uses the 1-byte ID 18; types without an ID take 13 bytes (0x00 and the 12-byte name).

Field sizes from BIP 324’s packet and message structure; the ID for ping read from its message-type table (line 560).

Bytes added to every message: v1’s 24-byte cleartext header against v2’s encrypted length, header byte, type ID and authentication tag.789

Encryption without authentication

v2 encrypts, but it does not authenticate the peer. Nothing in the handshake tells a node who it is talking to; the BIP says so plainly. The authors argue that in a permissionless network authentication only makes sense in specific settings, such as two nodes run by the same operator, and that it should be added separately, if at all.10

What unauthenticated encryption buys, in the authors’ account, is cost. A passive eavesdropper can no longer read the messages; to read traffic it has to become active, by sitting in the middle of the connection for its whole life, downgrading it to v1, or running its own nodes and getting honest ones to connect. Active attacks at scale are more expensive, and for connections an operator sets up by hand they are in principle detectable.1112

The tools for catching them are the protocol version and the session ID. Both ends derive the session ID from the key exchange, so it is identical on both sides of an honest connection and differs if someone has spliced themselves into the middle. A node may show it to its operator to compare with the peer’s operator out of band.13

Why not use TLS or Noise? The authors’ answer is that neither treats authentication as a separate, optional layer, neither produces a pseudorandom byte stream that can be shaped to resemble other traffic, neither supports secp256k1 natively, and both hand the application a stream where Bitcoin wants packets. Fixing all of that would forfeit the benefit of reusing them.14

The handshake

Each side starts by generating a fresh ephemeral key and sending its public key as 64 bytes of ElligatorSwift encoding. Every 64-byte string is a valid encoding of some curve point, so encodings sampled uniformly look like random bytes: unlike a plain 32-byte X coordinate (a random 32-byte string is a valid one only about half the time), they give an observer nothing to test. Each side may follow its key with up to 4095 bytes of garbage, so the first message need not be exactly 64 bytes long.1617

A responder also has to keep talking to v1 peers. It watches the first 16 bytes: if they are the network magic followed by “version” and padding, the start of every v1 connection, it switches to v1.1218

Both sides then decode the other’s 64 bytes to an X coordinate and compute X-only ECDH. The result is hashed together with both 64-byte encodings exactly as sent, initiator’s first, so an attacker cannot alter an encoding without breaking the rest of the stream. HKDF-SHA256, salted with the label “bitcoin_v2_shared_secret” and the network magic, expands that secret into the session ID, four cipher keys (a length key and a payload key in each direction) and two 16-byte garbage terminators.1920

FIG. A17.2 From two public keys to an encrypted packet Interactive

A · Interactive

Static view: the first vector with every stage shown. With JavaScript you can step through the handshake and choose among 5 published vectors.

  1. 1 Public keys out
  2. 2 Shared secret
  3. 3 Keys and session ID
  4. 4 Garbage terminator, version packet
  5. 5 Encrypted packets

From here on everything is encrypted packets: a 3-byte encrypted length, then ChaCha20-Poly1305 over a header byte and the contents, ending in a 16-byte tag.

This side: the initiator

sends 64 bytes (u ‖ t)
480eacf1536b…ee625af3 ‖ 245592c11127…0d0c846a
which decode to x
014e5bdbb1d7…6c5eb2d6 = x(priv · G), computed; that these 64 bytes decode to it is the vector’s claim
its garbage terminator
3ba1f51de6272aa28fd21059b91d3893

The peer: the responder

sends 64 bytes (u ‖ t)
ffffffffffff…22d5e441 ‖ 524d571a52b3…f98457ae
which decode to x
568146140669…70109183 (decoding from the vector)
its garbage terminator
faf3b317340de00e29f2181db270ff81

Derived on both sides

X-only ECDH
105781102830…b3987ced
shared secret
e500c670f1b3…5b3433a8 tagged hash of initiator’s 64 bytes ‖ responder’s 64 bytes ‖ x
initiator_L · initiator_P
67b155367abf…072176b8 · 93f5b4c59038…81e0d5f7
responder_L · responder_P
08fe46857ab4…c7330098 · 2271d5f5351a…30f9255c
session ID
d083d09c1bdf71795b39a9534601cf7c7a7e767e578c44a17dfaf43a3c18f98c the same on both ends unless someone is in the middle

Packet 0 from the initiator

  1. length, 3 bytes6aa28bencrypts 3f0000 = 63 (little-endian)
  2. header + contents, 64 bytes, encryptedc4b6719eca144ac33a3f17859317d5450e4978db9365ce61…
  3. Poly1305 tag, 16 bytesfa1cdc7eb99581c48ff2898ef92d3aa1
nonce (packet in epoch ‖ epoch)
000000000000000000000000 0 rekeys so far
associated data
4095 bytes: the garbage this side sent, authenticated by its first packet
total
83 bytes = 3 + 1 + 63 + 16

Packet 0 in each direction is the version packet (or a decoy before it), part of the handshake; v1 has no equivalent.

Source: BIP 324 packet_encoding_test_vectors.csv, row for packet 0 (line 4). Recomputed at build time by the tested model; ECDH, secret, keys, session ID and terminators equal the vector’s, and so does the whole packet. ElligatorSwift decodings are the vector’s own.

B · Worked example

BIP 324’s packet vector for packet 0, seen from the initiator: from two public keys to one encrypted packet.

12345
  1. Two 64-byte public keys cross the wire

    ours
    480eacf1536b52257bf8ce78d8f4ce09395d744767c6c129e7838947ee625af3245592c111275e877d5baae22584cb5f1153e67c16bcd7da767726cd0d0c846a
    theirs
    ffffffffffffffffffffffffffffffffffffffffffffffffffffffff22d5e441524d571a52b3def126189d3f416890a99d4da6ede2b0cde1760ce2c3f98457ae

    ElligatorSwift encodings: uniformly random-looking bytes that decode to curve X coordinates.

  2. X-only ECDH, hashed with both encodings

    x(ECDH)
    10578110283044630bc13a9f12b00eb0af7cba9f53506add2b57ae07b3987ced
    shared secret
    e500c670f1b32f60e05009bddcdbfa7153afb19c20479583a54b43d85b3433a8
  3. HKDF-SHA256 key schedule

    session ID
    d083d09c1bdf71795b39a9534601cf7c7a7e767e578c44a17dfaf43a3c18f98c
    initiator_P (our payload key)
    93f5b4c59038c16c3f09793976c75e522bf994635e3f1ef9f04e628281e0d5f7
  4. Garbage terminator, then encrypted packets

    our terminator
    3ba1f51de6272aa28fd21059b91d3893
  5. Packet 0: length, ciphertext, tag

    encrypted length
    6aa28b
    nonce
    000000000000000000000000
    tag
    fa1cdc7eb99581c48ff2898ef92d3aa1

    83 bytes in all for 63 bytes of contents.

Source: BIP 324 packet_encoding_test_vectors.csv (line 4); recomputed by the tested model and checked against the vector. ElligatorSwift decodings are taken from the vector; this site does not implement ElligatorSwift.

Five of BIP 324’s packet-encoding vectors, each seen from one side. The model recomputes the ECDH, secret, keys and session ID, each equal to the vector’s, and the packet: in full where the vector publishes it, and its last 128 bytes for packets 223 and 448, where that is all the vector gives. The ElligatorSwift decodings are the vector’s own.819202122

Each side sends its garbage terminator, then encrypted packets. The first packet in each direction carries the garbage that side sent as associated data, so the garbage is authenticated and cannot be changed in transit without the connection failing. Each side then sends a version packet with empty contents, possibly after decoys, to say it speaks v2; the responder’s goes out in its first flight, without waiting.2324

The authors explain that the terminator exists because the receiver has to find where the garbage ends. Scanning for a fixed 16-byte sequence is cheap, whereas trying to authenticate a packet at every offset would mean recomputing a Poly1305 tag for every byte received. A receiver reads at most 4111 bytes, 4095 of garbage and the terminator, before giving up.1725

Packets

After the handshake every byte on the wire belongs to a packet. A packet is 20 bytes plus its contents: a 3-byte length, encrypted, then ChaCha20-Poly1305 over a 1-byte header and the contents, ending in a 16-byte tag. Contents can be up to 2^24 − 1 bytes.8

The length is handled separately because a receiver must know where a packet ends before it can check it. It is encrypted with its own ChaCha20 stream, which keeps running from packet to packet, and is not covered by the tag; a wrong length still makes the packet fail authentication.26

BIP 324 defines one header flag, the highest bit, called the ignore bit; the other bits are ignored for now. A packet with it set is a decoy: the receiver checks that it decrypts and throws it away. Decoys are the protocol’s main means of shaping traffic, which the authors want to make it possible to conceal block propagation; how and when to send them is left out of scope.1227

Inside a packet, an application message starts with its type, either a one-byte ID from the BIP’s table or a zero byte and the same 12-byte ASCII name v1 uses, followed by the payload. Compared with v1’s 24-byte header, a message with a short ID carries 21 bytes of overhead; one without a short ID carries 33. The authors estimate that encrypting and authenticating costs about as much as the truncated double SHA-256 checksum it replaces.7928

Forgetting old keys

Both ciphers change their keys every 224 packets. The payload cipher’s nonce counts packets within the current epoch and numbers the epoch; after the 224th packet its new key is the first 32 bytes of encrypting 32 zero bytes under the old key, with the nonce’s packet field set to 0xffffffff. The length cipher replaces its key with the next 32 bytes of its own stream and moves to the next nonce.22

FIG. A17.3 Nonces and keys across a rekey
Payload cipher of the responder in a published vector
packetnonce: packet in epoch (4 B LE) ‖ epoch (8 B LE)key in use
000000000 0000000000000000fdf5a3e3e7…0b50b1
101000000 0000000000000000fdf5a3e3e7…0b50b1
222de000000 0000000000000000fdf5a3e3e7…0b50b1
223df000000 0000000000000000fdf5a3e3e7…0b50b1
22400000000 01000000000000009eae3d0883…f6bd32 new key
447df000000 01000000000000009eae3d0883…f6bd32
44800000000 02000000000000007bf2eccbbf…c290ff new key

Keys from BIP 324’s packet vector for packet 223 (line 5), run forward by the tested model. After every 224th packet the key is replaced by the first 32 bytes of encrypting 32 zero bytes under the old key. Keys after packet 223 are the model’s; the vectors check rekeying through the packets that follow.

The payload cipher from one of BIP 324’s vectors, run forward: the nonce resets and the key changes after packets 223 and 447.2122

This gives forward secrecy within a session: an attacker who steals the current keys cannot derive earlier ones, so it cannot read traffic recorded before the last rekey. The BIP does not refresh the key exchange during a session, and says why it does not consider that a priority.1229

Nodes advertise v2 with the NODE_P2P_V2 service flag. Because flags spread through untrusted relays, a node that is cut off as soon as it tries v2 is encouraged to retry over v1. v2 nodes keep accepting inbound v1 connections, to minimize the risk of splitting the network. Blocks, transactions, scripts and consensus rules are untouched: v2 changes how messages travel between two nodes, not what they say.61230

Evidence

Each numbered marker in the text points here, and the ↩ links lead back to every place that cites an entry. Quotes are verbatim from the BIP files at commit 3a10b5b, including their wiki markup; links open the exact lines; the quoted text sits under each entry. Labels say what kind of statement each is: a rule, the author’s rationale, history, a test vector, or our own inference.

  1. ↩ Author’s rationale The authors note that v1 peers talk over unencrypted, unauthenticated connections; the data is public but metadata can reveal private information, such as a transaction's source and timing to a global passive attacker.

    Quoted source text (2)

    peers talk to each other over unencrypted and unauthenticated connections.

    BIP 324, line 26

    While the relayed data itself is public in nature, the associated metadata may reveal private information and hamper privacy of users. For example, a global passive attacker eavesdropping on all Bitcoin P2P connections can trivially identify the source and timing of a transaction.

    BIP 324, line 28
  2. ↩ Author’s rationale The authors note v1 connections can be tampered with cheaply, and are self-revealing because they start with fixed magic bytes, which enables censorship.

    Quoted source text (2)

    Since connections are unauthenticated, they can be tampered with at a low cost and often even with a low risk of detection.

    BIP 324, line 29

    The protocol is self-revealing. For example, deep packet inspection can identify a P2P connection trivially because connections start with a fixed sequence of magic bytes. The ability to detect connections enables censorship

    BIP 324, line 30
  3. ↩ History BIP 324 (Mehta, Ruffing, Schnelli, Wuille), a Peer Services specification assigned in 2019, is recorded as Deployed and replaces BIP 151.

    Quoted source text (1)

    Layer: Peer Services Title: Version 2 P2P Encrypted Transport Protocol Authors: Dhruv Mehta <dhruv@bip324.com> Tim Ruffing <crypto@timruffing.de> Jonas Schnelli <dev@jonasschnelli.ch> Pieter Wuille <bitcoin-dev@wuille.net> Status: Deployed Type: Specification Assigned: 2019-03-08 License: BSD-3-Clause Version: 1.0.2 Replaces: 151

    BIP 324, lines 3–14
  4. ↩ Rule BIP 324 proposes a new P2P transport with opportunistic encryption, a mild bandwidth reduction, and upgrade negotiation before application messages.

    Quoted source text (1)

    This document proposes a new Bitcoin P2P transport protocol, which features opportunistic encryption, a mild bandwidth reduction, and the ability to negotiate upgrades before exchanging application messages.

    BIP 324, line 20
  5. ↩ Author’s rationale v2 aims to raise the cost of these attacks mainly through unauthenticated, opportunistic encryption, and makes the bytestream pseudorandom to a passive eavesdropper.

    Quoted source text (1)

    This proposal for a new P2P protocol version (v2) aims to improve upon this by raising the costs for performing these attacks substantially, primarily through the use of unauthenticated, opportunistic transport encryption. In addition, the bytestream on the wire is made pseudorandom (i.e., indistinguishable from uniformly random bytes) to a passive eavesdropper.

    BIP 324, line 32
  6. ↩ a b Editorial inference v2 changes only how P2P messages are carried: payloads and message types are those of the v1 protocol, and the BIP sits in the Peer Services layer, not consensus.

    Quoted source text (3)

    Layer: Peer Services

    BIP 324, line 3

    An unencrypted application layer '''contents''' is composed of:

    BIP 324, line 523

    a 12-byte ASCII message type (as in the v1 P2P protocol)

    BIP 324, line 528
  7. ↩ a b Test vector A v1 message header is 24 bytes (magic, command, length, checksum); a v2 packet adds 20 bytes plus a 1-byte type ID for listed types, 21 bytes in all, or 33 with a 13-byte type.

    Quoted source text (2)

    The total size of a packet is 20 bytes plus the length of its contents.

    BIP 324, line 157

    either a one byte ID in range ''1..255''

    BIP 324, line 528
  8. ↩ a b c Rule A packet is a 3-byte encrypted length, then ChaCha20Poly1305 over a 1-byte header and the contents; a packet is 20 bytes plus its contents, which may be up to 2^24 - 1 bytes.

    Quoted source text (3)

    The total size of a packet is 20 bytes plus the length of its contents.

    BIP 324, line 157

    * A 3-byte encrypted '''length''' field, encoding the length of the '''contents''' (between ''0'' and ''224-1''

    BIP 324, lines 160–163

    * An authenticated encryption of the '''plaintext''', which consists of: ** A 1-byte '''header''' which consists of transport layer protocol flags. Currently, only the highest bit is defined as the '''ignore bit'''.

    BIP 324, lines 161–162
  9. ↩ a b Rule Application contents are a message type, a 1-byte ID or 0x00 plus the 12-byte ASCII type as in v1, followed by the message payload.

    Quoted source text (2)

    | <code>message_type</code> || 1 or 13 || either a one byte ID in range ''1..255'' or <code>b'\x00'</code> followed by a 12-byte ASCII message type (as in the v1 P2P protocol)

    BIP 324, line 528

    | <code>message_payload</code> || <code>message_length</code> || message payload

    BIP 324, line 530
  10. ↩ a b Author’s rationale The proposal does not include peer authentication; the authors argue authentication should be addressed separately, if desired, and the session ID provides a basis for it.

    Quoted source text (2)

    The communication protocol establishing that the communication partner's identity matches who we expect them to be, through some public key mechanism. The proposal in this document does '''not''' include such a mechanism.

    BIP 324, line 42

    As a consequence, we believe that authentication should be addressed separately (if desired), and this proposal aims to provide a solid technical basis for future protocol upgrades, including the addition of optional authentication

    BIP 324, line 44
  11. ↩ Author’s rationale The authors argue encryption forces an eavesdropper to become active: a persistent MitM, downgrading to v1, or running its own nodes; for manual connections, comparing session IDs would expose an attacker.

    Quoted source text (3)

    Encryption, even when it is unauthenticated and only used when both endpoints support v2, impedes eavesdropping by forcing the attacker to become active: either by performing a persistent man-in-the-middle (MitM) attack, by downgrading connections to v1, or by spinning up their own nodes and getting honest nodes to make connections to them.

    BIP 324, line 34

    even very basic checks, e.g., operators manually comparing protocol versions and session IDs (as supported by the proposed protocol), will expose the attacker.

    BIP 324, line 34

    Active attacks at scale are more resource intensive in general, but in the case of manual, deliberate connections (as opposed to automatic, random ones), they are also in principle detectable

    BIP 324, line 34
  12. ↩ a b c d e Author’s rationale Goals include confidentiality against passive attacks, a pseudorandom and shapable bytestream, forward secrecy, upgradability, accepting inbound v1, and low overhead.

    Quoted source text (5)

    * Confidentiality against passive attacks: A passive attacker having recorded a v2 P2P bytestream (without timing and fragmentation information) must not be able to determine the plaintext being exchanged by the nodes.

    BIP 324, line 81

    * Pseudorandom bytestream: A passive attacker having recorded a v2 P2P bytestream (without timing information and fragmentation information) must not be able to distinguish it from a uniformly random bytestream.

    BIP 324, line 83

    * Forward secrecy: An eavesdropping attacker who compromises a peer's sessions secrets should not be able to decrypt past session traffic, except for the latest few packets.

    BIP 324, line 85

    * Compatibility: v2 clients will allow inbound v1 connections to minimize risk of network partitions.

    BIP 324, line 87

    * Shapable bytestream: It should be possible to shape the bytestream to increase resistance to traffic analysis (for example, to conceal block propagation)

    BIP 324, line 84
  13. ↩ a b Author’s rationale A session ID derived from the Diffie-Hellman negotiation identifies the channel; operators can compare it out of band, so an active MitM risks detection.

    Quoted source text (2)

    * Observability of active attacks: A session ID identifying the encrypted channel uniquely is derived deterministically from a Diffie-Hellman negotiation. An active man-in-the-middle attacker is forced to incur a risk of being detected as peer operators can compare session IDs manually

    BIP 324, line 82

    v2 clients supporting this proposal may present the entire session ID (encoded as a hex string) to the node operator to allow for manual, out of band comparison with the peer node operator.

    BIP 324, line 329
  14. ↩ Author’s rationale The authors argue TLS and Noise are unsuitable: they lack a modular treatment of authentication, a pseudorandom and shapable bytestream, native secp256k1 support, and a packet interface.

    Quoted source text (6)

    While it would be possible to rely on an off-the-shelf transport encryption protocol such as TLS or Noise, the specific requirements of the Bitcoin P2P network laid out above make these protocols an unsuitable choice.

    BIP 324, line 62

    The primary requirement which existing protocols fail to meet is a sufficiently modular treatment of encryption and authentication.

    BIP 324, line 64

    * Neither offers a pseudorandom bytestream. * Neither offers native support for elliptic curve cryptography on the curve secp256k1 as otherwise used in Bitcoin.

    BIP 324, lines 70–73

    * Neither offers shapability of the bytestream.

    BIP 324, line 72

    * Both provide a stream-based interface to the application layer, whereas Bitcoin requires a packet-based interface

    BIP 324, line 73

    this would negate the benefits of using them as off-the-shelf solution

    BIP 324, line 75
  15. ↩ Author’s rationale Traffic analysis of packet lengths and timing, and active attacks, can still reveal that v2 is in use.

    Quoted source text (1)

    Traffic analysis, e.g., observing packet lengths and timing, as well as active attacks can still reveal that the Bitcoin v2 P2P protocol is in use.

    BIP 324, line 48
  16. ↩ Rule Each side sends a 64-byte ElligatorSwift encoding of an ephemeral public key; every 512-bit string is a valid encoding, so encodings sampled uniformly look random.

    Quoted source text (2)

    Generates a random ephemeral secp256k1 private key and sends a corresponding 64-byte ElligatorSwift

    BIP 324, line 112

    While a random 256-bit string has about 50% chance of being a valid X coordinate on the secp256k1 curve, every 512-bit string is a valid ElligatorSwift encoding of a curve point, making the encoded point indistinguishable from random when using an encoder that can sample uniformly.

    BIP 324, line 112
  17. ↩ a b Rule Each side may send up to 4095 bytes of garbage after its public key, for shapability and to avoid a recognizable 64-byte pattern.

    Quoted source text (2)

    bytes of arbitrary data after their public key, called '''garbage''', providing a form of shapability and avoiding a recognizable pattern of exactly 64 bytes.

    BIP 324, line 113

    May send up to 4095

    BIP 324, line 113
  18. ↩ Rule The responder treats a connection as v1 if the first 16 bytes match the network magic followed by "version" and padding.

    Quoted source text (1)

    Waits until one byte is received which does not match the 16 bytes consisting of the network magic followed by "version\x00\x00\x00\x00\x00". If the first 16 bytes do match, the connection is treated as using the v1 protocol instead.

    BIP 324, line 115
  19. ↩ a b Rule Both sides compute X-only ECDH and hash it with the exact 64-byte encodings sent (initiator's first), so the encodings cannot be modified without a full MitM.

    Quoted source text (2)

    def v2_ecdh(priv, ellswift_theirs, ellswift_ours, initiating): ecdh_point_x32 = ellswift_ecdh_xonly(ellswift_theirs, priv) if initiating: # Initiating, place our public key encoding first. return sha256_tagged("bip324_ellswift_xonly_ecdh", ellswift_ours + ellswift_theirs + ecdh_point_x32)

    BIP 324, lines 214–221

    This makes sure that an attacker cannot modify the public key encoding used without modifying the rest of the stream. If a third party wants the ability to modify stream bytes, they need to perform a full MitM attack on the connection.

    BIP 324, line 121
  20. ↩ a b Rule HKDF-SHA256, salted with "bitcoin_v2_shared_secret" and the network magic, derives the session ID, four cipher keys and the two 16-byte garbage terminators.

    Quoted source text (1)

    # Include NETWORK_MAGIC to ensure a connection between nodes on different networks will immediately fail prk = HKDF_Extract(Hash=sha256, salt=b'bitcoin_v2_shared_secret' + NETWORK_MAGIC, ikm=ecdh_secret) peer.session_id = HKDF_Expand(Hash=sha256, PRK=prk, info=b'session_id', L=32) # Initialize the packet encryption ciphers. initiator_L = HKDF_Expand(Hash=sha256, PRK=prk, info=b'initiator_L', L=32) initiator_P = HKDF_Expand(Hash=sha256, PRK=prk, info=b'initiator_P', L=32) responder_L = HKDF_Expand(Hash=sha256, PRK=prk, info=b'responder_L', L=32) responder_P = HKDF_Expand(Hash=sha256, PRK=prk, info=b'responder_P', L=32) garbage_terminators = HKDF_Expand(Hash=sha256, PRK=prk, info=b'garbage_terminators', L=32) initiator_garbage_terminator = garbage_terminators[:16] responder_garbage_terminator = garbage_terminators[16:]

    BIP 324, lines 296–308
  21. ↩ a b Test vector This site's model reproduces all seven BIP 324 packet-encoding vectors: x(ours), X-only ECDH, shared secret, all HKDF outputs, session ID, the full packet for the three vectors that publish one and the published last 128 bytes for the other four, including packets after two, three and four rekeys and one of the largest size allowed (2^24 - 1 bytes of contents). ElligatorSwift decoding is not implemented: the model takes the decoded X coordinates from the vectors.

    Quoted source text (1)

    * [[bip-0324/packet_encoding_test_vectors.csv|Packet encoding vectors]] illustrate the lifecycle of the authenticated encryption scheme proposed in this document.

    BIP 324, line 589
  22. ↩ a b c Rule Both ciphers rekey every 224 messages. The AEAD's nonce is the packet number within the epoch and the epoch number; its new key is the first 32 bytes of encrypting 32 zero bytes under the old key with the nonce's packet field set to 0xffffffff. The length cipher takes the next 32 bytes of its own keystream as its new key.

    Quoted source text (4)

    To provide re-keying every 224 packets, we specify two wrappers.

    BIP 324, line 414

    nonce = ((self.packet_counter % REKEY_INTERVAL).to_bytes(4, 'little') + (self.packet_counter // REKEY_INTERVAL).to_bytes(8, 'little'))

    BIP 324, lines 429–437

    if (self.packet_counter + 1) % REKEY_INTERVAL == 0: rekey_nonce = b"\xFF\xFF\xFF\xFF" + nonce[4:] self.key = aead_chacha20_poly1305_encrypt(self.key, rekey_nonce, b"", b"\x00" * 32)[:32]

    BIP 324, lines 435–437

    rekeying every 224 chunks using the next 32 bytes of the block function output as new key

    BIP 324, line 448
  23. ↩ Rule Each side sends its 16-byte garbage terminator; the first encrypted packet in each direction authenticates the garbage sent as associated data, so a third party cannot modify it without consequence.

    Quoted source text (3)

    #** Send their 16-byte garbage terminator.

    BIP 324, line 123

    the first encrypted packet that will be sent in that direction (regardless of it being a decoy packet or not) will make use of the associated authenticated data (AAD) feature of the AEAD to authenticate the garbage that has been sent in that direction.

    BIP 324, line 127

    Without garbage authentication, the garbage would be modifiable by a third party without consequences.

    BIP 324, line 127
  24. ↩ Rule After the terminators, the responder and initiator each send a version packet with empty contents to indicate v2 support; other contents are reserved for future versions.

    Quoted source text (3)

    Sends a '''version packet''' with empty content, to indicate support for the v2 P2P protocol proposed by this document. Any other value for content is reserved for future versions.

    BIP 324, line 130

    Sends a '''version packet''' with empty content as well, to indicate support for the v2 P2P protocol.

    BIP 324, line 133

    Note that the version negotiation phase does not need to wait for the key exchange phase to complete; version packets can be sent immediately after sending the garbage terminator.

    BIP 324, line 149
  25. ↩ Author’s rationale A fixed 16-byte terminator is used because scanning for a byte sequence is much faster than trying to authenticate a packet at every offset; a receiver reads at most 4111 bytes looking for it.

    Quoted source text (2)

    While it is in principle possible to use the first packet after the garbage directly as a terminator (scan until a valid packet follows), this would be significantly slower than just scanning for a fixed byte sequence, as it would require recomputing a Poly1305 tag after every received byte.

    BIP 324, line 123

    #** Receive up to 4111 bytes, stopping when encountering the garbage terminator.

    BIP 324, line 124
  26. ↩ Rule The length field is encrypted with a separate ChaCha20 stream but not covered by the Poly1305 tag; incorrect lengths still make the packet fail authentication.

    Quoted source text (3)

    The Poly1305 authentication tag only covers the encrypted plaintext, and not the encrypted length field.

    BIP 324, line 170

    as incorrect lengths will still trigger authentication failure for the overall packet (the plaintext length is implicitly authenticated by ChaCha20Poly1305).

    BIP 324, line 170

    * Length encryption keeps drawing pseudorandom bytes from the same ChaCha20 cipher for multiple packets, rather than incrementing the nonce for every packet.

    BIP 324, line 169
  27. ↩ Rule Packets with the ignore bit set are decoys, ignored apart from verifying they decrypt; they are the main shapability mechanism.

    Quoted source text (2)

    Encrypted packets have an '''ignore bit''', which makes them '''decoy packets''' if set. Decoy packets are to be ignored by the receiver apart from verifying they decrypt correctly. Either peer may send such decoy packets at any point from here on. These form the primary shapability mechanism in the protocol.

    BIP 324, line 126

    How and when to use them is out of scope for this document.

    BIP 324, line 126
  28. ↩ Author’s rationale Encrypting and authenticating a v2 message costs roughly as much as v1's truncated double-SHA256 checksum.

    Quoted source text (1)

    Each v1 P2P message uses a double-SHA256 checksum truncated to 4 bytes. Roughly the same amount of computation power is required for encrypting and authenticating a v2 P2P message as proposed.

    BIP 324, line 519
  29. ↩ Author’s rationale Rekeying gives forward secrecy within a session: an attacker who compromises current secrets cannot derive past keys; ECDH is not refreshed.

    Quoted source text (2)

    Re-keying ensures [https://eprint.iacr.org/2001/035.pdf forward secrecy within a session], i.e., an attacker compromising the current session secrets cannot derive past encryption keys in the same session.

    BIP 324, line 174

    We do not believe protecting against that is a priority

    BIP 324, line 174
  30. ↩ Rule v2 support is signalled with the NODE_P2P_V2 = (1 << 11) service flag; clients met with immediate disconnection are encouraged to retry with v1.

    Quoted source text (2)

    Peers supporting the v2 transport protocol signal support by advertising the <code>NODE_P2P_V2 = (1 << 11)</code> service flag in addr relay. If met with immediate disconnection when establishing a v2 connection, clients implementing this proposal are encouraged to retry connecting using the v1 protocol.

    BIP 324, line 581

    An untrusted intermediary could falsely advertise a potential peer as supportive of v2 connections.

    BIP 324, line 581