1#![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#[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#[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 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 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 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 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 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 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}