Invert order of keys as per draft

This commit is contained in:
riccardom
2026-08-27 12:18:07 +02:00
parent d29faa7f46
commit 1cab588bc0
+11 -9
View File
@@ -12,10 +12,11 @@
// (their peer identity keys) so the derived key cannot be transplanted // (their peer identity keys) so the derived key cannot be transplanted
// to a different peer pair even if the transport authentication were bypassed. // to a different peer pair even if the transport authentication were bypassed.
// //
// Combiner note: this follows the IETF hybrid layout (X25519 ‖ ML-KEM on the // Combiner note: this follows draft-ietf-tls-ecdhe-mlkem for X25519MLKEM768 — on
// wire; ML-KEM_ss ‖ X25519_ss into the KDF) from // the wire ML-KEM ‖ X25519 (the draft deliberately reversed the share order for
// draft-kwiatkowski-tls-ecdhe-mlkem. The spike uses SHA-256 as the KDF; a // this group), and ML-KEM_ss ‖ X25519_ss fed into the KDF. The spike uses SHA-256
// production version should use HKDF with the RFC labels — see TODO below. // (also binding the transcript and peer identities); a production version should
// use HKDF — see TODO below.
package pqkem package pqkem
import ( import (
@@ -27,8 +28,9 @@ import (
) )
const ( const (
// OfferSize is the initiator message: X25519 public key ‖ ML-KEM-768 encapsulation key. // OfferSize is the initiator message: ML-KEM-768 encapsulation key ‖ X25519 public key
OfferSize = 32 + mlkem.EncapsulationKeySize768 // 1216 // (share order per draft-ietf-tls-ecdhe-mlkem for X25519MLKEM768).
OfferSize = mlkem.EncapsulationKeySize768 + 32 // 1216
// AnswerSize is the responder message: ML-KEM-768 ciphertext ‖ X25519 public key. // AnswerSize is the responder message: ML-KEM-768 ciphertext ‖ X25519 public key.
AnswerSize = mlkem.CiphertextSize768 + 32 // 1120 AnswerSize = mlkem.CiphertextSize768 + 32 // 1120
@@ -64,8 +66,8 @@ func NewInitiator() (*Initiator, error) {
} }
offer := make([]byte, 0, OfferSize) offer := make([]byte, 0, OfferSize)
offer = append(offer, x.PublicKey().Bytes()...)
offer = append(offer, dk.EncapsulationKey().Bytes()...) offer = append(offer, dk.EncapsulationKey().Bytes()...)
offer = append(offer, x.PublicKey().Bytes()...)
return &Initiator{x25519: x, mlkemDK: dk, offer: offer}, nil return &Initiator{x25519: x, mlkemDK: dk, offer: offer}, nil
} }
@@ -104,8 +106,8 @@ func Respond(offer []byte, b Binding) (answer []byte, psk PSK, err error) {
if len(offer) != OfferSize { if len(offer) != OfferSize {
return nil, PSK{}, fmt.Errorf("offer: got %d bytes, want %d", len(offer), OfferSize) return nil, PSK{}, fmt.Errorf("offer: got %d bytes, want %d", len(offer), OfferSize)
} }
peerX := offer[:32] peerEK := offer[:mlkem.EncapsulationKeySize768]
peerEK := offer[32:] peerX := offer[mlkem.EncapsulationKeySize768:]
ek, err := mlkem.NewEncapsulationKey768(peerEK) ek, err := mlkem.NewEncapsulationKey768(peerEK)
if err != nil { if err != nil {