┌───────────┐ ┌───────────┐
│ Initiator │ │ Responder │
└─────┬─────┘ └─────┬─────┘
│ │
│ │
┌───────────────────────────┤ │
│ │ │
└──────────────────────────►│ │
x, ellswift_X = │ │
ellswift_create()(1) │ │
│ │
│ ellswift_X + initiator_garbage(up to 4095 bytes)(2) │
├───────────────────────────────────────────────────────────►│
│ │
│ │
│ ├────────────────────────────┐
│ │ │
│ │◄───────────────────────────┘
│ │ y, ellswift_Y =
│ │ ellswift_create()(3)
│ │
│ ├────────────────────────────┐
│ │ │
│ │◄───────────────────────────┘
│ │ ecdh_secret = v2_ecdh(y,
│ │ ellswift_X, ellswift_Y,
│ │ initiating=False)(4)
│ │
│ ├────────────────────────────┐
│ │ │
│ │◄───────────────────────────┘
│ │ v2_initialize(ecdh_secret,
│ │ initiating=False)(5)
│ │
│ │
│ ellswift_Y + responder_garbage(up to 4095 bytes) + │
│ responder_garbage_terminator + v2_enc_package(RESPONDER_ |
│ TRANSPORT_VERSION, aad=responder_garbage)(6) │
│◄───────────────────────────────────────────────────────────┤
│ │
│ │
│ │
┌───────────────────────────┤ │
│ │ │
└──────────────────────────►│ │
ecdh_secret = v2_ecdh(X, │ │
ellswift_Y, ellswift_X, │ │
initiating=True)(7) │ │
│ │
┌───────────────────────────┤ │
│ │ │
└──────────────────────────►│ │
v2_initialize(ecdh_secret,│ │
initiating=True)(8) │ │
│ │
│ │
│ │
│ │
│ │
│ initiator_garbage_terminator + v2_enc_packet(INITIATOR_ │
│ TRANSPORT_VERSION, aad=initiator_garbage)(9) │
├───────────────────────────────────────────────────────────►│
│ │
│ │
│ │
x
and computes the 64-byte ElligatorSwift-encoded public key ellswift_X
. ElligatorSwift is used to achieve a random looking 512-bit stream that always corresponds to a valid public key, avoiding in this
way fingerprinting based on the key encoding.ellswift_X
alongside up to 4095 bytes of garbage to the responder. This provides a form of shapability (avoiding a recognizable pattern of sending exactly 64 bytes of data).
The responder receives data from the initiator and parses it byte-by-byte, until one of the bytes does not match the 16 bytes consisting of the network magic followed by version\\x00\\x00\\x00\\x00\\x00
. If the first 16 bytes match, the connection is
treated as v1 instead. If any of the first 4 bytes does not match the network magic, but the 12 subsequent do match the version message this may be interpreted as a v1 from a different network, and the connection can be dropped.
If the connection is not dropped, and flagged as v2, the rest remaining of the first 64 bytes can be parsed and decoded as ellswift_X
.y
and the corresponding ElligatorSwift-encoded public key ellswift_Y
.shared_secret
via X-only ECDH using his private key (y
) and the exchanged public keys (ellswift_X
and ellswift_Y
).shared_secret
(two for each direction: one for packet lengths, one for content encryption), alongside a session id
, and two 16-byte garbage terminators
(one per direction).ellswift_Y
alongside up to 4095 bytes of garbage, his garbage terminator and the first encrypted message containing the version message of the responder (RESPONDER_TRANSPORT_MESSAGE
) and authenticating the garbage.
In the current state, the version message is empty (signaling version 0), but the flag is there to allow for protocol updates. Garbage is authenticated to prevent any attacker from being able to alter data, even if its garbage (the bar is set for the protocol to be stateful)ellswift_Y
, the initiator can also derive the shared_secret
.session id
and garbage terminators
as the responder, and uses it to identify the garbage and authenticate it, ensuring, therefore, that the keys have been properly generated.garbage teminator
, signaling in this way that no more garbage is being sent and that the secure channel has been stablished. Notice this is required given data is sent as a bitstream, so the responder could have send back his bit while
the initiator was still sending garbage. It also serves as acknowledgment that the initiator has derived the shared_secret
and all the data that is derived from it.The specifics of how the ElligatorSwift keys are derived is not covered in these notes and is attributed to