Skip to main content

securedrop_protocol_minimal/keys/
bundle.rs

1use alloc::vec::Vec;
2use serde::{Deserialize, Serialize};
3
4use crate::message::{MessageKeyPair, MessagePublicKey};
5use crate::metadata::{MetadataKeyPair, MetadataPublicKey};
6use crate::primitives::ristretto255::DHPublicKey;
7use crate::sign::{JournalistEphemeralKey, Signature};
8
9/// The public keys that make up one ephemeral key bundle
10#[derive(Debug, Clone)]
11#[cfg_attr(not(hax), derive(Serialize, Deserialize))]
12pub struct KeyBundlePublic {
13    /// SD-APKE ephemeral key `pk_{J,i}^{APKE_E} = (pk1, pk2)`.
14    pub apke_pk: MessagePublicKey,
15    /// SD-PKE ephemeral key, used for metadata protection.
16    pub metadata_pk: MetadataPublicKey,
17}
18
19impl KeyBundlePublic {
20    /// Serialize the bundle public keys in canonical byte order for signing.
21    ///
22    /// Layout: `pk_{J,i}^{APKE_E}(DHKEM) || pk_{J,i}^{APKE_E}(ML-KEM) || pk_{J,i}^{PKE_E}(X-Wing)`
23    pub fn as_bytes(&self) -> Vec<u8> {
24        let mut out = Vec::new();
25        out.extend_from_slice(&self.apke_pk.as_bytes());
26        out.extend_from_slice(&self.metadata_pk.as_bytes());
27        out
28    }
29}
30
31pub(crate) struct MessageKeyBundle {
32    pub(crate) apke: MessageKeyPair,
33    pub(crate) metadata_kp: MetadataKeyPair,
34}
35
36impl MessageKeyBundle {
37    pub fn new(apke: MessageKeyPair, metadata_kp: MetadataKeyPair) -> Self {
38        Self { apke, metadata_kp }
39    }
40
41    pub(crate) fn public(&self) -> KeyBundlePublic {
42        KeyBundlePublic {
43            apke_pk: self.apke.public_key().clone(),
44            metadata_pk: self.metadata_kp.public_key().clone(),
45        }
46    }
47}
48
49#[derive(Debug, Clone)]
50pub(crate) struct LongtermKeyBundle {
51    pub(crate) apke: MessagePublicKey,
52    pub(crate) fetch_pk: DHPublicKey,
53}
54
55impl LongtermKeyBundle {
56    pub const LEN: usize = MessagePublicKey::LEN + DHPublicKey::LEN;
57
58    pub fn new(apke: MessagePublicKey, fetch_pk: DHPublicKey) -> Self {
59        Self { apke, fetch_pk }
60    }
61
62    /// Serialize long-term public keys into the canonical byte encoding.
63    ///
64    /// Byte layout (per spec ยง3.1): `pk_J^APKE || pk_J^fetch`
65    /// where `pk_J^APKE = pk_J^AKEM (DH-AKEM) || pk_J^PQ (ML-KEM)`
66    pub fn as_bytes(&self) -> [u8; Self::LEN] {
67        let apke_bytes = self.apke.as_bytes();
68        let fetch_bytes = self.fetch_pk.into_bytes();
69
70        let mut pubkey_bytes = [0u8; Self::LEN];
71        pubkey_bytes[..apke_bytes.len()].copy_from_slice(&apke_bytes);
72        pubkey_bytes[apke_bytes.len()..].copy_from_slice(&fetch_bytes);
73
74        pubkey_bytes
75    }
76}