use partial_default::PartialDefault;
use serde::{Deserialize, Serialize};
use super::{CallLinkPublicParams, CallLinkSecretParams};
use crate::common::serialization::ReservedByte;
use crate::common::simple_types::*;
use crate::crypto::uid_encryption;
use crate::crypto::uid_struct::UidStruct;
use crate::generic_server_params::{GenericServerPublicParams, GenericServerSecretParams};
use crate::groups::UuidCiphertext;
use crate::ZkGroupVerificationFailure;
const CREDENTIAL_LABEL: &[u8] = b"20230421_Signal_CallLinkAuthCredential";
#[derive(Serialize, Deserialize, PartialDefault)]
pub struct CallLinkAuthCredentialResponse {
reserved: ReservedByte,
proof: zkcredential::issuance::IssuanceProof,
}
impl CallLinkAuthCredentialResponse {
pub fn issue_credential(
user_id: libsignal_core::Aci,
redemption_time: Timestamp,
params: &GenericServerSecretParams,
randomness: RandomnessBytes,
) -> CallLinkAuthCredentialResponse {
let proof = zkcredential::issuance::IssuanceProofBuilder::new(CREDENTIAL_LABEL)
.add_attribute(&UidStruct::from_service_id(user_id.into()))
.add_public_attribute(&redemption_time)
.issue(¶ms.credential_key, randomness);
Self {
reserved: Default::default(),
proof,
}
}
pub fn receive(
self,
user_id: libsignal_core::Aci,
redemption_time: Timestamp,
params: &GenericServerPublicParams,
) -> Result<CallLinkAuthCredential, ZkGroupVerificationFailure> {
if !redemption_time.is_day_aligned() {
return Err(ZkGroupVerificationFailure);
}
let raw_credential = zkcredential::issuance::IssuanceProofBuilder::new(CREDENTIAL_LABEL)
.add_attribute(&UidStruct::from_service_id(user_id.into()))
.add_public_attribute(&redemption_time)
.verify(¶ms.credential_key, self.proof)
.map_err(|_| ZkGroupVerificationFailure)?;
Ok(CallLinkAuthCredential {
reserved: Default::default(),
credential: raw_credential,
})
}
}
#[derive(Serialize, Deserialize, PartialDefault)]
pub struct CallLinkAuthCredential {
reserved: ReservedByte,
credential: zkcredential::credentials::Credential,
}
impl CallLinkAuthCredential {
pub fn present(
&self,
user_id: libsignal_core::Aci,
redemption_time: Timestamp,
server_params: &GenericServerPublicParams,
call_link_params: &CallLinkSecretParams,
randomness: RandomnessBytes,
) -> CallLinkAuthCredentialPresentation {
let uid_attr = UidStruct::from_service_id(user_id.into());
let proof = zkcredential::presentation::PresentationProofBuilder::new(CREDENTIAL_LABEL)
.add_attribute(&uid_attr, &call_link_params.uid_enc_key_pair)
.present(&server_params.credential_key, &self.credential, randomness);
CallLinkAuthCredentialPresentation {
reserved: Default::default(),
proof,
ciphertext: call_link_params.uid_enc_key_pair.encrypt(&uid_attr),
redemption_time,
}
}
}
#[derive(Serialize, Deserialize, PartialDefault)]
pub struct CallLinkAuthCredentialPresentation {
reserved: ReservedByte,
pub(crate) proof: zkcredential::presentation::PresentationProof,
pub(crate) ciphertext: uid_encryption::Ciphertext,
pub(crate) redemption_time: Timestamp,
}
impl CallLinkAuthCredentialPresentation {
pub fn verify(
&self,
current_time: Timestamp,
server_params: &GenericServerSecretParams,
call_link_params: &CallLinkPublicParams,
) -> Result<(), ZkGroupVerificationFailure> {
crate::ServerSecretParams::check_auth_credential_redemption_time(
self.redemption_time,
current_time,
)?;
zkcredential::presentation::PresentationProofVerifier::new(CREDENTIAL_LABEL)
.add_attribute(&self.ciphertext, &call_link_params.uid_enc_public_key)
.add_public_attribute(&self.redemption_time)
.verify(&server_params.credential_key, &self.proof)
.map_err(|_| ZkGroupVerificationFailure)
}
pub fn get_user_id(&self) -> UuidCiphertext {
UuidCiphertext {
reserved: Default::default(),
ciphertext: self.ciphertext,
}
}
}