Blog

July 10, 2025 · Release · 9 min read

SecTLS: TLS 1.3 and QUIC with hybrid post-quantum key exchange

SecTLS is our TLS 1.3 and QUIC library with X25519+ML-KEM-768 hybrid key exchange. We describe its architecture and API, a phased migration path, and benchmarks against rustls and OpenSSL.

TLS protects virtually all internet communication: web browsing, API calls, email. Moving it to post-quantum cryptography has to happen without breaking compatibility with existing infrastructure.

SecTLS is our from-scratch implementation of TLS 1.3 and QUIC, built with post-quantum security as a core requirement rather than an afterthought.

Hybrid key exchange

The cryptographic community has reached consensus on a hybrid approach for the transition, combining classical and post-quantum key exchange for defense in depth:

Hybrid Shared Secret = HKDF(ECDH_Secret || ML-KEM_Secret)

The hybrid approach stays secure even if:

  • the post-quantum algorithm is later found vulnerable
  • the classical algorithm is broken by quantum computers
  • an implementation bug affects one component

SecTLS uses X25519 with ML-KEM-768, following the emerging IETF standards.

Cipher suites

SecTLS supports all mandatory TLS 1.3 cipher suites plus post-quantum hybrids:

Cipher SuiteKey ExchangeStatus
TLS_AES_256_GCM_SHA384X25519Standard
TLS_AES_128_GCM_SHA256X25519Standard
TLS_CHACHA20_POLY1305_SHA256X25519Standard
TLS_AES_256_GCM_SHA384X25519+ML-KEM-768Hybrid PQ
TLS_AES_128_GCM_SHA256X25519+ML-KEM-768Hybrid PQ

Architecture

Protocol and crypto layers

SecTLS separates cryptographic operations from protocol logic:

// Protocol layer - no crypto details
pub struct TlsConnection<T: Transport> {
    state: HandshakeState,
    transport: T,
    record_layer: RecordLayer,
}

// Crypto layer - pluggable implementations
pub trait CryptoProvider {
    type Kex: KeyExchange;
    type Aead: AuthenticatedEncryption;
    type Hash: HashFunction;
}

// Default provider uses OpenCrypt
pub struct OpenCryptProvider;

This allows easy algorithm upgrades, FIPS-validated crypto backends and HSM integration.

Zero-copy record processing

Records are processed without unnecessary memory copies:

// Traditional approach: multiple copies
let encrypted = read_record(&mut socket)?;       // Copy 1
let decrypted = decrypt(&encrypted, &key)?;      // Copy 2
let plaintext = remove_padding(&decrypted)?;     // Copy 3

// SecTLS: in-place processing
let mut buffer = read_record_into(&mut socket, &mut scratch)?;
decrypt_in_place(&mut buffer, &key)?;            // Single buffer
let plaintext = &buffer[..payload_len];          // Zero-copy view

This reduces memory bandwidth by 3x and improves cache utilization.

QUIC

SecTLS has native QUIC support with post-quantum key exchange:

use sectls::quic::{QuicConfig, QuicConnection};

let config = QuicConfig::builder()
    .with_hybrid_key_exchange(true)
    .with_certificate_chain(certs)
    .with_private_key(key)
    .build()?;

// Server
let mut listener = QuicListener::bind("0.0.0.0:443", config).await?;
while let Some(conn) = listener.accept().await {
    tokio::spawn(handle_connection(conn));
}

// Client
let conn = QuicConnection::connect("example.com:443", config).await?;
let (mut send, mut recv) = conn.open_bidirectional_stream().await?;

QUIC performance

Hybrid key exchange adds minimal overhead to QUIC handshakes:

MetricStandard QUICHybrid PQ QUICOverhead
0-RTT Handshake0ms0ms0%
1-RTT Handshake1.2ms1.4ms17%
Key Share Size32 bytes1,216 bytes+1,184 bytes
Throughput4.2 Gbps4.1 Gbps2%

The larger key share is amortized over the connection lifetime.

Migration strategy

Phase 1: dual-stack deployment

Start by deploying SecTLS alongside existing infrastructure:

// Accept both classical and hybrid connections
let config = TlsConfig::builder()
    .prefer_hybrid_key_exchange(true)
    .allow_classical_fallback(true)
    .build()?;

Phase 2: hybrid-first

Once client support is widespread:

let config = TlsConfig::builder()
    .require_hybrid_key_exchange(true)
    .build()?;

Phase 3: full post-quantum

When confidence in post-quantum algorithms matures:

let config = TlsConfig::builder()
    .require_post_quantum_only(true)  // ML-KEM without classical
    .build()?;

API examples

HTTPS server

use sectls::{TlsAcceptor, TlsConfig};
use tokio::net::TcpListener;

#[tokio::main]
async fn main() -> Result<()> {
    let config = TlsConfig::builder()
        .with_certificate_chain_file("cert.pem")?
        .with_private_key_file("key.pem")?
        .with_hybrid_key_exchange(true)
        .build()?;

    let acceptor = TlsAcceptor::new(config);
    let listener = TcpListener::bind("0.0.0.0:443").await?;

    loop {
        let (stream, _) = listener.accept().await?;
        let acceptor = acceptor.clone();

        tokio::spawn(async move {
            let tls_stream = acceptor.accept(stream).await?;
            handle_request(tls_stream).await
        });
    }
}

Client with certificate verification

use sectls::{TlsConnector, TlsConfig};

let config = TlsConfig::builder()
    .with_native_roots()  // Use system CA certificates
    .with_hybrid_key_exchange(true)
    .with_alpn_protocols(&["h2", "http/1.1"])
    .build()?;

let connector = TlsConnector::new(config);
let stream = TcpStream::connect("example.com:443").await?;
let tls_stream = connector.connect("example.com", stream).await?;

// Connection is now quantum-resistant

Security properties

SecTLS provides these guarantees:

  • Forward secrecy: compromised long-term keys don't reveal past session keys.
  • Post-quantum confidentiality: encrypted data stays confidential even against quantum adversaries.
  • Authentication: certificates verify the server's identity, and optionally the client's.
  • Integrity: AEAD authenticates every record, preventing tampering.
  • Replay protection: each connection uses unique session keys and nonces.

Benchmarks

Measured on an AMD Ryzen 9 7950X:

OperationSecTLS (Hybrid)rustlsOpenSSL
Full Handshake1.8ms1.2ms1.1ms
Resumed Handshake0.4ms0.3ms0.3ms
Encrypt 1KB0.8μs0.9μs0.7μs
Decrypt 1KB0.8μs0.9μs0.7μs
Throughput4.1 Gbps4.3 Gbps4.5 Gbps

The 50% handshake overhead comes mostly from the larger key shares, and is acceptable for most applications given the security benefit.

Installation

SecTLS is available now on GitHub:

# Add to Cargo.toml
[dependencies]
sectls = "0.1"

# Or with QUIC support
sectls = { version = "0.1", features = ["quic"] }

Detailed documentation, migration guides and example applications are included.

Planned features

  • Certificate Transparency: integration with CT logs for hybrid certificates
  • Encrypted Client Hello: privacy protection for SNI
  • Hardware acceleration: PKCS#11 and TPM support for key storage

Questions about this post, or working on something similar? Book a meeting.