Skip to main content

Crate pq_ratchet

Crate pq_ratchet 

Source
Expand description

§pq-ratchet

Post-quantum hybrid double ratchet. ML-KEM-768 meets X25519.

Signal added post-quantum resistance to their protocol in 2023 with the SPQR deployment. This crate implements the same SCKA epoch model: tie an ML-KEM-768 round-trip to each DH ratchet step so the symmetric chain handles reordering like it always did. An attacker has to break X25519 AND ML-KEM-768 to touch any session key.

§What you get

A key derivation state machine. Not encryption, not transport, not initial key agreement. You bring ChaCha20-Poly1305 or AES-256-GCM for the AEAD layer and whatever wire protocol you use. This crate derives the keys.

§Usage

use pq_ratchet::HybridRatchet;

// Shared secret from PQXDH or X3DH
let shared_secret = [0u8; 32];
let mut rng = rand::thread_rng();

let bob_dh_sk = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let bob_dh_pk = x25519_dalek::PublicKey::from(&bob_dh_sk);

let mut alice = HybridRatchet::init_sender(&shared_secret, bob_dh_pk.as_bytes(), &mut rng);
let mut bob   = HybridRatchet::init_receiver(&shared_secret, bob_dh_sk, &mut rng);

let (header, mk) = alice.ratchet_encrypt(&mut rng).unwrap();
let mk2 = bob.ratchet_decrypt(&header, &mut rng).unwrap();
assert_eq!(mk.as_bytes(), mk2.as_bytes());

§Key confirmation

There’s no explicit handshake to verify both sides derived the same keys. This matches Signal’s design. You confirm implicitly: if AEAD decryption succeeds, the keys matched. If it fails, the session is out of sync or someone’s tampering with your traffic. Surface those failures. Don’t silently retry.

§Performance

ML-KEM-768 key generation is the expensive part (triggered at each DH ratchet step). Run cargo bench to measure on your hardware. Within-epoch encrypt is just HKDF-SHA256. Cheap.

§Security

Not independently audited. The underlying ml-kem crate isn’t either. Don’t deploy without a review.

Structs§

Header
Per-message header transmitted alongside each ciphertext.
HybridRatchet
Hybrid Double Ratchet session state.
MessageKey
Single-use message key derived from the symmetric ratchet chain.
PqCt
Serialised ML-KEM-768 ciphertext (1088 bytes, carried in ratchet headers).
PqEk
Serialised ML-KEM-768 encapsulation key (1184 bytes, carried in ratchet headers).

Enums§

RatchetError
Errors returned by the hybrid Double Ratchet state machine.

Constants§

MAX_SKIP
Maximum skipped messages in a single chain step. Signal’s recommended value. Raise it if your transport layer reorders deeper than 1,000 messages.
MAX_SKIP_TOTAL
Hard cap on the total number of entries in the skipped-key cache across all DH epochs. Without this, a malicious peer can force unbounded memory growth by ratcheting through many epochs each with skipped messages.
PQ_CT_LEN
Byte length of an ML-KEM-768 ciphertext.
PQ_DK_LEN
Byte length of an ML-KEM-768 decapsulation key (private key, per FIPS 203 §7.2).
PQ_EK_LEN
Byte length of an ML-KEM-768 encapsulation key (public key).
PQ_SS_LEN
Byte length of the ML-KEM-768 shared secret output.