lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

ratchet.rs (57720B)


      1 use crate::error::RadrootsSimplexSmpCryptoError;
      2 use crate::message::{
      3     RADROOTS_SIMPLEX_SMP_NONCE_LENGTH, RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH, decrypt_padded,
      4     encrypt_padded,
      5 };
      6 use crate::official_ratchet::{
      7     RADROOTS_SIMPLEX_OFFICIAL_AES_IV_LENGTH, RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
      8     RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PRIVATE_KEY_LENGTH,
      9     RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PUBLIC_KEY_LENGTH,
     10     RADROOTS_SIMPLEX_OFFICIAL_X448_KEY_LENGTH, RadrootsSimplexOfficialAesGcmPayload,
     11     RadrootsSimplexOfficialEncryptedHeader, RadrootsSimplexOfficialEncryptedMessage,
     12     RadrootsSimplexOfficialMsgHeader, RadrootsSimplexOfficialSntrup761Keypair,
     13     RadrootsSimplexOfficialX3dhInit, decapsulate_official_sntrup761,
     14     decode_official_encrypted_header, decode_official_encrypted_message,
     15     decode_official_msg_header, derive_official_x448_shared_secret, encapsulate_official_sntrup761,
     16     encode_official_encrypted_header, encode_official_encrypted_message,
     17     encode_official_msg_header, generate_official_sntrup761_keypair,
     18     generate_official_x448_keypair, official_aes_gcm_decrypt_padded,
     19     official_aes_gcm_encrypt_padded, official_chain_kdf, official_ratchet_header_len,
     20     official_root_kdf,
     21 };
     22 use alloc::vec::Vec;
     23 use hkdf::Hkdf;
     24 use sha2::Sha512;
     25 
     26 const RADROOTS_SIMPLEX_AGENT_RATCHET_INFO: &[u8] = b"SimpleXAgentRatchetMessage";
     27 const RADROOTS_SIMPLEX_AGENT_RATCHET_OUTPUT_LENGTH: usize =
     28     RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH + RADROOTS_SIMPLEX_SMP_NONCE_LENGTH;
     29 const RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES: u32 = 512;
     30 
     31 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
     32 pub enum RadrootsSimplexSmpRatchetRole {
     33     Initiator,
     34     Responder,
     35 }
     36 
     37 #[derive(Debug, Clone, PartialEq, Eq)]
     38 pub struct RadrootsSimplexSmpRatchetHeader {
     39     pub previous_sending_chain_length: u32,
     40     pub message_number: u32,
     41     pub dh_public_key: Vec<u8>,
     42     pub pq_public_key: Option<Vec<u8>>,
     43     pub pq_ciphertext: Option<Vec<u8>>,
     44 }
     45 
     46 impl RadrootsSimplexSmpRatchetHeader {
     47     pub fn validate(&self) -> Result<(), RadrootsSimplexSmpCryptoError> {
     48         if self.dh_public_key.is_empty() {
     49             return Err(RadrootsSimplexSmpCryptoError::MissingRatchetKey(
     50                 "dh_public_key",
     51             ));
     52         }
     53         if self.pq_ciphertext.is_some() && self.pq_public_key.is_none() {
     54             return Err(RadrootsSimplexSmpCryptoError::IncompletePqHeader);
     55         }
     56         Ok(())
     57     }
     58 }
     59 
     60 #[derive(Debug, Clone, PartialEq, Eq)]
     61 pub struct RadrootsSimplexSmpSkippedMessageKey {
     62     pub header_key: Vec<u8>,
     63     pub message_number: u32,
     64     pub message_key: Vec<u8>,
     65     pub message_iv: [u8; RADROOTS_SIMPLEX_OFFICIAL_AES_IV_LENGTH],
     66 }
     67 
     68 #[derive(Debug, Clone, PartialEq, Eq)]
     69 pub struct RadrootsSimplexSmpRatchetState {
     70     pub role: RadrootsSimplexSmpRatchetRole,
     71     pub root_epoch: u64,
     72     pub previous_sending_chain_length: u32,
     73     pub sending_chain_length: u32,
     74     pub receiving_chain_length: u32,
     75     pub local_dh_public_key: Vec<u8>,
     76     pub remote_dh_public_key: Vec<u8>,
     77     pub current_pq_public_key: Option<Vec<u8>>,
     78     pub remote_pq_public_key: Option<Vec<u8>>,
     79     pub pending_outbound_pq_ciphertext: Option<Vec<u8>>,
     80     pub pending_inbound_pq_ciphertext: Option<Vec<u8>>,
     81     pub current_pq_shared_secret: Option<Vec<u8>>,
     82     pub local_pq_private_key: Option<Vec<u8>>,
     83     pub local_dh_private_key: Option<Vec<u8>>,
     84     pub official_associated_data: Option<Vec<u8>>,
     85     pub official_root_key: Option<Vec<u8>>,
     86     pub official_sending_chain_key: Option<Vec<u8>>,
     87     pub official_receiving_chain_key: Option<Vec<u8>>,
     88     pub official_sending_header_key: Option<Vec<u8>>,
     89     pub official_receiving_header_key: Option<Vec<u8>>,
     90     pub official_next_sending_header_key: Option<Vec<u8>>,
     91     pub official_next_receiving_header_key: Option<Vec<u8>>,
     92     pub official_skipped_message_keys: Vec<RadrootsSimplexSmpSkippedMessageKey>,
     93 }
     94 
     95 impl RadrootsSimplexSmpRatchetState {
     96     pub fn initiator(
     97         local_dh_public_key: Vec<u8>,
     98         remote_dh_public_key: Vec<u8>,
     99         remote_pq_public_key: Option<Vec<u8>>,
    100     ) -> Result<Self, RadrootsSimplexSmpCryptoError> {
    101         validate_public_key(&local_dh_public_key)?;
    102         validate_public_key(&remote_dh_public_key)?;
    103         if let Some(key) = remote_pq_public_key.as_deref() {
    104             validate_public_key(key)?;
    105         }
    106 
    107         Ok(Self {
    108             role: RadrootsSimplexSmpRatchetRole::Initiator,
    109             root_epoch: 0,
    110             previous_sending_chain_length: 0,
    111             sending_chain_length: 0,
    112             receiving_chain_length: 0,
    113             local_dh_public_key,
    114             remote_dh_public_key,
    115             current_pq_public_key: None,
    116             remote_pq_public_key,
    117             pending_outbound_pq_ciphertext: None,
    118             pending_inbound_pq_ciphertext: None,
    119             current_pq_shared_secret: None,
    120             local_pq_private_key: None,
    121             local_dh_private_key: None,
    122             official_associated_data: None,
    123             official_root_key: None,
    124             official_sending_chain_key: None,
    125             official_receiving_chain_key: None,
    126             official_sending_header_key: None,
    127             official_receiving_header_key: None,
    128             official_next_sending_header_key: None,
    129             official_next_receiving_header_key: None,
    130             official_skipped_message_keys: Vec::new(),
    131         })
    132     }
    133 
    134     pub fn responder(
    135         local_dh_public_key: Vec<u8>,
    136         remote_dh_public_key: Vec<u8>,
    137         local_pq_public_key: Option<Vec<u8>>,
    138     ) -> Result<Self, RadrootsSimplexSmpCryptoError> {
    139         validate_public_key(&local_dh_public_key)?;
    140         validate_public_key(&remote_dh_public_key)?;
    141         if let Some(key) = local_pq_public_key.as_deref() {
    142             validate_public_key(key)?;
    143         }
    144 
    145         Ok(Self {
    146             role: RadrootsSimplexSmpRatchetRole::Responder,
    147             root_epoch: 0,
    148             previous_sending_chain_length: 0,
    149             sending_chain_length: 0,
    150             receiving_chain_length: 0,
    151             local_dh_public_key,
    152             remote_dh_public_key,
    153             current_pq_public_key: local_pq_public_key,
    154             remote_pq_public_key: None,
    155             pending_outbound_pq_ciphertext: None,
    156             pending_inbound_pq_ciphertext: None,
    157             current_pq_shared_secret: None,
    158             local_pq_private_key: None,
    159             local_dh_private_key: None,
    160             official_associated_data: None,
    161             official_root_key: None,
    162             official_sending_chain_key: None,
    163             official_receiving_chain_key: None,
    164             official_sending_header_key: None,
    165             official_receiving_header_key: None,
    166             official_next_sending_header_key: None,
    167             official_next_receiving_header_key: None,
    168             official_skipped_message_keys: Vec::new(),
    169         })
    170     }
    171 
    172     pub fn initialize_official_sender(
    173         &mut self,
    174         local_dh_private_key: Vec<u8>,
    175         init: RadrootsSimplexOfficialX3dhInit,
    176     ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    177         validate_official_private_key(&local_dh_private_key)?;
    178         let root_dh =
    179             derive_official_x448_shared_secret(&local_dh_private_key, &self.remote_dh_public_key)?;
    180         let root = official_root_kdf(
    181             &init.ratchet_key,
    182             &root_dh,
    183             init.accepted_pq_shared_secret.as_deref(),
    184         )?;
    185         self.local_dh_private_key = Some(local_dh_private_key);
    186         self.official_associated_data = Some(init.associated_data);
    187         self.official_root_key = Some(root.root_key);
    188         self.official_sending_chain_key = Some(root.chain_key);
    189         self.official_receiving_chain_key = None;
    190         self.current_pq_shared_secret = init.accepted_pq_shared_secret;
    191         self.official_sending_header_key = Some(init.sending_header_key);
    192         self.official_receiving_header_key = None;
    193         self.official_next_sending_header_key = Some(root.next_header_key);
    194         self.official_next_receiving_header_key = Some(init.receiving_next_header_key);
    195         self.previous_sending_chain_length = 0;
    196         self.sending_chain_length = 0;
    197         self.receiving_chain_length = 0;
    198         self.root_epoch = 0;
    199         Ok(())
    200     }
    201 
    202     pub fn initialize_official_receiver(
    203         &mut self,
    204         local_dh_private_key: Vec<u8>,
    205         init: RadrootsSimplexOfficialX3dhInit,
    206     ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    207         validate_official_private_key(&local_dh_private_key)?;
    208         self.local_dh_private_key = Some(local_dh_private_key);
    209         self.official_associated_data = Some(init.associated_data);
    210         self.official_root_key = Some(init.ratchet_key);
    211         self.current_pq_shared_secret = init.accepted_pq_shared_secret;
    212         self.official_sending_chain_key = None;
    213         self.official_receiving_chain_key = None;
    214         self.official_sending_header_key = None;
    215         self.official_receiving_header_key = None;
    216         self.official_next_sending_header_key = Some(init.receiving_next_header_key);
    217         self.official_next_receiving_header_key = Some(init.sending_header_key);
    218         self.previous_sending_chain_length = 0;
    219         self.sending_chain_length = 0;
    220         self.receiving_chain_length = 0;
    221         self.root_epoch = 0;
    222         Ok(())
    223     }
    224 
    225     pub fn stage_outbound_pq_step(
    226         &mut self,
    227         pq_public_key: Vec<u8>,
    228         pq_ciphertext: Vec<u8>,
    229         shared_secret: Vec<u8>,
    230     ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    231         validate_public_key(&pq_public_key)?;
    232         if pq_ciphertext.is_empty() {
    233             return Err(RadrootsSimplexSmpCryptoError::InvalidCiphertextLength(0));
    234         }
    235         if shared_secret.is_empty() {
    236             return Err(RadrootsSimplexSmpCryptoError::InvalidSharedSecretLength(0));
    237         }
    238 
    239         self.current_pq_public_key = Some(pq_public_key);
    240         self.pending_outbound_pq_ciphertext = Some(pq_ciphertext);
    241         self.current_pq_shared_secret = Some(shared_secret);
    242         self.root_epoch = self.root_epoch.saturating_add(1);
    243         Ok(())
    244     }
    245 
    246     pub fn next_outbound_header(
    247         &mut self,
    248     ) -> Result<RadrootsSimplexSmpRatchetHeader, RadrootsSimplexSmpCryptoError> {
    249         validate_public_key(&self.local_dh_public_key)?;
    250         let header = RadrootsSimplexSmpRatchetHeader {
    251             previous_sending_chain_length: self.previous_sending_chain_length,
    252             message_number: self.sending_chain_length,
    253             dh_public_key: self.local_dh_public_key.clone(),
    254             pq_public_key: self.current_pq_public_key.clone(),
    255             pq_ciphertext: self.pending_outbound_pq_ciphertext.clone(),
    256         };
    257         header.validate()?;
    258         self.sending_chain_length = self.sending_chain_length.saturating_add(1);
    259         Ok(header)
    260     }
    261 
    262     pub fn apply_inbound_header(
    263         &mut self,
    264         header: &RadrootsSimplexSmpRatchetHeader,
    265         next_local_dh_public_key: Option<Vec<u8>>,
    266     ) -> Result<bool, RadrootsSimplexSmpCryptoError> {
    267         header.validate()?;
    268         let dh_advanced = header.dh_public_key != self.remote_dh_public_key;
    269 
    270         if dh_advanced {
    271             self.previous_sending_chain_length = self.sending_chain_length;
    272             self.sending_chain_length = 0;
    273             self.remote_dh_public_key = header.dh_public_key.clone();
    274             if let Some(next_local_key) = next_local_dh_public_key {
    275                 validate_public_key(&next_local_key)?;
    276                 self.local_dh_public_key = next_local_key;
    277             }
    278             self.root_epoch = self.root_epoch.saturating_add(1);
    279         } else if header.message_number < self.receiving_chain_length {
    280             return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression {
    281                 received: header.message_number,
    282                 current: self.receiving_chain_length,
    283             });
    284         }
    285 
    286         self.receiving_chain_length = header.message_number.saturating_add(1);
    287         if let Some(public_key) = header.pq_public_key.as_ref() {
    288             self.remote_pq_public_key = Some(public_key.clone());
    289         }
    290         if let Some(ciphertext) = header.pq_ciphertext.as_ref() {
    291             self.pending_inbound_pq_ciphertext = Some(ciphertext.clone());
    292         }
    293 
    294         Ok(dh_advanced)
    295     }
    296 
    297     pub fn complete_inbound_pq_step(
    298         &mut self,
    299         shared_secret: Vec<u8>,
    300     ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    301         if shared_secret.is_empty() {
    302             return Err(RadrootsSimplexSmpCryptoError::InvalidSharedSecretLength(0));
    303         }
    304         self.current_pq_shared_secret = Some(shared_secret);
    305         self.pending_inbound_pq_ciphertext = None;
    306         self.root_epoch = self.root_epoch.saturating_add(1);
    307         Ok(())
    308     }
    309 
    310     pub fn encrypt_payload(
    311         &mut self,
    312         shared_secret: &[u8],
    313         plaintext: &[u8],
    314         padded_len: usize,
    315     ) -> Result<(RadrootsSimplexSmpRatchetHeader, Vec<u8>), RadrootsSimplexSmpCryptoError> {
    316         let header = self.next_outbound_header()?;
    317         let associated_data = ratchet_header_associated_data(&header)?;
    318         let (message_key, nonce) = derive_ratchet_message_key(
    319             shared_secret,
    320             self.current_pq_shared_secret.as_deref(),
    321             self.root_epoch,
    322             &associated_data,
    323         )?;
    324         let ciphertext = encrypt_padded(&message_key, &nonce, plaintext, padded_len)?;
    325         Ok((header, ciphertext))
    326     }
    327 
    328     pub fn decrypt_payload(
    329         &mut self,
    330         shared_secret: &[u8],
    331         header: &RadrootsSimplexSmpRatchetHeader,
    332         ciphertext: &[u8],
    333     ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> {
    334         header.validate()?;
    335         if header.message_number < self.receiving_chain_length {
    336             return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression {
    337                 received: header.message_number,
    338                 current: self.receiving_chain_length,
    339             });
    340         }
    341         let associated_data = ratchet_header_associated_data(header)?;
    342         let (message_key, nonce) = derive_ratchet_message_key(
    343             shared_secret,
    344             self.current_pq_shared_secret.as_deref(),
    345             self.root_epoch,
    346             &associated_data,
    347         )?;
    348         let plaintext = decrypt_padded(&message_key, &nonce, ciphertext)?;
    349         self.apply_inbound_header(header, None)?;
    350         Ok(plaintext)
    351     }
    352 
    353     pub fn encrypt_official_payload(
    354         &mut self,
    355         _shared_secret: &[u8],
    356         plaintext: &[u8],
    357         padded_len: usize,
    358     ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> {
    359         let message_number = self.sending_chain_length;
    360         let header = RadrootsSimplexSmpRatchetHeader {
    361             previous_sending_chain_length: self.previous_sending_chain_length,
    362             message_number,
    363             dh_public_key: self.local_dh_public_key.clone(),
    364             pq_public_key: self.current_pq_public_key.clone(),
    365             pq_ciphertext: self.pending_outbound_pq_ciphertext.clone(),
    366         };
    367         header.validate()?;
    368         let header_plaintext = encode_official_msg_header(
    369             RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
    370             &official_msg_header_from_ratchet_header(&header),
    371         )?;
    372         let ratchet_ad = self.official_associated_data.clone().ok_or(
    373             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_associated_data"),
    374         )?;
    375         let sending_header_key = self.official_sending_header_key.clone().ok_or(
    376             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_sending_header_key"),
    377         )?;
    378         let sending_chain_key = self.official_sending_chain_key.clone().ok_or(
    379             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_sending_chain_key"),
    380         )?;
    381         let chain = official_chain_kdf(&sending_chain_key)?;
    382         let header_payload = official_aes_gcm_encrypt_padded(
    383             &sending_header_key,
    384             &chain.header_iv,
    385             &header_plaintext,
    386             official_ratchet_header_len(
    387                 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
    388                 self.pq_enabled(),
    389             )?,
    390             &ratchet_ad,
    391         )?;
    392         let encrypted_header = encode_official_encrypted_header(&official_encrypted_header(
    393             chain.header_iv,
    394             header_payload,
    395         )?)?;
    396         let message_ad = official_message_associated_data(&ratchet_ad, &encrypted_header);
    397         let message_payload = official_aes_gcm_encrypt_padded(
    398             &chain.message_key,
    399             &chain.message_iv,
    400             plaintext,
    401             padded_len,
    402             &message_ad,
    403         )?;
    404         self.official_sending_chain_key = Some(chain.chain_key);
    405         self.sending_chain_length = self.sending_chain_length.saturating_add(1);
    406         encode_official_encrypted_message(
    407             RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
    408             &RadrootsSimplexOfficialEncryptedMessage {
    409                 encrypted_header,
    410                 auth_tag: message_payload.auth_tag,
    411                 body: message_payload.ciphertext,
    412             },
    413         )
    414     }
    415 
    416     pub fn decrypt_official_payload(
    417         &mut self,
    418         _shared_secret: &[u8],
    419         encrypted_message: &[u8],
    420     ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> {
    421         let message = decode_official_encrypted_message(encrypted_message)?;
    422         let header = decode_official_encrypted_header(&message.encrypted_header)?;
    423         let ratchet_ad = self.official_associated_data.clone().ok_or(
    424             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_associated_data"),
    425         )?;
    426         if let Some(plaintext) =
    427             self.decrypt_official_skipped_payload(&header, &message, &ratchet_ad)?
    428         {
    429             return Ok(plaintext);
    430         }
    431         let (ratchet_step, ratchet_header) = self.decrypt_official_header(&header, &ratchet_ad)?;
    432         if ratchet_header.message_number < self.receiving_chain_length {
    433             return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression {
    434                 received: ratchet_header.message_number,
    435                 current: self.receiving_chain_length,
    436             });
    437         }
    438         if ratchet_step == OfficialRatchetStep::Advance {
    439             self.skip_official_receiving_messages_until(
    440                 ratchet_header.previous_sending_chain_length,
    441             )?;
    442             self.advance_official_receiving_ratchet(&ratchet_header)?;
    443         }
    444         self.skip_official_receiving_messages_until(ratchet_header.message_number)?;
    445         let receiving_chain_key = self.official_receiving_chain_key.clone().ok_or(
    446             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_receiving_chain_key"),
    447         )?;
    448         let chain = official_chain_kdf(&receiving_chain_key)?;
    449         let message_ad = official_message_associated_data(&ratchet_ad, &message.encrypted_header);
    450         let plaintext = official_aes_gcm_decrypt_padded(
    451             &chain.message_key,
    452             &chain.message_iv,
    453             &RadrootsSimplexOfficialAesGcmPayload {
    454                 auth_tag: message.auth_tag,
    455                 ciphertext: message.body,
    456             },
    457             &message_ad,
    458         )?;
    459         self.official_receiving_chain_key = Some(chain.chain_key);
    460         self.apply_inbound_header(&ratchet_header, None)?;
    461         Ok(plaintext)
    462     }
    463 
    464     pub fn is_official_payload_replay(
    465         &self,
    466         encrypted_message: &[u8],
    467     ) -> Result<bool, RadrootsSimplexSmpCryptoError> {
    468         let message = decode_official_encrypted_message(encrypted_message)?;
    469         let header = decode_official_encrypted_header(&message.encrypted_header)?;
    470         let ratchet_ad = self.official_associated_data.clone().ok_or(
    471             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_associated_data"),
    472         )?;
    473         for skipped in &self.official_skipped_message_keys {
    474             if let Ok(ratchet_header) =
    475                 decrypt_official_header_with_key(&header, &skipped.header_key, &ratchet_ad)
    476                 && ratchet_header.message_number == skipped.message_number
    477             {
    478                 return Ok(false);
    479             }
    480         }
    481         if let Some(receiving_header_key) = self.official_receiving_header_key.as_ref()
    482             && let Ok(ratchet_header) =
    483                 decrypt_official_header_with_key(&header, receiving_header_key, &ratchet_ad)
    484         {
    485             return Ok(ratchet_header.message_number < self.receiving_chain_length);
    486         }
    487         if let Some(next_receiving_header_key) = self.official_next_receiving_header_key.as_ref()
    488             && let Ok(ratchet_header) =
    489                 decrypt_official_header_with_key(&header, next_receiving_header_key, &ratchet_ad)
    490         {
    491             return Ok(ratchet_header.message_number < self.receiving_chain_length
    492                 && ratchet_header.previous_sending_chain_length < self.receiving_chain_length);
    493         }
    494         Ok(false)
    495     }
    496 
    497     fn decrypt_official_skipped_payload(
    498         &mut self,
    499         header: &RadrootsSimplexOfficialEncryptedHeader,
    500         message: &RadrootsSimplexOfficialEncryptedMessage,
    501         ratchet_ad: &[u8],
    502     ) -> Result<Option<Vec<u8>>, RadrootsSimplexSmpCryptoError> {
    503         for skipped in self.official_skipped_message_keys.clone() {
    504             let Ok(ratchet_header) =
    505                 decrypt_official_header_with_key(header, &skipped.header_key, ratchet_ad)
    506             else {
    507                 continue;
    508             };
    509             if ratchet_header.message_number != skipped.message_number {
    510                 continue;
    511             }
    512             let position = self
    513                 .official_skipped_message_keys
    514                 .iter()
    515                 .position(|entry| {
    516                     entry.header_key == skipped.header_key
    517                         && entry.message_number == skipped.message_number
    518                 })
    519                 .ok_or(RadrootsSimplexSmpCryptoError::RatchetMessageRegression {
    520                     received: ratchet_header.message_number,
    521                     current: self.receiving_chain_length,
    522                 })?;
    523             let skipped = self.official_skipped_message_keys.remove(position);
    524             let message_ad =
    525                 official_message_associated_data(ratchet_ad, &message.encrypted_header);
    526             let plaintext = official_aes_gcm_decrypt_padded(
    527                 &skipped.message_key,
    528                 &skipped.message_iv,
    529                 &RadrootsSimplexOfficialAesGcmPayload {
    530                     auth_tag: message.auth_tag.clone(),
    531                     ciphertext: message.body.clone(),
    532                 },
    533                 &message_ad,
    534             )?;
    535             return Ok(Some(plaintext));
    536         }
    537         Ok(None)
    538     }
    539 
    540     fn skip_official_receiving_messages_until(
    541         &mut self,
    542         until_message_number: u32,
    543     ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    544         if self.receiving_chain_length > until_message_number {
    545             return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression {
    546                 received: until_message_number,
    547                 current: self.receiving_chain_length,
    548             });
    549         }
    550         let skipped = until_message_number.saturating_sub(self.receiving_chain_length);
    551         if skipped > RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES {
    552             return Err(RadrootsSimplexSmpCryptoError::RatchetTooManySkipped {
    553                 skipped,
    554                 max: RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES,
    555             });
    556         }
    557         if skipped == 0 {
    558             return Ok(());
    559         }
    560         let mut receiving_chain_key = self.official_receiving_chain_key.clone().ok_or(
    561             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_receiving_chain_key"),
    562         )?;
    563         let receiving_header_key = self.official_receiving_header_key.clone().ok_or(
    564             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_receiving_header_key"),
    565         )?;
    566         while self.receiving_chain_length < until_message_number {
    567             let chain = official_chain_kdf(&receiving_chain_key)?;
    568             self.official_skipped_message_keys
    569                 .push(RadrootsSimplexSmpSkippedMessageKey {
    570                     header_key: receiving_header_key.clone(),
    571                     message_number: self.receiving_chain_length,
    572                     message_key: chain.message_key,
    573                     message_iv: chain.message_iv,
    574                 });
    575             receiving_chain_key = chain.chain_key;
    576             self.receiving_chain_length = self.receiving_chain_length.saturating_add(1);
    577         }
    578         self.official_receiving_chain_key = Some(receiving_chain_key);
    579         Ok(())
    580     }
    581 
    582     fn decrypt_official_header(
    583         &self,
    584         header: &RadrootsSimplexOfficialEncryptedHeader,
    585         ratchet_ad: &[u8],
    586     ) -> Result<(OfficialRatchetStep, RadrootsSimplexSmpRatchetHeader), RadrootsSimplexSmpCryptoError>
    587     {
    588         if let Some(receiving_header_key) = self.official_receiving_header_key.as_ref()
    589             && let Ok(ratchet_header) =
    590                 decrypt_official_header_with_key(header, receiving_header_key, ratchet_ad)
    591         {
    592             return Ok((OfficialRatchetStep::Same, ratchet_header));
    593         }
    594         let next_receiving_header_key = self.official_next_receiving_header_key.as_ref().ok_or(
    595             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_next_receiving_header_key"),
    596         )?;
    597         decrypt_official_header_with_key(header, next_receiving_header_key, ratchet_ad)
    598             .map(|ratchet_header| (OfficialRatchetStep::Advance, ratchet_header))
    599     }
    600 
    601     fn advance_official_receiving_ratchet(
    602         &mut self,
    603         header: &RadrootsSimplexSmpRatchetHeader,
    604     ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    605         let pq_step = self.official_pq_receiving_step(header)?;
    606         let local_private_key = self.local_dh_private_key.clone().ok_or(
    607             RadrootsSimplexSmpCryptoError::MissingRatchetKey("local_dh_private_key"),
    608         )?;
    609         let root_key = self.official_root_key.clone().ok_or(
    610             RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_root_key"),
    611         )?;
    612         let receiving_dh =
    613             derive_official_x448_shared_secret(&local_private_key, &header.dh_public_key)?;
    614         let receiving_root = official_root_kdf(
    615             &root_key,
    616             &receiving_dh,
    617             pq_step.receiving_shared_secret.as_deref(),
    618         )?;
    619         let next_local_keypair = generate_official_x448_keypair()?;
    620         let sending_dh = derive_official_x448_shared_secret(
    621             &next_local_keypair.private_key,
    622             &header.dh_public_key,
    623         )?;
    624         let sending_root = official_root_kdf(
    625             &receiving_root.root_key,
    626             &sending_dh,
    627             pq_step.sending_shared_secret.as_deref(),
    628         )?;
    629         self.previous_sending_chain_length = self.sending_chain_length;
    630         self.sending_chain_length = 0;
    631         self.receiving_chain_length = 0;
    632         self.remote_dh_public_key = header.dh_public_key.clone();
    633         self.remote_pq_public_key = header.pq_public_key.clone();
    634         self.pending_inbound_pq_ciphertext = header.pq_ciphertext.clone();
    635         if let Some(next_pq_keypair) = pq_step.next_local_keypair {
    636             self.current_pq_public_key = Some(next_pq_keypair.public_key);
    637             self.local_pq_private_key = Some(next_pq_keypair.private_key);
    638             self.pending_outbound_pq_ciphertext = pq_step.pending_outbound_pq_ciphertext;
    639             self.current_pq_shared_secret = pq_step.sending_shared_secret;
    640         } else if pq_step.receiving_shared_secret.is_some() {
    641             self.current_pq_shared_secret = pq_step.receiving_shared_secret;
    642         }
    643         self.local_dh_public_key = next_local_keypair.public_key;
    644         self.local_dh_private_key = Some(next_local_keypair.private_key);
    645         self.official_root_key = Some(sending_root.root_key);
    646         self.official_receiving_chain_key = Some(receiving_root.chain_key);
    647         self.official_receiving_header_key = self.official_next_receiving_header_key.take();
    648         self.official_next_receiving_header_key = Some(receiving_root.next_header_key);
    649         self.official_sending_chain_key = Some(sending_root.chain_key);
    650         self.official_sending_header_key = self.official_next_sending_header_key.take();
    651         self.official_next_sending_header_key = Some(sending_root.next_header_key);
    652         Ok(())
    653     }
    654 
    655     fn official_pq_receiving_step(
    656         &self,
    657         header: &RadrootsSimplexSmpRatchetHeader,
    658     ) -> Result<OfficialPqReceivingStep, RadrootsSimplexSmpCryptoError> {
    659         let Some(remote_pq_public_key) = header.pq_public_key.as_deref() else {
    660             return Ok(OfficialPqReceivingStep::default());
    661         };
    662         validate_official_pq_public_key(remote_pq_public_key)?;
    663         let receiving_shared_secret = match header.pq_ciphertext.as_deref() {
    664             Some(ciphertext) => {
    665                 let local_pq_private_key = self.local_pq_private_key.as_deref().ok_or(
    666                     RadrootsSimplexSmpCryptoError::MissingRatchetKey("local_pq_private_key"),
    667                 )?;
    668                 validate_official_pq_private_key(local_pq_private_key)?;
    669                 Some(decapsulate_official_sntrup761(
    670                     local_pq_private_key,
    671                     ciphertext,
    672                 )?)
    673             }
    674             None => None,
    675         };
    676         if !self.pq_enabled() {
    677             return Ok(OfficialPqReceivingStep {
    678                 receiving_shared_secret,
    679                 ..OfficialPqReceivingStep::default()
    680             });
    681         }
    682         let next_local_keypair = generate_official_sntrup761_keypair()?;
    683         let seed = random_official_pq_seed()?;
    684         let (pending_outbound_pq_ciphertext, sending_shared_secret) =
    685             encapsulate_official_sntrup761(remote_pq_public_key, &seed)?;
    686         Ok(OfficialPqReceivingStep {
    687             receiving_shared_secret,
    688             next_local_keypair: Some(next_local_keypair),
    689             pending_outbound_pq_ciphertext: Some(pending_outbound_pq_ciphertext),
    690             sending_shared_secret: Some(sending_shared_secret),
    691         })
    692     }
    693 
    694     fn pq_enabled(&self) -> bool {
    695         self.current_pq_public_key.is_some()
    696             || self.remote_pq_public_key.is_some()
    697             || self.current_pq_shared_secret.is_some()
    698             || self.local_pq_private_key.is_some()
    699     }
    700 }
    701 
    702 #[derive(Debug, Default, Clone, PartialEq, Eq)]
    703 struct OfficialPqReceivingStep {
    704     receiving_shared_secret: Option<Vec<u8>>,
    705     next_local_keypair: Option<RadrootsSimplexOfficialSntrup761Keypair>,
    706     pending_outbound_pq_ciphertext: Option<Vec<u8>>,
    707     sending_shared_secret: Option<Vec<u8>>,
    708 }
    709 
    710 fn validate_public_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> {
    711     if value.is_empty() {
    712         return Err(RadrootsSimplexSmpCryptoError::InvalidPublicKeyLength(0));
    713     }
    714     Ok(())
    715 }
    716 
    717 fn validate_official_pq_public_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> {
    718     if value.len() != RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PUBLIC_KEY_LENGTH {
    719         return Err(RadrootsSimplexSmpCryptoError::InvalidPqKeyLength(
    720             value.len(),
    721         ));
    722     }
    723     Ok(())
    724 }
    725 
    726 fn validate_official_pq_private_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> {
    727     if value.len() != RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PRIVATE_KEY_LENGTH {
    728         return Err(RadrootsSimplexSmpCryptoError::InvalidPrivateKeyLength(
    729             value.len(),
    730         ));
    731     }
    732     Ok(())
    733 }
    734 
    735 fn random_official_pq_seed() -> Result<[u8; 32], RadrootsSimplexSmpCryptoError> {
    736     let mut seed = [0_u8; 32];
    737     getrandom::getrandom(&mut seed)
    738         .map_err(|_| RadrootsSimplexSmpCryptoError::EntropyUnavailable)?;
    739     Ok(seed)
    740 }
    741 
    742 fn validate_official_private_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> {
    743     if value.len() != RADROOTS_SIMPLEX_OFFICIAL_X448_KEY_LENGTH {
    744         return Err(RadrootsSimplexSmpCryptoError::InvalidPrivateKeyLength(
    745             value.len(),
    746         ));
    747     }
    748     Ok(())
    749 }
    750 
    751 fn derive_ratchet_message_key(
    752     shared_secret: &[u8],
    753     pq_shared_secret: Option<&[u8]>,
    754     root_epoch: u64,
    755     associated_data: &[u8],
    756 ) -> Result<(Vec<u8>, [u8; RADROOTS_SIMPLEX_SMP_NONCE_LENGTH]), RadrootsSimplexSmpCryptoError> {
    757     let mut ikm = Vec::with_capacity(shared_secret.len() + pq_shared_secret.map_or(0, <[u8]>::len));
    758     ikm.extend_from_slice(shared_secret);
    759     if let Some(secret) = pq_shared_secret {
    760         ikm.extend_from_slice(secret);
    761     }
    762     let mut salt = Vec::with_capacity(8 + associated_data.len());
    763     salt.extend_from_slice(&root_epoch.to_be_bytes());
    764     salt.extend_from_slice(associated_data);
    765     let hkdf = Hkdf::<Sha512>::new(Some(&salt), &ikm);
    766     let mut output = [0_u8; RADROOTS_SIMPLEX_AGENT_RATCHET_OUTPUT_LENGTH];
    767     hkdf.expand(RADROOTS_SIMPLEX_AGENT_RATCHET_INFO, &mut output)
    768         .map_err(|_| {
    769             RadrootsSimplexSmpCryptoError::InvalidKeyDerivationLength(
    770                 RADROOTS_SIMPLEX_AGENT_RATCHET_OUTPUT_LENGTH,
    771             )
    772         })?;
    773     let mut nonce = [0_u8; RADROOTS_SIMPLEX_SMP_NONCE_LENGTH];
    774     nonce.copy_from_slice(&output[RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH..]);
    775     Ok((
    776         output[..RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH].to_vec(),
    777         nonce,
    778     ))
    779 }
    780 
    781 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    782 enum OfficialRatchetStep {
    783     Same,
    784     Advance,
    785 }
    786 
    787 fn decrypt_official_header_with_key(
    788     header: &RadrootsSimplexOfficialEncryptedHeader,
    789     header_key: &[u8],
    790     ratchet_ad: &[u8],
    791 ) -> Result<RadrootsSimplexSmpRatchetHeader, RadrootsSimplexSmpCryptoError> {
    792     let header_plaintext = official_aes_gcm_decrypt_padded(
    793         header_key,
    794         &header.iv,
    795         &RadrootsSimplexOfficialAesGcmPayload {
    796             auth_tag: header.auth_tag.clone(),
    797             ciphertext: header.body.clone(),
    798         },
    799         ratchet_ad,
    800     )?;
    801     Ok(ratchet_header_from_official_msg_header(
    802         decode_official_msg_header(header.version, &header_plaintext)?,
    803     ))
    804 }
    805 
    806 fn official_encrypted_header(
    807     iv: [u8; crate::official_ratchet::RADROOTS_SIMPLEX_OFFICIAL_AES_IV_LENGTH],
    808     payload: RadrootsSimplexOfficialAesGcmPayload,
    809 ) -> Result<RadrootsSimplexOfficialEncryptedHeader, RadrootsSimplexSmpCryptoError> {
    810     Ok(RadrootsSimplexOfficialEncryptedHeader {
    811         version: RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
    812         iv,
    813         auth_tag: payload.auth_tag,
    814         body: payload.ciphertext,
    815     })
    816 }
    817 
    818 fn official_message_associated_data(ratchet_ad: &[u8], encrypted_header: &[u8]) -> Vec<u8> {
    819     let mut associated_data = Vec::with_capacity(ratchet_ad.len() + encrypted_header.len());
    820     associated_data.extend_from_slice(ratchet_ad);
    821     associated_data.extend_from_slice(encrypted_header);
    822     associated_data
    823 }
    824 
    825 fn official_msg_header_from_ratchet_header(
    826     header: &RadrootsSimplexSmpRatchetHeader,
    827 ) -> RadrootsSimplexOfficialMsgHeader {
    828     RadrootsSimplexOfficialMsgHeader {
    829         max_version: RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
    830         dh_public_key: header.dh_public_key.clone(),
    831         pq_public_key: header.pq_public_key.clone(),
    832         pq_ciphertext: header.pq_ciphertext.clone(),
    833         previous_sending_chain_length: header.previous_sending_chain_length,
    834         message_number: header.message_number,
    835     }
    836 }
    837 
    838 fn ratchet_header_from_official_msg_header(
    839     header: RadrootsSimplexOfficialMsgHeader,
    840 ) -> RadrootsSimplexSmpRatchetHeader {
    841     RadrootsSimplexSmpRatchetHeader {
    842         previous_sending_chain_length: header.previous_sending_chain_length,
    843         message_number: header.message_number,
    844         dh_public_key: header.dh_public_key,
    845         pq_public_key: header.pq_public_key,
    846         pq_ciphertext: header.pq_ciphertext,
    847     }
    848 }
    849 
    850 fn ratchet_header_associated_data(
    851     header: &RadrootsSimplexSmpRatchetHeader,
    852 ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> {
    853     let mut buffer = Vec::new();
    854     buffer.extend_from_slice(&header.previous_sending_chain_length.to_be_bytes());
    855     buffer.extend_from_slice(&header.message_number.to_be_bytes());
    856     push_large_bytes(&mut buffer, &header.dh_public_key)?;
    857     push_maybe_large_bytes(&mut buffer, header.pq_public_key.as_deref())?;
    858     push_maybe_large_bytes(&mut buffer, header.pq_ciphertext.as_deref())?;
    859     Ok(buffer)
    860 }
    861 
    862 fn push_maybe_large_bytes(
    863     buffer: &mut Vec<u8>,
    864     value: Option<&[u8]>,
    865 ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    866     match value {
    867         Some(value) => {
    868             buffer.push(1);
    869             push_large_bytes(buffer, value)
    870         }
    871         None => {
    872             buffer.push(0);
    873             Ok(())
    874         }
    875     }
    876 }
    877 
    878 fn push_large_bytes(
    879     buffer: &mut Vec<u8>,
    880     value: &[u8],
    881 ) -> Result<(), RadrootsSimplexSmpCryptoError> {
    882     if value.len() > u16::MAX as usize {
    883         return Err(RadrootsSimplexSmpCryptoError::InvalidMessageLength {
    884             actual: value.len(),
    885             padded: u16::MAX as usize,
    886         });
    887     }
    888     buffer.extend_from_slice(&(value.len() as u16).to_be_bytes());
    889     buffer.extend_from_slice(value);
    890     Ok(())
    891 }
    892 
    893 #[cfg(test)]
    894 mod tests {
    895     use super::*;
    896     use crate::official_ratchet::{
    897         RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, RADROOTS_SIMPLEX_OFFICIAL_E2E_KDF_VERSION,
    898         RadrootsSimplexOfficialX3dhParams, decode_official_encrypted_header,
    899         decode_official_encrypted_message, official_sntrup761_keypair_from_seed,
    900         official_x3dh_receiver_init, official_x3dh_receiver_init_accepting_pq,
    901         official_x3dh_sender_init, official_x3dh_sender_init_accepting_pq,
    902         official_x448_keypair_from_seed,
    903     };
    904     use radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpVersionRange;
    905 
    906     fn official_sender_receiver_ratchets() -> (
    907         RadrootsSimplexSmpRatchetState,
    908         RadrootsSimplexSmpRatchetState,
    909     ) {
    910         let receiver_key_1 = official_x448_keypair_from_seed(b"rr-synth-ratchet-rcv-1");
    911         let receiver_key_2 = official_x448_keypair_from_seed(b"rr-synth-ratchet-rcv-2");
    912         let sender_key_1 = official_x448_keypair_from_seed(b"rr-synth-ratchet-snd-1");
    913         let sender_key_2 = official_x448_keypair_from_seed(b"rr-synth-ratchet-snd-2");
    914         let receiver_params = RadrootsSimplexOfficialX3dhParams {
    915             version_range: RadrootsSimplexSmpVersionRange::new(
    916                 RADROOTS_SIMPLEX_OFFICIAL_E2E_KDF_VERSION,
    917                 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
    918             )
    919             .unwrap(),
    920             key_1: receiver_key_1.public_key.clone(),
    921             key_2: receiver_key_2.public_key.clone(),
    922             pq_public_key: None,
    923             pq_ciphertext: None,
    924         };
    925         let sender_params = RadrootsSimplexOfficialX3dhParams {
    926             version_range: receiver_params.version_range,
    927             key_1: sender_key_1.public_key.clone(),
    928             key_2: sender_key_2.public_key.clone(),
    929             pq_public_key: None,
    930             pq_ciphertext: None,
    931         };
    932         let sender_init =
    933             official_x3dh_sender_init(&sender_key_1, &sender_key_2, &receiver_params).unwrap();
    934         let receiver_init =
    935             official_x3dh_receiver_init(&receiver_key_1, &receiver_key_2, &sender_params).unwrap();
    936         let mut sender = RadrootsSimplexSmpRatchetState::responder(
    937             sender_key_2.public_key.clone(),
    938             receiver_key_2.public_key.clone(),
    939             None,
    940         )
    941         .unwrap();
    942         sender
    943             .initialize_official_sender(sender_key_2.private_key, sender_init)
    944             .unwrap();
    945         let mut receiver = RadrootsSimplexSmpRatchetState::initiator(
    946             receiver_key_2.public_key.clone(),
    947             receiver_key_1.public_key.clone(),
    948             None,
    949         )
    950         .unwrap();
    951         receiver
    952             .initialize_official_receiver(receiver_key_2.private_key, receiver_init)
    953             .unwrap();
    954         (sender, receiver)
    955     }
    956 
    957     fn official_pq_sender_receiver_ratchets() -> (
    958         RadrootsSimplexSmpRatchetState,
    959         RadrootsSimplexSmpRatchetState,
    960     ) {
    961         let receiver_key_1 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-rcv-1");
    962         let receiver_key_2 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-rcv-2");
    963         let receiver_pq_keypair = official_sntrup761_keypair_from_seed(b"rr-synth-pq-rcv-kem");
    964         let sender_key_1 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-snd-1");
    965         let sender_key_2 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-snd-2");
    966         let sender_pq_keypair = official_sntrup761_keypair_from_seed(b"rr-synth-pq-snd-kem");
    967         let receiver_params = RadrootsSimplexOfficialX3dhParams {
    968             version_range: RadrootsSimplexSmpVersionRange::new(
    969                 RADROOTS_SIMPLEX_OFFICIAL_E2E_KDF_VERSION,
    970                 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION,
    971             )
    972             .unwrap(),
    973             key_1: receiver_key_1.public_key.clone(),
    974             key_2: receiver_key_2.public_key.clone(),
    975             pq_public_key: Some(receiver_pq_keypair.public_key.clone()),
    976             pq_ciphertext: None,
    977         };
    978         let sender_init = official_x3dh_sender_init_accepting_pq(
    979             &sender_key_1,
    980             &sender_key_2,
    981             sender_pq_keypair,
    982             &receiver_params,
    983             b"rr-synth-pq-x3dh-accept",
    984         )
    985         .unwrap();
    986         let receiver_init = official_x3dh_receiver_init_accepting_pq(
    987             &receiver_key_1,
    988             &receiver_key_2,
    989             &receiver_pq_keypair,
    990             &sender_init.sender_params,
    991         )
    992         .unwrap();
    993         let mut sender = RadrootsSimplexSmpRatchetState::responder(
    994             sender_key_2.public_key.clone(),
    995             receiver_key_2.public_key.clone(),
    996             sender_init.sender_params.pq_public_key.clone(),
    997         )
    998         .unwrap();
    999         sender
   1000             .initialize_official_sender(sender_key_2.private_key, sender_init.init)
   1001             .unwrap();
   1002         sender.current_pq_public_key = sender_init.sender_params.pq_public_key.clone();
   1003         sender.pending_outbound_pq_ciphertext = sender_init.sender_params.pq_ciphertext.clone();
   1004         sender.local_pq_private_key = Some(sender_init.local_pq_keypair.private_key);
   1005         let mut receiver = RadrootsSimplexSmpRatchetState::initiator(
   1006             receiver_key_2.public_key.clone(),
   1007             receiver_key_1.public_key.clone(),
   1008             None,
   1009         )
   1010         .unwrap();
   1011         receiver.current_pq_public_key = Some(receiver_pq_keypair.public_key);
   1012         receiver.local_pq_private_key = Some(receiver_pq_keypair.private_key);
   1013         receiver
   1014             .initialize_official_receiver(receiver_key_2.private_key, receiver_init.init)
   1015             .unwrap();
   1016         (sender, receiver)
   1017     }
   1018 
   1019     #[test]
   1020     fn stages_outbound_pq_state_and_emits_header() {
   1021         let mut state = RadrootsSimplexSmpRatchetState::responder(
   1022             b"bob-dh".to_vec(),
   1023             b"alice-dh".to_vec(),
   1024             Some(b"bob-pq".to_vec()),
   1025         )
   1026         .unwrap();
   1027         state
   1028             .stage_outbound_pq_step(
   1029                 b"bob-pq-next".to_vec(),
   1030                 b"ciphertext".to_vec(),
   1031                 b"shared-secret".to_vec(),
   1032             )
   1033             .unwrap();
   1034 
   1035         let header = state.next_outbound_header().unwrap();
   1036         assert_eq!(header.message_number, 0);
   1037         assert_eq!(header.pq_public_key, Some(b"bob-pq-next".to_vec()));
   1038         assert_eq!(header.pq_ciphertext, Some(b"ciphertext".to_vec()));
   1039         assert_eq!(state.sending_chain_length, 1);
   1040     }
   1041 
   1042     #[test]
   1043     fn applies_inbound_dh_and_pq_transition() {
   1044         let mut state = RadrootsSimplexSmpRatchetState::initiator(
   1045             b"alice-dh".to_vec(),
   1046             b"bob-dh".to_vec(),
   1047             Some(b"bob-pq".to_vec()),
   1048         )
   1049         .unwrap();
   1050         state.sending_chain_length = 4;
   1051 
   1052         let advanced = state
   1053             .apply_inbound_header(
   1054                 &RadrootsSimplexSmpRatchetHeader {
   1055                     previous_sending_chain_length: 2,
   1056                     message_number: 0,
   1057                     dh_public_key: b"bob-dh-next".to_vec(),
   1058                     pq_public_key: Some(b"bob-pq-next".to_vec()),
   1059                     pq_ciphertext: Some(b"ciphertext".to_vec()),
   1060                 },
   1061                 Some(b"alice-dh-next".to_vec()),
   1062             )
   1063             .unwrap();
   1064 
   1065         assert!(advanced);
   1066         assert_eq!(state.previous_sending_chain_length, 4);
   1067         assert_eq!(state.sending_chain_length, 0);
   1068         assert_eq!(state.receiving_chain_length, 1);
   1069         assert_eq!(state.remote_pq_public_key, Some(b"bob-pq-next".to_vec()));
   1070         assert_eq!(
   1071             state.pending_inbound_pq_ciphertext,
   1072             Some(b"ciphertext".to_vec())
   1073         );
   1074 
   1075         state
   1076             .complete_inbound_pq_step(b"shared-secret".to_vec())
   1077             .unwrap();
   1078         assert_eq!(
   1079             state.current_pq_shared_secret,
   1080             Some(b"shared-secret".to_vec())
   1081         );
   1082         assert_eq!(state.pending_inbound_pq_ciphertext, None);
   1083     }
   1084 
   1085     #[test]
   1086     fn rejects_incomplete_pq_header() {
   1087         let header = RadrootsSimplexSmpRatchetHeader {
   1088             previous_sending_chain_length: 0,
   1089             message_number: 0,
   1090             dh_public_key: b"dh".to_vec(),
   1091             pq_public_key: None,
   1092             pq_ciphertext: Some(b"ciphertext".to_vec()),
   1093         };
   1094 
   1095         let error = header.validate().unwrap_err();
   1096         assert_eq!(error, RadrootsSimplexSmpCryptoError::IncompletePqHeader);
   1097     }
   1098 
   1099     #[test]
   1100     fn encrypts_payload_and_advances_receive_state() {
   1101         let mut sender =
   1102             RadrootsSimplexSmpRatchetState::initiator(vec![1_u8; 56], vec![2_u8; 56], None)
   1103                 .unwrap();
   1104         let mut receiver =
   1105             RadrootsSimplexSmpRatchetState::responder(vec![2_u8; 56], vec![1_u8; 56], None)
   1106                 .unwrap();
   1107         let shared_secret = [7_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1108 
   1109         let (header, ciphertext) = sender
   1110             .encrypt_payload(&shared_secret, b"agent body", 64)
   1111             .unwrap();
   1112 
   1113         assert_ne!(ciphertext, b"agent body");
   1114         let plaintext = receiver
   1115             .decrypt_payload(&shared_secret, &header, &ciphertext)
   1116             .unwrap();
   1117         assert_eq!(plaintext, b"agent body");
   1118         assert_eq!(receiver.receiving_chain_length, 1);
   1119     }
   1120 
   1121     #[test]
   1122     fn rejects_tampered_ratchet_header() {
   1123         let mut sender =
   1124             RadrootsSimplexSmpRatchetState::initiator(vec![1_u8; 56], vec![2_u8; 56], None)
   1125                 .unwrap();
   1126         let mut receiver =
   1127             RadrootsSimplexSmpRatchetState::responder(vec![2_u8; 56], vec![1_u8; 56], None)
   1128                 .unwrap();
   1129         let shared_secret = [9_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1130         let (mut header, ciphertext) = sender
   1131             .encrypt_payload(&shared_secret, b"agent body", 64)
   1132             .unwrap();
   1133         header.message_number = header.message_number.saturating_add(1);
   1134 
   1135         let error = receiver
   1136             .decrypt_payload(&shared_secret, &header, &ciphertext)
   1137             .unwrap_err();
   1138         assert!(matches!(
   1139             error,
   1140             RadrootsSimplexSmpCryptoError::InvalidCiphertextLength(_)
   1141         ));
   1142     }
   1143 
   1144     #[test]
   1145     fn stages_large_pq_material_in_header() {
   1146         let mut sender = RadrootsSimplexSmpRatchetState::initiator(
   1147             b"alice-dh".to_vec(),
   1148             b"bob-dh".to_vec(),
   1149             None,
   1150         )
   1151         .unwrap();
   1152         sender
   1153             .stage_outbound_pq_step(vec![1_u8; 1158], vec![2_u8; 1039], vec![3_u8; 32])
   1154             .unwrap();
   1155 
   1156         let header = sender.next_outbound_header().unwrap();
   1157         assert_eq!(header.pq_public_key.as_ref().unwrap().len(), 1158);
   1158         assert_eq!(header.pq_ciphertext.as_ref().unwrap().len(), 1039);
   1159         assert!(ratchet_header_associated_data(&header).unwrap().len() > 2200);
   1160     }
   1161 
   1162     #[test]
   1163     fn encrypts_official_payload_as_opaque_message() {
   1164         let (mut sender, mut receiver) = official_sender_receiver_ratchets();
   1165         let shared_secret = [11_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1166 
   1167         let encrypted = sender
   1168             .encrypt_official_payload(&shared_secret, b"official agent body", 96)
   1169             .unwrap();
   1170         assert_ne!(encrypted, b"official agent body");
   1171         assert_eq!(encrypted.len(), 2 + 124 + 16 + 96);
   1172 
   1173         let plaintext = receiver
   1174             .decrypt_official_payload(&shared_secret, &encrypted)
   1175             .unwrap();
   1176         assert_eq!(plaintext, b"official agent body");
   1177         assert_eq!(receiver.receiving_chain_length, 1);
   1178     }
   1179 
   1180     #[test]
   1181     fn detects_official_payload_replay_without_consuming_skipped_messages() {
   1182         let (mut sender, mut receiver) = official_sender_receiver_ratchets();
   1183         let shared_secret = [14_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1184         let first = sender
   1185             .encrypt_official_payload(&shared_secret, b"first", 96)
   1186             .unwrap();
   1187         let second = sender
   1188             .encrypt_official_payload(&shared_secret, b"second", 96)
   1189             .unwrap();
   1190         let third = sender
   1191             .encrypt_official_payload(&shared_secret, b"third", 96)
   1192             .unwrap();
   1193 
   1194         assert_eq!(
   1195             receiver
   1196                 .decrypt_official_payload(&shared_secret, &second)
   1197                 .unwrap(),
   1198             b"second"
   1199         );
   1200         assert!(!receiver.is_official_payload_replay(&first).unwrap());
   1201         assert_eq!(
   1202             receiver
   1203                 .decrypt_official_payload(&shared_secret, &third)
   1204                 .unwrap(),
   1205             b"third"
   1206         );
   1207         assert_eq!(
   1208             receiver
   1209                 .decrypt_official_payload(&shared_secret, &first)
   1210                 .unwrap(),
   1211             b"first"
   1212         );
   1213         assert!(receiver.is_official_payload_replay(&first).unwrap());
   1214     }
   1215 
   1216     #[test]
   1217     fn advances_official_pq_ratchet_in_both_directions() {
   1218         let (mut sender, mut receiver) = official_pq_sender_receiver_ratchets();
   1219         let shared_secret = [21_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1220 
   1221         let encrypted = sender
   1222             .encrypt_official_payload(&shared_secret, b"pq first", 96)
   1223             .unwrap();
   1224         let plaintext = receiver
   1225             .decrypt_official_payload(&shared_secret, &encrypted)
   1226             .unwrap();
   1227         assert_eq!(plaintext, b"pq first");
   1228         assert!(receiver.pending_outbound_pq_ciphertext.is_some());
   1229         assert!(receiver.local_pq_private_key.is_some());
   1230 
   1231         let reply = receiver
   1232             .encrypt_official_payload(&shared_secret, b"pq reply", 96)
   1233             .unwrap();
   1234         let reply_plaintext = sender
   1235             .decrypt_official_payload(&shared_secret, &reply)
   1236             .unwrap();
   1237         assert_eq!(reply_plaintext, b"pq reply");
   1238         assert!(sender.pending_outbound_pq_ciphertext.is_some());
   1239         assert!(sender.local_pq_private_key.is_some());
   1240     }
   1241 
   1242     #[test]
   1243     fn retains_accepted_pq_ciphertext_across_same_sending_chain_headers() {
   1244         let (mut sender, _) = official_pq_sender_receiver_ratchets();
   1245         let shared_secret = [22_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1246         let header_key = sender.official_sending_header_key.clone().unwrap();
   1247         let ratchet_ad = sender.official_associated_data.clone().unwrap();
   1248         let first = sender
   1249             .encrypt_official_payload(&shared_secret, b"pq first", 96)
   1250             .unwrap();
   1251         let second = sender
   1252             .encrypt_official_payload(&shared_secret, b"pq second", 96)
   1253             .unwrap();
   1254 
   1255         let first_message = decode_official_encrypted_message(&first).unwrap();
   1256         let first_header = decrypt_official_header_with_key(
   1257             &decode_official_encrypted_header(&first_message.encrypted_header).unwrap(),
   1258             &header_key,
   1259             &ratchet_ad,
   1260         )
   1261         .unwrap();
   1262         let second_message = decode_official_encrypted_message(&second).unwrap();
   1263         let second_header = decrypt_official_header_with_key(
   1264             &decode_official_encrypted_header(&second_message.encrypted_header).unwrap(),
   1265             &header_key,
   1266             &ratchet_ad,
   1267         )
   1268         .unwrap();
   1269 
   1270         assert!(first_header.pq_ciphertext.is_some());
   1271         assert_eq!(first_header.pq_ciphertext, second_header.pq_ciphertext);
   1272         assert_eq!(second_header.message_number, 1);
   1273     }
   1274 
   1275     #[test]
   1276     fn decrypts_official_skipped_messages_once() {
   1277         let (mut sender, mut receiver) = official_sender_receiver_ratchets();
   1278         let shared_secret = [12_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1279         let first = sender
   1280             .encrypt_official_payload(&shared_secret, b"first", 96)
   1281             .unwrap();
   1282         let second = sender
   1283             .encrypt_official_payload(&shared_secret, b"second", 96)
   1284             .unwrap();
   1285         let third = sender
   1286             .encrypt_official_payload(&shared_secret, b"third", 96)
   1287             .unwrap();
   1288 
   1289         assert_eq!(
   1290             receiver
   1291                 .decrypt_official_payload(&shared_secret, &third)
   1292                 .unwrap(),
   1293             b"third"
   1294         );
   1295         assert_eq!(receiver.receiving_chain_length, 3);
   1296         assert_eq!(receiver.official_skipped_message_keys.len(), 2);
   1297         assert_eq!(
   1298             receiver
   1299                 .decrypt_official_payload(&shared_secret, &first)
   1300                 .unwrap(),
   1301             b"first"
   1302         );
   1303         assert_eq!(
   1304             receiver
   1305                 .decrypt_official_payload(&shared_secret, &second)
   1306                 .unwrap(),
   1307             b"second"
   1308         );
   1309         assert!(receiver.official_skipped_message_keys.is_empty());
   1310 
   1311         let replay = receiver
   1312             .decrypt_official_payload(&shared_secret, &first)
   1313             .unwrap_err();
   1314         assert!(matches!(
   1315             replay,
   1316             RadrootsSimplexSmpCryptoError::RatchetMessageRegression {
   1317                 received: 0,
   1318                 current: 3
   1319             }
   1320         ));
   1321     }
   1322 
   1323     #[test]
   1324     fn rejects_too_many_official_skipped_messages() {
   1325         let (mut sender, mut receiver) = official_sender_receiver_ratchets();
   1326         let shared_secret = [13_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1327         let mut encrypted = Vec::new();
   1328         for index in 0..=RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES + 1 {
   1329             encrypted = sender
   1330                 .encrypt_official_payload(&shared_secret, &index.to_be_bytes(), 96)
   1331                 .unwrap();
   1332         }
   1333 
   1334         let error = receiver
   1335             .decrypt_official_payload(&shared_secret, &encrypted)
   1336             .unwrap_err();
   1337         assert_eq!(
   1338             error,
   1339             RadrootsSimplexSmpCryptoError::RatchetTooManySkipped {
   1340                 skipped: RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES + 1,
   1341                 max: RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES
   1342             }
   1343         );
   1344         assert_eq!(
   1345             error.to_string(),
   1346             "SMP ratchet skipped 513 messages, exceeding maximum 512"
   1347         );
   1348     }
   1349 
   1350     #[test]
   1351     fn rejects_tampered_official_payload_body() {
   1352         let (mut sender, mut receiver) = official_sender_receiver_ratchets();
   1353         let shared_secret = [12_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1354         let mut encrypted = sender
   1355             .encrypt_official_payload(&shared_secret, b"official agent body", 96)
   1356             .unwrap();
   1357         let last = encrypted.len() - 1;
   1358         encrypted[last] ^= 1;
   1359 
   1360         let error = receiver
   1361             .decrypt_official_payload(&shared_secret, &encrypted)
   1362             .unwrap_err();
   1363         assert_eq!(
   1364             error,
   1365             RadrootsSimplexSmpCryptoError::AesGcmAuthenticationFailed
   1366         );
   1367     }
   1368 
   1369     #[test]
   1370     fn decrypts_official_payloads_received_out_of_order() {
   1371         let (mut sender, mut receiver) = official_sender_receiver_ratchets();
   1372         let shared_secret = [13_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1373         let encrypted_0 = sender
   1374             .encrypt_official_payload(&shared_secret, b"first official body", 96)
   1375             .unwrap();
   1376         let encrypted_1 = sender
   1377             .encrypt_official_payload(&shared_secret, b"second official body", 96)
   1378             .unwrap();
   1379 
   1380         let plaintext_1 = receiver
   1381             .decrypt_official_payload(&shared_secret, &encrypted_1)
   1382             .unwrap();
   1383         assert_eq!(plaintext_1, b"second official body");
   1384         assert_eq!(receiver.receiving_chain_length, 2);
   1385         assert_eq!(receiver.official_skipped_message_keys.len(), 1);
   1386 
   1387         let plaintext_0 = receiver
   1388             .decrypt_official_payload(&shared_secret, &encrypted_0)
   1389             .unwrap();
   1390         assert_eq!(plaintext_0, b"first official body");
   1391         assert!(receiver.official_skipped_message_keys.is_empty());
   1392         assert_eq!(receiver.receiving_chain_length, 2);
   1393     }
   1394 
   1395     #[test]
   1396     fn rejects_too_many_official_skipped_payloads() {
   1397         let (mut sender, mut receiver) = official_sender_receiver_ratchets();
   1398         let shared_secret = [14_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH];
   1399         let mut encrypted = Vec::new();
   1400         for index in 0..514 {
   1401             encrypted = sender
   1402                 .encrypt_official_payload(&shared_secret, &[index as u8], 96)
   1403                 .unwrap();
   1404         }
   1405 
   1406         let error = receiver
   1407             .decrypt_official_payload(&shared_secret, &encrypted)
   1408             .unwrap_err();
   1409         assert_eq!(
   1410             error,
   1411             RadrootsSimplexSmpCryptoError::RatchetTooManySkipped {
   1412                 skipped: 513,
   1413                 max: 512
   1414             }
   1415         );
   1416     }
   1417 }