Skip to main content

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::{DeviceId, IdentityKey, KyberPreKeyId, PublicKey, Result, SignalProtocolError, kem};
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.pre_key_id.zip(content.pre_key_public),
93            content.signed_pre_key_id.ok_or_else(|| {
94                SignalProtocolError::InvalidArgument("signed_pre_key_id is required".to_string())
95            })?,
96            content.signed_pre_key_public.ok_or_else(|| {
97                SignalProtocolError::InvalidArgument(
98                    "signed_pre_key_public is required".to_string(),
99                )
100            })?,
101            content.signed_pre_key_signature.ok_or_else(|| {
102                SignalProtocolError::InvalidArgument(
103                    "signed_pre_key_signature is required".to_string(),
104                )
105            })?,
106            content.kyber_pre_key_id.ok_or_else(|| {
107                SignalProtocolError::InvalidArgument("kyber_pre_key_id is required".to_string())
108            })?,
109            content.kyber_pre_key_public.ok_or_else(|| {
110                SignalProtocolError::InvalidArgument("kyber_pre_key_public is required".to_string())
111            })?,
112            content.kyber_pre_key_signature.ok_or_else(|| {
113                SignalProtocolError::InvalidArgument(
114                    "kyber_pre_key_signature is required".to_string(),
115                )
116            })?,
117            content.identity_key.ok_or_else(|| {
118                SignalProtocolError::InvalidArgument("identity_key is required".to_string())
119            })?,
120        )
121    }
122}
123
124#[derive(Clone)]
125pub struct PreKeyBundle {
126    registration_id: u32,
127    device_id: DeviceId,
128    pre_key_id: Option<PreKeyId>,
129    pre_key_public: Option<PublicKey>,
130    ec_signed_pre_key: SignedPreKey,
131    identity_key: IdentityKey,
132    kyber_pre_key: KyberPreKey,
133}
134
135impl PreKeyBundle {
136    #[expect(clippy::too_many_arguments)]
137    pub fn new(
138        registration_id: u32,
139        device_id: DeviceId,
140        pre_key: Option<(PreKeyId, PublicKey)>,
141        signed_pre_key_id: SignedPreKeyId,
142        signed_pre_key_public: PublicKey,
143        signed_pre_key_signature: Vec<u8>,
144        kyber_pre_key_id: KyberPreKeyId,
145        kyber_pre_key_public: kem::PublicKey,
146        kyber_pre_key_signature: Vec<u8>,
147        identity_key: IdentityKey,
148    ) -> Result<Self> {
149        let (pre_key_id, pre_key_public) = match pre_key {
150            None => (None, None),
151            Some((id, key)) => (Some(id), Some(key)),
152        };
153
154        let ec_signed_pre_key = SignedPreKey::new(
155            signed_pre_key_id,
156            signed_pre_key_public,
157            signed_pre_key_signature,
158        );
159
160        let kyber_pre_key = KyberPreKey::new(
161            kyber_pre_key_id,
162            kyber_pre_key_public,
163            kyber_pre_key_signature,
164        );
165
166        Ok(Self {
167            registration_id,
168            device_id,
169            pre_key_id,
170            pre_key_public,
171            ec_signed_pre_key,
172            identity_key,
173            kyber_pre_key,
174        })
175    }
176
177    pub fn registration_id(&self) -> Result<u32> {
178        Ok(self.registration_id)
179    }
180
181    pub fn device_id(&self) -> Result<DeviceId> {
182        Ok(self.device_id)
183    }
184
185    pub fn pre_key_id(&self) -> Result<Option<PreKeyId>> {
186        Ok(self.pre_key_id)
187    }
188
189    pub fn pre_key_public(&self) -> Result<Option<PublicKey>> {
190        Ok(self.pre_key_public)
191    }
192
193    pub fn signed_pre_key_id(&self) -> Result<SignedPreKeyId> {
194        Ok(self.ec_signed_pre_key.id)
195    }
196
197    pub fn signed_pre_key_public(&self) -> Result<PublicKey> {
198        Ok(self.ec_signed_pre_key.public_key)
199    }
200
201    pub fn signed_pre_key_signature(&self) -> Result<&[u8]> {
202        Ok(self.ec_signed_pre_key.signature.as_ref())
203    }
204
205    pub fn identity_key(&self) -> Result<&IdentityKey> {
206        Ok(&self.identity_key)
207    }
208
209    pub fn kyber_pre_key_id(&self) -> Result<KyberPreKeyId> {
210        Ok(self.kyber_pre_key.id)
211    }
212
213    pub fn kyber_pre_key_public(&self) -> Result<&kem::PublicKey> {
214        Ok(&self.kyber_pre_key.public_key)
215    }
216
217    pub fn kyber_pre_key_signature(&self) -> Result<&[u8]> {
218        Ok(&self.kyber_pre_key.signature)
219    }
220
221    pub fn modify<F>(self, modify: F) -> Result<Self>
222    where
223        F: FnOnce(&mut PreKeyBundleContent),
224    {
225        let mut content = self.into();
226        modify(&mut content);
227        content.try_into()
228    }
229}