pq_ratchet/lib.rs
1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3//! # pq-ratchet
4//!
5//! Post-quantum hybrid double ratchet. ML-KEM-768 meets X25519.
6//!
7//! Signal added post-quantum resistance to their protocol in 2023 with the SPQR
8//! deployment. This crate implements the same SCKA epoch model: tie an ML-KEM-768
9//! round-trip to each DH ratchet step so the symmetric chain handles reordering
10//! like it always did. An attacker has to break X25519 AND ML-KEM-768 to touch
11//! any session key.
12//!
13//! ## What you get
14//!
15//! A key derivation state machine. Not encryption, not transport, not initial
16//! key agreement. You bring ChaCha20-Poly1305 or AES-256-GCM for the AEAD layer
17//! and whatever wire protocol you use. This crate derives the keys.
18//!
19//! ## Usage
20//!
21//! ```no_run
22//! use pq_ratchet::HybridRatchet;
23//!
24//! // Shared secret from PQXDH or X3DH
25//! let shared_secret = [0u8; 32];
26//! let mut rng = rand::thread_rng();
27//!
28//! let bob_dh_sk = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
29//! let bob_dh_pk = x25519_dalek::PublicKey::from(&bob_dh_sk);
30//!
31//! let mut alice = HybridRatchet::init_sender(&shared_secret, bob_dh_pk.as_bytes(), &mut rng);
32//! let mut bob = HybridRatchet::init_receiver(&shared_secret, bob_dh_sk, &mut rng);
33//!
34//! let (header, mk) = alice.ratchet_encrypt(&mut rng).unwrap();
35//! let mk2 = bob.ratchet_decrypt(&header, &mut rng).unwrap();
36//! assert_eq!(mk.as_bytes(), mk2.as_bytes());
37//! ```
38//!
39//! ## Key confirmation
40//!
41//! There's no explicit handshake to verify both sides derived the same keys.
42//! This matches Signal's design. You confirm implicitly: if AEAD decryption
43//! succeeds, the keys matched. If it fails, the session is out of sync or
44//! someone's tampering with your traffic. Surface those failures. Don't
45//! silently retry.
46//!
47//! ## Performance
48//!
49//! ML-KEM-768 key generation is the expensive part (triggered at each DH ratchet
50//! step). Run `cargo bench` to measure on your hardware. Within-epoch encrypt
51//! is just HKDF-SHA256. Cheap.
52//!
53//! ## Security
54//!
55//! Not independently audited. The underlying `ml-kem` crate isn't either.
56//! Don't deploy without a review.
57//!
58//! [Signal Double Ratchet]: https://signal.org/docs/specifications/doubleratchet/
59
60mod error;
61mod kdf;
62mod ratchet;
63mod scka;
64
65pub use error::RatchetError;
66pub use ratchet::{Header, HybridRatchet, MessageKey, MAX_SKIP, MAX_SKIP_TOTAL};
67pub use scka::{PqCt, PqEk, PQ_CT_LEN, PQ_DK_LEN, PQ_EK_LEN, PQ_SS_LEN};