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 ProfileKeyCredentialRequestProof {
29    poksho_proof: Vec<u8>,
30}
31
32#[derive(Serialize, Deserialize, Clone, PartialDefault)]
33pub struct ExpiringProfileKeyCredentialIssuanceProof {
34    poksho_proof: Vec<u8>,
35}
36
37#[derive(Serialize, Deserialize, Clone, PartialDefault)]
38pub struct ReceiptCredentialIssuanceProof {
39    poksho_proof: Vec<u8>,
40}
41
42/// Deprecated; use [ExpiringProfileKeyCredentialPresentationProof] instead.
43///
44/// Kept around so that v1 ProfileKeyCredentialPresentations can still be deserialized,
45/// even though they can't be verified.
46#[derive(Serialize, Deserialize, Clone, PartialDefault)]
47pub struct ProfileKeyCredentialPresentationProofV1 {
48    C_x0: RistrettoPoint,
49    C_x1: RistrettoPoint,
50    C_y1: RistrettoPoint,
51    C_y2: RistrettoPoint,
52    C_y3: RistrettoPoint,
53    C_y4: RistrettoPoint,
54    C_V: RistrettoPoint,
55    C_z: RistrettoPoint,
56    poksho_proof: Vec<u8>,
57}
58
59/// Deprecated; use [ExpiringProfileKeyCredentialPresentationProof] instead.
60///
61/// Kept around so that v2 ProfileKeyCredentialPresentations can still be deserialized,
62/// even though they can't be verified.
63#[derive(Serialize, Deserialize, Clone, PartialDefault)]
64pub struct ProfileKeyCredentialPresentationProofV2 {
65    C_x0: RistrettoPoint,
66    C_x1: RistrettoPoint,
67    C_y1: RistrettoPoint,
68    C_y2: RistrettoPoint,
69    C_y3: RistrettoPoint,
70    C_y4: RistrettoPoint,
71    C_V: RistrettoPoint,
72    C_z: RistrettoPoint,
73    poksho_proof: Vec<u8>,
74}
75
76#[derive(Serialize, Deserialize, Clone, PartialDefault)]
77pub struct ExpiringProfileKeyCredentialPresentationProof {
78    C_x0: RistrettoPoint,
79    C_x1: RistrettoPoint,
80    C_y1: RistrettoPoint,
81    C_y2: RistrettoPoint,
82    C_y3: RistrettoPoint,
83    C_y4: RistrettoPoint,
84    C_y5: RistrettoPoint,
85    C_V: RistrettoPoint,
86    poksho_proof: Vec<u8>,
87}
88
89#[derive(Serialize, Deserialize, Clone, PartialDefault)]
90pub struct ReceiptCredentialPresentationProof {
91    C_x0: RistrettoPoint,
92    C_x1: RistrettoPoint,
93    C_y1: RistrettoPoint,
94    C_y2: RistrettoPoint,
95    C_V: RistrettoPoint,
96    poksho_proof: Vec<u8>,
97}
98
99impl ProfileKeyCredentialRequestProof {
100    pub fn get_poksho_statement() -> poksho::Statement {
101        let mut st = poksho::Statement::new();
102        st.add("Y", &[("y", "G")]);
103        st.add("D1", &[("r1", "G")]);
104        st.add("E1", &[("r2", "G")]);
105        st.add("J3", &[("j3", "G_j3")]);
106        st.add("D2-J1", &[("r1", "Y"), ("j3", "-G_j1")]);
107        st.add("E2-J2", &[("r2", "Y"), ("j3", "-G_j2")]);
108        st
109    }
110
111    pub fn new(
112        key_pair: profile_key_credential_request::KeyPair,
113        ciphertext: profile_key_credential_request::CiphertextWithSecretNonce,
114        commitment: profile_key_commitment::CommitmentWithSecretNonce,
115        sho: &mut Sho,
116    ) -> ProfileKeyCredentialRequestProof {
117        let commitment_system = profile_key_commitment::SystemParams::get_hardcoded();
118
119        let mut scalar_args = poksho::ScalarArgs::new();
120        scalar_args.add("y", key_pair.y);
121        scalar_args.add("r1", ciphertext.r1);
122        scalar_args.add("r2", ciphertext.r2);
123        scalar_args.add("j3", commitment.j3);
124
125        let mut point_args = poksho::PointArgs::new();
126        point_args.add("Y", key_pair.Y);
127        point_args.add("D1", ciphertext.D1);
128        point_args.add("E1", ciphertext.E1);
129        point_args.add("J3", commitment.J3);
130        point_args.add("G_j3", commitment_system.G_j3);
131        point_args.add("D2-J1", ciphertext.D2 - commitment.J1);
132        point_args.add("-G_j1", -commitment_system.G_j1);
133        point_args.add("E2-J2", ciphertext.E2 - commitment.J2);
134        point_args.add("-G_j2", -commitment_system.G_j2);
135
136        let poksho_proof = Self::get_poksho_statement()
137            .prove(
138                &scalar_args,
139                &point_args,
140                &[],
141                &sho.squeeze_as_array::<RANDOMNESS_LEN>(),
142            )
143            .unwrap();
144        ProfileKeyCredentialRequestProof { poksho_proof }
145    }
146
147    pub fn verify(
148        &self,
149        public_key: profile_key_credential_request::PublicKey,
150        ciphertext: profile_key_credential_request::Ciphertext,
151        commitment: profile_key_commitment::Commitment,
152    ) -> Result<(), ZkGroupVerificationFailure> {
153        let commitment_system = profile_key_commitment::SystemParams::get_hardcoded();
154
155        let mut point_args = poksho::PointArgs::new();
156        point_args.add("Y", public_key.Y);
157        point_args.add("D1", ciphertext.D1);
158        point_args.add("E1", ciphertext.E1);
159        point_args.add("J3", commitment.J3);
160        point_args.add("G_j3", commitment_system.G_j3);
161        point_args.add("D2-J1", ciphertext.D2 - commitment.J1);
162        point_args.add("-G_j1", -commitment_system.G_j1);
163        point_args.add("E2-J2", ciphertext.E2 - commitment.J2);
164        point_args.add("-G_j2", -commitment_system.G_j2);
165
166        match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) {
167            Err(_) => Err(ZkGroupVerificationFailure),
168            Ok(_) => Ok(()),
169        }
170    }
171}
172
173impl ExpiringProfileKeyCredentialIssuanceProof {
174    pub fn get_poksho_statement() -> poksho::Statement {
175        let mut st = poksho::Statement::new();
176        st.add("C_W", &[("w", "G_w"), ("wprime", "G_wprime")]);
177        st.add(
178            "G_V-I",
179            &[
180                ("x0", "G_x0"),
181                ("x1", "G_x1"),
182                ("y1", "G_y1"),
183                ("y2", "G_y2"),
184                ("y3", "G_y3"),
185                ("y4", "G_y4"),
186                ("y5", "G_y5"),
187            ],
188        );
189        st.add("S1", &[("y3", "D1"), ("y4", "E1"), ("rprime", "G")]);
190        st.add(
191            "S2",
192            &[
193                ("y3", "D2"),
194                ("y4", "E2"),
195                ("rprime", "Y"),
196                ("w", "G_w"),
197                ("x0", "U"),
198                ("x1", "tU"),
199                ("y1", "M1"),
200                ("y2", "M2"),
201                ("y5", "M5"),
202            ],
203        );
204        st
205    }
206
207    pub fn new(
208        key_pair: credentials::KeyPair<credentials::ExpiringProfileKeyCredential>,
209        request_public_key: profile_key_credential_request::PublicKey,
210        request: profile_key_credential_request::Ciphertext,
211        blinded_credential: credentials::BlindedExpiringProfileKeyCredentialWithSecretNonce,
212        uid: uid_struct::UidStruct,
213        credential_expiration_time: Timestamp,
214        sho: &mut Sho,
215    ) -> Self {
216        let credentials_system = credentials::SystemParams::get_hardcoded();
217
218        let m5 = TimestampStruct::calc_m_from(credential_expiration_time);
219        let M5 = m5 * credentials_system.G_m5;
220
221        let mut scalar_args = poksho::ScalarArgs::new();
222        scalar_args.add("w", key_pair.w);
223        scalar_args.add("wprime", key_pair.wprime);
224        scalar_args.add("x0", key_pair.x0);
225        scalar_args.add("x1", key_pair.x1);
226        scalar_args.add("y1", key_pair.y[1]);
227        scalar_args.add("y2", key_pair.y[2]);
228        scalar_args.add("y3", key_pair.y[3]);
229        scalar_args.add("y4", key_pair.y[4]);
230        scalar_args.add("y5", key_pair.y[5]);
231        scalar_args.add("rprime", blinded_credential.rprime);
232
233        let mut point_args = poksho::PointArgs::new();
234        point_args.add("C_W", key_pair.C_W);
235        point_args.add("G_w", credentials_system.G_w);
236        point_args.add("G_wprime", credentials_system.G_wprime);
237        point_args.add("G_V-I", credentials_system.G_V - key_pair.I);
238        point_args.add("G_x0", credentials_system.G_x0);
239        point_args.add("G_x1", credentials_system.G_x1);
240        point_args.add("G_y1", credentials_system.G_y[1]);
241        point_args.add("G_y2", credentials_system.G_y[2]);
242        point_args.add("G_y3", credentials_system.G_y[3]);
243        point_args.add("G_y4", credentials_system.G_y[4]);
244        point_args.add("G_y5", credentials_system.G_y[5]);
245        point_args.add("S1", blinded_credential.S1);
246        point_args.add("D1", request.D1);
247        point_args.add("E1", request.E1);
248        point_args.add("S2", blinded_credential.S2);
249        point_args.add("D2", request.D2);
250        point_args.add("E2", request.E2);
251        point_args.add("Y", request_public_key.Y);
252        point_args.add("U", blinded_credential.U);
253        point_args.add("tU", blinded_credential.t * blinded_credential.U);
254        point_args.add("M1", uid.M1);
255        point_args.add("M2", uid.M2);
256        point_args.add("M5", M5);
257
258        let poksho_proof = Self::get_poksho_statement()
259            .prove(
260                &scalar_args,
261                &point_args,
262                &[],
263                &sho.squeeze_as_array::<RANDOMNESS_LEN>(),
264            )
265            .unwrap();
266        ExpiringProfileKeyCredentialIssuanceProof { poksho_proof }
267    }
268
269    pub fn verify(
270        &self,
271        credentials_public_key: credentials::PublicKey,
272        request_public_key: profile_key_credential_request::PublicKey,
273        aci_bytes: UidBytes,
274        request: profile_key_credential_request::Ciphertext,
275        blinded_credential: credentials::BlindedExpiringProfileKeyCredential,
276        credential_expiration_time: Timestamp,
277    ) -> Result<(), ZkGroupVerificationFailure> {
278        let credentials_system = credentials::SystemParams::get_hardcoded();
279        let aci = libsignal_core::Aci::from_uuid_bytes(aci_bytes);
280        let uid = uid_struct::UidStruct::from_service_id(aci.into());
281
282        let m5 = TimestampStruct::calc_m_from(credential_expiration_time);
283        let M5 = m5 * credentials_system.G_m5;
284
285        let mut point_args = poksho::PointArgs::new();
286        point_args.add("C_W", credentials_public_key.C_W);
287        point_args.add("G_w", credentials_system.G_w);
288        point_args.add("G_wprime", credentials_system.G_wprime);
289        point_args.add("G_V-I", credentials_system.G_V - credentials_public_key.I);
290        point_args.add("G_x0", credentials_system.G_x0);
291        point_args.add("G_x1", credentials_system.G_x1);
292        point_args.add("G_y1", credentials_system.G_y[1]);
293        point_args.add("G_y2", credentials_system.G_y[2]);
294        point_args.add("G_y3", credentials_system.G_y[3]);
295        point_args.add("G_y4", credentials_system.G_y[4]);
296        point_args.add("G_y5", credentials_system.G_y[5]);
297        point_args.add("S1", blinded_credential.S1);
298        point_args.add("D1", request.D1);
299        point_args.add("E1", request.E1);
300        point_args.add("S2", blinded_credential.S2);
301        point_args.add("D2", request.D2);
302        point_args.add("E2", request.E2);
303        point_args.add("Y", request_public_key.Y);
304        point_args.add("U", blinded_credential.U);
305        point_args.add("tU", blinded_credential.t * blinded_credential.U);
306        point_args.add("M1", uid.M1);
307        point_args.add("M2", uid.M2);
308        point_args.add("M5", M5);
309
310        match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) {
311            Err(_) => Err(ZkGroupVerificationFailure),
312            Ok(_) => Ok(()),
313        }
314    }
315}
316
317impl ReceiptCredentialIssuanceProof {
318    pub fn get_poksho_statement() -> poksho::Statement {
319        let mut st = poksho::Statement::new();
320
321        st.add("C_W", &[("w", "G_w"), ("wprime", "G_wprime")]);
322        st.add(
323            "G_V-I",
324            &[
325                ("x0", "G_x0"),
326                ("x1", "G_x1"),
327                ("y1", "G_y1"),
328                ("y2", "G_y2"),
329            ],
330        );
331        st.add("S1", &[("y2", "D1"), ("rprime", "G")]);
332        st.add(
333            "S2",
334            &[
335                ("y2", "D2"),
336                ("rprime", "Y"),
337                ("w", "G_w"),
338                ("x0", "U"),
339                ("x1", "tU"),
340                ("y1", "M1"),
341            ],
342        );
343        st
344    }
345
346    pub fn new(
347        key_pair: credentials::KeyPair<credentials::ReceiptCredential>,
348        request_public_key: receipt_credential_request::PublicKey,
349        request: receipt_credential_request::Ciphertext,
350        blinded_credential: credentials::BlindedReceiptCredentialWithSecretNonce,
351        receipt_expiration_time: Timestamp,
352        receipt_level: ReceiptLevel,
353        sho: &mut Sho,
354    ) -> Self {
355        let credentials_system = credentials::SystemParams::get_hardcoded();
356
357        let m1 = ReceiptStruct::calc_m1_from(receipt_expiration_time, receipt_level);
358
359        let mut scalar_args = poksho::ScalarArgs::new();
360        scalar_args.add("w", key_pair.w);
361        scalar_args.add("wprime", key_pair.wprime);
362        scalar_args.add("x0", key_pair.x0);
363        scalar_args.add("x1", key_pair.x1);
364        scalar_args.add("y1", key_pair.y[1]);
365        scalar_args.add("y2", key_pair.y[2]);
366        scalar_args.add("rprime", blinded_credential.rprime);
367
368        let mut point_args = poksho::PointArgs::new();
369        point_args.add("C_W", key_pair.C_W);
370        point_args.add("G_w", credentials_system.G_w);
371        point_args.add("G_wprime", credentials_system.G_wprime);
372        point_args.add("G_V-I", credentials_system.G_V - key_pair.I);
373        point_args.add("G_x0", credentials_system.G_x0);
374        point_args.add("G_x1", credentials_system.G_x1);
375        point_args.add("G_y1", credentials_system.G_y[1]);
376        point_args.add("G_y2", credentials_system.G_y[2]);
377        point_args.add("S1", blinded_credential.S1);
378        point_args.add("D1", request.D1);
379        point_args.add("S2", blinded_credential.S2);
380        point_args.add("D2", request.D2);
381        point_args.add("Y", request_public_key.Y);
382        point_args.add("U", blinded_credential.U);
383        point_args.add("tU", blinded_credential.t * blinded_credential.U);
384        point_args.add("M1", m1 * credentials_system.G_m1);
385
386        let poksho_proof = Self::get_poksho_statement()
387            .prove(
388                &scalar_args,
389                &point_args,
390                &[],
391                &sho.squeeze_as_array::<RANDOMNESS_LEN>(),
392            )
393            .unwrap();
394        Self { poksho_proof }
395    }
396
397    pub fn verify(
398        &self,
399        credentials_public_key: credentials::PublicKey,
400        request_public_key: receipt_credential_request::PublicKey,
401        request: receipt_credential_request::Ciphertext,
402        blinded_credential: credentials::BlindedReceiptCredential,
403        receipt_struct: ReceiptStruct,
404    ) -> Result<(), ZkGroupVerificationFailure> {
405        let credentials_system = credentials::SystemParams::get_hardcoded();
406
407        let M = credentials::convert_to_points_receipt_struct(receipt_struct);
408
409        let mut point_args = poksho::PointArgs::new();
410        point_args.add("C_W", credentials_public_key.C_W);
411        point_args.add("G_w", credentials_system.G_w);
412        point_args.add("G_wprime", credentials_system.G_wprime);
413        point_args.add("G_V-I", credentials_system.G_V - credentials_public_key.I);
414        point_args.add("G_x0", credentials_system.G_x0);
415        point_args.add("G_x1", credentials_system.G_x1);
416        point_args.add("G_y1", credentials_system.G_y[1]);
417        point_args.add("G_y2", credentials_system.G_y[2]);
418        point_args.add("S1", blinded_credential.S1);
419        point_args.add("D1", request.D1);
420        point_args.add("S2", blinded_credential.S2);
421        point_args.add("D2", request.D2);
422        point_args.add("Y", request_public_key.Y);
423        point_args.add("U", blinded_credential.U);
424        point_args.add("tU", blinded_credential.t * blinded_credential.U);
425        point_args.add("M1", M[0]);
426
427        match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) {
428            Err(_) => Err(ZkGroupVerificationFailure),
429            Ok(_) => Ok(()),
430        }
431    }
432}
433
434impl ProfileKeyCredentialPresentationProofV1 {
435    pub(crate) fn from_invalid_proof(poksho_proof: Vec<u8>) -> Self {
436        Self {
437            C_x0: RISTRETTO_BASEPOINT_POINT,
438            C_x1: RISTRETTO_BASEPOINT_POINT,
439            C_y1: RISTRETTO_BASEPOINT_POINT,
440            C_y2: RISTRETTO_BASEPOINT_POINT,
441            C_y3: RISTRETTO_BASEPOINT_POINT,
442            C_y4: RISTRETTO_BASEPOINT_POINT,
443            C_V: RISTRETTO_BASEPOINT_POINT,
444            C_z: RISTRETTO_BASEPOINT_POINT,
445            poksho_proof,
446        }
447    }
448}
449
450impl ExpiringProfileKeyCredentialPresentationProof {
451    pub fn get_poksho_statement() -> poksho::Statement {
452        let mut st = poksho::Statement::new();
453        st.add("Z", &[("z", "I")]);
454        st.add("C_x1", &[("t", "C_x0"), ("z0", "G_x0"), ("z", "G_x1")]);
455        st.add(
456            "A+B",
457            &[
458                ("a1", "G_a1"),
459                ("a2", "G_a2"),
460                ("b1", "G_b1"),
461                ("b2", "G_b2"),
462            ],
463        );
464        st.add("C_y2-E_A2", &[("z", "G_y2"), ("a2", "-E_A1")]);
465        st.add("E_A1", &[("a1", "C_y1"), ("z1", "G_y1")]);
466        st.add("C_y4-E_B2", &[("z", "G_y4"), ("b2", "-E_B1")]);
467        st.add("E_B1", &[("b1", "C_y3"), ("z2", "G_y3")]);
468        st.add("0", &[("z1", "I"), ("a1", "Z")]);
469        st.add("0", &[("z2", "I"), ("b1", "Z")]);
470        st
471    }
472
473    #[expect(clippy::too_many_arguments)]
474    pub fn new(
475        uid_enc_key_pair: uid_encryption::KeyPair,
476        profile_key_enc_key_pair: profile_key_encryption::KeyPair,
477        credentials_public_key: credentials::PublicKey,
478        credential: credentials::ExpiringProfileKeyCredential,
479        uid_ciphertext: uid_encryption::Ciphertext,
480        profile_key_ciphertext: profile_key_encryption::Ciphertext,
481        aci_bytes: UidBytes,
482        profile_key_bytes: ProfileKeyBytes,
483        sho: &mut Sho,
484    ) -> Self {
485        let credentials_system = credentials::SystemParams::get_hardcoded();
486        let uid_system = uid_encryption::SystemParams::get_hardcoded();
487        let profile_key_system = profile_key_encryption::SystemParams::get_hardcoded();
488        let aci = libsignal_core::Aci::from_uuid_bytes(aci_bytes);
489        let uid = uid_struct::UidStruct::from_service_id(aci.into());
490        let profile_key = profile_key_struct::ProfileKeyStruct::new(profile_key_bytes, aci_bytes);
491
492        let z = sho.get_scalar();
493
494        let C_y1 = z * credentials_system.G_y[1] + uid.M1;
495        let C_y2 = z * credentials_system.G_y[2] + uid.M2;
496        let C_y3 = z * credentials_system.G_y[3] + profile_key.M3;
497        let C_y4 = z * credentials_system.G_y[4] + profile_key.M4;
498        let C_y5 = z * credentials_system.G_y[5];
499
500        let C_x0 = z * credentials_system.G_x0 + credential.U;
501        let C_V = z * credentials_system.G_V + credential.V;
502        let C_x1 = z * credentials_system.G_x1 + credential.t * credential.U;
503
504        let z0 = -z * credential.t;
505        let z1 = -z * uid_enc_key_pair.a1;
506        let z2 = -z * profile_key_enc_key_pair.a1;
507
508        let I = credentials_public_key.I;
509        let Z = z * I;
510
511        let [E_A1, E_A2] = uid_ciphertext.as_points();
512        let [E_B1, E_B2] = profile_key_ciphertext.as_points();
513
514        // Scalars listed in order of stmts for debugging
515        let mut scalar_args = poksho::ScalarArgs::new();
516        scalar_args.add("z", z);
517        scalar_args.add("t", credential.t);
518        scalar_args.add("z0", z0);
519        scalar_args.add("a1", uid_enc_key_pair.a1);
520        scalar_args.add("a2", uid_enc_key_pair.a2);
521        scalar_args.add("b1", profile_key_enc_key_pair.a1);
522        scalar_args.add("b2", profile_key_enc_key_pair.a2);
523        scalar_args.add("z1", z1);
524        scalar_args.add("z2", z2);
525
526        // Points listed in order of stmts for debugging
527        let mut point_args = poksho::PointArgs::new();
528        point_args.add("Z", Z);
529        point_args.add("I", I);
530
531        point_args.add("C_x1", C_x1);
532        point_args.add("C_x0", C_x0);
533        point_args.add("G_x0", credentials_system.G_x0);
534        point_args.add("G_x1", credentials_system.G_x1);
535
536        point_args.add(
537            "A+B",
538            uid_enc_key_pair.public_key.A + profile_key_enc_key_pair.public_key.A,
539        );
540        point_args.add("G_a1", uid_system.G_a1);
541        point_args.add("G_a2", uid_system.G_a2);
542        point_args.add("G_b1", profile_key_system.G_b1);
543        point_args.add("G_b2", profile_key_system.G_b2);
544
545        point_args.add("C_y2-E_A2", C_y2 - E_A2);
546        point_args.add("G_y2", credentials_system.G_y[2]);
547        point_args.add("-E_A1", -E_A1);
548        point_args.add("E_A1", E_A1);
549        point_args.add("C_y1", C_y1);
550        point_args.add("G_y1", credentials_system.G_y[1]);
551
552        point_args.add("C_y4-E_B2", C_y4 - E_B2);
553        point_args.add("G_y4", credentials_system.G_y[4]);
554        point_args.add("-E_B1", -E_B1);
555        point_args.add("E_B1", E_B1);
556        point_args.add("C_y3", C_y3);
557        point_args.add("G_y3", credentials_system.G_y[3]);
558        point_args.add("0", RistrettoPoint::identity());
559
560        let poksho_proof = Self::get_poksho_statement()
561            .prove(
562                &scalar_args,
563                &point_args,
564                &[],
565                &sho.squeeze_as_array::<RANDOMNESS_LEN>(),
566            )
567            .unwrap();
568
569        ExpiringProfileKeyCredentialPresentationProof {
570            C_y1,
571            C_y2,
572            C_y3,
573            C_y4,
574            C_y5,
575            C_x0,
576            C_x1,
577            C_V,
578            poksho_proof,
579        }
580    }
581
582    pub fn verify(
583        &self,
584        credentials_key_pair: credentials::KeyPair<credentials::ExpiringProfileKeyCredential>,
585        uid_ciphertext: uid_encryption::Ciphertext,
586        uid_enc_public_key: uid_encryption::PublicKey,
587        profile_key_ciphertext: profile_key_encryption::Ciphertext,
588        profile_key_enc_public_key: profile_key_encryption::PublicKey,
589        credential_expiration_time: Timestamp,
590    ) -> Result<(), ZkGroupVerificationFailure> {
591        let uid_enc_system = uid_encryption::SystemParams::get_hardcoded();
592        let profile_key_enc_system = profile_key_encryption::SystemParams::get_hardcoded();
593        let credentials_system = credentials::SystemParams::get_hardcoded();
594
595        let Self {
596            C_x0,
597            C_x1,
598            C_y1,
599            C_y2,
600            C_y3,
601            C_y4,
602            C_y5,
603            C_V,
604            poksho_proof,
605        } = self;
606
607        let (C_x0, C_x1, C_y1, C_y2, C_y3, C_y4, C_V) =
608            (*C_x0, *C_x1, *C_y1, *C_y2, *C_y3, *C_y4, *C_V);
609
610        let credentials::KeyPair {
611            W,
612            x0,
613            x1,
614            y: OneBased([y1, y2, y3, y4, y5]),
615            I,
616            ..
617        } = credentials_key_pair;
618
619        let [E_A1, E_A2] = uid_ciphertext.as_points();
620        let [E_B1, E_B2] = profile_key_ciphertext.as_points();
621        let m5 = TimestampStruct::calc_m_from(credential_expiration_time);
622        let M5 = m5 * credentials_system.G_m5;
623
624        let Z = C_V
625            - W
626            - x0 * C_x0
627            - x1 * C_x1
628            - (y1 * C_y1)
629            - (y2 * C_y2)
630            - (y3 * C_y3)
631            - (y4 * C_y4)
632            - (y5 * (C_y5 + M5));
633
634        // Points listed in order of stmts for debugging
635        let mut point_args = poksho::PointArgs::new();
636        point_args.add("Z", Z);
637        point_args.add("I", I);
638        point_args.add("C_x1", C_x1);
639        point_args.add("C_x0", C_x0);
640        point_args.add("G_x0", credentials_system.G_x0);
641        point_args.add("G_x1", credentials_system.G_x1);
642
643        point_args.add("A+B", uid_enc_public_key.A + profile_key_enc_public_key.A);
644        point_args.add("G_a1", uid_enc_system.G_a1);
645        point_args.add("G_a2", uid_enc_system.G_a2);
646        point_args.add("G_b1", profile_key_enc_system.G_b1);
647        point_args.add("G_b2", profile_key_enc_system.G_b2);
648
649        point_args.add("C_y2-E_A2", C_y2 - E_A2);
650        point_args.add("G_y2", credentials_system.G_y[2]);
651        point_args.add("-E_A1", -E_A1);
652        point_args.add("E_A1", E_A1);
653        point_args.add("C_y1", C_y1);
654        point_args.add("G_y1", credentials_system.G_y[1]);
655
656        point_args.add("C_y4-E_B2", C_y4 - E_B2);
657        point_args.add("G_y4", credentials_system.G_y[4]);
658        point_args.add("-E_B1", -E_B1);
659        point_args.add("E_B1", E_B1);
660        point_args.add("C_y3", C_y3);
661        point_args.add("G_y3", credentials_system.G_y[3]);
662        point_args.add("0", RistrettoPoint::identity());
663
664        match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) {
665            Err(_) => Err(ZkGroupVerificationFailure),
666            Ok(_) => Ok(()),
667        }
668    }
669}
670
671impl ReceiptCredentialPresentationProof {
672    pub fn get_poksho_statement() -> poksho::Statement {
673        let mut st = poksho::Statement::new();
674
675        st.add("Z", &[("z", "I")]);
676        st.add("C_x1", &[("t", "C_x0"), ("-zt", "G_x0"), ("z", "G_x1")]);
677        st.add("C_y1", &[("z", "G_y1")]);
678        st.add("C_y2", &[("z", "G_y2")]);
679        st
680    }
681
682    pub fn new(
683        credentials_public_key: credentials::PublicKey,
684        credential: credentials::ReceiptCredential,
685        sho: &mut Sho,
686    ) -> Self {
687        let credentials_system = credentials::SystemParams::get_hardcoded();
688
689        let z = sho.get_scalar();
690
691        let C_y1 = z * credentials_system.G_y[1];
692        let C_y2 = z * credentials_system.G_y[2];
693
694        let I = credentials_public_key.I;
695        let Z = z * I;
696        let C_x0 = z * credentials_system.G_x0 + credential.U;
697        let C_x1 = z * credentials_system.G_x1 + credential.t * credential.U;
698        let C_V = z * credentials_system.G_V + credential.V;
699
700        // Scalars listed in order of stmts for debugging
701        let mut scalar_args = poksho::ScalarArgs::new();
702        scalar_args.add("z", z);
703        scalar_args.add("t", credential.t);
704        scalar_args.add("-zt", -z * credential.t);
705
706        // Points listed in order of stmts for debugging
707        let mut point_args = poksho::PointArgs::new();
708        point_args.add("Z", Z);
709        point_args.add("I", I);
710        point_args.add("C_x0", C_x0);
711        point_args.add("C_x1", C_x1);
712        point_args.add("C_y1", C_y1);
713        point_args.add("C_y2", C_y2);
714        point_args.add("G_x0", credentials_system.G_x0);
715        point_args.add("G_x1", credentials_system.G_x1);
716        point_args.add("G_y1", credentials_system.G_y[1]);
717        point_args.add("G_y2", credentials_system.G_y[2]);
718
719        let poksho_proof = Self::get_poksho_statement()
720            .prove(
721                &scalar_args,
722                &point_args,
723                &[],
724                &sho.squeeze_as_array::<RANDOMNESS_LEN>(),
725            )
726            .unwrap();
727
728        Self {
729            C_x0,
730            C_x1,
731            C_y1,
732            C_y2,
733            C_V,
734            poksho_proof,
735        }
736    }
737
738    pub fn verify(
739        &self,
740        credentials_key_pair: credentials::KeyPair<credentials::ReceiptCredential>,
741        receipt_struct: ReceiptStruct,
742    ) -> Result<(), ZkGroupVerificationFailure> {
743        let credentials_system = credentials::SystemParams::get_hardcoded();
744        let M = credentials::convert_to_points_receipt_struct(receipt_struct);
745
746        let Self {
747            C_x0,
748            C_x1,
749            C_y1,
750            C_y2,
751            C_V,
752            poksho_proof,
753        } = self;
754        let (C_x0, C_x1, C_y1, C_y2, C_V) = (*C_x0, *C_x1, *C_y1, *C_y2, *C_V);
755
756        let credentials::KeyPair {
757            W,
758            x0,
759            x1,
760            y: OneBased([y1, y2, ..]),
761            I,
762            ..
763        } = credentials_key_pair;
764
765        let Z = C_V - W - x0 * C_x0 - x1 * C_x1 - y1 * (C_y1 + M[0]) - y2 * (C_y2 + M[1]);
766
767        // Points listed in order of stmts for debugging
768        let mut point_args = poksho::PointArgs::new();
769        point_args.add("Z", Z);
770        point_args.add("I", I);
771        point_args.add("C_x0", C_x0);
772        point_args.add("C_x1", C_x1);
773        point_args.add("C_y1", C_y1);
774        point_args.add("C_y2", C_y2);
775        point_args.add("G_x0", credentials_system.G_x0);
776        point_args.add("G_x1", credentials_system.G_x1);
777        point_args.add("G_y1", credentials_system.G_y[1]);
778        point_args.add("G_y2", credentials_system.G_y[2]);
779
780        match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) {
781            Err(_) => Err(ZkGroupVerificationFailure),
782            Ok(_) => Ok(()),
783        }
784    }
785}