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