On Mon, Jul 06, 2026 at 07:23:41PM -0400, Nick Sullivan wrote:
> Dear TLS,
> 
> I'm sharing a draft for the group's consideration.
> draft-sullivan-tls-xof-ciphers-00 runs the entire TLS 1.3 key schedule
> on a single Keccak permutation, instead of HKDF built on HMAC built on
> the cipher suite's hash, which today is always SHA-2. This is newly
> practical because deployments using SHA-3, ML-KEM, or ML-DSA already
> carry a Keccak permutation, so the primitive is already in the stack.

This looks pretty complicated.

I came up with the following design for high-performance TLS 1.3 key
schedule based on (Turbo)Keccak:

- Start with a XOF. XOF(input,len) invokes XOF on input and returns
  len bytes of output. XOFid is identifier for the XOF. For performance,
  it should be 8 bytes. I think XOF should be (Turbo)Shake256.

- XOFs do not have natural output length. So let L be some fixed length.
  For performance, L should be multiple of 8 at most 48. This is also
  used as Hash.length. I think L should be 48.

- But L might not be suitable length for binders. So let Lb be length of
  binder. I think Lb should be 32.

- For performance, extra derives for rachet should be avoided, and XOF
  can cheaply give 2L byte output, so let state consist of two L byte
  subkeys. Left(x) gives the first subkey, and Right(x) gives the
  second.

- For compatibility with things like QUIC, Right(x) can also be applied
  to L byte string, yielding x.

- Let Rachet(x,input) = XOF(XOFid||Left(x)||input, 2*L).
  This operation mixes in input and irreversibly mixes it, acting like
  combination of HKDF-Extract and Derive-Secret("derived").

- Transcript hash is XOF(messages,L).

- Let Output(x,label,context,len) = XOF(Right(x)||HkdfLabel,len).
  HkdfLabel is as in section 7.1 of RFC8446. This acts like
  HKDF-Expand-Label in RFC 8446.

- The key schedule from RFC8446 is modified as follows:

  * All HKDF-Extract are replaced by Rachet.
  * All "derived" operations are removed (since Rachet already
    does the equivalent).
  * All HKDF-Expand-Label are replaced by Output.
  * All transcript hashes of "" are replaced by empty context.
    (binder_key, TLS-Exporter labels)
  * All traffic secrets have length 2*L (since those are states, the
    early/handshake ones never use the first L bytes, but that is
    ~free).
  * verify_data is computed as Output(BaseKey,"finished",transcript,Lb).
    (Directly in one step, instead of expand+MAC).
  * Traffic secrets are racheted by using Rachet with empty input
    (instead of HKDF-Expand-Label. EKU could use non-empty input).
  * AEAD key material is computed as
    write_key||write_iv = Output(traffic_secret,"key",len).
    (generating the whole thing in one go, instead of separate
    "key"/"iv" derivations).

- Extracting traffic secret (e.g. for QUIC) gives Right(traffic_secret).
  Because Output works with L byte keys, the application can use Output.


Ignoring the transcript and assuming no PSK, I count that this needs
15 decks on both sides (3 for rachets, 8 for encryption keys, 2 for
finished, 1 for exporters and 1 for resumption).


Even if this is closer to the existing key schedule than
draft-sullivan-tls-xof-ciphers, it still could be very problematic to
implement (I have not even tried to do that) and of course needs a new
security proof.




-Ilari

_______________________________________________
TLS mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to