1use crate::{
16 error::VBAccumulatorError,
17 prelude::{MembershipWitness, NonMembershipWitness, PreparedPublicKey, PreparedSetupParams},
18 setup::SetupParams,
19};
20use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
21use ark_ff::Zero;
22use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
23use ark_std::{
24 collections::BTreeMap, io::Write, ops::Neg, rand::RngCore, vec, vec::Vec, UniformRand,
25};
26use core::mem;
27use dock_crypto_utils::{
28 randomized_pairing_check::RandomizedPairingChecker, serde_utils::ArkObjectBytes,
29};
30use schnorr_pok::{
31 discrete_log::{PokDiscreteLog, PokDiscreteLogProtocol},
32 partial::PartialSchnorrResponse,
33 SchnorrCommitment,
34};
35use serde::{Deserialize, Serialize};
36use serde_with::serde_as;
37use short_group_sig::weak_bb_sig_pok_cdh::{PoKOfSignatureG1, PoKOfSignatureG1Protocol};
38use zeroize::{Zeroize, ZeroizeOnDrop};
39
40#[derive(Default, Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
43pub struct MembershipProofProtocol<E: Pairing>(pub PoKOfSignatureG1Protocol<E>);
44
45#[derive(
47 Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
48)]
49#[serde(bound = "")]
50pub struct MembershipProof<E: Pairing>(pub PoKOfSignatureG1<E>);
51
52#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
54pub struct NonMembershipProofProtocol<E: Pairing> {
55 #[zeroize(skip)]
57 pub C_prime: E::G1Affine,
58 #[zeroize(skip)]
60 pub C_bar: E::G1Affine,
61 #[zeroize(skip)]
63 pub J: E::G1Affine,
64 pub sc_comm_1: SchnorrCommitment<E::G1Affine>,
66 sc_wits_1: (E::ScalarField, E::ScalarField, E::ScalarField),
68 pub sc_comm_2: PokDiscreteLogProtocol<E::G1Affine>,
70}
71
72#[serde_as]
73#[derive(
74 Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
75)]
76pub struct NonMembershipProof<E: Pairing> {
77 #[serde_as(as = "ArkObjectBytes")]
79 pub C_prime: E::G1Affine,
80 #[serde_as(as = "ArkObjectBytes")]
82 pub C_bar: E::G1Affine,
83 #[serde_as(as = "ArkObjectBytes")]
85 pub J: E::G1Affine,
86 #[serde_as(as = "ArkObjectBytes")]
88 pub t_1: E::G1Affine,
89 pub sc_resp_1: PartialSchnorrResponse<E::G1Affine>,
90 pub sc_2: PokDiscreteLog<E::G1Affine>,
92}
93
94impl<E: Pairing> MembershipProofProtocol<E> {
95 pub fn init<R: RngCore>(
96 rng: &mut R,
97 element: E::ScalarField,
98 element_blinding: Option<E::ScalarField>,
99 accumulator_value: &E::G1Affine,
100 witness: &MembershipWitness<E::G1Affine>,
101 ) -> Self {
102 Self(PoKOfSignatureG1Protocol::init(
103 rng,
104 witness,
105 element,
106 element_blinding,
107 accumulator_value,
108 ))
109 }
110
111 pub fn challenge_contribution<W: Write>(
112 &self,
113 accumulator_value: &E::G1Affine,
114 writer: W,
115 ) -> Result<(), VBAccumulatorError> {
116 self.0.challenge_contribution(accumulator_value, writer)?;
117 Ok(())
118 }
119
120 pub fn gen_proof(
121 self,
122 challenge: &E::ScalarField,
123 ) -> Result<MembershipProof<E>, VBAccumulatorError> {
124 let proof = self.0.clone().gen_proof(challenge);
125 Ok(MembershipProof(proof))
126 }
127
128 pub fn gen_partial_proof(
129 self,
130 challenge: &E::ScalarField,
131 ) -> Result<MembershipProof<E>, VBAccumulatorError> {
132 let proof = self.0.clone().gen_partial_proof(challenge);
133 Ok(MembershipProof(proof))
134 }
135}
136
137impl<E: Pairing> MembershipProof<E> {
138 pub fn verify(
139 &self,
140 accumulator_value: &E::G1Affine,
141 challenge: &E::ScalarField,
142 pk: impl Into<PreparedPublicKey<E>>,
143 params: impl Into<PreparedSetupParams<E>>,
144 ) -> Result<(), VBAccumulatorError> {
145 let params = params.into();
146 self.0
147 .verify(challenge, pk.into().0, accumulator_value, params.P_tilde)?;
148 Ok(())
149 }
150
151 pub fn verify_partial(
152 &self,
153 resp_for_element: &E::ScalarField,
154 accumulator_value: &E::G1Affine,
155 challenge: &E::ScalarField,
156 pk: impl Into<PreparedPublicKey<E>>,
157 params: impl Into<PreparedSetupParams<E>>,
158 ) -> Result<(), VBAccumulatorError> {
159 let params = params.into();
160 self.0.verify_partial(
161 resp_for_element,
162 challenge,
163 pk.into().0,
164 accumulator_value,
165 params.P_tilde,
166 )?;
167 Ok(())
168 }
169
170 pub fn verify_with_randomized_pairing_checker(
171 &self,
172 accumulator_value: &E::G1Affine,
173 challenge: &E::ScalarField,
174 pk: impl Into<PreparedPublicKey<E>>,
175 params: impl Into<PreparedSetupParams<E>>,
176 pairing_checker: &mut RandomizedPairingChecker<E>,
177 ) -> Result<(), VBAccumulatorError> {
178 let params = params.into();
179 self.0.verify_with_randomized_pairing_checker(
180 challenge,
181 pk.into().0,
182 accumulator_value,
183 params.P_tilde,
184 pairing_checker,
185 )?;
186 Ok(())
187 }
188
189 pub fn verify_partial_with_randomized_pairing_checker(
190 &self,
191 resp_for_element: &E::ScalarField,
192 accumulator_value: &E::G1Affine,
193 challenge: &E::ScalarField,
194 pk: impl Into<PreparedPublicKey<E>>,
195 params: impl Into<PreparedSetupParams<E>>,
196 pairing_checker: &mut RandomizedPairingChecker<E>,
197 ) -> Result<(), VBAccumulatorError> {
198 let params = params.into();
199 self.0.verify_partial_with_randomized_pairing_checker(
200 resp_for_element,
201 challenge,
202 pk.into().0,
203 accumulator_value,
204 params.P_tilde,
205 pairing_checker,
206 )?;
207 Ok(())
208 }
209
210 pub fn challenge_contribution<W: Write>(
211 &self,
212 accumulator_value: &E::G1Affine,
213 writer: W,
214 ) -> Result<(), VBAccumulatorError> {
215 self.0.challenge_contribution(accumulator_value, writer)?;
216 Ok(())
217 }
218
219 pub fn get_schnorr_response_for_element(&self) -> Option<&E::ScalarField> {
220 self.0.get_resp_for_message()
221 }
222}
223
224impl<E: Pairing> NonMembershipProofProtocol<E> {
225 pub fn init<R: RngCore>(
226 rng: &mut R,
227 element: E::ScalarField,
228 element_blinding: Option<E::ScalarField>,
229 accumulator_value: E::G1Affine,
230 witness: &NonMembershipWitness<E::G1Affine>,
231 params: &SetupParams<E>,
232 Q: impl Into<E::G1Affine>,
233 ) -> Self {
234 let r = E::ScalarField::rand(rng);
235 let element_blinding = element_blinding.unwrap_or_else(|| E::ScalarField::rand(rng));
236 let Q = Q.into();
237 let d_prime = witness.d * r;
238 let C_prime = witness.C * r;
239 let C_prime_neg = C_prime.neg();
240 let g1_neg = params.P.into_group().neg();
241 let C_bar =
243 (accumulator_value * r + C_prime_neg * element + g1_neg * d_prime).into_affine();
244 let d_prime_blinding = E::ScalarField::rand(rng);
245 let J = (Q * d_prime).into_affine();
247 let sc_comm_1 = SchnorrCommitment::new(
248 &[accumulator_value, C_prime_neg.into(), g1_neg.into()],
249 vec![
250 E::ScalarField::rand(rng),
251 element_blinding,
252 d_prime_blinding,
253 ],
254 );
255 let sc_wits_1 = (r, element, d_prime);
256 let sc_comm_2 = PokDiscreteLogProtocol::init(d_prime, d_prime_blinding, &Q);
257
258 Self {
259 C_prime: C_prime.into(),
260 C_bar,
261 J,
262 sc_comm_1,
263 sc_comm_2,
264 sc_wits_1,
265 }
266 }
267
268 pub fn challenge_contribution<W: Write>(
269 &self,
270 accumulator_value: &E::G1Affine,
271 params: &SetupParams<E>,
272 Q: &E::G1Affine,
273 writer: W,
274 ) -> Result<(), VBAccumulatorError> {
275 Self::compute_challenge_contribution(
276 &self.C_prime,
277 &self.C_bar,
278 &self.J,
279 accumulator_value,
280 params,
281 Q,
282 &self.sc_comm_1.t,
283 &self.sc_comm_2.t,
284 writer,
285 )
286 }
287
288 pub fn gen_proof(
289 self,
290 challenge: &E::ScalarField,
291 ) -> Result<NonMembershipProof<E>, VBAccumulatorError> {
292 let wits = BTreeMap::from([(0, self.sc_wits_1.0), (1, self.sc_wits_1.1)]);
293 self._gen_proof(wits, challenge)
305 }
306
307 pub fn gen_partial_proof(
308 self,
309 challenge: &E::ScalarField,
310 ) -> Result<NonMembershipProof<E>, VBAccumulatorError> {
311 let wits = BTreeMap::from([(0, self.sc_wits_1.0)]);
312 self._gen_proof(wits, challenge)
324 }
325
326 pub fn compute_challenge_contribution<W: Write>(
327 C_prime: &E::G1Affine,
328 C_bar: &E::G1Affine,
329 J: &E::G1Affine,
330 accumulator_value: &E::G1Affine,
331 params: &SetupParams<E>,
332 Q: &E::G1Affine,
333 t_1: &E::G1Affine,
334 t_2: &E::G1Affine,
335 mut writer: W,
336 ) -> Result<(), VBAccumulatorError> {
337 C_bar.serialize_compressed(&mut writer)?;
338 C_prime.serialize_compressed(&mut writer)?;
339 J.serialize_compressed(&mut writer)?;
340 accumulator_value.serialize_compressed(&mut writer)?;
341 params.P.serialize_compressed(&mut writer)?;
342 Q.serialize_compressed(&mut writer)?;
343 t_1.serialize_compressed(&mut writer)?;
344 t_2.serialize_compressed(&mut writer)?;
345 Ok(())
346 }
347
348 fn _gen_proof(
349 mut self,
350 wits: BTreeMap<usize, E::ScalarField>,
351 challenge: &E::ScalarField,
352 ) -> Result<NonMembershipProof<E>, VBAccumulatorError> {
353 Ok(NonMembershipProof {
354 C_prime: self.C_prime,
355 C_bar: self.C_bar,
356 J: self.J,
357 t_1: self.sc_comm_1.t,
358 sc_resp_1: self.sc_comm_1.partial_response(wits, challenge)?,
359 sc_2: mem::take(&mut self.sc_comm_2).gen_proof(challenge),
360 })
361 }
362}
363
364impl<E: Pairing> NonMembershipProof<E> {
365 pub fn verify(
366 &self,
367 accumulator_value: E::G1Affine,
368 challenge: &E::ScalarField,
369 pk: impl Into<PreparedPublicKey<E>>,
370 params: impl Into<PreparedSetupParams<E>>,
371 Q: impl Into<E::G1Affine>,
372 ) -> Result<(), VBAccumulatorError> {
373 let params = params.into();
374 self.verify_except_pairing(None, accumulator_value, challenge, ¶ms, Q)?;
375 if !E::multi_pairing(
376 [
377 E::G1Prepared::from(self.C_bar),
378 E::G1Prepared::from(-(self.C_prime.into_group())),
379 ],
380 [params.P_tilde, pk.into().0],
381 )
382 .is_zero()
383 {
384 return Err(VBAccumulatorError::IncorrectRandomizedWitness);
385 }
386 Ok(())
387 }
388
389 pub fn verify_with_randomized_pairing_checker(
390 &self,
391 accumulator_value: E::G1Affine,
392 challenge: &E::ScalarField,
393 pk: impl Into<PreparedPublicKey<E>>,
394 params: impl Into<PreparedSetupParams<E>>,
395 Q: impl Into<E::G1Affine>,
396 pairing_checker: &mut RandomizedPairingChecker<E>,
397 ) -> Result<(), VBAccumulatorError> {
398 let params = params.into();
399 self.verify_except_pairing(None, accumulator_value, challenge, ¶ms, Q)?;
400 pairing_checker.add_sources(&self.C_prime, pk.into().0, &self.C_bar, params.P_tilde);
401 Ok(())
402 }
403
404 pub fn verify_partial(
405 &self,
406 resp_for_element: &E::ScalarField,
407 accumulator_value: E::G1Affine,
408 challenge: &E::ScalarField,
409 pk: impl Into<PreparedPublicKey<E>>,
410 params: impl Into<PreparedSetupParams<E>>,
411 Q: impl Into<E::G1Affine>,
412 ) -> Result<(), VBAccumulatorError> {
413 let params = params.into();
414 self.verify_except_pairing(
415 Some(resp_for_element),
416 accumulator_value,
417 challenge,
418 ¶ms,
419 Q,
420 )?;
421 if !E::multi_pairing(
422 [
423 E::G1Prepared::from(self.C_bar),
424 E::G1Prepared::from(-(self.C_prime.into_group())),
425 ],
426 [params.P_tilde, pk.into().0],
427 )
428 .is_zero()
429 {
430 return Err(VBAccumulatorError::IncorrectRandomizedWitness);
431 }
432 Ok(())
433 }
434
435 pub fn verify_partial_with_randomized_pairing_checker(
436 &self,
437 resp_for_element: &E::ScalarField,
438 accumulator_value: E::G1Affine,
439 challenge: &E::ScalarField,
440 pk: impl Into<PreparedPublicKey<E>>,
441 params: impl Into<PreparedSetupParams<E>>,
442 Q: impl Into<E::G1Affine>,
443 pairing_checker: &mut RandomizedPairingChecker<E>,
444 ) -> Result<(), VBAccumulatorError> {
445 let params = params.into();
446 self.verify_except_pairing(
447 Some(resp_for_element),
448 accumulator_value,
449 challenge,
450 ¶ms,
451 Q,
452 )?;
453 pairing_checker.add_sources(&self.C_prime, pk.into().0, &self.C_bar, params.P_tilde);
454 Ok(())
455 }
456
457 pub fn challenge_contribution<W: Write>(
458 &self,
459 accumulator_value: &E::G1Affine,
460 params: &SetupParams<E>,
461 Q: &E::G1Affine,
462 writer: W,
463 ) -> Result<(), VBAccumulatorError> {
464 NonMembershipProofProtocol::<E>::compute_challenge_contribution(
465 &self.C_prime,
466 &self.C_bar,
467 &self.J,
468 accumulator_value,
469 params,
470 Q,
471 &self.t_1,
472 &self.sc_2.t,
473 writer,
474 )
475 }
476
477 pub fn get_schnorr_response_for_element(&self) -> Option<&E::ScalarField> {
478 self.sc_resp_1.get_response(1).ok()
479 }
480
481 fn verify_except_pairing(
482 &self,
483 resp_for_element: Option<&E::ScalarField>,
484 accumulator_value: E::G1Affine,
485 challenge: &E::ScalarField,
486 params: &PreparedSetupParams<E>,
487 Q: impl Into<E::G1Affine>,
488 ) -> Result<(), VBAccumulatorError> {
489 if self.C_prime.is_zero() {
490 return Err(VBAccumulatorError::CannotBeZero);
491 }
492 if self.J.is_zero() {
493 return Err(VBAccumulatorError::CannotBeZero);
494 }
495 if !self.sc_2.verify(&self.J, &Q.into(), challenge) {
496 return Err(VBAccumulatorError::IncorrectRandomizedWitness);
497 }
498
499 let mut missing_responses = BTreeMap::from([(2, self.sc_2.response)]);
501 if !self.sc_resp_1.responses.contains_key(&1) {
502 match resp_for_element {
503 Some(r) => {
504 missing_responses.insert(1, *r);
505 }
506 _ => return Err(VBAccumulatorError::MissingSchnorrResponseForElement),
507 }
508 }
509 self.sc_resp_1.is_valid(
510 &[
511 accumulator_value,
512 self.C_prime.into_group().neg().into(),
513 params.P.into_group().neg().into(),
514 ],
515 &self.C_bar,
516 &self.t_1,
517 challenge,
518 missing_responses,
519 )?;
520
521 Ok(())
522 }
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528 use crate::positive::{tests::setup_positive_accum, Accumulator};
529 use std::time::{Duration, Instant};
530
531 use crate::universal::tests::setup_universal_accum;
532 use ark_bls12_381::{Bls12_381, Fr, G1Affine};
533 use ark_std::{
534 rand::{rngs::StdRng, SeedableRng},
535 UniformRand,
536 };
537 use blake2::Blake2b512;
538 use schnorr_pok::compute_random_oracle_challenge;
539
540 #[test]
541 fn membership_proof_positive_accumulator() {
542 let mut rng = StdRng::seed_from_u64(0u64);
544
545 let (params, keypair, mut accumulator, mut state) = setup_positive_accum(&mut rng);
546 let prepared_params = PreparedSetupParams::from(params.clone());
547 let prepared_pk = PreparedPublicKey::from(keypair.public_key.clone());
548
549 let mut elems = vec![];
550 let mut witnesses = vec![];
551 let count = 10;
552
553 for _ in 0..count {
554 let elem = Fr::rand(&mut rng);
555 accumulator = accumulator
556 .add(elem, &keypair.secret_key, &mut state)
557 .unwrap();
558 elems.push(elem);
559 }
560
561 for i in 0..count {
562 let w = accumulator
563 .get_membership_witness(&elems[i], &keypair.secret_key, &state)
564 .unwrap();
565 assert!(accumulator.verify_membership(&elems[i], &w, &keypair.public_key, ¶ms));
566 witnesses.push(w);
567 }
568
569 let mut proof_create_duration = Duration::default();
570 let mut proof_verif_duration = Duration::default();
571
572 for i in 0..count {
573 let start = Instant::now();
574 let protocol = MembershipProofProtocol::init(
575 &mut rng,
576 elems[i],
577 None,
578 accumulator.value(),
579 &witnesses[i],
580 );
581 let mut chal_bytes_prover = vec![];
582 protocol
583 .challenge_contribution(accumulator.value(), &mut chal_bytes_prover)
584 .unwrap();
585 let challenge_prover =
586 compute_random_oracle_challenge::<Fr, Blake2b512>(&chal_bytes_prover);
587 let proof = protocol.gen_proof(&challenge_prover).unwrap();
588 proof_create_duration += start.elapsed();
589
590 let start = Instant::now();
591 let mut chal_bytes_verifier = vec![];
592 proof
593 .challenge_contribution(accumulator.value(), &mut chal_bytes_verifier)
594 .unwrap();
595 let challenge_verifier =
596 compute_random_oracle_challenge::<Fr, Blake2b512>(&chal_bytes_verifier);
597 proof
598 .verify(
599 accumulator.value(),
600 &challenge_verifier,
601 prepared_pk.clone(),
602 prepared_params.clone(),
603 )
604 .unwrap();
605 proof_verif_duration += start.elapsed();
606 }
607
608 println!(
609 "Time to create {} membership proofs is {:?}",
610 count, proof_create_duration
611 );
612 println!(
613 "Time to verify {} membership proofs is {:?}",
614 count, proof_verif_duration
615 );
616 }
617
618 #[test]
619 fn non_membership_proof_universal_accumulator() {
620 let max = 100;
622 let mut rng = StdRng::seed_from_u64(0u64);
623
624 let (params, keypair, mut accumulator, initial_elems, mut state) =
625 setup_universal_accum(&mut rng, max);
626
627 let prepared_params = PreparedSetupParams::from(params.clone());
628 let prepared_pk = PreparedPublicKey::from(keypair.public_key.clone());
629
630 let Q = G1Affine::rand(&mut rng);
631
632 let mut elems = vec![];
633 let mut witnesses = vec![];
634 let count = 10;
635
636 for _ in 0..50 {
637 accumulator = accumulator
638 .add(
639 Fr::rand(&mut rng),
640 &keypair.secret_key,
641 &initial_elems,
642 &mut state,
643 )
644 .unwrap();
645 }
646
647 for _ in 0..count {
648 let elem = Fr::rand(&mut rng);
649 let w = accumulator
650 .get_non_membership_witness(&elem, &keypair.secret_key, &mut state, ¶ms)
651 .unwrap();
652 assert!(accumulator.verify_non_membership(&elem, &w, &keypair.public_key, ¶ms));
653 elems.push(elem);
654 witnesses.push(w);
655 }
656
657 let mut proof_create_duration = Duration::default();
658 let mut proof_verif_duration = Duration::default();
659
660 for i in 0..count {
661 let start = Instant::now();
662 let protocol = NonMembershipProofProtocol::<Bls12_381>::init(
663 &mut rng,
664 elems[i],
665 None,
666 *accumulator.value(),
667 &witnesses[i],
668 ¶ms,
669 Q.clone(),
670 );
671
672 let mut chal_bytes_prover = vec![];
673 protocol
674 .challenge_contribution(accumulator.value(), ¶ms, &Q, &mut chal_bytes_prover)
675 .unwrap();
676 let challenge_prover =
677 compute_random_oracle_challenge::<Fr, Blake2b512>(&chal_bytes_prover);
678 let proof = protocol.gen_proof(&challenge_prover).unwrap();
679 proof_create_duration += start.elapsed();
680
681 let start = Instant::now();
682 let mut chal_bytes_verifier = vec![];
683 proof
684 .challenge_contribution(accumulator.value(), ¶ms, &Q, &mut chal_bytes_verifier)
685 .unwrap();
686 let challenge_verifier =
687 compute_random_oracle_challenge::<Fr, Blake2b512>(&chal_bytes_verifier);
688 proof
689 .verify(
690 *accumulator.value(),
691 &challenge_verifier,
692 prepared_pk.clone(),
693 prepared_params.clone(),
694 Q.clone(),
695 )
696 .unwrap();
697 proof_verif_duration += start.elapsed();
698 }
699
700 println!(
701 "Time to create {} non-membership proofs is {:?}",
702 count, proof_create_duration
703 );
704 println!(
705 "Time to verify {} non-membership proofs is {:?}",
706 count, proof_verif_duration
707 );
708 }
709}