libsignal_protocol/
ratchet.rs1mod keys;
7
8use rand::{CryptoRng, Rng};
9
10pub(crate) use self::keys::{ChainKey, MessageKeyGenerator, RootKey};
11use crate::handshake::Handshake;
12use crate::pqxdh::{HandshakeKeys, Pqxdh};
13pub use crate::pqxdh::{InitiatorParameters, RecipientParameters};
16use crate::protocol::CIPHERTEXT_MESSAGE_CURRENT_VERSION;
17use crate::state::SessionState;
18use crate::{KeyPair, Result, SessionRecord, SignalProtocolError, consts};
19
20#[doc(hidden)]
23pub type AliceSignalProtocolParameters = InitiatorParameters;
24#[doc(hidden)]
25pub type BobSignalProtocolParameters<'a> = RecipientParameters<'a>;
26
27fn spqr_chain_params(self_connection: bool) -> spqr::ChainParams {
28 #[allow(clippy::needless_update)]
29 spqr::ChainParams {
30 max_jump: if self_connection {
31 u32::MAX
32 } else {
33 consts::MAX_FORWARD_JUMPS.try_into().expect("should be <4B")
34 },
35 max_ooo_keys: consts::MAX_MESSAGE_KEYS.try_into().expect("should be <4B"),
36 ..Default::default()
37 }
38}
39
40pub(crate) fn initialize_alice_session<R: Rng + CryptoRng>(
45 parameters: &InitiatorParameters,
46 csprng: &mut R,
47) -> Result<SessionState> {
48 let (
49 kyber_ciphertext,
50 HandshakeKeys {
51 root_key,
52 chain_key,
53 pqr_key,
54 },
55 ) = Pqxdh::initiate(parameters, csprng)?;
56
57 initialize_initiator_session(
58 parameters,
59 root_key,
60 chain_key,
61 pqr_key,
62 kyber_ciphertext,
63 csprng,
64 )
65}
66
67fn initialize_initiator_session<R: Rng + CryptoRng>(
68 parameters: &InitiatorParameters,
69 root_key: RootKey,
70 chain_key: ChainKey,
71 pqr_key: [u8; 32],
72 kyber_ciphertext: crate::kem::SerializedCiphertext,
73 csprng: &mut R,
74) -> Result<SessionState> {
75 let local_identity = parameters.our_identity_key_pair().identity_key();
76
77 let sending_ratchet_key = KeyPair::generate(csprng);
78 let (sending_chain_root_key, sending_chain_chain_key) = root_key.create_chain(
79 parameters.their_ratchet_key(),
80 &sending_ratchet_key.private_key,
81 )?;
82
83 let pqr_state = spqr::initial_state(spqr::Params {
84 auth_key: &pqr_key,
85 version: spqr::Version::V1,
86 direction: spqr::Direction::A2B,
87 min_version: spqr::Version::V1, chain_params: spqr_chain_params(parameters.self_session()),
89 })
90 .map_err(|e| {
91 SignalProtocolError::InvalidArgument(format!(
94 "post-quantum ratchet: error creating initial A2B state: {e}"
95 ))
96 })?;
97
98 let mut session = SessionState::new(
99 CIPHERTEXT_MESSAGE_CURRENT_VERSION,
100 local_identity,
101 parameters.their_identity_key(),
102 &sending_chain_root_key,
103 ¶meters.our_ephemeral_key_pair().public_key,
104 pqr_state,
105 )
106 .with_receiver_chain(parameters.their_ratchet_key(), &chain_key)
107 .with_sender_chain(&sending_ratchet_key, &sending_chain_chain_key);
108
109 session.set_kyber_ciphertext(kyber_ciphertext);
110
111 Ok(session)
112}
113
114pub(crate) fn initialize_bob_session(
119 parameters: &RecipientParameters,
120 our_ratchet_key_pair: &KeyPair,
121) -> Result<SessionState> {
122 let HandshakeKeys {
123 root_key,
124 chain_key,
125 pqr_key,
126 } = Pqxdh::accept(parameters)?;
127
128 initialize_recipient_session(
129 parameters,
130 our_ratchet_key_pair,
131 root_key,
132 chain_key,
133 pqr_key,
134 )
135}
136
137fn initialize_recipient_session(
138 parameters: &RecipientParameters,
139 our_ratchet_key_pair: &KeyPair,
140 root_key: RootKey,
141 chain_key: ChainKey,
142 pqr_key: [u8; 32],
143) -> Result<SessionState> {
144 let local_identity = parameters.our_identity_key_pair().identity_key();
145
146 let pqr_state = spqr::initial_state(spqr::Params {
147 auth_key: &pqr_key,
148 version: spqr::Version::V1,
149 direction: spqr::Direction::B2A,
150 min_version: spqr::Version::V1, chain_params: spqr_chain_params(parameters.self_session()),
152 })
153 .map_err(|e| {
154 SignalProtocolError::InvalidArgument(format!(
157 "post-quantum ratchet: error creating initial B2A state: {e}"
158 ))
159 })?;
160
161 let session = SessionState::new(
162 CIPHERTEXT_MESSAGE_CURRENT_VERSION,
163 local_identity,
164 parameters.their_identity_key(),
165 &root_key,
166 parameters.their_ephemeral_key(),
167 pqr_state,
168 )
169 .with_sender_chain(our_ratchet_key_pair, &chain_key);
170
171 Ok(session)
172}
173
174pub fn initialize_alice_session_record<R: Rng + CryptoRng>(
175 parameters: &InitiatorParameters,
176 csprng: &mut R,
177) -> Result<SessionRecord> {
178 Ok(SessionRecord::new(initialize_alice_session(
179 parameters, csprng,
180 )?))
181}
182
183pub fn initialize_bob_session_record(
184 parameters: &RecipientParameters,
185 our_ratchet_key_pair: &KeyPair,
186) -> Result<SessionRecord> {
187 Ok(SessionRecord::new(initialize_bob_session(
188 parameters,
189 our_ratchet_key_pair,
190 )?))
191}