libsignal_protocol/state/
bundle.rs

1//
2// Copyright 2020 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6use std::clone::Clone;
7
8use crate::state::{PreKeyId, SignedPreKeyId};
9use crate::{kem, DeviceId, IdentityKey, KyberPreKeyId, PublicKey, Result, SignalProtocolError};
10
11#[derive(Clone)]
12struct SignedPreKey {
13    id: SignedPreKeyId,
14    public_key: PublicKey,
15    signature: Vec<u8>,
16}
17
18impl SignedPreKey {
19    fn new(id: SignedPreKeyId, public_key: PublicKey, signature: Vec<u8>) -> Self {
20        Self {
21            id,
22            public_key,
23            signature,
24        }
25    }
26}
27
28#[derive(Clone)]
29struct KyberPreKey {
30    id: KyberPreKeyId,
31    public_key: kem::PublicKey,
32    signature: Vec<u8>,
33}
34
35impl KyberPreKey {
36    fn new(id: KyberPreKeyId, public_key: kem::PublicKey, signature: Vec<u8>) -> Self {
37        Self {
38            id,
39            public_key,
40            signature,
41        }
42    }
43}
44
45// Represents the raw contents of the pre-key bundle without any notion of required/optional
46// fields.
47// Can be used as a "builder" for PreKeyBundle, in which case all the validation will happen in
48// PreKeyBundle::new.
49pub struct PreKeyBundleContent {
50    pub registration_id: Option<u32>,
51    pub device_id: Option<DeviceId>,
52    pub pre_key_id: Option<PreKeyId>,
53    pub pre_key_public: Option<PublicKey>,
54    pub signed_pre_key_id: Option<SignedPreKeyId>,
55    pub signed_pre_key_public: Option<PublicKey>,
56    pub signed_pre_key_signature: Option<Vec<u8>>,
57    pub identity_key: Option<IdentityKey>,
58    pub kyber_pre_key_id: Option<KyberPreKeyId>,
59    pub kyber_pre_key_public: Option<kem::PublicKey>,
60    pub kyber_pre_key_signature: Option<Vec<u8>>,
61}
62
63impl From<PreKeyBundle> for PreKeyBundleContent {
64    fn from(bundle: PreKeyBundle) -> Self {
65        Self {
66            registration_id: Some(bundle.registration_id),
67            device_id: Some(bundle.device_id),
68            pre_key_id: bundle.pre_key_id,
69            pre_key_public: bundle.pre_key_public,
70            signed_pre_key_id: Some(bundle.ec_signed_pre_key.id),
71            signed_pre_key_public: Some(bundle.ec_signed_pre_key.public_key),
72            signed_pre_key_signature: Some(bundle.ec_signed_pre_key.signature),
73            identity_key: Some(bundle.identity_key),
74            kyber_pre_key_id: Some(bundle.kyber_pre_key.id),
75            kyber_pre_key_public: Some(bundle.kyber_pre_key.public_key),
76            kyber_pre_key_signature: Some(bundle.kyber_pre_key.signature),
77        }
78    }
79}
80
81impl TryFrom<PreKeyBundleContent> for PreKeyBundle {
82    type Error = SignalProtocolError;
83
84    fn try_from(content: PreKeyBundleContent) -> Result<Self> {
85        PreKeyBundle::new(
86            content.registration_id.ok_or_else(|| {
87                SignalProtocolError::InvalidArgument("registration_id is required".to_string())
88            })?,
89            content.device_id.ok_or_else(|| {
90                SignalProtocolError::InvalidArgument("device_id is required".to_string())
91            })?,
92            content
93                .pre_key_id
94                .and_then(|id| content.pre_key_public.map(|public| (id, public))),
95            content.signed_pre_key_id.ok_or_else(|| {
96                SignalProtocolError::InvalidArgument("signed_pre_key_id is required".to_string())
97            })?,
98            content.signed_pre_key_public.ok_or_else(|| {
99                SignalProtocolError::InvalidArgument(
100                    "signed_pre_key_public is required".to_string(),
101                )
102            })?,
103            content.signed_pre_key_signature.ok_or_else(|| {
104                SignalProtocolError::InvalidArgument(
105                    "signed_pre_key_signature is required".to_string(),
106                )
107            })?,
108            content.kyber_pre_key_id.ok_or_else(|| {
109                SignalProtocolError::InvalidArgument("kyber_pre_key_id is required".to_string())
110            })?,
111            content.kyber_pre_key_public.ok_or_else(|| {
112                SignalProtocolError::InvalidArgument("kyber_pre_key_public is required".to_string())
113            })?,
114            content.kyber_pre_key_signature.ok_or_else(|| {
115                SignalProtocolError::InvalidArgument(
116                    "kyber_pre_key_signature is required".to_string(),
117                )
118            })?,
119            content.identity_key.ok_or_else(|| {
120                SignalProtocolError::InvalidArgument("identity_key is required".to_string())
121            })?,
122        )
123    }
124}
125
126#[derive(Clone)]
127pub struct PreKeyBundle {
128    registration_id: u32,
129    device_id: DeviceId,
130    pre_key_id: Option<PreKeyId>,
131    pre_key_public: Option<PublicKey>,
132    ec_signed_pre_key: SignedPreKey,
133    identity_key: IdentityKey,
134    kyber_pre_key: KyberPreKey,
135}
136
137impl PreKeyBundle {
138    #[expect(clippy::too_many_arguments)]
139    pub fn new(
140        registration_id: u32,
141        device_id: DeviceId,
142        pre_key: Option<(PreKeyId, PublicKey)>,
143        signed_pre_key_id: SignedPreKeyId,
144        signed_pre_key_public: PublicKey,
145        signed_pre_key_signature: Vec<u8>,
146        kyber_pre_key_id: KyberPreKeyId,
147        kyber_pre_key_public: kem::PublicKey,
148        kyber_pre_key_signature: Vec<u8>,
149        identity_key: IdentityKey,
150    ) -> Result<Self> {
151        let (pre_key_id, pre_key_public) = match pre_key {
152            None => (None, None),
153            Some((id, key)) => (Some(id), Some(key)),
154        };
155
156        let ec_signed_pre_key = SignedPreKey::new(
157            signed_pre_key_id,
158            signed_pre_key_public,
159            signed_pre_key_signature,
160        );
161
162        let kyber_pre_key = KyberPreKey::new(
163            kyber_pre_key_id,
164            kyber_pre_key_public,
165            kyber_pre_key_signature,
166        );
167
168        Ok(Self {
169            registration_id,
170            device_id,
171            pre_key_id,
172            pre_key_public,
173            ec_signed_pre_key,
174            identity_key,
175            kyber_pre_key,
176        })
177    }
178
179    pub fn registration_id(&self) -> Result<u32> {
180        Ok(self.registration_id)
181    }
182
183    pub fn device_id(&self) -> Result<DeviceId> {
184        Ok(self.device_id)
185    }
186
187    pub fn pre_key_id(&self) -> Result<Option<PreKeyId>> {
188        Ok(self.pre_key_id)
189    }
190
191    pub fn pre_key_public(&self) -> Result<Option<PublicKey>> {
192        Ok(self.pre_key_public)
193    }
194
195    pub fn signed_pre_key_id(&self) -> Result<SignedPreKeyId> {
196        Ok(self.ec_signed_pre_key.id)
197    }
198
199    pub fn signed_pre_key_public(&self) -> Result<PublicKey> {
200        Ok(self.ec_signed_pre_key.public_key)
201    }
202
203    pub fn signed_pre_key_signature(&self) -> Result<&[u8]> {
204        Ok(self.ec_signed_pre_key.signature.as_ref())
205    }
206
207    pub fn identity_key(&self) -> Result<&IdentityKey> {
208        Ok(&self.identity_key)
209    }
210
211    pub fn kyber_pre_key_id(&self) -> Result<KyberPreKeyId> {
212        Ok(self.kyber_pre_key.id)
213    }
214
215    pub fn kyber_pre_key_public(&self) -> Result<&kem::PublicKey> {
216        Ok(&self.kyber_pre_key.public_key)
217    }
218
219    pub fn kyber_pre_key_signature(&self) -> Result<&[u8]> {
220        Ok(&self.kyber_pre_key.signature)
221    }
222
223    pub fn modify<F>(self, modify: F) -> Result<Self>
224    where
225        F: FnOnce(&mut PreKeyBundleContent),
226    {
227        let mut content = self.into();
228        modify(&mut content);
229        content.try_into()
230    }
231}