libcrux_psq/lib.rs
1//! # PQ-PSK
2//!
3//! This crate implements a protocol for establishing and mutually
4//! registering a PQ-PSK between an initiator and a responder.
5//!
6//! ```rust
7//! use rand::RngCore;
8//! use libcrux_ml_kem::mlkem768::MlKem768KeyPair;
9//! use tls_codec::{Serialize, Deserialize};
10//! use libcrux_psq::{
11//! handshake::{builders::*, ciphersuites::*, types::*, HandshakeError},
12//! session::{Session, SessionError, SessionBinding},
13//! Channel, IntoSession,
14//! };
15//!
16//! let mut rng = rand::rng();
17//!
18//! // External setup: Responder keys
19//! let responder_mlkem_keys = libcrux_ml_kem::mlkem768::rand::generate_key_pair(&mut rng);
20//!
21//! let responder_ecdh_keys = DHKeyPair::new(&mut rng);
22//!
23//! // External setup: Initiator keys
24//! let initiator_ecdh_keys = DHKeyPair::new(&mut rng);
25//!
26//! let ctx = b"Test Context";
27//! let aad_initiator_query = b"Test Data Initiator Query";
28//! let aad_initiator_outer = b"Test Data I Outer";
29//! let aad_initiator_inner = b"Test Data I Inner";
30//! let aad_responder = b"Test Data R";
31//!
32//! let mut msg_channel = vec![0u8; 4096];
33//! let mut payload_buf_responder = vec![0u8; 4096];
34//! let mut payload_buf_initiator = vec![0u8; 4096];
35//!
36//! let responder_ciphersuite_id = CiphersuiteName::X25519_MLKEM768_X25519_CHACHA20POLY1305_HKDFSHA256;
37//!
38//! // Setup query initiator
39//! let mut query_initiator = PrincipalBuilder::new(rand::rng())
40//! .outer_aad(aad_initiator_query)
41//! .context(ctx)
42//! .build_query_initiator(&responder_ecdh_keys.pk)
43//! .unwrap();
44//!
45//! // Setup responder
46//! let mut responder_ciphersuite = CiphersuiteBuilder::new(responder_ciphersuite_id)
47//! .longterm_x25519_keys(&responder_ecdh_keys)
48//! .longterm_mlkem_encapsulation_key(responder_mlkem_keys.public_key())
49//! .longterm_mlkem_decapsulation_key(responder_mlkem_keys.private_key())
50//! .build_responder_ciphersuite().unwrap();
51//!
52//! let mut responder = PrincipalBuilder::new(rand::rng())
53//! .context(ctx)
54//! .outer_aad(aad_responder)
55//! .recent_keys_upper_bound(30)
56//! .build_responder(responder_ciphersuite).unwrap();
57//!
58//! // Query the responder for its ciphersuite
59//! let query_payload_initiator = b"Query_init"; // This message is application defined
60//! let len_i = query_initiator
61//! .write_message(query_payload_initiator, &mut msg_channel)
62//! .unwrap();
63//!
64//! // Read first message at the responder
65//! let (len_r_deserialized, len_r_payload) = responder
66//! .read_message(&msg_channel, &mut payload_buf_responder)
67//! .unwrap();
68//!
69//! // Respond
70//! let query_payload_responder = responder_ciphersuite_id.tls_serialize_detached().unwrap();
71//! let len_r = responder
72//! .write_message(&query_payload_responder, &mut msg_channel)
73//! .unwrap();
74//!
75//! // Finalize on query initiator
76//! let (len_i_deserialized, len_i_payload) = query_initiator
77//! .read_message(&msg_channel, &mut payload_buf_initiator)
78//! .unwrap();
79//!
80//! let responder_ciphersuite_id_received = CiphersuiteName::tls_deserialize(&mut std::io::Cursor::new(&payload_buf_initiator)).unwrap();
81//!
82//! assert_eq!(responder_ciphersuite_id, responder_ciphersuite_id_received);
83//!
84//! // Setup Registration initiator with received ciphersuite
85//! let initiator_ciphersuite = CiphersuiteBuilder::new(responder_ciphersuite_id_received)
86//! .longterm_x25519_keys(&initiator_ecdh_keys)
87//! .peer_longterm_x25519_pk(&responder_ecdh_keys.pk)
88//! .peer_longterm_mlkem_pk(responder_mlkem_keys.public_key())
89//! .build_initiator_ciphersuite().unwrap();
90//!
91//! let mut initiator = PrincipalBuilder::new(rand::rng())
92//! .outer_aad(aad_initiator_outer)
93//! .inner_aad(aad_initiator_inner)
94//! .context(ctx)
95//! .build_registration_initiator(initiator_ciphersuite).unwrap();
96//!
97//! // Send first message
98//! let registration_payload_initiator = b"Registration_init";
99//! let len_i = initiator.write_message(registration_payload_initiator, &mut msg_channel).unwrap();
100//!
101//! // Read first message
102//! let (len_r_deserialized, len_r_payload) =
103//! responder.read_message(&msg_channel, &mut payload_buf_responder).unwrap();
104//!
105//! // Respond
106//! let registration_payload_responder = b"Registration_respond";
107//! let len_r = responder.write_message(registration_payload_responder, &mut msg_channel).unwrap();
108//!
109//! // Finalize on registration initiator
110//! let (len_i_deserialized, len_i_payload) =
111//! initiator.read_message(&msg_channel, &mut payload_buf_initiator).unwrap();
112//!
113//! // Ready for transport mode
114//! assert!(initiator.is_handshake_finished());
115//! assert!(responder.is_handshake_finished());
116//!
117//! let i_transport = initiator.into_session().unwrap();
118//! let mut r_transport = responder.into_session().unwrap();
119//!
120//! // test serialization, deserialization
121//! let mut session_storage = vec![0u8; 4096];
122//! i_transport.serialize(&mut session_storage,
123//! SessionBinding {
124//! initiator_authenticator: &(&initiator_ecdh_keys.pk).authenticator(),
125//! responder_ecdh_pk: &responder_ecdh_keys.pk,
126//! responder_pq_pk: Some(responder_mlkem_keys.public_key().into())
127//! }).unwrap();
128//!
129//! let mut i_transport = Session::deserialize(
130//! &session_storage,
131//! SessionBinding {
132//! initiator_authenticator: &(&initiator_ecdh_keys.pk).authenticator(),
133//! responder_ecdh_pk: &responder_ecdh_keys.pk,
134//! responder_pq_pk: Some(responder_mlkem_keys.public_key().into())
135//! }
136//! ).unwrap();
137//!
138//! let mut channel_i = i_transport.transport_channel().unwrap();
139//! let mut channel_r = r_transport.transport_channel().unwrap();
140//!
141//! assert_eq!(channel_i.identifier(), channel_r.identifier());
142//!
143//! let app_data_i = b"Derived session hey".as_slice();
144//! let app_data_r = b"Derived session ho".as_slice();
145//!
146//! let len_i = channel_i.write_message(app_data_i, &mut msg_channel).unwrap();
147//!
148//! let (len_r_deserialized, len_r_payload) =
149//! channel_r.read_message(&msg_channel, &mut payload_buf_responder).unwrap();
150//!
151//! let len_r = channel_r.write_message(app_data_r, &mut msg_channel).unwrap();
152//!
153//! let (len_i_deserialized, len_i_payload) =
154//! channel_i.read_message(&msg_channel, &mut payload_buf_initiator).unwrap();
155//! ```
156
157#![warn(missing_docs)]
158
159mod aead;
160pub mod handshake;
161pub mod session;
162mod traits;
163
164#[doc(inline)]
165pub use traits::{Channel, IntoSession};
166
167#[cfg(feature = "v1")]
168pub mod v1;
169
170#[cfg(feature = "classic-mceliece")]
171pub mod classic_mceliece;