1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//! # 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
//!
//! ```no_run
//! 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.
//!
//! [Signal Double Ratchet]: https://signal.org/docs/specifications/doubleratchet/
pub use RatchetError;
pub use ;
pub use ;