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
93#[derive(derive_more::From)]
94pub enum AnyProfileKeyCredentialPresentation {
95    V1(ProfileKeyCredentialPresentationV1),
96    V2(ProfileKeyCredentialPresentationV2),
97    V3(ExpiringProfileKeyCredentialPresentation),
98}
99
100impl AnyProfileKeyCredentialPresentation {
101    pub fn new(presentation_bytes: &[u8]) -> Result<Self, ZkGroupDeserializationFailure> {
102        match presentation_bytes[0] {
103            PRESENTATION_VERSION_1 => {
104                crate::deserialize::<ProfileKeyCredentialPresentationV1>(presentation_bytes)
105                    .map(AnyProfileKeyCredentialPresentation::V1)
106            }
107            PRESENTATION_VERSION_2 => {
108                crate::deserialize::<ProfileKeyCredentialPresentationV2>(presentation_bytes)
109                    .map(AnyProfileKeyCredentialPresentation::V2)
110            }
111            PRESENTATION_VERSION_3 => {
112                crate::deserialize::<ExpiringProfileKeyCredentialPresentation>(presentation_bytes)
113                    .map(AnyProfileKeyCredentialPresentation::V3)
114            }
115            _ => Err(ZkGroupDeserializationFailure::new::<Self>()),
116        }
117    }
118
119    pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext {
120        match self {
121            AnyProfileKeyCredentialPresentation::V1(presentation) => {
122                presentation.get_uuid_ciphertext()
123            }
124            AnyProfileKeyCredentialPresentation::V2(presentation) => {
125                presentation.get_uuid_ciphertext()
126            }
127            AnyProfileKeyCredentialPresentation::V3(presentation) => {
128                presentation.get_uuid_ciphertext()
129            }
130        }
131    }
132
133    pub fn get_profile_key_ciphertext(&self) -> api::groups::ProfileKeyCiphertext {
134        match self {
135            AnyProfileKeyCredentialPresentation::V1(presentation) => {
136                presentation.get_profile_key_ciphertext()
137            }
138            AnyProfileKeyCredentialPresentation::V2(presentation) => {
139                presentation.get_profile_key_ciphertext()
140            }
141            AnyProfileKeyCredentialPresentation::V3(presentation) => {
142                presentation.get_profile_key_ciphertext()
143            }
144        }
145    }
146
147    pub fn to_structurally_valid_v1_presentation_bytes(&self) -> Vec<u8> {
148        let v1 = ProfileKeyCredentialPresentationV1 {
149            version: PRESENTATION_VERSION_1,
150            proof: crypto::proofs::ProfileKeyCredentialPresentationProofV1::from_invalid_proof(
151                // Hardcoded length of a valid v1 proof.
152                vec![0; 0x0140],
153            ),
154            uid_enc_ciphertext: self.get_uuid_ciphertext().ciphertext,
155            profile_key_enc_ciphertext: self.get_profile_key_ciphertext().ciphertext,
156        };
157        let result = crate::serialize(&v1);
158        debug_assert_eq!(result.len(), PROFILE_KEY_CREDENTIAL_PRESENTATION_V1_LEN);
159        result
160    }
161}
162
163impl Serialize for AnyProfileKeyCredentialPresentation {
164    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
165    where
166        S: Serializer,
167    {
168        match self {
169            AnyProfileKeyCredentialPresentation::V1(presentation) => {
170                presentation.serialize(serializer)
171            }
172            AnyProfileKeyCredentialPresentation::V2(presentation) => {
173                presentation.serialize(serializer)
174            }
175            AnyProfileKeyCredentialPresentation::V3(presentation) => {
176                presentation.serialize(serializer)
177            }
178        }
179    }
180}