1use crate::error::DoryError;
29use crate::messages::VMVMessage;
30use crate::mode::Mode;
31use crate::primitives::arithmetic::{DoryRoutines, Field, Group, PairingCurve};
32use crate::primitives::poly::MultilinearLagrange;
33use crate::primitives::transcript::Transcript;
34use crate::proof::DoryProof;
35use crate::reduce_and_fold::{DoryProverState, DoryVerifierState};
36use crate::setup::{ProverSetup, VerifierSetup};
37
38#[allow(clippy::type_complexity)]
76#[allow(clippy::too_many_arguments)]
77#[tracing::instrument(skip_all, name = "create_evaluation_proof")]
78pub fn create_evaluation_proof<F, E, M1, M2, T, P, Mo>(
79 polynomial: &P,
80 point: &[F],
81 row_commitments: Option<Vec<E::G1>>,
82 commit_blind: F,
83 nu: usize,
84 sigma: usize,
85 setup: &ProverSetup<E>,
86 transcript: &mut T,
87) -> Result<(DoryProof<E::G1, E::G2, E::GT>, Option<F>), DoryError>
88where
89 F: Field,
90 E: PairingCurve,
91 E::G1: Group<Scalar = F>,
92 E::G2: Group<Scalar = F>,
93 E::GT: Group<Scalar = F>,
94 M1: DoryRoutines<E::G1>,
95 M2: DoryRoutines<E::G2>,
96 T: Transcript<Curve = E>,
97 P: MultilinearLagrange<F>,
98 Mo: Mode,
99{
100 if point.len() != nu + sigma {
101 return Err(DoryError::InvalidPointDimension {
102 expected: nu + sigma,
103 actual: point.len(),
104 });
105 }
106
107 if nu > sigma {
109 return Err(DoryError::InvalidSize {
110 expected: sigma,
111 actual: nu,
112 });
113 }
114
115 let (row_commitments, commit_blind) = match row_commitments {
116 Some(rc) => (rc, commit_blind),
117 None => {
118 let (_, rc, blind) = polynomial.commit::<E, Mo, M1>(nu, sigma, setup)?;
119 (rc, blind)
120 }
121 };
122
123 let (left_vec, right_vec) = polynomial.compute_evaluation_vectors(point, nu, sigma);
124 let v_vec = polynomial.vector_matrix_product(&left_vec, nu, sigma);
125
126 let mut padded_row_commitments = row_commitments.clone();
127 if nu < sigma {
128 padded_row_commitments.resize(1 << sigma, E::G1::identity());
129 }
130
131 let (r_c, r_d2, r_e1, r_e2): (F, F, F, F) =
133 (Mo::sample(), Mo::sample(), Mo::sample(), Mo::sample());
134
135 let g2_fin = &setup.g2_vec[0];
136
137 let t_vec_v = M1::msm(&padded_row_commitments, &v_vec);
139 let c = Mo::mask(E::pair(&t_vec_v, g2_fin), &setup.ht, &r_c);
140
141 let d2 = Mo::mask(
143 E::pair(&M1::msm(&setup.g1_vec[..1 << sigma], &v_vec), g2_fin),
144 &setup.ht,
145 &r_d2,
146 );
147
148 let e1 = Mo::mask(M1::msm(&row_commitments, &left_vec), &setup.h1, &r_e1);
150
151 let vmv_message = VMVMessage { c, d2, e1 };
152
153 transcript.append_serde(b"vmv_c", &vmv_message.c);
154 transcript.append_serde(b"vmv_d2", &vmv_message.d2);
155 transcript.append_serde(b"vmv_e1", &vmv_message.e1);
156
157 #[cfg(feature = "zk")]
158 let (zk_e2, zk_y_com, zk_sigma1, zk_sigma2, zk_r_y) = if Mo::BLINDING {
159 use crate::reduce_and_fold::{generate_sigma1_proof, generate_sigma2_proof};
160 let y = polynomial.evaluate(point);
161 let r_y: F = Mo::sample();
162 let e2 = Mo::mask(g2_fin.scale(&y), &setup.h2, &r_e2);
163 let y_com = setup.g1_vec[0].scale(&y) + setup.h1.scale(&r_y);
164 transcript.append_serde(b"vmv_e2", &e2);
165 transcript.append_serde(b"vmv_y_com", &y_com);
166 let s1 = generate_sigma1_proof::<E, T>(&y, &r_e2, &r_y, setup, transcript);
167 let s2 = generate_sigma2_proof::<E, T>(&r_e1, &-r_d2, setup, transcript);
168 (Some(e2), Some(y_com), Some(s1), Some(s2), Some(r_y))
169 } else {
170 (None, None, None, None, None)
171 };
172
173 let v2 = M2::fixed_base_vector_scalar_mul(g2_fin, &v_vec);
175
176 let mut padded_right_vec = right_vec.clone();
177 let mut padded_left_vec = left_vec.clone();
178 if nu < sigma {
179 padded_right_vec.resize(1 << sigma, F::zero());
180 padded_left_vec.resize(1 << sigma, F::zero());
181 }
182
183 let mut prover_state: DoryProverState<'_, E, Mo> = DoryProverState::new(
184 padded_row_commitments, v2, Some(v_vec), padded_right_vec, padded_left_vec, setup,
190 );
191 prover_state.set_initial_blinds(commit_blind, r_c, r_d2, r_e1, r_e2);
192
193 let num_rounds = nu.max(sigma);
194 let mut first_messages = Vec::with_capacity(num_rounds);
195 let mut second_messages = Vec::with_capacity(num_rounds);
196
197 for _round in 0..num_rounds {
198 let first_msg = prover_state.compute_first_message::<M1, M2>();
199
200 transcript.append_serde(b"d1_left", &first_msg.d1_left);
201 transcript.append_serde(b"d1_right", &first_msg.d1_right);
202 transcript.append_serde(b"d2_left", &first_msg.d2_left);
203 transcript.append_serde(b"d2_right", &first_msg.d2_right);
204 transcript.append_serde(b"e1_beta", &first_msg.e1_beta);
205 transcript.append_serde(b"e2_beta", &first_msg.e2_beta);
206
207 let beta = transcript.challenge_scalar(b"beta");
208 prover_state.apply_first_challenge::<M1, M2>(&beta);
209 first_messages.push(first_msg);
210
211 let second_msg = prover_state.compute_second_message::<M1, M2>();
212
213 transcript.append_serde(b"c_plus", &second_msg.c_plus);
214 transcript.append_serde(b"c_minus", &second_msg.c_minus);
215 transcript.append_serde(b"e1_plus", &second_msg.e1_plus);
216 transcript.append_serde(b"e1_minus", &second_msg.e1_minus);
217 transcript.append_serde(b"e2_plus", &second_msg.e2_plus);
218 transcript.append_serde(b"e2_minus", &second_msg.e2_minus);
219
220 let alpha = transcript.challenge_scalar(b"alpha");
221 prover_state.apply_second_challenge::<M1, M2>(&alpha);
222 second_messages.push(second_msg);
223 }
224
225 let gamma = transcript.challenge_scalar(b"gamma");
226
227 #[cfg(feature = "zk")]
228 let scalar_product_proof = if Mo::BLINDING {
229 Some(prover_state.scalar_product_proof(transcript))
230 } else {
231 None
232 };
233
234 let final_message = prover_state.compute_final_message::<M1, M2>(&gamma);
235
236 transcript.append_serde(b"final_e1", &final_message.e1);
237 transcript.append_serde(b"final_e2", &final_message.e2);
238 let _d = transcript.challenge_scalar(b"d");
239
240 let proof = DoryProof {
241 vmv_message,
242 first_messages,
243 second_messages,
244 final_message,
245 nu,
246 sigma,
247 #[cfg(feature = "zk")]
248 e2: zk_e2,
249 #[cfg(feature = "zk")]
250 y_com: zk_y_com,
251 #[cfg(feature = "zk")]
252 sigma1_proof: zk_sigma1,
253 #[cfg(feature = "zk")]
254 sigma2_proof: zk_sigma2,
255 #[cfg(feature = "zk")]
256 scalar_product_proof,
257 };
258 #[cfg(feature = "zk")]
259 return Ok((proof, zk_r_y));
260 #[cfg(not(feature = "zk"))]
261 Ok((proof, None))
262}
263
264#[tracing::instrument(skip_all, name = "verify_evaluation_proof")]
297pub fn verify_evaluation_proof<F, E, M1, M2, T>(
298 commitment: E::GT,
299 evaluation: F,
300 point: &[F],
301 proof: &DoryProof<E::G1, E::G2, E::GT>,
302 setup: VerifierSetup<E>,
303 transcript: &mut T,
304) -> Result<(), DoryError>
305where
306 F: Field,
307 E: PairingCurve,
308 E::G1: Group<Scalar = F>,
309 E::G2: Group<Scalar = F>,
310 E::GT: Group<Scalar = F>,
311 M1: DoryRoutines<E::G1>,
312 M2: DoryRoutines<E::G2>,
313 T: Transcript<Curve = E>,
314{
315 let nu = proof.nu;
316 let sigma = proof.sigma;
317
318 if point.len() != nu + sigma {
319 return Err(DoryError::InvalidPointDimension {
320 expected: nu + sigma,
321 actual: point.len(),
322 });
323 }
324
325 let vmv_message = &proof.vmv_message;
326 transcript.append_serde(b"vmv_c", &vmv_message.c);
327 transcript.append_serde(b"vmv_d2", &vmv_message.d2);
328 transcript.append_serde(b"vmv_e1", &vmv_message.e1);
329
330 #[cfg(feature = "zk")]
331 let (e2, is_zk) = match (&proof.e2, &proof.y_com) {
332 (Some(pe2), Some(yc)) => {
333 use crate::reduce_and_fold::{verify_sigma1_proof, verify_sigma2_proof};
334 transcript.append_serde(b"vmv_e2", pe2);
335 transcript.append_serde(b"vmv_y_com", yc);
336 match (&proof.sigma1_proof, &proof.sigma2_proof) {
337 (Some(s1), Some(s2)) => {
338 verify_sigma1_proof::<E, T>(pe2, yc, s1, &setup, transcript)?;
339 verify_sigma2_proof::<E, T>(
340 &vmv_message.e1,
341 &vmv_message.d2,
342 s2,
343 &setup,
344 transcript,
345 )?;
346 }
347 _ => return Err(DoryError::InvalidProof),
348 }
349 (*pe2, true)
350 }
351 (None, None) => (setup.g2_0.scale(&evaluation), false),
352 _ => return Err(DoryError::InvalidProof),
353 };
354 #[cfg(not(feature = "zk"))]
355 let (e2, _is_zk) = (setup.g2_0.scale(&evaluation), false);
356
357 let num_rounds = sigma;
360
361 let max_rounds = setup.max_log_n / 2;
363 if num_rounds > max_rounds
364 || proof.first_messages.len() != num_rounds
365 || proof.second_messages.len() != num_rounds
366 {
367 return Err(DoryError::InvalidProof);
368 }
369
370 let s1_coords: Vec<F> = point[..sigma].to_vec();
375 let mut s2_coords: Vec<F> = vec![F::zero(); sigma];
379 s2_coords[..nu].copy_from_slice(&point[sigma..sigma + nu]);
380
381 let mut verifier_state = DoryVerifierState::new(
382 vmv_message.c, commitment, vmv_message.d2, vmv_message.e1, e2, s1_coords, s2_coords, num_rounds,
390 setup.clone(),
391 );
392
393 for round in 0..num_rounds {
394 let first_msg = &proof.first_messages[round];
395 let second_msg = &proof.second_messages[round];
396
397 transcript.append_serde(b"d1_left", &first_msg.d1_left);
398 transcript.append_serde(b"d1_right", &first_msg.d1_right);
399 transcript.append_serde(b"d2_left", &first_msg.d2_left);
400 transcript.append_serde(b"d2_right", &first_msg.d2_right);
401 transcript.append_serde(b"e1_beta", &first_msg.e1_beta);
402 transcript.append_serde(b"e2_beta", &first_msg.e2_beta);
403 let beta = transcript.challenge_scalar(b"beta");
404
405 transcript.append_serde(b"c_plus", &second_msg.c_plus);
406 transcript.append_serde(b"c_minus", &second_msg.c_minus);
407 transcript.append_serde(b"e1_plus", &second_msg.e1_plus);
408 transcript.append_serde(b"e1_minus", &second_msg.e1_minus);
409 transcript.append_serde(b"e2_plus", &second_msg.e2_plus);
410 transcript.append_serde(b"e2_minus", &second_msg.e2_minus);
411 let alpha = transcript.challenge_scalar(b"alpha");
412
413 verifier_state.process_round(first_msg, second_msg, &alpha, &beta)?;
414 }
415
416 let gamma = transcript.challenge_scalar(b"gamma");
417
418 #[cfg(feature = "zk")]
420 let zk_data = if is_zk {
421 if let Some(ref sp) = proof.scalar_product_proof {
422 for (l, v) in [
423 (b"sigma_p1" as &[u8], &sp.p1),
424 (b"sigma_p2", &sp.p2),
425 (b"sigma_q", &sp.q),
426 (b"sigma_r", &sp.r),
427 ] {
428 transcript.append_serde(l, v);
429 }
430 let c = transcript.challenge_scalar(b"sigma_c");
431 Some((sp, c))
432 } else {
433 return Err(DoryError::InvalidProof);
434 }
435 } else {
436 None
437 };
438
439 transcript.append_serde(b"final_e1", &proof.final_message.e1);
441 transcript.append_serde(b"final_e2", &proof.final_message.e2);
442 let d = transcript.challenge_scalar(b"d");
443
444 #[cfg(feature = "zk")]
445 let zk = zk_data.as_ref().map(|(sp, c)| (*sp, c));
446 #[cfg(not(feature = "zk"))]
447 let zk: Option<(&crate::messages::ScalarProductProof<_, _, _, _>, _)> = None;
448
449 verifier_state.verify_final(&proof.final_message, &gamma, &d, zk)
450}