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(presentation) => self
207 .verify_expiring_profile_key_credential_presentation(
208 group_public_params,
209 presentation,
210 current_time,
211 ),
212 api::profiles::AnyProfileKeyCredentialPresentation::V4(presentation) => self
213 .verify_expiring_profile_key_credential_presentation(
214 group_public_params,
215 presentation,
216 current_time,
217 ),
218 }
219 }
220
221 pub fn verify_expiring_profile_key_credential_presentation<const V: u8>(
222 &self,
223 group_public_params: api::groups::GroupPublicParams,
224 presentation: &api::profiles::ExpiringProfileKeyCredentialPresentation<V>,
225 current_time: Timestamp,
226 ) -> Result<(), ZkGroupVerificationFailure> {
227 let credentials_key_pair = self.expiring_profile_key_credentials_key_pair;
228 let uid_enc_public_key = group_public_params.uid_enc_public_key;
229 let profile_key_enc_public_key = group_public_params.profile_key_enc_public_key;
230
231 presentation.proof.verify(
232 credentials_key_pair,
233 presentation.uid_enc_ciphertext,
234 uid_enc_public_key,
235 presentation.profile_key_enc_ciphertext,
236 profile_key_enc_public_key,
237 presentation.credential_expiration_time,
238 V >= PRESENTATION_VERSION_4,
239 )?;
240
241 if presentation.credential_expiration_time <= current_time {
242 return Err(ZkGroupVerificationFailure);
243 }
244
245 Ok(())
246 }
247
248 pub fn issue_expiring_profile_key_credential(
249 &self,
250 randomness: RandomnessBytes,
251 request: &api::profiles::ProfileKeyCredentialRequest,
252 aci: libsignal_core::Aci,
253 commitment: api::profiles::ProfileKeyCommitment,
254 credential_expiration_time: Timestamp,
255 ) -> Result<api::profiles::ExpiringProfileKeyCredentialResponse, ZkGroupVerificationFailure>
256 {
257 let mut sho = Sho::new(
258 b"Signal_ZKGroup_20220508_Random_ServerSecretParams_IssueExpiringProfileKeyCredential",
259 &randomness,
260 );
261
262 request.proof.verify(
263 request.public_key,
264 request.ciphertext,
265 commitment.commitment,
266 )?;
267
268 let uid = crypto::uid_struct::UidStruct::from_service_id(aci.into());
269 let blinded_credential_with_secret_nonce = self
270 .expiring_profile_key_credentials_key_pair
271 .create_blinded_expiring_profile_key_credential(
272 uid,
273 request.public_key,
274 request.ciphertext,
275 credential_expiration_time,
276 &mut sho,
277 );
278
279 let proof = crypto::proofs::ExpiringProfileKeyCredentialIssuanceProof::new(
280 self.expiring_profile_key_credentials_key_pair,
281 request.public_key,
282 request.ciphertext,
283 blinded_credential_with_secret_nonce,
284 uid,
285 credential_expiration_time,
286 &mut sho,
287 );
288
289 Ok(api::profiles::ExpiringProfileKeyCredentialResponse {
290 reserved: Default::default(),
291 blinded_credential: blinded_credential_with_secret_nonce
292 .get_blinded_expiring_profile_key_credential(),
293 credential_expiration_time,
294 proof,
295 })
296 }
297
298 pub fn issue_receipt_credential(
299 &self,
300 randomness: RandomnessBytes,
301 request: &api::receipts::ReceiptCredentialRequest,
302 receipt_expiration_time: Timestamp,
303 receipt_level: ReceiptLevel,
304 ) -> api::receipts::ReceiptCredentialResponse {
305 let mut sho = Sho::new(
306 b"Signal_ZKGroup_20210919_Random_ServerSecretParams_IssueReceiptCredential",
307 &randomness,
308 );
309
310 let blinded_credential_with_secret_nonce = self
311 .receipt_credentials_key_pair
312 .create_blinded_receipt_credential(
313 request.public_key,
314 request.ciphertext,
315 receipt_expiration_time,
316 receipt_level,
317 &mut sho,
318 );
319
320 let proof = crypto::proofs::ReceiptCredentialIssuanceProof::new(
321 self.receipt_credentials_key_pair,
322 request.public_key,
323 request.ciphertext,
324 blinded_credential_with_secret_nonce,
325 receipt_expiration_time,
326 receipt_level,
327 &mut sho,
328 );
329
330 api::receipts::ReceiptCredentialResponse {
331 reserved: Default::default(),
332 receipt_expiration_time,
333 receipt_level,
334 blinded_credential: blinded_credential_with_secret_nonce
335 .get_blinded_receipt_credential(),
336 proof,
337 }
338 }
339
340 pub fn verify_receipt_credential_presentation(
341 &self,
342 presentation: &api::receipts::ReceiptCredentialPresentation,
343 ) -> Result<(), ZkGroupVerificationFailure> {
344 presentation.proof.verify(
345 self.receipt_credentials_key_pair,
346 presentation.get_receipt_struct(),
347 )
348 }
349}
350
351impl ServerPublicParams {
352 pub fn get_endorsement_public_key(&self) -> EndorsementPublicKey {
353 EndorsementPublicKey {
354 reserved: Default::default(),
355 public_key: self.endorsement_public_key.clone(),
356 }
357 }
358
359 pub fn verify_signature(
360 &self,
361 message: &[u8],
362 signature: NotarySignatureBytes,
363 ) -> Result<(), ZkGroupVerificationFailure> {
364 self.sig_public_key.verify(message, signature)
365 }
366
367 pub fn create_profile_key_credential_request_context(
368 &self,
369 randomness: RandomnessBytes,
370 aci: libsignal_core::Aci,
371 profile_key: api::profiles::ProfileKey,
372 ) -> api::profiles::ProfileKeyCredentialRequestContext {
373 let mut sho = Sho::new(
374 b"Signal_ZKGroup_20200424_Random_ServerPublicParams_CreateProfileKeyCredentialRequestContext",
375 &randomness,
376 );
377 let uid_bytes = uuid::Uuid::from(aci).into_bytes();
378 let profile_key_struct =
379 crypto::profile_key_struct::ProfileKeyStruct::new(profile_key.bytes, uid_bytes);
380
381 let commitment_with_secret_nonce =
382 crypto::profile_key_commitment::CommitmentWithSecretNonce::new(
383 profile_key_struct,
384 uid_bytes,
385 );
386
387 let key_pair = crypto::profile_key_credential_request::KeyPair::generate(&mut sho);
388 let ciphertext_with_secret_nonce = key_pair.encrypt(profile_key_struct, &mut sho);
389
390 let proof = crypto::proofs::ProfileKeyCredentialRequestProof::new(
391 key_pair,
392 ciphertext_with_secret_nonce,
393 commitment_with_secret_nonce,
394 &mut sho,
395 );
396
397 api::profiles::ProfileKeyCredentialRequestContext {
398 reserved: Default::default(),
399 aci_bytes: uid_bytes,
400 profile_key_bytes: profile_key_struct.bytes,
401 key_pair,
402 ciphertext_with_secret_nonce,
403 proof,
404 }
405 }
406
407 pub fn receive_expiring_profile_key_credential(
408 &self,
409 context: &api::profiles::ProfileKeyCredentialRequestContext,
410 response: &api::profiles::ExpiringProfileKeyCredentialResponse,
411 current_time: Timestamp,
412 ) -> Result<api::profiles::ExpiringProfileKeyCredential, ZkGroupVerificationFailure> {
413 response.proof.verify(
414 self.expiring_profile_key_credentials_public_key,
415 context.key_pair.get_public_key(),
416 context.aci_bytes,
417 context.ciphertext_with_secret_nonce.get_ciphertext(),
418 response.blinded_credential,
419 response.credential_expiration_time,
420 )?;
421
422 if !response.credential_expiration_time.is_day_aligned() {
423 return Err(ZkGroupVerificationFailure);
424 }
425 let days_remaining = response
426 .credential_expiration_time
427 .saturating_seconds_since(current_time)
428 / SECONDS_PER_DAY;
429 if days_remaining == 0 || days_remaining > 7 {
430 return Err(ZkGroupVerificationFailure);
431 }
432
433 let credential = context
434 .key_pair
435 .decrypt_blinded_expiring_profile_key_credential(response.blinded_credential);
436
437 Ok(api::profiles::ExpiringProfileKeyCredential {
438 reserved: Default::default(),
439 credential,
440 aci_bytes: context.aci_bytes,
441 profile_key_bytes: context.profile_key_bytes,
442 credential_expiration_time: response.credential_expiration_time,
443 })
444 }
445
446 pub fn create_expiring_profile_key_credential_presentation<const V: u8>(
447 &self,
448 randomness: RandomnessBytes,
449 group_secret_params: api::groups::GroupSecretParams,
450 expiring_profile_key_credential: api::profiles::ExpiringProfileKeyCredential,
451 ) -> api::profiles::ExpiringProfileKeyCredentialPresentation<V> {
452 let mut sho = Sho::new(
453 b"Signal_ZKGroup_20220508_Random_ServerPublicParams_CreateExpiringProfileKeyCredentialPresentation",
454 &randomness,
455 );
456
457 let uid_enc_key_pair = group_secret_params.uid_enc_key_pair;
458 let profile_key_enc_key_pair = group_secret_params.profile_key_enc_key_pair;
459 let credentials_public_key = self.expiring_profile_key_credentials_public_key;
460
461 let uid = expiring_profile_key_credential.aci();
462 let uuid_ciphertext = group_secret_params.encrypt_service_id(uid.into());
463 let profile_key_ciphertext = group_secret_params
464 .encrypt_profile_key_bytes(expiring_profile_key_credential.profile_key_bytes, uid);
465
466 let proof = crypto::proofs::ExpiringProfileKeyCredentialPresentationProof::new(
467 uid_enc_key_pair,
468 profile_key_enc_key_pair,
469 credentials_public_key,
470 expiring_profile_key_credential.credential,
471 uuid_ciphertext.ciphertext,
472 profile_key_ciphertext.ciphertext,
473 expiring_profile_key_credential.aci_bytes,
474 expiring_profile_key_credential.profile_key_bytes,
475 V >= PRESENTATION_VERSION_4,
476 &mut sho,
477 );
478
479 api::profiles::ExpiringProfileKeyCredentialPresentation {
480 version: VersionByte,
481 proof,
482 uid_enc_ciphertext: uuid_ciphertext.ciphertext,
483 profile_key_enc_ciphertext: profile_key_ciphertext.ciphertext,
484 credential_expiration_time: expiring_profile_key_credential.credential_expiration_time,
485 }
486 }
487
488 pub fn create_receipt_credential_request_context(
489 &self,
490 randomness: RandomnessBytes,
491 receipt_serial_bytes: ReceiptSerialBytes,
492 ) -> api::receipts::ReceiptCredentialRequestContext {
493 let mut sho = Sho::new(
494 b"Signal_ZKGroup_20210919_Random_ServerPublicParams_CreateReceiptCredentialRequestContext",
495 &randomness,
496 );
497
498 let key_pair = crypto::receipt_credential_request::KeyPair::generate(&mut sho);
499 let ciphertext_with_secret_nonce = key_pair.encrypt(receipt_serial_bytes, &mut sho);
500
501 api::receipts::ReceiptCredentialRequestContext {
502 reserved: Default::default(),
503 receipt_serial_bytes,
504 key_pair,
505 ciphertext_with_secret_nonce,
506 }
507 }
508
509 pub fn receive_receipt_credential(
510 &self,
511 context: &api::receipts::ReceiptCredentialRequestContext,
512 response: &api::receipts::ReceiptCredentialResponse,
513 ) -> Result<api::receipts::ReceiptCredential, ZkGroupVerificationFailure> {
514 if !response.receipt_expiration_time.is_day_aligned() {
515 return Err(ZkGroupVerificationFailure);
516 }
517
518 let receipt_struct = crypto::receipt_struct::ReceiptStruct::new(
519 context.receipt_serial_bytes,
520 response.receipt_expiration_time,
521 response.receipt_level,
522 );
523 response.proof.verify(
524 self.receipt_credentials_public_key,
525 context.key_pair.get_public_key(),
526 context.ciphertext_with_secret_nonce.get_ciphertext(),
527 response.blinded_credential,
528 receipt_struct,
529 )?;
530 let credential = context
531 .key_pair
532 .decrypt_blinded_receipt_credential(response.blinded_credential);
533 Ok(api::receipts::ReceiptCredential {
534 reserved: Default::default(),
535 credential,
536 receipt_expiration_time: response.receipt_expiration_time,
537 receipt_level: response.receipt_level,
538 receipt_serial_bytes: context.receipt_serial_bytes,
539 })
540 }
541
542 pub fn create_receipt_credential_presentation(
543 &self,
544 randomness: RandomnessBytes,
545 receipt_credential: &api::receipts::ReceiptCredential,
546 ) -> api::receipts::ReceiptCredentialPresentation {
547 let mut sho = Sho::new(
548 b"Signal_ZKGroup_20210919_Random_ServerPublicParams_CreateReceiptCredentialPresentation",
549 &randomness,
550 );
551 let proof = crypto::proofs::ReceiptCredentialPresentationProof::new(
552 self.receipt_credentials_public_key,
553 receipt_credential.credential,
554 &mut sho,
555 );
556 api::receipts::ReceiptCredentialPresentation {
557 reserved: Default::default(),
558 proof,
559 receipt_expiration_time: receipt_credential.receipt_expiration_time,
560 receipt_level: receipt_credential.receipt_level,
561 receipt_serial_bytes: receipt_credential.receipt_serial_bytes,
562 }
563 }
564}
565
566#[derive(Clone, Serialize, Deserialize, PartialDefault)]
567pub struct EndorsementServerRootKeyPair {
568 reserved: ReservedByte,
569 pub(crate) key_pair: zkcredential::endorsements::ServerRootKeyPair,
570}
571
572impl AsRef<zkcredential::endorsements::ServerRootKeyPair> for EndorsementServerRootKeyPair {
573 fn as_ref(&self) -> &zkcredential::endorsements::ServerRootKeyPair {
574 &self.key_pair
575 }
576}
577
578impl EndorsementServerRootKeyPair {
579 pub fn public_key(&self) -> EndorsementPublicKey {
580 EndorsementPublicKey {
581 reserved: self.reserved,
582 public_key: self.key_pair.public_key().clone(),
583 }
584 }
585}
586
587#[derive(Clone, Serialize, Deserialize, PartialDefault)]
588pub struct EndorsementPublicKey {
589 reserved: ReservedByte,
590 public_key: zkcredential::endorsements::ServerRootPublicKey,
591}
592
593impl AsRef<zkcredential::endorsements::ServerRootPublicKey> for EndorsementPublicKey {
594 fn as_ref(&self) -> &zkcredential::endorsements::ServerRootPublicKey {
595 &self.public_key
596 }
597}