LPsLux Proposals
Post-Quantum Cryptography
LP-2212

PQ MLS Group Chat Profile

Draft

PQ MLS Group Chat Profile for LuxDA Bus and Lux Network

Category
Core
Created
2026-01-02

Abstract

This LP defines the post-quantum MLS (Messaging Layer Security) profile for LuxDA Bus group chat, specifying algorithm selection and extensions for PQ security.

Motivation

MLS (RFC 9420) provides scalable group encryption but its default cipher suites use classical cryptography. This LP:

  1. Defines PQ-safe cipher suites for MLS
  2. Specifies hybrid KEM construction for TreeKEM
  3. Ensures backward compatibility during migration

Specification

1. PQ Cipher Suites

type MLSCipherSuite uint16

const (
    // Classical (for compatibility)
    MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519        MLSCipherSuite = 0x0001
    MLS_128_DHKEMP256_AES128GCM_SHA256_P256             MLSCipherSuite = 0x0002

    // Hybrid PQ (recommended)
    MLS_128_XWING_AES128GCM_SHA256_MLDSA65              MLSCipherSuite = 0x0100
    MLS_256_XWING_AES256GCM_SHA512_MLDSA87              MLSCipherSuite = 0x0101

    // Pure PQ (future)
    MLS_128_MLKEM768_AES128GCM_SHA256_MLDSA65           MLSCipherSuite = 0x0200
    MLS_256_MLKEM1024_AES256GCM_SHA512_MLDSA87          MLSCipherSuite = 0x0201
)

2. Default Suite

// LuxDA Bus default cipher suite
var DefaultMLSCipherSuite = MLS_128_XWING_AES128GCM_SHA256_MLDSA65

3. Hybrid HPKE Construction

MLS uses HPKE for encryption. We define hybrid HPKE:

type HybridHPKE struct {
    ClassicalKEM  *X25519KEM
    PQKEM         *MLKEM768
}

// Encapsulate produces hybrid ciphertext
func (h *HybridHPKE) Encapsulate(pk *HybridPublicKey) (
    ct []byte,      // X25519 ct || ML-KEM ct
    ss []byte,      // Combined shared secret
    err error,
) {
    // X25519 encapsulation
    ctClassical, ssClassical, _ := h.ClassicalKEM.Encapsulate(pk.Classical)

    // ML-KEM encapsulation
    ctPQ, ssPQ, _ := h.PQKEM.Encapsulate(pk.PQ)

    // Combine ciphertexts
    ct = append(ctClassical, ctPQ...)

    // Combine secrets with domain separation
    ss = hkdf.Extract(sha256.New,
        append(ssClassical, ssPQ...),
        []byte("HybridHPKE"))

    return ct, ss, nil
}

4. TreeKEM with Hybrid Keys

type TreeKEMNode struct {
    PublicKey    *HybridPublicKey
    PrivateKey   *HybridPrivateKey  // Only for path nodes
    ParentHash   [32]byte
    UnmergedLeaves []LeafIndex
}

type HybridPublicKey struct {
    Classical  *X25519PublicKey
    PQ         *MLKEMPublicKey
}

type HybridPrivateKey struct {
    Classical  *X25519PrivateKey
    PQ         *MLKEMPrivateKey
}

5. Key Package Extension

type PQKeyPackage struct {
    // Standard MLS fields
    ProtocolVersion  ProtocolVersion
    CipherSuite      MLSCipherSuite
    InitKey          *HybridPublicKey
    LeafNode         LeafNode

    // PQ extensions
    Extensions       []Extension
    Signature        []byte  // ML-DSA signature
}

// PQ Extension types
const (
    ExtPQCapabilities  ExtensionType = 0xFF01
    ExtPQPreferences   ExtensionType = 0xFF02
)

type PQCapabilities struct {
    SupportedSuites    []MLSCipherSuite
    PreferredSuite     MLSCipherSuite
    ClassicalFallback  bool
}

6. Commit Message Signing

type MLSCommit struct {
    Proposals      []ProposalRef
    Path           *UpdatePath

    // Signed with ML-DSA
    Signature      []byte
}

func SignCommit(commit *MLSCommit, sigKey *MLDSAPrivateKey) error {
    // Compute commit content
    content := commit.Serialize()

    // Sign with ML-DSA-65
    sig, err := mldsa.Sign(sigKey, content)
    if err != nil {
        return err
    }

    commit.Signature = sig
    return nil
}

7. Welcome Message Encryption

type PQWelcome struct {
    CipherSuite    MLSCipherSuite
    Secrets        []EncryptedGroupSecrets

    // Each secret encrypted with hybrid HPKE
    // to the recipient's KeyPackage init key
}

type EncryptedGroupSecrets struct {
    NewMember      KeyPackageRef
    EncryptedData  []byte  // Hybrid HPKE ciphertext
}

8. Group State

type PQGroupState struct {
    GroupID        GroupID
    Epoch          uint64
    CipherSuite    MLSCipherSuite
    Tree           *TreeKEMTree

    // Derived secrets
    EpochSecret    [32]byte
    SenderDataSecret [32]byte
    EncryptionSecret [32]byte

    // Authentication keys
    ConfirmationKey [32]byte
    MembershipKey   [32]byte
}

9. Migration Support

type MigrationProposal struct {
    Type           ProposalType  // ReInit
    GroupID        GroupID
    ProtocolVersion ProtocolVersion
    CipherSuite    MLSCipherSuite  // New PQ suite
    Extensions     []Extension
}

// Migrate group from classical to PQ suite
func ProposeMLSMigration(
    group *MLSGroup,
    targetSuite MLSCipherSuite,
) (*MigrationProposal, error)

10. Performance Considerations

OperationClassicalHybrid PQOverhead
KeyPackage size200 B2.5 KB12.5x
Welcome size500 B3 KB6x
Commit size1 KB4 KB4x
TreeKEM update2 ms15 ms7.5x

Security Considerations

  1. Hybrid approach: Both classical and PQ must be broken
  2. Forward secrecy: TreeKEM ratcheting provides FS per epoch
  3. Post-compromise security: Adding/removing members heals tree
  4. Signature security: ML-DSA provides PQ authentication
  5. Large key sizes: May impact mobile bandwidth; consider compression

Test Plan

  1. Interoperability with reference MLS implementations
  2. Group operations (add, remove, update) with PQ suite
  3. Migration from classical to PQ suite
  4. Performance benchmarks on various group sizes
  5. Memory usage profiling

References

  • RFC 9420: Messaging Layer Security (MLS)
  • LP-6462: Group Chat
  • LP-2200: PQ Crypto SDK

LP-2212 v1.0.0 - 2026-01-02