vb_accumulator/
proofs_cdh.rs

1//! Alternate implementation of zero knowledge proof protocols for membership and non-membership witnesses. The protocol for proving
2//! membership is the protocol for proof of knowledge of weak-BB signature proposed by Camenisch et. al where the prover does not do pairings.
3//! The protocol for proving non-membership is an extension of this protocol as:
4//! Non membership witness is `(C, d)`, accumulator value is `V`, non-member is `y`, secret key is `alpha` and public generators `P`
5//! and `P_tilde` satisfying the relation `C*(y + alpha) + P*d = V`.Both prover and verifier have access to a public generator `Q` such that
6//! discrete log of `Q` wrt `P` is not known.
7//! 1. Prover picks a random `r` from Z_p.
8//! 2. Prover randomizes the witness as `(C' = C * r, d' = d * r)`
9//! 3. Prover creates `C_bar = V * r - C * y * r - P * d * r = V * r - C' * y - P * d'` and `J = Q * d * r = Q * d'` and
10//! sends both to the verifier
11//! 4. Prover creates proof for knowledge of `r`, `y`, `d'` in the relations `C_bar = V * r - C' * y - P * d'` and `J = Q * d'`.
12//! 5. Verifier checks proofs from point 4 and that `C'` and `J` are not 0 (ensuring D is not 0).
13//! 6. Verifier checks `e(C_bar, P_tilde) = e(C', pk)`
14
15use 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/// A wrapper over the protocol for proof of knowledge of weak-BB signature. The accumulator witness is the weak-BB signature and the
41/// accumulator value becomes g1 in that protocol
42#[derive(Default, Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
43pub struct MembershipProofProtocol<E: Pairing>(pub PoKOfSignatureG1Protocol<E>);
44
45/// A wrapper over the proof of knowledge of weak-BB signature
46#[derive(
47    Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
48)]
49#[serde(bound = "")]
50pub struct MembershipProof<E: Pairing>(pub PoKOfSignatureG1<E>);
51
52/// An extension over the protocol for proof of knowledge of weak-BB signature.
53#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
54pub struct NonMembershipProofProtocol<E: Pairing> {
55    /// The randomized witness `C'`
56    #[zeroize(skip)]
57    pub C_prime: E::G1Affine,
58    /// `V * r - C' * y - P * d'`
59    #[zeroize(skip)]
60    pub C_bar: E::G1Affine,
61    /// The commitment to the randomized witness `Q * d'`
62    #[zeroize(skip)]
63    pub J: E::G1Affine,
64    /// For relation `C_bar = V * r - C' * y - P * d'`
65    pub sc_comm_1: SchnorrCommitment<E::G1Affine>,
66    /// (r, y, d')
67    sc_wits_1: (E::ScalarField, E::ScalarField, E::ScalarField),
68    /// For relation `J = Q * d'`
69    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    /// The randomized witness `C'`
78    #[serde_as(as = "ArkObjectBytes")]
79    pub C_prime: E::G1Affine,
80    /// `V * r - C' * y - P * d'`
81    #[serde_as(as = "ArkObjectBytes")]
82    pub C_bar: E::G1Affine,
83    /// The commitment to the randomized witness `Q * d'`
84    #[serde_as(as = "ArkObjectBytes")]
85    pub J: E::G1Affine,
86    /// For relation `C_bar = V * r - C' * y - P * d'`
87    #[serde_as(as = "ArkObjectBytes")]
88    pub t_1: E::G1Affine,
89    pub sc_resp_1: PartialSchnorrResponse<E::G1Affine>,
90    /// For relation `J = Q * d'`
91    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        // C_bar = accumulator_value * r - C' * element - g1 * d * r
242        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        // J = Q * d * r
246        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        // Ok(NonMembershipProof {
294        //     C_prime: self.C_prime,
295        //     C_bar: self.C_bar,
296        //     J: self.J,
297        //     t_1: self.sc_comm_1.t,
298        //     sc_resp_1: self.sc_comm_1.partial_response(
299        //         wits,
300        //         challenge,
301        //     )?,
302        //     sc_2: mem::take(&mut self.sc_comm_2).gen_proof(challenge),
303        // })
304        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        // Ok(NonMembershipProof {
313        //     C_prime: self.C_prime,
314        //     C_bar: self.C_bar,
315        //     J: self.J,
316        //     t_1: self.sc_comm_1.t,
317        //     sc_resp_1: self.sc_comm_1.partial_response(
318        //         wits,
319        //         challenge,
320        //     )?,
321        //     sc_2: mem::take(&mut self.sc_comm_2).gen_proof(challenge),
322        // })
323        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, &params, 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, &params, 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            &params,
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            &params,
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        // d'(=d*r) is same in both relations
500        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        // Proof of knowledge of membership witness
543        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, &params));
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        // Proof of knowledge of non-membership witness
621        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, &params)
651                .unwrap();
652            assert!(accumulator.verify_non_membership(&elem, &w, &keypair.public_key, &params));
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                &params,
669                Q.clone(),
670            );
671
672            let mut chal_bytes_prover = vec![];
673            protocol
674                .challenge_contribution(accumulator.value(), &params, &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(), &params, &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}