Filename: 358-unified-handshake-extensions.md
Title: Unifying circuit handshake extensions
Author: Nick Mathewson
Created: 27 March 2025
Status: Open

Introduction

We currently have two circuit extension handshakes that accept "extra data" (encrypted to the recipient, not forward-secure): ntorv3 and hs-ntor.

This "extra data" field is used to send a set of extensions between the initiator and responder. But although the handshakes use identical for their extensions, and use these for similar purposes, they have separate sets of extensions, and separate definitions for extension types.

This proposal suggests a mechanism by which we can unify these sets of handshake extensions in the future.

The status quo.

Currently, both ntorv3 and hs-ntor use the same format for their extensions:

     N_EXTENSIONS     [1 byte]
     N_EXTENSIONS times:
        EXT_FIELD_TYPE [1 byte]
        EXT_FIELD_LEN  [1 byte]
        EXT_FIELD      [EXT_FIELD_LEN bytes]

They differ, however, in that ntorv3 allows extensions in the response message as well as the request, whereas hs-ntor only supports extensions in the request.

They have, however, different definitions for EXT_FIELD_TYPE.

In ntorv3, EXT_FIELD_TYPE can be:

  • 1 – CC_FIELD_REQUEST [Client to server]
  • 2 – CC_FIELD_RESPONSE [Server to client]
  • 3 – Subprotocol Request [Client to Server] (reserved, see proposal 346)

In hs-ntor, EXT_FIELD_TYPE can be:

  • 1 - Congestion control request
  • 2 - POW negotiation.

Note that the only conflict between the two is in the definition of EXT_FIELD_TYPE 2.

Proposed unification

In the future, these extension namespaces should be unified. We can achieve this by saying that "client" and "service" extensions (those sent by the initiator and responder respectively) have different namespaces. Thus, the Server->Client 2 (CC_FIELD_RESPONSE) does not conflict with the Client->Server 2 (POW). No renaming is necessary here.

For each EXT_FIELD_TYPE, we should define whether it can appear in an onion service INTRODUCE handshake, in a regular CREATE2 handshake, or both. We should also specify whether it can appear in a client→server extension, a server→client extension, or both.

Under this scheme, our unified set of extensions would become:

TypeSent byNameCreate?Introduce?
1ClientCC_REQUESTYY
2ServiceCC_RESPONSEYN
2ClientPOWNY
3ClientSUBPROTOYY

(Note that so long as we are using hs-ntor, there are no Service→Client extensions supported by introduce messages.)

Future directions

We may want to eventually use ntorv3 or its successors with onion services, so that responses can include extensions. That is a separate proposal.

In a future circuit handshake, we may want to add support for extensions longer than 255 bytes. This only makes sense once we have fragmented messages; it might be a logical part of any postquantum circuit handshake.