zkgroup/api/profiles/
profile_key_version.rs

1//
2// Copyright 2020 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6use serde::ser::SerializeTuple;
7use serde::{Serialize, Serializer};
8
9use super::ProfileKey;
10use crate::common::sho::Sho;
11use crate::common::simple_types::*;
12use crate::{
13    api, PROFILE_KEY_LEN, PROFILE_KEY_VERSION_ENCODED_LEN, PROFILE_KEY_VERSION_LEN, UUID_LEN,
14};
15
16/// An identifier for a particular (profile key, ACI) combination.
17///
18/// A profile key version, properly encoded, is a hexadecimal ASCII string, meant to be put directly
19/// into, e.g. HTTP requests.
20///
21/// Note that it is not a "*profile* version"; a Signal user can change their profile without
22/// rotating their profile key, and the profile key version will not change either.
23#[derive(Copy, Clone)]
24pub struct ProfileKeyVersion {
25    ascii: ProfileKeyVersionEncodedBytes,
26}
27
28impl AsRef<str> for ProfileKeyVersion {
29    fn as_ref(&self) -> &str {
30        // An "encoded" profile key version is hexadecimal ASCII.
31        std::str::from_utf8(&self.ascii).expect("ASCII")
32    }
33}
34
35impl Serialize for ProfileKeyVersion {
36    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
37    where
38        S: Serializer,
39    {
40        let mut seq = serializer.serialize_tuple(self.ascii.len()).unwrap();
41        for b in self.ascii.iter() {
42            seq.serialize_element(b)?;
43        }
44        seq.end()
45    }
46}
47
48impl ProfileKey {
49    // Defined here so it can construct a ProfileKeyVersion directly without making the `ascii`
50    // field public.
51    pub fn get_profile_key_version(
52        &self,
53        user_id: libsignal_core::Aci,
54    ) -> api::profiles::ProfileKeyVersion {
55        let uid_bytes = uuid::Uuid::from(user_id).into_bytes();
56        let mut combined_array = [0u8; PROFILE_KEY_LEN + UUID_LEN];
57        combined_array[..PROFILE_KEY_LEN].copy_from_slice(&self.bytes);
58        combined_array[PROFILE_KEY_LEN..].copy_from_slice(&uid_bytes);
59        let mut sho = Sho::new(
60            b"Signal_ZKGroup_20200424_ProfileKeyAndUid_ProfileKey_GetProfileKeyVersion",
61            &combined_array,
62        );
63
64        let mut pkv_hex_array: [u8; PROFILE_KEY_VERSION_ENCODED_LEN] =
65            [0u8; PROFILE_KEY_VERSION_ENCODED_LEN];
66        hex::encode_to_slice(
67            sho.squeeze_as_array::<PROFILE_KEY_VERSION_LEN>(),
68            &mut pkv_hex_array,
69        )
70        .expect("lengths match");
71        api::profiles::ProfileKeyVersion {
72            ascii: pkv_hex_array,
73        }
74    }
75}