zkgroup/api/call_links/
auth_credential.rs1use partial_default::PartialDefault;
13use serde::{Deserialize, Serialize};
14
15use super::{CallLinkPublicParams, CallLinkSecretParams};
16use crate::common::serialization::ReservedByte;
17use crate::common::simple_types::*;
18use crate::crypto::uid_encryption;
19use crate::crypto::uid_struct::UidStruct;
20use crate::generic_server_params::{GenericServerPublicParams, GenericServerSecretParams};
21use crate::groups::UuidCiphertext;
22use crate::ZkGroupVerificationFailure;
23
24const CREDENTIAL_LABEL: &[u8] = b"20230421_Signal_CallLinkAuthCredential";
25
26#[derive(Serialize, Deserialize, PartialDefault)]
27pub struct CallLinkAuthCredentialResponse {
28 reserved: ReservedByte,
29 proof: zkcredential::issuance::IssuanceProof,
30 }
33
34impl CallLinkAuthCredentialResponse {
35 pub fn issue_credential(
36 user_id: libsignal_core::Aci,
37 redemption_time: Timestamp,
38 params: &GenericServerSecretParams,
39 randomness: RandomnessBytes,
40 ) -> CallLinkAuthCredentialResponse {
41 let proof = zkcredential::issuance::IssuanceProofBuilder::new(CREDENTIAL_LABEL)
42 .add_attribute(&UidStruct::from_service_id(user_id.into()))
43 .add_public_attribute(&redemption_time)
44 .issue(¶ms.credential_key, randomness);
45 Self {
46 reserved: Default::default(),
47 proof,
48 }
49 }
50
51 pub fn receive(
52 self,
53 user_id: libsignal_core::Aci,
54 redemption_time: Timestamp,
55 params: &GenericServerPublicParams,
56 ) -> Result<CallLinkAuthCredential, ZkGroupVerificationFailure> {
57 if !redemption_time.is_day_aligned() {
58 return Err(ZkGroupVerificationFailure);
59 }
60
61 let raw_credential = zkcredential::issuance::IssuanceProofBuilder::new(CREDENTIAL_LABEL)
62 .add_attribute(&UidStruct::from_service_id(user_id.into()))
63 .add_public_attribute(&redemption_time)
64 .verify(¶ms.credential_key, self.proof)
65 .map_err(|_| ZkGroupVerificationFailure)?;
66 Ok(CallLinkAuthCredential {
67 reserved: Default::default(),
68 credential: raw_credential,
69 })
70 }
71}
72
73#[derive(Serialize, Deserialize, PartialDefault)]
74pub struct CallLinkAuthCredential {
75 reserved: ReservedByte,
76 credential: zkcredential::credentials::Credential,
77 }
80
81impl CallLinkAuthCredential {
82 pub fn present(
83 &self,
84 user_id: libsignal_core::Aci,
85 redemption_time: Timestamp,
86 server_params: &GenericServerPublicParams,
87 call_link_params: &CallLinkSecretParams,
88 randomness: RandomnessBytes,
89 ) -> CallLinkAuthCredentialPresentation {
90 let uid_attr = UidStruct::from_service_id(user_id.into());
91 let proof = zkcredential::presentation::PresentationProofBuilder::new(CREDENTIAL_LABEL)
92 .add_attribute(&uid_attr, &call_link_params.uid_enc_key_pair)
93 .present(&server_params.credential_key, &self.credential, randomness);
94 CallLinkAuthCredentialPresentation {
95 reserved: Default::default(),
96 proof,
97 ciphertext: call_link_params.uid_enc_key_pair.encrypt(&uid_attr),
98 redemption_time,
99 }
100 }
101}
102
103#[derive(Serialize, Deserialize, PartialDefault)]
104pub struct CallLinkAuthCredentialPresentation {
105 reserved: ReservedByte,
106 pub(crate) proof: zkcredential::presentation::PresentationProof,
107 pub(crate) ciphertext: uid_encryption::Ciphertext,
108 pub(crate) redemption_time: Timestamp,
109}
110
111impl CallLinkAuthCredentialPresentation {
112 pub fn verify(
113 &self,
114 current_time: Timestamp,
115 server_params: &GenericServerSecretParams,
116 call_link_params: &CallLinkPublicParams,
117 ) -> Result<(), ZkGroupVerificationFailure> {
118 crate::ServerSecretParams::check_auth_credential_redemption_time(
119 self.redemption_time,
120 current_time,
121 )?;
122
123 zkcredential::presentation::PresentationProofVerifier::new(CREDENTIAL_LABEL)
124 .add_attribute(&self.ciphertext, &call_link_params.uid_enc_public_key)
125 .add_public_attribute(&self.redemption_time)
126 .verify(&server_params.credential_key, &self.proof)
127 .map_err(|_| ZkGroupVerificationFailure)
128 }
129
130 pub fn get_user_id(&self) -> UuidCiphertext {
131 UuidCiphertext {
132 reserved: Default::default(),
133 ciphertext: self.ciphertext,
134 }
135 }
136}