libsignal_protocol/state/
kyber_prekey.rs

1//
2// Copyright 2023 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6use std::fmt;
7
8use rand::TryRngCore as _;
9
10use crate::proto::storage::SignedPreKeyRecordStructure;
11use crate::state::GenericSignedPreKey;
12use crate::{kem, PrivateKey, Result, Timestamp};
13
14/// A unique identifier selecting among this client's known signed pre-keys.
15#[derive(
16    Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, derive_more::From, derive_more::Into,
17)]
18pub struct KyberPreKeyId(u32);
19
20impl fmt::Display for KyberPreKeyId {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        write!(f, "{}", self.0)
23    }
24}
25
26#[derive(Debug, Clone)]
27pub struct KyberPreKeyRecord {
28    signed_pre_key: SignedPreKeyRecordStructure,
29}
30
31impl GenericSignedPreKey for KyberPreKeyRecord {
32    type KeyPair = kem::KeyPair;
33    type Id = KyberPreKeyId;
34
35    fn get_storage(&self) -> &SignedPreKeyRecordStructure {
36        &self.signed_pre_key
37    }
38
39    fn from_storage(storage: SignedPreKeyRecordStructure) -> Self {
40        Self {
41            signed_pre_key: storage,
42        }
43    }
44}
45
46impl KyberPreKeyRecord {
47    pub fn secret_key(&self) -> Result<kem::SecretKey> {
48        kem::SecretKey::deserialize(&self.signed_pre_key.private_key)
49    }
50}
51
52impl KyberPreKeyRecord {
53    pub fn generate(
54        kyber_key_type: kem::KeyType,
55        id: KyberPreKeyId,
56        signing_key: &PrivateKey,
57    ) -> Result<KyberPreKeyRecord> {
58        let mut rng = rand::rngs::OsRng.unwrap_err();
59        let key_pair = kem::KeyPair::generate(kyber_key_type, &mut rng);
60        let signature = signing_key
61            .calculate_signature(&key_pair.public_key.serialize(), &mut rng)?
62            .into_vec();
63        let timestamp = std::time::SystemTime::now()
64            .duration_since(std::time::SystemTime::UNIX_EPOCH)
65            .expect("Time should move forward")
66            .as_millis();
67        Ok(KyberPreKeyRecord::new(
68            id,
69            Timestamp::from_epoch_millis(timestamp.try_into().expect("Timestamp too large")),
70            &key_pair,
71            &signature,
72        ))
73    }
74}