zkgroup/api/call_links/
params.rs

1//
2// Copyright 2023 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6use partial_default::PartialDefault;
7use serde::{Deserialize, Serialize};
8
9use crate::common::errors::*;
10use crate::common::serialization::ReservedByte;
11use crate::common::sho::*;
12use crate::crypto::uid_encryption;
13use crate::{api, crypto};
14
15#[derive(Copy, Clone, Serialize, Deserialize, PartialDefault)]
16pub struct CallLinkSecretParams {
17    reserved: ReservedByte,
18    pub(crate) uid_enc_key_pair:
19        zkcredential::attributes::KeyPair<crypto::uid_encryption::UidEncryptionDomain>,
20}
21
22impl AsRef<uid_encryption::KeyPair> for CallLinkSecretParams {
23    fn as_ref(&self) -> &uid_encryption::KeyPair {
24        &self.uid_enc_key_pair
25    }
26}
27
28#[derive(Copy, Clone, Serialize, Deserialize, PartialDefault)]
29pub struct CallLinkPublicParams {
30    reserved: ReservedByte,
31    pub(crate) uid_enc_public_key:
32        zkcredential::attributes::PublicKey<crypto::uid_encryption::UidEncryptionDomain>,
33}
34
35impl CallLinkSecretParams {
36    const ROOT_KEY_MAX_BYTES_FOR_SHO: usize = 16;
37
38    pub fn derive_from_root_key(root_key: &[u8]) -> Self {
39        let byte_count = Self::ROOT_KEY_MAX_BYTES_FOR_SHO.min(root_key.len());
40        let mut sho = Sho::new(
41            b"Signal_ZKGroup_20230419_CallLinkSecretParams_DeriveFromRootKey",
42            &root_key[..byte_count],
43        );
44        let uid_enc_key_pair = zkcredential::attributes::KeyPair::derive_from(sho.as_mut());
45
46        Self {
47            reserved: Default::default(),
48            uid_enc_key_pair,
49        }
50    }
51
52    pub fn get_public_params(&self) -> CallLinkPublicParams {
53        CallLinkPublicParams {
54            reserved: Default::default(),
55            uid_enc_public_key: self.uid_enc_key_pair.public_key,
56        }
57    }
58
59    pub fn encrypt_uid(&self, user_id: libsignal_core::Aci) -> api::groups::UuidCiphertext {
60        let uid = crypto::uid_struct::UidStruct::from_service_id(user_id.into());
61        self.encrypt_uid_struct(uid)
62    }
63
64    fn encrypt_uid_struct(
65        &self,
66        uid: crypto::uid_struct::UidStruct,
67    ) -> api::groups::UuidCiphertext {
68        let ciphertext = self.uid_enc_key_pair.encrypt(&uid);
69        api::groups::UuidCiphertext {
70            reserved: Default::default(),
71            ciphertext,
72        }
73    }
74
75    pub fn decrypt_uid(
76        &self,
77        ciphertext: api::groups::UuidCiphertext,
78    ) -> Result<libsignal_core::Aci, ZkGroupVerificationFailure> {
79        let uid = crypto::uid_encryption::UidEncryptionDomain::decrypt(
80            &self.uid_enc_key_pair,
81            &ciphertext.ciphertext,
82        )?;
83        uid.try_into().map_err(|_| ZkGroupVerificationFailure)
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use crate::call_links::CallLinkSecretParams;
90
91    #[test]
92    fn test_call_link_secret_params_ignores_extra_bytes() {
93        let bytes_0 = b"0123456789012345";
94        let bytes_1 = b"012345678901234512345";
95
96        assert_eq!(
97            bytes_0.len(),
98            CallLinkSecretParams::ROOT_KEY_MAX_BYTES_FOR_SHO
99        );
100
101        assert!(bytes_1.len() > CallLinkSecretParams::ROOT_KEY_MAX_BYTES_FOR_SHO);
102
103        let secret_params_0 = CallLinkSecretParams::derive_from_root_key(bytes_0);
104        let secret_params_1 = CallLinkSecretParams::derive_from_root_key(bytes_1);
105
106        assert_eq!(
107            secret_params_0.uid_enc_key_pair.a1,
108            secret_params_1.uid_enc_key_pair.a1
109        );
110        assert_eq!(
111            secret_params_0.uid_enc_key_pair.a2,
112            secret_params_1.uid_enc_key_pair.a2
113        );
114        assert!(
115            secret_params_0.uid_enc_key_pair.public_key
116                == secret_params_1.uid_enc_key_pair.public_key
117        );
118    }
119}