1use ark_ec::pairing::Pairing;
2use ark_ec::twisted_edwards::{Affine, TECurveConfig};
3use ark_ec::CurveGroup;
4use ark_ff::PrimeField;
5use ark_std::rand::RngCore;
6use w3f_pcs::pcs::kzg::KZG;
7use w3f_pcs::pcs::{RawVerifierKey, PCS};
8use w3f_plonk_common::kzg_acc::KzgAccumulator;
9use w3f_plonk_common::piop::VerifierPiop;
10use w3f_plonk_common::transcript::PlonkTranscript;
11use w3f_plonk_common::verifier::{Challenges, PlonkVerifier};
12
13use crate::piop::params::PiopParams;
14use crate::piop::{FixedColumnsCommitted, PiopVerifier, VerifierKey};
15use crate::{ArkTranscript, RingProof};
16use ark_std::vec::Vec;
17
18pub struct RingVerifier<F, CS, Jubjub, T = ArkTranscript>
19where
20 F: PrimeField,
21 CS: PCS<F>,
22 Jubjub: TECurveConfig<BaseField = F>,
23 T: PlonkTranscript<F, CS>,
24{
25 piop_params: PiopParams<F, Jubjub>,
26 fixed_columns_committed: FixedColumnsCommitted<F, CS::C>,
27 plonk_verifier: PlonkVerifier<F, CS, T>,
28}
29
30impl<F, CS, Jubjub, T> RingVerifier<F, CS, Jubjub, T>
31where
32 F: PrimeField,
33 CS: PCS<F>,
34 Jubjub: TECurveConfig<BaseField = F>,
35 T: PlonkTranscript<F, CS>,
36{
37 pub fn init(
38 verifier_key: VerifierKey<F, CS>,
39 piop_params: PiopParams<F, Jubjub>,
40 empty_transcript: T,
41 ) -> Self {
42 let pcs_vk = verifier_key.pcs_raw_vk.prepare();
43 let plonk_verifier = PlonkVerifier::init(pcs_vk, &verifier_key, empty_transcript);
44 Self {
45 piop_params,
46 fixed_columns_committed: verifier_key.fixed_columns_committed,
47 plonk_verifier,
48 }
49 }
50
51 pub fn verify(&self, proof: RingProof<F, CS>, result: Affine<Jubjub>) -> bool {
52 let (challenges, mut rng) = self.plonk_verifier.restore_challenges(
53 &result,
54 &proof,
55 PiopVerifier::<F, CS::C, Affine<Jubjub>>::N_COLUMNS + 1,
57 PiopVerifier::<F, CS::C, Affine<Jubjub>>::N_CONSTRAINTS,
58 );
59 let seed = self.piop_params.seed;
60 let seed_plus_result = (seed + result).into_affine();
61 let domain_at_zeta = self.piop_params.domain.evaluate(challenges.zeta);
62 let piop = PiopVerifier::<_, _, Affine<Jubjub>>::init(
63 domain_at_zeta,
64 self.fixed_columns_committed.clone(),
65 proof.column_commitments.clone(),
66 proof.columns_at_zeta.clone(),
67 (seed.x, seed.y),
68 (seed_plus_result.x, seed_plus_result.y),
69 );
70
71 self.plonk_verifier
72 .verify(piop, proof, challenges, &mut rng)
73 }
74
75 pub fn piop_params(&self) -> &PiopParams<F, Jubjub> {
76 &self.piop_params
77 }
78
79 pub fn verify_batch(
80 &self,
81 proofs: Vec<RingProof<F, CS>>,
82 results: Vec<Affine<Jubjub>>,
83 ) -> bool {
84 for (proof, result) in proofs.into_iter().zip(results) {
85 let res = self.verify(proof, result);
86 if !res {
87 return false;
88 }
89 }
90 true
91 }
92}
93
94pub struct KzgBatchVerifier<E, J, T = ArkTranscript>
96where
97 E: Pairing,
98 J: TECurveConfig<BaseField = E::ScalarField>,
99 T: PlonkTranscript<E::ScalarField, KZG<E>>,
100{
101 pub acc: KzgAccumulator<E>,
102 pub verifier: RingVerifier<E::ScalarField, KZG<E>, J, T>,
103}
104
105pub struct PreparedBatchItem<E, J>
107where
108 E: Pairing,
109 J: TECurveConfig<BaseField = E::ScalarField>,
110{
111 piop: PiopVerifier<E::ScalarField, <KZG<E> as PCS<E::ScalarField>>::C, Affine<J>>,
112 proof: RingProof<E::ScalarField, KZG<E>>,
113 challenges: Challenges<E::ScalarField>,
114 entropy: [u8; 32],
115}
116
117impl<E, J, T> KzgBatchVerifier<E, J, T>
118where
119 E: Pairing,
120 J: TECurveConfig<BaseField = E::ScalarField>,
121 T: PlonkTranscript<E::ScalarField, KZG<E>>,
122{
123 pub fn prepare(
132 &self,
133 proof: RingProof<E::ScalarField, KZG<E>>,
134 result: Affine<J>,
135 ) -> PreparedBatchItem<E, J> {
136 let (challenges, mut rng) = self.verifier.plonk_verifier.restore_challenges(
137 &result,
138 &proof,
139 PiopVerifier::<E::ScalarField, <KZG<E> as PCS<_>>::C, Affine<J>>::N_COLUMNS + 1,
141 PiopVerifier::<E::ScalarField, <KZG<E> as PCS<_>>::C, Affine<J>>::N_CONSTRAINTS,
142 );
143 let seed = self.verifier.piop_params.seed;
144 let seed_plus_result = (seed + result).into_affine();
145 let domain_at_zeta = self.verifier.piop_params.domain.evaluate(challenges.zeta);
146 let piop = PiopVerifier::<_, _, Affine<J>>::init(
147 domain_at_zeta,
148 self.verifier.fixed_columns_committed.clone(),
149 proof.column_commitments.clone(),
150 proof.columns_at_zeta.clone(),
151 (seed.x, seed.y),
152 (seed_plus_result.x, seed_plus_result.y),
153 );
154
155 let mut entropy = [0_u8; 32];
157 rng.fill_bytes(&mut entropy);
158
159 PreparedBatchItem {
160 piop,
161 proof,
162 challenges,
163 entropy,
164 }
165 }
166
167 pub fn push_prepared(&mut self, item: PreparedBatchItem<E, J>) {
175 let mut ts = self.verifier.plonk_verifier.transcript_prelude.clone();
176 ts._add_serializable(b"batch-entropy", &item.entropy);
177 self.acc
178 .accumulate(item.piop, item.proof, item.challenges, &mut ts.to_rng());
179 }
180
181 pub fn push(&mut self, proof: RingProof<E::ScalarField, KZG<E>>, result: Affine<J>) {
186 let item = self.prepare(proof, result);
187 self.push_prepared(item);
188 }
189
190 pub fn verify(&self) -> bool {
192 self.acc.verify()
193 }
194}
195
196impl<E, J, T> RingVerifier<E::ScalarField, KZG<E>, J, T>
197where
198 E: Pairing,
199 J: TECurveConfig<BaseField = E::ScalarField>,
200 T: PlonkTranscript<E::ScalarField, KZG<E>>,
201{
202 pub fn kzg_batch_verifier(self) -> KzgBatchVerifier<E, J, T> {
204 KzgBatchVerifier {
205 acc: KzgAccumulator::<E>::new(self.plonk_verifier.pcs_vk.clone()),
206 verifier: self,
207 }
208 }
209
210 pub fn verify_batch_kzg(
212 self,
213 proofs: Vec<RingProof<E::ScalarField, KZG<E>>>,
214 results: Vec<Affine<J>>,
215 ) -> bool {
216 let mut batch = self.kzg_batch_verifier();
217 for (proof, result) in proofs.into_iter().zip(results) {
218 batch.push(proof, result);
219 }
220 batch.verify()
221 }
222}