zkgroup/api/profiles/
profile_key_credential_presentation.rs

1//
2// Copyright 2020-2022 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6use partial_default::PartialDefault;
7use serde::{Deserialize, Serialize, Serializer};
8
9use crate::common::constants::*;
10use crate::common::errors::*;
11use crate::common::serialization::VersionByte;
12use crate::common::simple_types::*;
13use crate::{api, crypto};
14
15#[derive(Serialize, Deserialize, PartialDefault)]
16pub struct ProfileKeyCredentialPresentationV1 {
17    pub(crate) version: u8, // Not ReservedByte or VersionByte to allow deserializing a V2 presentation as V1.
18    pub(crate) proof: crypto::proofs::ProfileKeyCredentialPresentationProofV1,
19    pub(crate) uid_enc_ciphertext: crypto::uid_encryption::Ciphertext,
20    pub(crate) profile_key_enc_ciphertext: crypto::profile_key_encryption::Ciphertext,
21}
22
23impl ProfileKeyCredentialPresentationV1 {
24    pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext {
25        api::groups::UuidCiphertext {
26            reserved: Default::default(),
27            ciphertext: self.uid_enc_ciphertext,
28        }
29    }
30
31    pub fn get_profile_key_ciphertext(&self) -> api::groups::ProfileKeyCiphertext {
32        api::groups::ProfileKeyCiphertext {
33            reserved: Default::default(),
34            ciphertext: self.profile_key_enc_ciphertext,
35        }
36    }
37}
38
39/// Like [`ProfileKeyCredentialPresentationV1`], but with an optimized proof.
40#[derive(Serialize, Deserialize, PartialDefault)]
41pub struct ProfileKeyCredentialPresentationV2 {
42    pub(crate) version: VersionByte<PRESENTATION_VERSION_2>,
43    pub(crate) proof: crypto::proofs::ProfileKeyCredentialPresentationProofV2,
44    pub(crate) uid_enc_ciphertext: crypto::uid_encryption::Ciphertext,
45    pub(crate) profile_key_enc_ciphertext: crypto::profile_key_encryption::Ciphertext,
46}
47
48impl ProfileKeyCredentialPresentationV2 {
49    pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext {
50        api::groups::UuidCiphertext {
51            reserved: Default::default(),
52            ciphertext: self.uid_enc_ciphertext,
53        }
54    }
55
56    pub fn get_profile_key_ciphertext(&self) -> api::groups::ProfileKeyCiphertext {
57        api::groups::ProfileKeyCiphertext {
58            reserved: Default::default(),
59            ciphertext: self.profile_key_enc_ciphertext,
60        }
61    }
62}
63
64#[derive(Serialize, Deserialize, PartialDefault)]
65pub struct ExpiringProfileKeyCredentialPresentation {
66    pub(crate) version: VersionByte<PRESENTATION_VERSION_3>,
67    pub(crate) proof: crypto::proofs::ExpiringProfileKeyCredentialPresentationProof,
68    pub(crate) uid_enc_ciphertext: crypto::uid_encryption::Ciphertext,
69    pub(crate) profile_key_enc_ciphertext: crypto::profile_key_encryption::Ciphertext,
70    pub(crate) credential_expiration_time: Timestamp,
71}
72
73impl ExpiringProfileKeyCredentialPresentation {
74    pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext {
75        api::groups::UuidCiphertext {
76            reserved: Default::default(),
77            ciphertext: self.uid_enc_ciphertext,
78        }
79    }
80
81    pub fn get_profile_key_ciphertext(&self) -> api::groups::ProfileKeyCiphertext {
82        api::groups::ProfileKeyCiphertext {
83            reserved: Default::default(),
84            ciphertext: self.profile_key_enc_ciphertext,
85        }
86    }
87
88    pub fn get_expiration_time(&self) -> Timestamp {
89        self.credential_expiration_time
90    }
91}
92
93pub enum AnyProfileKeyCredentialPresentation {
94    V1(ProfileKeyCredentialPresentationV1),
95    V2(ProfileKeyCredentialPresentationV2),
96    V3(ExpiringProfileKeyCredentialPresentation),
97}
98
99impl AnyProfileKeyCredentialPresentation {
100    pub fn new(presentation_bytes: &[u8]) -> Result<Self, ZkGroupDeserializationFailure> {
101        match presentation_bytes[0] {
102            PRESENTATION_VERSION_1 => {
103                crate::deserialize::<ProfileKeyCredentialPresentationV1>(presentation_bytes)
104                    .map(AnyProfileKeyCredentialPresentation::V1)
105            }
106            PRESENTATION_VERSION_2 => {
107                crate::deserialize::<ProfileKeyCredentialPresentationV2>(presentation_bytes)
108                    .map(AnyProfileKeyCredentialPresentation::V2)
109            }
110            PRESENTATION_VERSION_3 => {
111                crate::deserialize::<ExpiringProfileKeyCredentialPresentation>(presentation_bytes)
112                    .map(AnyProfileKeyCredentialPresentation::V3)
113            }
114            _ => Err(ZkGroupDeserializationFailure::new::<Self>()),
115        }
116    }
117
118    pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext {
119        match self {
120            AnyProfileKeyCredentialPresentation::V1(presentation) => {
121                presentation.get_uuid_ciphertext()
122            }
123            AnyProfileKeyCredentialPresentation::V2(presentation) => {
124                presentation.get_uuid_ciphertext()
125            }
126            AnyProfileKeyCredentialPresentation::V3(presentation) => {
127                presentation.get_uuid_ciphertext()
128            }
129        }
130    }
131
132    pub fn get_profile_key_ciphertext(&self) -> api::groups::ProfileKeyCiphertext {
133        match self {
134            AnyProfileKeyCredentialPresentation::V1(presentation) => {
135                presentation.get_profile_key_ciphertext()
136            }
137            AnyProfileKeyCredentialPresentation::V2(presentation) => {
138                presentation.get_profile_key_ciphertext()
139            }
140            AnyProfileKeyCredentialPresentation::V3(presentation) => {
141                presentation.get_profile_key_ciphertext()
142            }
143        }
144    }
145
146    pub fn to_structurally_valid_v1_presentation_bytes(&self) -> Vec<u8> {
147        let v1 = ProfileKeyCredentialPresentationV1 {
148            version: PRESENTATION_VERSION_1,
149            proof: crypto::proofs::ProfileKeyCredentialPresentationProofV1::from_invalid_proof(
150                // Hardcoded length of a valid v1 proof.
151                vec![0; 0x0140],
152            ),
153            uid_enc_ciphertext: self.get_uuid_ciphertext().ciphertext,
154            profile_key_enc_ciphertext: self.get_profile_key_ciphertext().ciphertext,
155        };
156        let result = crate::serialize(&v1);
157        debug_assert_eq!(result.len(), PROFILE_KEY_CREDENTIAL_PRESENTATION_V1_LEN);
158        result
159    }
160}
161
162impl Serialize for AnyProfileKeyCredentialPresentation {
163    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
164    where
165        S: Serializer,
166    {
167        match self {
168            AnyProfileKeyCredentialPresentation::V1(presentation) => {
169                presentation.serialize(serializer)
170            }
171            AnyProfileKeyCredentialPresentation::V2(presentation) => {
172                presentation.serialize(serializer)
173            }
174            AnyProfileKeyCredentialPresentation::V3(presentation) => {
175                presentation.serialize(serializer)
176            }
177        }
178    }
179}
180
181impl From<ProfileKeyCredentialPresentationV1> for AnyProfileKeyCredentialPresentation {
182    fn from(presentation: ProfileKeyCredentialPresentationV1) -> Self {
183        Self::V1(presentation)
184    }
185}
186impl From<ProfileKeyCredentialPresentationV2> for AnyProfileKeyCredentialPresentation {
187    fn from(presentation: ProfileKeyCredentialPresentationV2) -> Self {
188        Self::V2(presentation)
189    }
190}
191impl From<ExpiringProfileKeyCredentialPresentation> for AnyProfileKeyCredentialPresentation {
192    fn from(presentation: ExpiringProfileKeyCredentialPresentation) -> Self {
193        Self::V3(presentation)
194    }
195}