1use partial_default::PartialDefault;
7use serde::{Deserialize, Serialize};
8
9use crate::common::constants::*;
10use crate::common::errors::*;
11use crate::common::serialization::{ReservedByte, VersionByte};
12use crate::common::sho::*;
13use crate::common::simple_types::*;
14use crate::{api, crypto};
15
16#[derive(Clone, Serialize, Deserialize, PartialDefault)]
17pub struct ServerSecretParams {
18 reserved: ReservedByte,
19 auth_credentials_key_pair: crypto::credentials::KeyPair<crypto::credentials::AuthCredential>,
21
22 pub(crate) profile_key_credentials_key_pair:
24 crypto::credentials::KeyPair<crypto::credentials::ProfileKeyCredential>,
25
26 sig_key_pair: crypto::signature::KeyPair,
27 receipt_credentials_key_pair:
28 crypto::credentials::KeyPair<crypto::credentials::ReceiptCredential>,
29
30 pni_credentials_key_pair: crypto::credentials::KeyPair<crypto::credentials::PniCredential>,
32
33 expiring_profile_key_credentials_key_pair:
34 crypto::credentials::KeyPair<crypto::credentials::ExpiringProfileKeyCredential>,
35
36 auth_credentials_with_pni_key_pair:
38 crypto::credentials::KeyPair<crypto::credentials::AuthCredentialWithPni>,
39
40 pub(crate) generic_credential_key_pair: zkcredential::credentials::CredentialKeyPair,
41 pub(crate) endorsement_key_pair: zkcredential::endorsements::ServerRootKeyPair,
42}
43
44impl AsRef<zkcredential::endorsements::ServerRootKeyPair> for ServerSecretParams {
45 fn as_ref(&self) -> &zkcredential::endorsements::ServerRootKeyPair {
46 &self.endorsement_key_pair
47 }
48}
49
50#[derive(Clone, Serialize, Deserialize, PartialDefault)]
51pub struct ServerPublicParams {
52 reserved: ReservedByte,
53 auth_credentials_public_key: crypto::credentials::PublicKey,
55
56 pub(crate) profile_key_credentials_public_key: crypto::credentials::PublicKey,
58
59 sig_public_key: crypto::signature::PublicKey,
60 receipt_credentials_public_key: crypto::credentials::PublicKey,
61
62 pni_credentials_public_key: crypto::credentials::PublicKey,
64
65 expiring_profile_key_credentials_public_key: crypto::credentials::PublicKey,
66
67 auth_credentials_with_pni_public_key: crypto::credentials::PublicKey,
69
70 pub(crate) generic_credential_public_key: zkcredential::credentials::CredentialPublicKey,
71 pub(crate) endorsement_public_key: zkcredential::endorsements::ServerRootPublicKey,
72}
73
74impl AsRef<zkcredential::endorsements::ServerRootPublicKey> for ServerPublicParams {
75 fn as_ref(&self) -> &zkcredential::endorsements::ServerRootPublicKey {
76 &self.endorsement_public_key
77 }
78}
79
80impl ServerSecretParams {
81 pub fn generate(randomness: RandomnessBytes) -> Self {
82 let mut sho = Sho::new(
83 b"Signal_ZKGroup_20200424_Random_ServerSecretParams_Generate",
84 &randomness,
85 );
86
87 let auth_credentials_key_pair = crypto::credentials::KeyPair::generate(&mut sho);
88 let profile_key_credentials_key_pair = crypto::credentials::KeyPair::generate(&mut sho);
89 let sig_key_pair = crypto::signature::KeyPair::generate(&mut sho);
90 let receipt_credentials_key_pair = crypto::credentials::KeyPair::generate(&mut sho);
91 let pni_credentials_key_pair = crypto::credentials::KeyPair::generate(&mut sho);
92 let expiring_profile_key_credentials_key_pair =
93 crypto::credentials::KeyPair::generate(&mut sho);
94 let auth_credentials_with_pni_key_pair = crypto::credentials::KeyPair::generate(&mut sho);
95 let generic_credential_key_pair =
96 zkcredential::credentials::CredentialKeyPair::generate(randomness);
97 let endorsement_key_pair =
98 zkcredential::endorsements::ServerRootKeyPair::generate(randomness);
99
100 Self {
101 reserved: Default::default(),
102 auth_credentials_key_pair,
103 profile_key_credentials_key_pair,
104 sig_key_pair,
105 receipt_credentials_key_pair,
106 pni_credentials_key_pair,
107 expiring_profile_key_credentials_key_pair,
108 auth_credentials_with_pni_key_pair,
109 generic_credential_key_pair,
110 endorsement_key_pair,
111 }
112 }
113
114 pub fn get_endorsement_root_key_pair(&self) -> EndorsementServerRootKeyPair {
115 EndorsementServerRootKeyPair {
116 reserved: Default::default(),
117 key_pair: self.endorsement_key_pair.clone(),
118 }
119 }
120
121 pub fn get_public_params(&self) -> ServerPublicParams {
122 ServerPublicParams {
123 reserved: Default::default(),
124 auth_credentials_public_key: self.auth_credentials_key_pair.get_public_key(),
125 profile_key_credentials_public_key: self
126 .profile_key_credentials_key_pair
127 .get_public_key(),
128 sig_public_key: self.sig_key_pair.get_public_key(),
129 receipt_credentials_public_key: self.receipt_credentials_key_pair.get_public_key(),
130 pni_credentials_public_key: self.pni_credentials_key_pair.get_public_key(),
131 expiring_profile_key_credentials_public_key: self
132 .expiring_profile_key_credentials_key_pair
133 .get_public_key(),
134 auth_credentials_with_pni_public_key: self
135 .auth_credentials_with_pni_key_pair
136 .get_public_key(),
137 generic_credential_public_key: self.generic_credential_key_pair.public_key().clone(),
138 endorsement_public_key: self.endorsement_key_pair.public_key().clone(),
139 }
140 }
141
142 pub fn sign(&self, randomness: RandomnessBytes, message: &[u8]) -> NotarySignatureBytes {
143 let mut sho = Sho::new(
144 b"Signal_ZKGroup_20200424_Random_ServerSecretParams_Sign",
145 &randomness,
146 );
147 self.sig_key_pair.sign(message, &mut sho)
148 }
149
150 pub(crate) fn check_auth_credential_redemption_time(
156 redemption_time: Timestamp,
157 current_time: Timestamp,
158 ) -> Result<(), ZkGroupVerificationFailure> {
159 let acceptable_start_time = redemption_time
160 .checked_sub_seconds(SECONDS_PER_DAY)
161 .ok_or(ZkGroupVerificationFailure)?;
162 let acceptable_end_time = redemption_time
163 .checked_add_seconds(2 * SECONDS_PER_DAY)
164 .ok_or(ZkGroupVerificationFailure)?;
165
166 if !(acceptable_start_time..=acceptable_end_time).contains(¤t_time) {
167 return Err(ZkGroupVerificationFailure);
168 }
169
170 Ok(())
171 }
172
173 pub fn verify_auth_credential_presentation(
174 &self,
175 group_public_params: api::groups::GroupPublicParams,
176 presentation: &api::auth::AnyAuthCredentialPresentation,
177 current_time: Timestamp,
178 ) -> Result<(), ZkGroupVerificationFailure> {
179 Self::check_auth_credential_redemption_time(
180 presentation.get_redemption_time(),
181 current_time,
182 )?;
183
184 match presentation {
185 api::auth::AnyAuthCredentialPresentation::V4(presentation) => {
186 presentation.verify(self, &group_public_params, presentation.redemption_time())
187 }
188 }
189 }
190
191 pub fn verify_profile_key_credential_presentation(
192 &self,
193 group_public_params: api::groups::GroupPublicParams,
194 presentation: &api::profiles::AnyProfileKeyCredentialPresentation,
195 current_time: Timestamp,
196 ) -> Result<(), ZkGroupVerificationFailure> {
197 match presentation {
198 api::profiles::AnyProfileKeyCredentialPresentation::V1(_) => {
199 Err(ZkGroupVerificationFailure)
200 }
201
202 api::profiles::AnyProfileKeyCredentialPresentation::V2(_) => {
203 Err(ZkGroupVerificationFailure)
204 }
205
206 api::profiles::AnyProfileKeyCredentialPresentation::V3(_) => {
207 Err(ZkGroupVerificationFailure)
208 }
209 api::profiles::AnyProfileKeyCredentialPresentation::V4(presentation) => self
210 .verify_expiring_profile_key_credential_presentation(
211 group_public_params,
212 presentation,
213 current_time,
214 ),
215 }
216 }
217
218 pub fn verify_expiring_profile_key_credential_presentation(
219 &self,
220 group_public_params: api::groups::GroupPublicParams,
221 presentation: &api::profiles::ExpiringProfileKeyCredentialPresentationV2,
222 current_time: Timestamp,
223 ) -> Result<(), ZkGroupVerificationFailure> {
224 let credentials_key_pair = self.expiring_profile_key_credentials_key_pair;
225 let uid_enc_public_key = group_public_params.uid_enc_public_key;
226 let profile_key_enc_public_key = group_public_params.profile_key_enc_public_key;
227
228 presentation.proof.verify(
229 credentials_key_pair,
230 presentation.uid_enc_ciphertext,
231 uid_enc_public_key,
232 presentation.profile_key_enc_ciphertext,
233 profile_key_enc_public_key,
234 presentation.credential_expiration_time,
235 )?;
236
237 if presentation.credential_expiration_time <= current_time {
238 return Err(ZkGroupVerificationFailure);
239 }
240
241 Ok(())
242 }
243
244 pub fn issue_expiring_profile_key_credential(
245 &self,
246 randomness: RandomnessBytes,
247 request: &api::profiles::ProfileKeyCredentialRequest,
248 aci: libsignal_core::Aci,
249 commitment: api::profiles::ProfileKeyCommitment,
250 credential_expiration_time: Timestamp,
251 ) -> Result<api::profiles::ExpiringProfileKeyCredentialResponse, ZkGroupVerificationFailure>
252 {
253 let mut sho = Sho::new(
254 b"Signal_ZKGroup_20220508_Random_ServerSecretParams_IssueExpiringProfileKeyCredential",
255 &randomness,
256 );
257
258 request.proof.verify(
259 request.public_key,
260 request.ciphertext,
261 commitment.commitment,
262 )?;
263
264 let uid = crypto::uid_struct::UidStruct::from_service_id(aci.into());
265 let blinded_credential_with_secret_nonce = self
266 .expiring_profile_key_credentials_key_pair
267 .create_blinded_expiring_profile_key_credential(
268 uid,
269 request.public_key,
270 request.ciphertext,
271 credential_expiration_time,
272 &mut sho,
273 );
274
275 let proof = crypto::proofs::ExpiringProfileKeyCredentialIssuanceProof::new(
276 self.expiring_profile_key_credentials_key_pair,
277 request.public_key,
278 request.ciphertext,
279 blinded_credential_with_secret_nonce,
280 uid,
281 credential_expiration_time,
282 &mut sho,
283 );
284
285 Ok(api::profiles::ExpiringProfileKeyCredentialResponse {
286 reserved: Default::default(),
287 blinded_credential: blinded_credential_with_secret_nonce
288 .get_blinded_expiring_profile_key_credential(),
289 credential_expiration_time,
290 proof,
291 })
292 }
293
294 pub fn issue_receipt_credential(
295 &self,
296 randomness: RandomnessBytes,
297 request: &api::receipts::ReceiptCredentialRequest,
298 receipt_expiration_time: Timestamp,
299 receipt_level: ReceiptLevel,
300 ) -> api::receipts::ReceiptCredentialResponse {
301 let mut sho = Sho::new(
302 b"Signal_ZKGroup_20210919_Random_ServerSecretParams_IssueReceiptCredential",
303 &randomness,
304 );
305
306 let blinded_credential_with_secret_nonce = self
307 .receipt_credentials_key_pair
308 .create_blinded_receipt_credential(
309 request.public_key,
310 request.ciphertext,
311 receipt_expiration_time,
312 receipt_level,
313 &mut sho,
314 );
315
316 let proof = crypto::proofs::ReceiptCredentialIssuanceProof::new(
317 self.receipt_credentials_key_pair,
318 request.public_key,
319 request.ciphertext,
320 blinded_credential_with_secret_nonce,
321 receipt_expiration_time,
322 receipt_level,
323 &mut sho,
324 );
325
326 api::receipts::ReceiptCredentialResponse {
327 reserved: Default::default(),
328 receipt_expiration_time,
329 receipt_level,
330 blinded_credential: blinded_credential_with_secret_nonce
331 .get_blinded_receipt_credential(),
332 proof,
333 }
334 }
335
336 pub fn verify_receipt_credential_presentation(
337 &self,
338 presentation: &api::receipts::ReceiptCredentialPresentation,
339 ) -> Result<(), ZkGroupVerificationFailure> {
340 presentation.proof.verify(
341 self.receipt_credentials_key_pair,
342 presentation.get_receipt_struct(),
343 )
344 }
345}
346
347impl ServerPublicParams {
348 pub fn get_endorsement_public_key(&self) -> EndorsementPublicKey {
349 EndorsementPublicKey {
350 reserved: Default::default(),
351 public_key: self.endorsement_public_key.clone(),
352 }
353 }
354
355 pub fn verify_signature(
356 &self,
357 message: &[u8],
358 signature: NotarySignatureBytes,
359 ) -> Result<(), ZkGroupVerificationFailure> {
360 self.sig_public_key.verify(message, signature)
361 }
362
363 pub fn create_profile_key_credential_request_context(
364 &self,
365 randomness: RandomnessBytes,
366 aci: libsignal_core::Aci,
367 profile_key: api::profiles::ProfileKey,
368 ) -> api::profiles::ProfileKeyCredentialRequestContext {
369 let mut sho = Sho::new(
370 b"Signal_ZKGroup_20200424_Random_ServerPublicParams_CreateProfileKeyCredentialRequestContext",
371 &randomness,
372 );
373 let uid_bytes = uuid::Uuid::from(aci).into_bytes();
374 let profile_key_struct =
375 crypto::profile_key_struct::ProfileKeyStruct::new(profile_key.bytes, uid_bytes);
376
377 let commitment_with_secret_nonce =
378 crypto::profile_key_commitment::CommitmentWithSecretNonce::new(
379 profile_key_struct,
380 uid_bytes,
381 );
382
383 let key_pair = crypto::profile_key_credential_request::KeyPair::generate(&mut sho);
384 let ciphertext_with_secret_nonce = key_pair.encrypt(profile_key_struct, &mut sho);
385
386 let proof = crypto::proofs::ProfileKeyCredentialRequestProof::new(
387 key_pair,
388 ciphertext_with_secret_nonce,
389 commitment_with_secret_nonce,
390 &mut sho,
391 );
392
393 api::profiles::ProfileKeyCredentialRequestContext {
394 reserved: Default::default(),
395 aci_bytes: uid_bytes,
396 profile_key_bytes: profile_key_struct.bytes,
397 key_pair,
398 ciphertext_with_secret_nonce,
399 proof,
400 }
401 }
402
403 pub fn receive_expiring_profile_key_credential(
404 &self,
405 context: &api::profiles::ProfileKeyCredentialRequestContext,
406 response: &api::profiles::ExpiringProfileKeyCredentialResponse,
407 current_time: Timestamp,
408 ) -> Result<api::profiles::ExpiringProfileKeyCredential, ZkGroupVerificationFailure> {
409 response.proof.verify(
410 self.expiring_profile_key_credentials_public_key,
411 context.key_pair.get_public_key(),
412 context.aci_bytes,
413 context.ciphertext_with_secret_nonce.get_ciphertext(),
414 response.blinded_credential,
415 response.credential_expiration_time,
416 )?;
417
418 if !response.credential_expiration_time.is_day_aligned() {
419 return Err(ZkGroupVerificationFailure);
420 }
421 let days_remaining = response
422 .credential_expiration_time
423 .saturating_seconds_since(current_time)
424 / SECONDS_PER_DAY;
425 if days_remaining == 0 || days_remaining > 7 {
426 return Err(ZkGroupVerificationFailure);
427 }
428
429 let credential = context
430 .key_pair
431 .decrypt_blinded_expiring_profile_key_credential(response.blinded_credential);
432
433 Ok(api::profiles::ExpiringProfileKeyCredential {
434 reserved: Default::default(),
435 credential,
436 aci_bytes: context.aci_bytes,
437 profile_key_bytes: context.profile_key_bytes,
438 credential_expiration_time: response.credential_expiration_time,
439 })
440 }
441
442 pub fn create_expiring_profile_key_credential_presentation(
443 &self,
444 randomness: RandomnessBytes,
445 group_secret_params: api::groups::GroupSecretParams,
446 expiring_profile_key_credential: api::profiles::ExpiringProfileKeyCredential,
447 ) -> api::profiles::ExpiringProfileKeyCredentialPresentationV2 {
448 let mut sho = Sho::new(
449 b"Signal_ZKGroup_20220508_Random_ServerPublicParams_CreateExpiringProfileKeyCredentialPresentation",
450 &randomness,
451 );
452
453 let uid_enc_key_pair = group_secret_params.uid_enc_key_pair;
454 let profile_key_enc_key_pair = group_secret_params.profile_key_enc_key_pair;
455 let credentials_public_key = self.expiring_profile_key_credentials_public_key;
456
457 let uid = expiring_profile_key_credential.aci();
458 let uuid_ciphertext = group_secret_params.encrypt_service_id(uid.into());
459 let profile_key_ciphertext = group_secret_params
460 .encrypt_profile_key_bytes(expiring_profile_key_credential.profile_key_bytes, uid);
461
462 let proof = crypto::proofs::ExpiringProfileKeyCredentialPresentationProof::new(
463 uid_enc_key_pair,
464 profile_key_enc_key_pair,
465 credentials_public_key,
466 expiring_profile_key_credential.credential,
467 uuid_ciphertext.ciphertext,
468 profile_key_ciphertext.ciphertext,
469 expiring_profile_key_credential.aci_bytes,
470 expiring_profile_key_credential.profile_key_bytes,
471 &mut sho,
472 );
473
474 api::profiles::ExpiringProfileKeyCredentialPresentation {
475 version: VersionByte,
476 proof,
477 uid_enc_ciphertext: uuid_ciphertext.ciphertext,
478 profile_key_enc_ciphertext: profile_key_ciphertext.ciphertext,
479 credential_expiration_time: expiring_profile_key_credential.credential_expiration_time,
480 }
481 }
482
483 pub fn create_receipt_credential_request_context(
484 &self,
485 randomness: RandomnessBytes,
486 receipt_serial_bytes: ReceiptSerialBytes,
487 ) -> api::receipts::ReceiptCredentialRequestContext {
488 let mut sho = Sho::new(
489 b"Signal_ZKGroup_20210919_Random_ServerPublicParams_CreateReceiptCredentialRequestContext",
490 &randomness,
491 );
492
493 let key_pair = crypto::receipt_credential_request::KeyPair::generate(&mut sho);
494 let ciphertext_with_secret_nonce = key_pair.encrypt(receipt_serial_bytes, &mut sho);
495
496 api::receipts::ReceiptCredentialRequestContext {
497 reserved: Default::default(),
498 receipt_serial_bytes,
499 key_pair,
500 ciphertext_with_secret_nonce,
501 }
502 }
503
504 pub fn receive_receipt_credential(
505 &self,
506 context: &api::receipts::ReceiptCredentialRequestContext,
507 response: &api::receipts::ReceiptCredentialResponse,
508 ) -> Result<api::receipts::ReceiptCredential, ZkGroupVerificationFailure> {
509 if !response.receipt_expiration_time.is_day_aligned() {
510 return Err(ZkGroupVerificationFailure);
511 }
512
513 let receipt_struct = crypto::receipt_struct::ReceiptStruct::new(
514 context.receipt_serial_bytes,
515 response.receipt_expiration_time,
516 response.receipt_level,
517 );
518 response.proof.verify(
519 self.receipt_credentials_public_key,
520 context.key_pair.get_public_key(),
521 context.ciphertext_with_secret_nonce.get_ciphertext(),
522 response.blinded_credential,
523 receipt_struct,
524 )?;
525 let credential = context
526 .key_pair
527 .decrypt_blinded_receipt_credential(response.blinded_credential);
528 Ok(api::receipts::ReceiptCredential {
529 reserved: Default::default(),
530 credential,
531 receipt_expiration_time: response.receipt_expiration_time,
532 receipt_level: response.receipt_level,
533 receipt_serial_bytes: context.receipt_serial_bytes,
534 })
535 }
536
537 pub fn create_receipt_credential_presentation(
538 &self,
539 randomness: RandomnessBytes,
540 receipt_credential: &api::receipts::ReceiptCredential,
541 ) -> api::receipts::ReceiptCredentialPresentation {
542 let mut sho = Sho::new(
543 b"Signal_ZKGroup_20210919_Random_ServerPublicParams_CreateReceiptCredentialPresentation",
544 &randomness,
545 );
546 let proof = crypto::proofs::ReceiptCredentialPresentationProof::new(
547 self.receipt_credentials_public_key,
548 receipt_credential.credential,
549 &mut sho,
550 );
551 api::receipts::ReceiptCredentialPresentation {
552 reserved: Default::default(),
553 proof,
554 receipt_expiration_time: receipt_credential.receipt_expiration_time,
555 receipt_level: receipt_credential.receipt_level,
556 receipt_serial_bytes: receipt_credential.receipt_serial_bytes,
557 }
558 }
559}
560
561#[derive(Clone, Serialize, Deserialize, PartialDefault)]
562pub struct EndorsementServerRootKeyPair {
563 reserved: ReservedByte,
564 pub(crate) key_pair: zkcredential::endorsements::ServerRootKeyPair,
565}
566
567impl AsRef<zkcredential::endorsements::ServerRootKeyPair> for EndorsementServerRootKeyPair {
568 fn as_ref(&self) -> &zkcredential::endorsements::ServerRootKeyPair {
569 &self.key_pair
570 }
571}
572
573impl EndorsementServerRootKeyPair {
574 pub fn public_key(&self) -> EndorsementPublicKey {
575 EndorsementPublicKey {
576 reserved: self.reserved,
577 public_key: self.key_pair.public_key().clone(),
578 }
579 }
580}
581
582#[derive(Clone, Serialize, Deserialize, PartialDefault)]
583pub struct EndorsementPublicKey {
584 reserved: ReservedByte,
585 public_key: zkcredential::endorsements::ServerRootPublicKey,
586}
587
588impl AsRef<zkcredential::endorsements::ServerRootPublicKey> for EndorsementPublicKey {
589 fn as_ref(&self) -> &zkcredential::endorsements::ServerRootPublicKey {
590 &self.public_key
591 }
592}