zkgroup/crypto/
proofs.rs

1//
2// Copyright 2020-2022 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6#![allow(non_snake_case)]
7
8use curve25519_dalek_signal::constants::RISTRETTO_BASEPOINT_POINT;
9use curve25519_dalek_signal::ristretto::RistrettoPoint;
10use curve25519_dalek_signal::traits::Identity;
11use partial_default::PartialDefault;
12use serde::{Deserialize, Serialize};
13use zkcredential::attributes::Attribute;
14
15use crate::common::array_utils::OneBased;
16use crate::common::constants::*;
17use crate::common::errors::*;
18use crate::common::sho::*;
19use crate::common::simple_types::*;
20use crate::crypto::receipt_struct::ReceiptStruct;
21use crate::crypto::timestamp_struct::TimestampStruct;
22use crate::crypto::{
23    credentials, profile_key_commitment, profile_key_credential_request, profile_key_encryption,
24    profile_key_struct, receipt_credential_request, uid_encryption, uid_struct,
25};
26
27#[derive(Serialize, Deserialize, Clone, PartialDefault)]
28pub struct AuthCredentialWithPniIssuanceProof {
29    poksho_proof: Vec<u8>,
30}
31
32#[derive(Serialize, Deserialize, Clone, PartialDefault)]
33pub struct ProfileKeyCredentialRequestProof {
34    poksho_proof: Vec<u8>,
35}
36
37#[derive(Serialize, Deserialize, Clone, PartialDefault)]
38pub struct ExpiringProfileKeyCredentialIssuanceProof {
39    poksho_proof: Vec<u8>,
40}
41
42#[derive(Serialize, Deserialize, Clone, PartialDefault)]
43pub struct ReceiptCredentialIssuanceProof {
44    poksho_proof: Vec<u8>,
45}
46
47#[derive(Serialize, Deserialize, Clone, PartialDefault)]
48pub struct AuthCredentialWithPniPresentationProof {
49    C_x0: RistrettoPoint,
50    C_x1: RistrettoPoint,
51    C_y1: RistrettoPoint,
52    C_y2: RistrettoPoint,
53    C_y3: RistrettoPoint,
54    C_y4: RistrettoPoint,
55    C_y5: RistrettoPoint,
56    C_V: RistrettoPoint,
57    poksho_proof: Vec<u8>,
58}
59
60/// Deprecated; use [ExpiringProfileKeyCredentialPresentationProof] instead.
61///
62/// Kept around so that v1 ProfileKeyCredentialPresentations can still be deserialized,
63/// even though they can't be verified.
64#[derive(Serialize, Deserialize, Clone, PartialDefault)]
65pub struct ProfileKeyCredentialPresentationProofV1 {
66    C_x0: RistrettoPoint,
67    C_x1: RistrettoPoint,
68    C_y1: RistrettoPoint,
69    C_y2: RistrettoPoint,
70    C_y3: RistrettoPoint,
71    C_y4: RistrettoPoint,
72    C_V: RistrettoPoint,
73    C_z: RistrettoPoint,
74    poksho_proof: Vec<u8>,
75}
76
77/// Deprecated; use [ExpiringProfileKeyCredentialPresentationProof] instead.
78///
79/// Kept around so that v2 ProfileKeyCredentialPresentations can still be deserialized,
80/// even though they can't be verified.
81#[derive(Serialize, Deserialize, Clone, PartialDefault)]
82pub struct ProfileKeyCredentialPresentationProofV2 {
83    C_x0: RistrettoPoint,
84    C_x1: RistrettoPoint,
85    C_y1: RistrettoPoint,
86    C_y2: RistrettoPoint,
87    C_y3: RistrettoPoint,
88    C_y4: RistrettoPoint,
89    C_V: RistrettoPoint,
90    C_z: RistrettoPoint,
91    poksho_proof: Vec<u8>,
92}
93
94#[derive(Serialize, Deserialize, Clone, PartialDefault)]
95pub struct ExpiringProfileKeyCredentialPresentationProof {
96    C_x0: RistrettoPoint,
97    C_x1: RistrettoPoint,
98    C_y1: RistrettoPoint,
99    C_y2: RistrettoPoint,
100    C_y3: RistrettoPoint,
101    C_y4: RistrettoPoint,
102    C_y5: RistrettoPoint,
103    C_V: RistrettoPoint,
104    poksho_proof: Vec<u8>,
105}
106
107#[derive(Serialize, Deserialize, Clone, PartialDefault)]
108pub struct ReceiptCredentialPresentationProof {
109    C_x0: RistrettoPoint,
110    C_x1: RistrettoPoint,
111    C_y1: RistrettoPoint,
112    C_y2: RistrettoPoint,
113    C_V: RistrettoPoint,
114    poksho_proof: Vec<u8>,
115}
116
117impl AuthCredentialWithPniIssuanceProof {
118    pub fn get_poksho_statement() -> poksho::Statement {
119        let mut st = poksho::Statement::new();
120        st.add("C_W", &[("w", "G_w"), ("wprime", "G_wprime")]);
121        st.add(
122            "G_V-I",
123            &[
124                ("x0", "G_x0"),
125                ("x1", "G_x1"),
126                ("y1", "G_y1"),
127                ("y2", "G_y2"),
128                ("y3", "G_y3"),
129                ("y4", "G_y4"),
130                ("y5", "G_y5"),
131            ],
132        );
133        st.add(
134            "V",
135            &[
136                ("w", "G_w"),
137                ("x0", "U"),
138                ("x1", "tU"),
139                ("y1", "M1"),
140                ("y2", "M2"),
141                ("y3", "M3"),
142                ("y4", "M4"),
143                ("y5", "M5"),
144            ],
145        );
146        st
147    }
148
149    pub fn new(
150        key_pair: credentials::KeyPair<credentials::AuthCredentialWithPni>,
151        credential: credentials::AuthCredentialWithPni,
152        aci: uid_struct::UidStruct,
153        pni: uid_struct::UidStruct,
154        redemption_time: Timestamp,
155        sho: &mut Sho,
156    ) -> Self {
157        let system = credentials::SystemParams::get_hardcoded();
158
159        let M = OneBased(credentials::convert_to_points_aci_pni_timestamp(
160            aci,
161            pni,
162            redemption_time,
163        ));
164
165        let mut scalar_args = poksho::ScalarArgs::new();
166        scalar_args.add("w", key_pair.w);
167        scalar_args.add("wprime", key_pair.wprime);
168        scalar_args.add("x0", key_pair.x0);
169        scalar_args.add("x1", key_pair.x1);
170        scalar_args.add("y1", key_pair.y[1]);
171        scalar_args.add("y2", key_pair.y[2]);
172        scalar_args.add("y3", key_pair.y[3]);
173        scalar_args.add("y4", key_pair.y[4]);
174        scalar_args.add("y5", key_pair.y[5]);
175
176        let mut point_args = poksho::PointArgs::new();
177        point_args.add("C_W", key_pair.C_W);
178        point_args.add("G_w", system.G_w);
179        point_args.add("G_wprime", system.G_wprime);
180        point_args.add("G_V-I", system.G_V - key_pair.I);
181        point_args.add("G_x0", system.G_x0);
182        point_args.add("G_x1", system.G_x1);
183        point_args.add("G_y1", system.G_y[1]);
184        point_args.add("G_y2", system.G_y[2]);
185        point_args.add("G_y3", system.G_y[3]);
186        point_args.add("G_y4", system.G_y[4]);
187        point_args.add("G_y5", system.G_y[5]);
188        point_args.add("V", credential.V);
189        point_args.add("U", credential.U);
190        point_args.add("tU", credential.t * credential.U);
191        point_args.add("M1", M[1]);
192        point_args.add("M2", M[2]);
193        point_args.add("M3", M[3]);
194        point_args.add("M4", M[4]);
195        point_args.add("M5", M[5]);
196
197        let poksho_proof = Self::get_poksho_statement()
198            .prove(
199                &scalar_args,
200                &point_args,
201                &[],
202                &sho.squeeze(RANDOMNESS_LEN)[..],
203            )
204            .unwrap();
205        Self { poksho_proof }
206    }
207
208    pub fn verify(
209        &self,
210        public_key: credentials::PublicKey,
211        credential: credentials::AuthCredentialWithPni,
212        aci_struct: uid_struct::UidStruct,
213        pni_struct: uid_struct::UidStruct,
214        redemption_time: Timestamp,
215    ) -> Result<(), ZkGroupVerificationFailure> {
216        let system = credentials::SystemParams::get_hardcoded();
217
218        let M = OneBased(credentials::convert_to_points_aci_pni_timestamp(
219            aci_struct,
220            pni_struct,
221            redemption_time,
222        ));
223
224        let mut point_args = poksho::PointArgs::new();
225        point_args.add("C_W", public_key.C_W);
226        point_args.add("G_w", system.G_w);
227        point_args.add("G_wprime", system.G_wprime);
228        point_args.add("G_V-I", system.G_V - public_key.I);
229        point_args.add("G_x0", system.G_x0);
230        point_args.add("G_x1", system.G_x1);
231        point_args.add("G_y1", system.G_y[1]);
232        point_args.add("G_y2", system.G_y[2]);
233        point_args.add("G_y3", system.G_y[3]);
234        point_args.add("G_y4", system.G_y[4]);
235        point_args.add("G_y5", system.G_y[5]);
236        point_args.add("V", credential.V);
237        point_args.add("U", credential.U);
238        point_args.add("tU", credential.t * credential.U);
239        point_args.add("M1", M[1]);
240        point_args.add("M2", M[2]);
241        point_args.add("M3", M[3]);
242        point_args.add("M4", M[4]);
243        point_args.add("M5", M[5]);
244
245        match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) {
246            Err(_) => Err(ZkGroupVerificationFailure),
247            Ok(_) => Ok(()),
248        }
249    }
250}
251
252impl ProfileKeyCredentialRequestProof {
253    pub fn get_poksho_statement() -> poksho::Statement {
254        let mut st = poksho::Statement::new();
255        st.add("Y", &[("y", "G")]);
256        st.add("D1", &[("r1", "G")]);
257        st.add("E1", &[("r2", "G")]);
258        st.add("J3", &[("j3", "G_j3")]);
259        st.add("D2-J1", &[("r1", "Y"), ("j3", "-G_j1")]);
260        st.add("E2-J2", &[("r2", "Y"), ("j3", "-G_j2")]);
261        st
262    }
263
264    pub fn new(
265        key_pair: profile_key_credential_request::KeyPair,
266        ciphertext: profile_key_credential_request::CiphertextWithSecretNonce,
267        commitment: profile_key_commitment::CommitmentWithSecretNonce,
268        sho: &mut Sho,
269    ) -> ProfileKeyCredentialRequestProof {
270        let commitment_system = profile_key_commitment::SystemParams::get_hardcoded();
271
272        let mut scalar_args = poksho::ScalarArgs::new();
273        scalar_args.add("y", key_pair.y);
274        scalar_args.add("r1", ciphertext.r1);
275        scalar_args.add("r2", ciphertext.r2);
276        scalar_args.add("j3", commitment.j3);
277
278        let mut point_args = poksho::PointArgs::new();
279        point_args.add("Y", key_pair.Y);
280        point_args.add("D1", ciphertext.D1);
281        point_args.add("E1", ciphertext.E1);
282        point_args.add("J3", commitment.J3);
283        point_args.add("G_j3", commitment_system.G_j3);
284        point_args.add("D2-J1", ciphertext.D2 - commitment.J1);
285        point_args.add("-G_j1", -commitment_system.G_j1);
286        point_args.add("E2-J2", ciphertext.E2 - commitment.J2);
287        point_args.add("-G_j2", -commitment_system.G_j2);
288
289        let poksho_proof = Self::get_poksho_statement()
290            .prove(
291                &scalar_args,
292                &point_args,
293                &[],
294                &sho.squeeze(RANDOMNESS_LEN)[..],
295            )
296            .unwrap();
297        ProfileKeyCredentialRequestProof { poksho_proof }
298    }
299
300    pub fn verify(
301        &self,
302        public_key: profile_key_credential_request::PublicKey,
303        ciphertext: profile_key_credential_request::Ciphertext,
304        commitment: profile_key_commitment::Commitment,
305    ) -> Result<(), ZkGroupVerificationFailure> {
306        let commitment_system = profile_key_commitment::SystemParams::get_hardcoded();
307
308        let mut point_args = poksho::PointArgs::new();
309        point_args.add("Y", public_key.Y);
310        point_args.add("D1", ciphertext.D1);
311        point_args.add("E1", ciphertext.E1);
312        point_args.add("J3", commitment.J3);
313        point_args.add("G_j3", commitment_system.G_j3);
314        point_args.add("D2-J1", ciphertext.D2 - commitment.J1);
315        point_args.add("-G_j1", -commitment_system.G_j1);
316        point_args.add("E2-J2", ciphertext.E2 - commitment.J2);
317        point_args.add("-G_j2", -commitment_system.G_j2);
318
319        match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) {
320            Err(_) => Err(ZkGroupVerificationFailure),
321            Ok(_) => Ok(()),
322        }
323    }
324}
325
326impl ExpiringProfileKeyCredentialIssuanceProof {
327    pub fn get_poksho_statement() -> poksho::Statement {
328        let mut st = poksho::Statement::new();
329        st.add("C_W", &[("w", "G_w"), ("wprime", "G_wprime")]);
330        st.add(
331            "G_V-I",
332            &[
333                ("x0", "G_x0"),
334                ("x1", "G_x1"),
335                ("y1", "G_y1"),
336                ("y2", "G_y2"),
337                ("y3", "G_y3"),
338                ("y4", "G_y4"),
339                ("y5", "G_y5"),
340            ],
341        );
342        st.add("S1", &[("y3", "D1"), ("y4", "E1"), ("rprime", "G")]);
343        st.add(
344            "S2",
345            &[
346                ("y3", "D2"),
347                ("y4", "E2"),
348                ("rprime", "Y"),
349                ("w", "G_w"),
350                ("x0", "U"),
351                ("x1", "tU"),
352                ("y1", "M1"),
353                ("y2", "M2"),
354                ("y5", "M5"),
355            ],
356        );
357        st
358    }
359
360    pub fn new(
361        key_pair: credentials::KeyPair<credentials::ExpiringProfileKeyCredential>,
362        request_public_key: profile_key_credential_request::PublicKey,
363        request: profile_key_credential_request::Ciphertext,
364        blinded_credential: credentials::BlindedExpiringProfileKeyCredentialWithSecretNonce,
365        uid: uid_struct::UidStruct,
366        credential_expiration_time: Timestamp,
367        sho: &mut Sho,
368    ) -> Self {
369        let credentials_system = credentials::SystemParams::get_hardcoded();
370
371        let m5 = TimestampStruct::calc_m_from(credential_expiration_time);
372        let M5 = m5 * credentials_system.G_m5;
373
374        let mut scalar_args = poksho::ScalarArgs::new();
375        scalar_args.add("w", key_pair.w);
376        scalar_args.add("wprime", key_pair.wprime);
377        scalar_args.add("x0", key_pair.x0);
378        scalar_args.add("x1", key_pair.x1);
379        scalar_args.add("y1", key_pair.y[1]);
380        scalar_args.add("y2", key_pair.y[2]);
381        scalar_args.add("y3", key_pair.y[3]);
382        scalar_args.add("y4", key_pair.y[4]);
383        scalar_args.add("y5", key_pair.y[5]);
384        scalar_args.add("rprime", blinded_credential.rprime);
385
386        let mut point_args = poksho::PointArgs::new();
387        point_args.add("C_W", key_pair.C_W);
388        point_args.add("G_w", credentials_system.G_w);
389        point_args.add("G_wprime", credentials_system.G_wprime);
390        point_args.add("G_V-I", credentials_system.G_V - key_pair.I);
391        point_args.add("G_x0", credentials_system.G_x0);
392        point_args.add("G_x1", credentials_system.G_x1);
393        point_args.add("G_y1", credentials_system.G_y[1]);
394        point_args.add("G_y2", credentials_system.G_y[2]);
395        point_args.add("G_y3", credentials_system.G_y[3]);
396        point_args.add("G_y4", credentials_system.G_y[4]);
397        point_args.add("G_y5", credentials_system.G_y[5]);
398        point_args.add("S1", blinded_credential.S1);
399        point_args.add("D1", request.D1);
400        point_args.add("E1", request.E1);
401        point_args.add("S2", blinded_credential.S2);
402        point_args.add("D2", request.D2);
403        point_args.add("E2", request.E2);
404        point_args.add("Y", request_public_key.Y);
405        point_args.add("U", blinded_credential.U);
406        point_args.add("tU", blinded_credential.t * blinded_credential.U);
407        point_args.add("M1", uid.M1);
408        point_args.add("M2", uid.M2);
409        point_args.add("M5", M5);
410
411        let poksho_proof = Self::get_poksho_statement()
412            .prove(
413                &scalar_args,
414                &point_args,
415                &[],
416                &sho.squeeze(RANDOMNESS_LEN)[..],
417            )
418            .unwrap();
419        ExpiringProfileKeyCredentialIssuanceProof { poksho_proof }
420    }
421
422    pub fn verify(
423        &self,
424        credentials_public_key: credentials::PublicKey,
425        request_public_key: profile_key_credential_request::PublicKey,
426        aci_bytes: UidBytes,
427        request: profile_key_credential_request::Ciphertext,
428        blinded_credential: credentials::BlindedExpiringProfileKeyCredential,
429        credential_expiration_time: Timestamp,
430    ) -> Result<(), ZkGroupVerificationFailure> {
431        let credentials_system = credentials::SystemParams::get_hardcoded();
432        let aci = libsignal_core::Aci::from_uuid_bytes(aci_bytes);
433        let uid = uid_struct::UidStruct::from_service_id(aci.into());
434
435        let m5 = TimestampStruct::calc_m_from(credential_expiration_time);
436        let M5 = m5 * credentials_system.G_m5;
437
438        let mut point_args = poksho::PointArgs::new();
439        point_args.add("C_W", credentials_public_key.C_W);
440        point_args.add("G_w", credentials_system.G_w);
441        point_args.add("G_wprime", credentials_system.G_wprime);
442        point_args.add("G_V-I", credentials_system.G_V - credentials_public_key.I);
443        point_args.add("G_x0", credentials_system.G_x0);
444        point_args.add("G_x1", credentials_system.G_x1);
445        point_args.add("G_y1", credentials_system.G_y[1]);
446        point_args.add("G_y2", credentials_system.G_y[2]);
447        point_args.add("G_y3", credentials_system.G_y[3]);
448        point_args.add("G_y4", credentials_system.G_y[4]);
449        point_args.add("G_y5", credentials_system.G_y[5]);
450        point_args.add("S1", blinded_credential.S1);
451        point_args.add("D1", request.D1);
452        point_args.add("E1", request.E1);
453        point_args.add("S2", blinded_credential.S2);
454        point_args.add("D2", request.D2);
455        point_args.add("E2", request.E2);
456        point_args.add("Y", request_public_key.Y);
457        point_args.add("U", blinded_credential.U);
458        point_args.add("tU", blinded_credential.t * blinded_credential.U);
459        point_args.add("M1", uid.M1);
460        point_args.add("M2", uid.M2);
461        point_args.add("M5", M5);
462
463        match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) {
464            Err(_) => Err(ZkGroupVerificationFailure),
465            Ok(_) => Ok(()),
466        }
467    }
468}
469
470impl ReceiptCredentialIssuanceProof {
471    pub fn get_poksho_statement() -> poksho::Statement {
472        let mut st = poksho::Statement::new();
473
474        st.add("C_W", &[("w", "G_w"), ("wprime", "G_wprime")]);
475        st.add(
476            "G_V-I",
477            &[
478                ("x0", "G_x0"),
479                ("x1", "G_x1"),
480                ("y1", "G_y1"),
481                ("y2", "G_y2"),
482            ],
483        );
484        st.add("S1", &[("y2", "D1"), ("rprime", "G")]);
485        st.add(
486            "S2",
487            &[
488                ("y2", "D2"),
489                ("rprime", "Y"),
490                ("w", "G_w"),
491                ("x0", "U"),
492                ("x1", "tU"),
493                ("y1", "M1"),
494            ],
495        );
496        st
497    }
498
499    pub fn new(
500        key_pair: credentials::KeyPair<credentials::ReceiptCredential>,
501        request_public_key: receipt_credential_request::PublicKey,
502        request: receipt_credential_request::Ciphertext,
503        blinded_credential: credentials::BlindedReceiptCredentialWithSecretNonce,
504        receipt_expiration_time: Timestamp,
505        receipt_level: ReceiptLevel,
506        sho: &mut Sho,
507    ) -> Self {
508        let credentials_system = credentials::SystemParams::get_hardcoded();
509
510        let m1 = ReceiptStruct::calc_m1_from(receipt_expiration_time, receipt_level);
511
512        let mut scalar_args = poksho::ScalarArgs::new();
513        scalar_args.add("w", key_pair.w);
514        scalar_args.add("wprime", key_pair.wprime);
515        scalar_args.add("x0", key_pair.x0);
516        scalar_args.add("x1", key_pair.x1);
517        scalar_args.add("y1", key_pair.y[1]);
518        scalar_args.add("y2", key_pair.y[2]);
519        scalar_args.add("rprime", blinded_credential.rprime);
520
521        let mut point_args = poksho::PointArgs::new();
522        point_args.add("C_W", key_pair.C_W);
523        point_args.add("G_w", credentials_system.G_w);
524        point_args.add("G_wprime", credentials_system.G_wprime);
525        point_args.add("G_V-I", credentials_system.G_V - key_pair.I);
526        point_args.add("G_x0", credentials_system.G_x0);
527        point_args.add("G_x1", credentials_system.G_x1);
528        point_args.add("G_y1", credentials_system.G_y[1]);
529        point_args.add("G_y2", credentials_system.G_y[2]);
530        point_args.add("S1", blinded_credential.S1);
531        point_args.add("D1", request.D1);
532        point_args.add("S2", blinded_credential.S2);
533        point_args.add("D2", request.D2);
534        point_args.add("Y", request_public_key.Y);
535        point_args.add("U", blinded_credential.U);
536        point_args.add("tU", blinded_credential.t * blinded_credential.U);
537        point_args.add("M1", m1 * credentials_system.G_m1);
538
539        let poksho_proof = Self::get_poksho_statement()
540            .prove(
541                &scalar_args,
542                &point_args,
543                &[],
544                &sho.squeeze(RANDOMNESS_LEN)[..],
545            )
546            .unwrap();
547        Self { poksho_proof }
548    }
549
550    pub fn verify(
551        &self,
552        credentials_public_key: credentials::PublicKey,
553        request_public_key: receipt_credential_request::PublicKey,
554        request: receipt_credential_request::Ciphertext,
555        blinded_credential: credentials::BlindedReceiptCredential,
556        receipt_struct: ReceiptStruct,
557    ) -> Result<(), ZkGroupVerificationFailure> {
558        let credentials_system = credentials::SystemParams::get_hardcoded();
559
560        let M = credentials::convert_to_points_receipt_struct(receipt_struct);
561
562        let mut point_args = poksho::PointArgs::new();
563        point_args.add("C_W", credentials_public_key.C_W);
564        point_args.add("G_w", credentials_system.G_w);
565        point_args.add("G_wprime", credentials_system.G_wprime);
566        point_args.add("G_V-I", credentials_system.G_V - credentials_public_key.I);
567        point_args.add("G_x0", credentials_system.G_x0);
568        point_args.add("G_x1", credentials_system.G_x1);
569        point_args.add("G_y1", credentials_system.G_y[1]);
570        point_args.add("G_y2", credentials_system.G_y[2]);
571        point_args.add("S1", blinded_credential.S1);
572        point_args.add("D1", request.D1);
573        point_args.add("S2", blinded_credential.S2);
574        point_args.add("D2", request.D2);
575        point_args.add("Y", request_public_key.Y);
576        point_args.add("U", blinded_credential.U);
577        point_args.add("tU", blinded_credential.t * blinded_credential.U);
578        point_args.add("M1", M[0]);
579
580        match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) {
581            Err(_) => Err(ZkGroupVerificationFailure),
582            Ok(_) => Ok(()),
583        }
584    }
585}
586
587impl AuthCredentialWithPniPresentationProof {
588    pub fn get_poksho_statement() -> poksho::Statement {
589        let mut st = poksho::Statement::new();
590        st.add("Z", &[("z", "I")]);
591        st.add("C_x1", &[("t", "C_x0"), ("z0", "G_x0"), ("z", "G_x1")]);
592        st.add("A", &[("a1", "G_a1"), ("a2", "G_a2")]);
593        st.add("C_y2-E_A2", &[("z", "G_y2"), ("a2", "-E_A1")]);
594        st.add("E_A1", &[("a1", "C_y1"), ("z1", "G_y1")]);
595        st.add("C_y4-E_B2", &[("z", "G_y4"), ("a2", "-E_B1")]);
596        st.add("E_B1", &[("a1", "C_y3"), ("z1", "G_y3")]);
597        st.add("0", &[("z1", "I"), ("a1", "Z")]);
598        st
599    }
600
601    #[allow(clippy::too_many_arguments)]
602    pub fn new(
603        credentials_public_key: credentials::PublicKey,
604        uid_enc_key_pair: uid_encryption::KeyPair,
605        credential: credentials::AuthCredentialWithPni,
606        aci: uid_struct::UidStruct,
607        aci_ciphertext: uid_encryption::Ciphertext,
608        pni: uid_struct::UidStruct,
609        pni_ciphertext: uid_encryption::Ciphertext,
610        redemption_time: Timestamp,
611        sho: &mut Sho,
612    ) -> Self {
613        let credentials_system = credentials::SystemParams::get_hardcoded();
614        let uid_system = uid_encryption::SystemParams::get_hardcoded();
615        let M = OneBased(credentials::convert_to_points_aci_pni_timestamp(
616            aci,
617            pni,
618            redemption_time,
619        ));
620
621        let z = sho.get_scalar();
622
623        let C_y1 = z * credentials_system.G_y[1] + M[1];
624        let C_y2 = z * credentials_system.G_y[2] + M[2];
625        let C_y3 = z * credentials_system.G_y[3] + M[3];
626        let C_y4 = z * credentials_system.G_y[4] + M[4];
627        let C_y5 = z * credentials_system.G_y[5];
628
629        let C_x0 = z * credentials_system.G_x0 + credential.U;
630        let C_V = z * credentials_system.G_V + credential.V;
631        let C_x1 = z * credentials_system.G_x1 + credential.t * credential.U;
632
633        let z0 = -z * credential.t;
634        let z1 = -z * uid_enc_key_pair.a1;
635
636        let I = credentials_public_key.I;
637        let Z = z * I;
638
639        let [E_A1, E_A2] = aci_ciphertext.as_points();
640        let [E_B1, E_B2] = pni_ciphertext.as_points();
641
642        // Scalars listed in order of stmts for debugging
643        let mut scalar_args = poksho::ScalarArgs::new();
644        scalar_args.add("z", z);
645        scalar_args.add("t", credential.t);
646        scalar_args.add("z0", z0);
647        scalar_args.add("a1", uid_enc_key_pair.a1);
648        scalar_args.add("a2", uid_enc_key_pair.a2);
649        scalar_args.add("z1", z1);
650
651        // Points listed in order of stmts for debugging
652        let mut point_args = poksho::PointArgs::new();
653        point_args.add("Z", Z);
654        point_args.add("I", I);
655
656        point_args.add("C_x1", C_x1);
657        point_args.add("C_x0", C_x0);
658        point_args.add("G_x0", credentials_system.G_x0);
659        point_args.add("G_x1", credentials_system.G_x1);
660
661        point_args.add("A", uid_enc_key_pair.public_key.A);
662        point_args.add("G_a1", uid_system.G_a1);
663        point_args.add("G_a2", uid_system.G_a2);
664
665        point_args.add("C_y2-E_A2", C_y2 - E_A2);
666        point_args.add("G_y2", credentials_system.G_y[2]);
667        point_args.add("-E_A1", -E_A1);
668        point_args.add("E_A1", E_A1);
669        point_args.add("C_y1", C_y1);
670        point_args.add("G_y1", credentials_system.G_y[1]);
671
672        point_args.add("C_y4-E_B2", C_y4 - E_B2);
673        point_args.add("G_y4", credentials_system.G_y[4]);
674        point_args.add("-E_B1", -E_B1);
675        point_args.add("E_B1", E_B1);
676        point_args.add("C_y3", C_y3);
677        point_args.add("G_y3", credentials_system.G_y[3]);
678        point_args.add("0", RistrettoPoint::identity());
679
680        let poksho_proof = Self::get_poksho_statement()
681            .prove(
682                &scalar_args,
683                &point_args,
684                &[],
685                &sho.squeeze(RANDOMNESS_LEN)[..],
686            )
687            .unwrap();
688
689        Self {
690            C_x0,
691            C_x1,
692            C_y1,
693            C_y2,
694            C_y3,
695            C_y4,
696            C_y5,
697            C_V,
698            poksho_proof,
699        }
700    }
701
702    pub fn verify(
703        &self,
704        credentials_key_pair: credentials::KeyPair<credentials::AuthCredentialWithPni>,
705        uid_enc_public_key: uid_encryption::PublicKey,
706        aci_ciphertext: uid_encryption::Ciphertext,
707        pni_ciphertext: uid_encryption::Ciphertext,
708        redemption_time: Timestamp,
709    ) -> Result<(), ZkGroupVerificationFailure> {
710        let uid_enc_system = uid_encryption::SystemParams::get_hardcoded();
711        let credentials_system = credentials::SystemParams::get_hardcoded();
712
713        let Self {
714            C_x0,
715            C_x1,
716            C_y1,
717            C_y2,
718            C_y3,
719            C_y4,
720            C_y5,
721            C_V,
722            poksho_proof,
723        } = self;
724
725        let (C_x0, C_x1, C_y1, C_y2, C_y3, C_y4, C_y5, C_V) =
726            (*C_x0, *C_x1, *C_y1, *C_y2, *C_y3, *C_y4, *C_y5, *C_V);
727
728        let credentials::KeyPair {
729            W,
730            x0,
731            x1,
732            y: OneBased([y1, y2, y3, y4, y5]),
733            I,
734            ..
735        } = credentials_key_pair;
736
737        let [E_A1, E_A2] = aci_ciphertext.as_points();
738        let [E_B1, E_B2] = pni_ciphertext.as_points();
739        let m5 = TimestampStruct::calc_m_from(redemption_time);
740        let M5 = m5 * credentials_system.G_m5;
741        let Z = C_V
742            - W
743            - x0 * C_x0
744            - x1 * C_x1
745            - y1 * C_y1
746            - y2 * C_y2
747            - y3 * C_y3
748            - y4 * C_y4
749            - y5 * (C_y5 + M5);
750
751        // Points listed in order of stmts for debugging
752        let mut point_args = poksho::PointArgs::new();
753        point_args.add("Z", Z);
754        point_args.add("I", I);
755        point_args.add("C_x1", C_x1);
756        point_args.add("C_x0", C_x0);
757        point_args.add("G_x0", credentials_system.G_x0);
758        point_args.add("G_x1", credentials_system.G_x1);
759
760        point_args.add("A", uid_enc_public_key.A);
761        point_args.add("G_a1", uid_enc_system.G_a1);
762        point_args.add("G_a2", uid_enc_system.G_a2);
763
764        point_args.add("C_y2-E_A2", C_y2 - E_A2);
765        point_args.add("G_y2", credentials_system.G_y[2]);
766        point_args.add("-E_A1", -E_A1);
767        point_args.add("E_A1", E_A1);
768        point_args.add("C_y1", C_y1);
769        point_args.add("G_y1", credentials_system.G_y[1]);
770
771        point_args.add("C_y4-E_B2", C_y4 - E_B2);
772        point_args.add("G_y4", credentials_system.G_y[4]);
773        point_args.add("-E_B1", -E_B1);
774        point_args.add("E_B1", E_B1);
775        point_args.add("C_y3", C_y3);
776        point_args.add("G_y3", credentials_system.G_y[3]);
777        point_args.add("0", RistrettoPoint::identity());
778
779        match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) {
780            Err(_) => Err(ZkGroupVerificationFailure),
781            Ok(_) => Ok(()),
782        }
783    }
784}
785
786impl ProfileKeyCredentialPresentationProofV1 {
787    pub(crate) fn from_invalid_proof(poksho_proof: Vec<u8>) -> Self {
788        Self {
789            C_x0: RISTRETTO_BASEPOINT_POINT,
790            C_x1: RISTRETTO_BASEPOINT_POINT,
791            C_y1: RISTRETTO_BASEPOINT_POINT,
792            C_y2: RISTRETTO_BASEPOINT_POINT,
793            C_y3: RISTRETTO_BASEPOINT_POINT,
794            C_y4: RISTRETTO_BASEPOINT_POINT,
795            C_V: RISTRETTO_BASEPOINT_POINT,
796            C_z: RISTRETTO_BASEPOINT_POINT,
797            poksho_proof,
798        }
799    }
800}
801
802impl ExpiringProfileKeyCredentialPresentationProof {
803    pub fn get_poksho_statement() -> poksho::Statement {
804        let mut st = poksho::Statement::new();
805        st.add("Z", &[("z", "I")]);
806        st.add("C_x1", &[("t", "C_x0"), ("z0", "G_x0"), ("z", "G_x1")]);
807        st.add(
808            "A+B",
809            &[
810                ("a1", "G_a1"),
811                ("a2", "G_a2"),
812                ("b1", "G_b1"),
813                ("b2", "G_b2"),
814            ],
815        );
816        st.add("C_y2-E_A2", &[("z", "G_y2"), ("a2", "-E_A1")]);
817        st.add("E_A1", &[("a1", "C_y1"), ("z1", "G_y1")]);
818        st.add("C_y4-E_B2", &[("z", "G_y4"), ("b2", "-E_B1")]);
819        st.add("E_B1", &[("b1", "C_y3"), ("z2", "G_y3")]);
820        st.add("0", &[("z1", "I"), ("a1", "Z")]);
821        st.add("0", &[("z2", "I"), ("b1", "Z")]);
822        st
823    }
824
825    #[allow(clippy::too_many_arguments)]
826    pub fn new(
827        uid_enc_key_pair: uid_encryption::KeyPair,
828        profile_key_enc_key_pair: profile_key_encryption::KeyPair,
829        credentials_public_key: credentials::PublicKey,
830        credential: credentials::ExpiringProfileKeyCredential,
831        uid_ciphertext: uid_encryption::Ciphertext,
832        profile_key_ciphertext: profile_key_encryption::Ciphertext,
833        aci_bytes: UidBytes,
834        profile_key_bytes: ProfileKeyBytes,
835        sho: &mut Sho,
836    ) -> Self {
837        let credentials_system = credentials::SystemParams::get_hardcoded();
838        let uid_system = uid_encryption::SystemParams::get_hardcoded();
839        let profile_key_system = profile_key_encryption::SystemParams::get_hardcoded();
840        let aci = libsignal_core::Aci::from_uuid_bytes(aci_bytes);
841        let uid = uid_struct::UidStruct::from_service_id(aci.into());
842        let profile_key = profile_key_struct::ProfileKeyStruct::new(profile_key_bytes, aci_bytes);
843
844        let z = sho.get_scalar();
845
846        let C_y1 = z * credentials_system.G_y[1] + uid.M1;
847        let C_y2 = z * credentials_system.G_y[2] + uid.M2;
848        let C_y3 = z * credentials_system.G_y[3] + profile_key.M3;
849        let C_y4 = z * credentials_system.G_y[4] + profile_key.M4;
850        let C_y5 = z * credentials_system.G_y[5];
851
852        let C_x0 = z * credentials_system.G_x0 + credential.U;
853        let C_V = z * credentials_system.G_V + credential.V;
854        let C_x1 = z * credentials_system.G_x1 + credential.t * credential.U;
855
856        let z0 = -z * credential.t;
857        let z1 = -z * uid_enc_key_pair.a1;
858        let z2 = -z * profile_key_enc_key_pair.a1;
859
860        let I = credentials_public_key.I;
861        let Z = z * I;
862
863        let [E_A1, E_A2] = uid_ciphertext.as_points();
864        let [E_B1, E_B2] = profile_key_ciphertext.as_points();
865
866        // Scalars listed in order of stmts for debugging
867        let mut scalar_args = poksho::ScalarArgs::new();
868        scalar_args.add("z", z);
869        scalar_args.add("t", credential.t);
870        scalar_args.add("z0", z0);
871        scalar_args.add("a1", uid_enc_key_pair.a1);
872        scalar_args.add("a2", uid_enc_key_pair.a2);
873        scalar_args.add("b1", profile_key_enc_key_pair.a1);
874        scalar_args.add("b2", profile_key_enc_key_pair.a2);
875        scalar_args.add("z1", z1);
876        scalar_args.add("z2", z2);
877
878        // Points listed in order of stmts for debugging
879        let mut point_args = poksho::PointArgs::new();
880        point_args.add("Z", Z);
881        point_args.add("I", I);
882
883        point_args.add("C_x1", C_x1);
884        point_args.add("C_x0", C_x0);
885        point_args.add("G_x0", credentials_system.G_x0);
886        point_args.add("G_x1", credentials_system.G_x1);
887
888        point_args.add(
889            "A+B",
890            uid_enc_key_pair.public_key.A + profile_key_enc_key_pair.public_key.A,
891        );
892        point_args.add("G_a1", uid_system.G_a1);
893        point_args.add("G_a2", uid_system.G_a2);
894        point_args.add("G_b1", profile_key_system.G_b1);
895        point_args.add("G_b2", profile_key_system.G_b2);
896
897        point_args.add("C_y2-E_A2", C_y2 - E_A2);
898        point_args.add("G_y2", credentials_system.G_y[2]);
899        point_args.add("-E_A1", -E_A1);
900        point_args.add("E_A1", E_A1);
901        point_args.add("C_y1", C_y1);
902        point_args.add("G_y1", credentials_system.G_y[1]);
903
904        point_args.add("C_y4-E_B2", C_y4 - E_B2);
905        point_args.add("G_y4", credentials_system.G_y[4]);
906        point_args.add("-E_B1", -E_B1);
907        point_args.add("E_B1", E_B1);
908        point_args.add("C_y3", C_y3);
909        point_args.add("G_y3", credentials_system.G_y[3]);
910        point_args.add("0", RistrettoPoint::identity());
911
912        let poksho_proof = Self::get_poksho_statement()
913            .prove(
914                &scalar_args,
915                &point_args,
916                &[],
917                &sho.squeeze(RANDOMNESS_LEN)[..],
918            )
919            .unwrap();
920
921        ExpiringProfileKeyCredentialPresentationProof {
922            C_y1,
923            C_y2,
924            C_y3,
925            C_y4,
926            C_y5,
927            C_x0,
928            C_x1,
929            C_V,
930            poksho_proof,
931        }
932    }
933
934    pub fn verify(
935        &self,
936        credentials_key_pair: credentials::KeyPair<credentials::ExpiringProfileKeyCredential>,
937        uid_ciphertext: uid_encryption::Ciphertext,
938        uid_enc_public_key: uid_encryption::PublicKey,
939        profile_key_ciphertext: profile_key_encryption::Ciphertext,
940        profile_key_enc_public_key: profile_key_encryption::PublicKey,
941        credential_expiration_time: Timestamp,
942    ) -> Result<(), ZkGroupVerificationFailure> {
943        let uid_enc_system = uid_encryption::SystemParams::get_hardcoded();
944        let profile_key_enc_system = profile_key_encryption::SystemParams::get_hardcoded();
945        let credentials_system = credentials::SystemParams::get_hardcoded();
946
947        let Self {
948            C_x0,
949            C_x1,
950            C_y1,
951            C_y2,
952            C_y3,
953            C_y4,
954            C_y5,
955            C_V,
956            poksho_proof,
957        } = self;
958
959        let (C_x0, C_x1, C_y1, C_y2, C_y3, C_y4, C_V) =
960            (*C_x0, *C_x1, *C_y1, *C_y2, *C_y3, *C_y4, *C_V);
961
962        let credentials::KeyPair {
963            W,
964            x0,
965            x1,
966            y: OneBased([y1, y2, y3, y4, y5]),
967            I,
968            ..
969        } = credentials_key_pair;
970
971        let [E_A1, E_A2] = uid_ciphertext.as_points();
972        let [E_B1, E_B2] = profile_key_ciphertext.as_points();
973        let m5 = TimestampStruct::calc_m_from(credential_expiration_time);
974        let M5 = m5 * credentials_system.G_m5;
975
976        let Z = C_V
977            - W
978            - x0 * C_x0
979            - x1 * C_x1
980            - (y1 * C_y1)
981            - (y2 * C_y2)
982            - (y3 * C_y3)
983            - (y4 * C_y4)
984            - (y5 * (C_y5 + M5));
985
986        // Points listed in order of stmts for debugging
987        let mut point_args = poksho::PointArgs::new();
988        point_args.add("Z", Z);
989        point_args.add("I", I);
990        point_args.add("C_x1", C_x1);
991        point_args.add("C_x0", C_x0);
992        point_args.add("G_x0", credentials_system.G_x0);
993        point_args.add("G_x1", credentials_system.G_x1);
994
995        point_args.add("A+B", uid_enc_public_key.A + profile_key_enc_public_key.A);
996        point_args.add("G_a1", uid_enc_system.G_a1);
997        point_args.add("G_a2", uid_enc_system.G_a2);
998        point_args.add("G_b1", profile_key_enc_system.G_b1);
999        point_args.add("G_b2", profile_key_enc_system.G_b2);
1000
1001        point_args.add("C_y2-E_A2", C_y2 - E_A2);
1002        point_args.add("G_y2", credentials_system.G_y[2]);
1003        point_args.add("-E_A1", -E_A1);
1004        point_args.add("E_A1", E_A1);
1005        point_args.add("C_y1", C_y1);
1006        point_args.add("G_y1", credentials_system.G_y[1]);
1007
1008        point_args.add("C_y4-E_B2", C_y4 - E_B2);
1009        point_args.add("G_y4", credentials_system.G_y[4]);
1010        point_args.add("-E_B1", -E_B1);
1011        point_args.add("E_B1", E_B1);
1012        point_args.add("C_y3", C_y3);
1013        point_args.add("G_y3", credentials_system.G_y[3]);
1014        point_args.add("0", RistrettoPoint::identity());
1015
1016        match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) {
1017            Err(_) => Err(ZkGroupVerificationFailure),
1018            Ok(_) => Ok(()),
1019        }
1020    }
1021}
1022
1023impl ReceiptCredentialPresentationProof {
1024    pub fn get_poksho_statement() -> poksho::Statement {
1025        let mut st = poksho::Statement::new();
1026
1027        st.add("Z", &[("z", "I")]);
1028        st.add("C_x1", &[("t", "C_x0"), ("-zt", "G_x0"), ("z", "G_x1")]);
1029        st.add("C_y1", &[("z", "G_y1")]);
1030        st.add("C_y2", &[("z", "G_y2")]);
1031        st
1032    }
1033
1034    pub fn new(
1035        credentials_public_key: credentials::PublicKey,
1036        credential: credentials::ReceiptCredential,
1037        sho: &mut Sho,
1038    ) -> Self {
1039        let credentials_system = credentials::SystemParams::get_hardcoded();
1040
1041        let z = sho.get_scalar();
1042
1043        let C_y1 = z * credentials_system.G_y[1];
1044        let C_y2 = z * credentials_system.G_y[2];
1045
1046        let I = credentials_public_key.I;
1047        let Z = z * I;
1048        let C_x0 = z * credentials_system.G_x0 + credential.U;
1049        let C_x1 = z * credentials_system.G_x1 + credential.t * credential.U;
1050        let C_V = z * credentials_system.G_V + credential.V;
1051
1052        // Scalars listed in order of stmts for debugging
1053        let mut scalar_args = poksho::ScalarArgs::new();
1054        scalar_args.add("z", z);
1055        scalar_args.add("t", credential.t);
1056        scalar_args.add("-zt", -z * credential.t);
1057
1058        // Points listed in order of stmts for debugging
1059        let mut point_args = poksho::PointArgs::new();
1060        point_args.add("Z", Z);
1061        point_args.add("I", I);
1062        point_args.add("C_x0", C_x0);
1063        point_args.add("C_x1", C_x1);
1064        point_args.add("C_y1", C_y1);
1065        point_args.add("C_y2", C_y2);
1066        point_args.add("G_x0", credentials_system.G_x0);
1067        point_args.add("G_x1", credentials_system.G_x1);
1068        point_args.add("G_y1", credentials_system.G_y[1]);
1069        point_args.add("G_y2", credentials_system.G_y[2]);
1070
1071        let poksho_proof = Self::get_poksho_statement()
1072            .prove(
1073                &scalar_args,
1074                &point_args,
1075                &[],
1076                &sho.squeeze(RANDOMNESS_LEN)[..],
1077            )
1078            .unwrap();
1079
1080        Self {
1081            C_x0,
1082            C_x1,
1083            C_y1,
1084            C_y2,
1085            C_V,
1086            poksho_proof,
1087        }
1088    }
1089
1090    pub fn verify(
1091        &self,
1092        credentials_key_pair: credentials::KeyPair<credentials::ReceiptCredential>,
1093        receipt_struct: ReceiptStruct,
1094    ) -> Result<(), ZkGroupVerificationFailure> {
1095        let credentials_system = credentials::SystemParams::get_hardcoded();
1096        let M = credentials::convert_to_points_receipt_struct(receipt_struct);
1097
1098        let Self {
1099            C_x0,
1100            C_x1,
1101            C_y1,
1102            C_y2,
1103            C_V,
1104            poksho_proof,
1105        } = self;
1106        let (C_x0, C_x1, C_y1, C_y2, C_V) = (*C_x0, *C_x1, *C_y1, *C_y2, *C_V);
1107
1108        let credentials::KeyPair {
1109            W,
1110            x0,
1111            x1,
1112            y: OneBased([y1, y2, ..]),
1113            I,
1114            ..
1115        } = credentials_key_pair;
1116
1117        let Z = C_V - W - x0 * C_x0 - x1 * C_x1 - y1 * (C_y1 + M[0]) - y2 * (C_y2 + M[1]);
1118
1119        // Points listed in order of stmts for debugging
1120        let mut point_args = poksho::PointArgs::new();
1121        point_args.add("Z", Z);
1122        point_args.add("I", I);
1123        point_args.add("C_x0", C_x0);
1124        point_args.add("C_x1", C_x1);
1125        point_args.add("C_y1", C_y1);
1126        point_args.add("C_y2", C_y2);
1127        point_args.add("G_x0", credentials_system.G_x0);
1128        point_args.add("G_x1", credentials_system.G_x1);
1129        point_args.add("G_y1", credentials_system.G_y[1]);
1130        point_args.add("G_y2", credentials_system.G_y[2]);
1131
1132        match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) {
1133            Err(_) => Err(ZkGroupVerificationFailure),
1134            Ok(_) => Ok(()),
1135        }
1136    }
1137}