1use crate::error::DoryError;
30use crate::messages::VMVMessage;
31use crate::mode::Mode;
32use crate::primitives::arithmetic::{DoryRoutines, Field, Group, PairingCurve};
33use crate::primitives::poly::MultilinearLagrange;
34use crate::primitives::transcript::Transcript;
35use crate::proof::DoryProof;
36use crate::proof::ProofMode;
37use crate::reduce_and_fold::{DoryProverState, DoryVerifierState, FinalCheck};
38use crate::setup::{ProverSetup, VerifierSetup};
39
40#[allow(clippy::type_complexity)]
81#[allow(clippy::too_many_arguments)]
82#[tracing::instrument(skip_all, name = "create_evaluation_proof")]
83pub fn create_evaluation_proof<F, E, M1, M2, T, P, Mo>(
84 polynomial: &P,
85 point: &[F],
86 row_commitments: Option<Vec<E::G1>>,
87 commit_blind: F,
88 nu: usize,
89 sigma: usize,
90 setup: &ProverSetup<E>,
91 transcript: &mut T,
92) -> Result<(DoryProof<E::G1, E::G2, E::GT>, Option<F>), DoryError>
93where
94 F: Field,
95 E: PairingCurve,
96 E::G1: Group<Scalar = F>,
97 E::G2: Group<Scalar = F>,
98 E::GT: Group<Scalar = F>,
99 M1: DoryRoutines<E::G1>,
100 M2: DoryRoutines<E::G2>,
101 T: Transcript<Curve = E>,
102 P: MultilinearLagrange<F>,
103 Mo: Mode,
104{
105 if point.len() != nu + sigma {
106 return Err(DoryError::InvalidPointDimension {
107 expected: nu + sigma,
108 actual: point.len(),
109 });
110 }
111
112 if nu > sigma {
114 return Err(DoryError::InvalidSize {
115 expected: sigma,
116 actual: nu,
117 });
118 }
119
120 let (row_commitments, commit_blind) = match row_commitments {
121 Some(rc) => (rc, commit_blind),
122 None => {
123 let (_, rc, blind) = polynomial.commit::<E, Mo, M1>(nu, sigma, setup)?;
124 (rc, blind)
125 }
126 };
127
128 let (left_vec, right_vec) = polynomial.compute_evaluation_vectors(point, nu, sigma);
129 let v_vec = polynomial.vector_matrix_product(&left_vec, nu, sigma);
130
131 let mut padded_row_commitments = row_commitments.clone();
132 if nu < sigma {
133 padded_row_commitments.resize(1 << sigma, E::G1::identity());
134 }
135
136 let (r_c, r_d2, r_e1, r_e2): (F, F, F, F) =
138 (Mo::sample(), Mo::sample(), Mo::sample(), Mo::sample());
139
140 let g2_fin = &setup.g2_vec[0];
141
142 let t_vec_v = M1::msm(&padded_row_commitments, &v_vec);
144 let c = Mo::mask(E::pair(&t_vec_v, g2_fin), &setup.ht, &r_c);
145
146 let d2 = Mo::mask(
148 E::pair(&M1::msm(&setup.g1_vec[..1 << sigma], &v_vec), g2_fin),
149 &setup.ht,
150 &r_d2,
151 );
152
153 let e1 = Mo::mask(M1::msm(&row_commitments, &left_vec), &setup.h1, &r_e1);
155
156 let vmv_message = VMVMessage { c, d2, e1 };
157
158 transcript.append_serde(b"vmv_c", &vmv_message.c);
159 transcript.append_serde(b"vmv_d2", &vmv_message.d2);
160 transcript.append_serde(b"vmv_e1", &vmv_message.e1);
161
162 #[cfg(feature = "zk")]
163 let (zk_e2, zk_y_com, zk_sigma1, zk_sigma2, zk_r_y) = if Mo::BLINDING {
164 use crate::reduce_and_fold::{generate_sigma1_proof, generate_sigma2_proof};
165 let y = polynomial.evaluate(point);
166 let r_y: F = Mo::sample();
167 let e2 = Mo::mask(g2_fin.scale(&y), &setup.h2, &r_e2);
168 let y_com = setup.g1_vec[0].scale(&y) + setup.h1.scale(&r_y);
169 transcript.append_serde(b"vmv_e2", &e2);
170 transcript.append_serde(b"vmv_y_com", &y_com);
171 let s1 = generate_sigma1_proof::<E, T>(&y, &r_e2, &r_y, setup, transcript);
172 let s2 = generate_sigma2_proof::<E, T>(&r_e1, &-r_d2, setup, transcript);
173 (Some(e2), Some(y_com), Some(s1), Some(s2), Some(r_y))
174 } else {
175 (None, None, None, None, None)
176 };
177
178 let v2 = M2::fixed_base_vector_scalar_mul(g2_fin, &v_vec);
180
181 let mut padded_right_vec = right_vec.clone();
182 let mut padded_left_vec = left_vec.clone();
183 if nu < sigma {
184 padded_right_vec.resize(1 << sigma, F::zero());
185 padded_left_vec.resize(1 << sigma, F::zero());
186 }
187
188 let mut prover_state: DoryProverState<'_, E, Mo> = DoryProverState::new(
189 padded_row_commitments, v2, Some(v_vec), padded_right_vec, padded_left_vec, setup,
195 );
196 prover_state.set_initial_blinds(commit_blind, r_c, r_d2, r_e1, r_e2);
197
198 let num_rounds = nu.max(sigma);
199 let mut first_messages = Vec::with_capacity(num_rounds);
200 let mut second_messages = Vec::with_capacity(num_rounds);
201
202 for _round in 0..num_rounds {
203 let first_msg = prover_state.compute_first_message::<M1, M2>();
204
205 transcript.append_serde(b"d1_left", &first_msg.d1_left);
206 transcript.append_serde(b"d1_right", &first_msg.d1_right);
207 transcript.append_serde(b"d2_left", &first_msg.d2_left);
208 transcript.append_serde(b"d2_right", &first_msg.d2_right);
209 transcript.append_serde(b"e1_beta", &first_msg.e1_beta);
210 transcript.append_serde(b"e2_beta", &first_msg.e2_beta);
211
212 let beta = transcript.challenge_scalar(b"beta");
213 prover_state.apply_first_challenge::<M1, M2>(&beta);
214 first_messages.push(first_msg);
215
216 let second_msg = prover_state.compute_second_message::<M1, M2>();
217
218 transcript.append_serde(b"c_plus", &second_msg.c_plus);
219 transcript.append_serde(b"c_minus", &second_msg.c_minus);
220 transcript.append_serde(b"e1_plus", &second_msg.e1_plus);
221 transcript.append_serde(b"e1_minus", &second_msg.e1_minus);
222 transcript.append_serde(b"e2_plus", &second_msg.e2_plus);
223 transcript.append_serde(b"e2_minus", &second_msg.e2_minus);
224
225 let alpha = transcript.challenge_scalar(b"alpha");
226 prover_state.apply_second_challenge::<M1, M2>(&alpha);
227 second_messages.push(second_msg);
228 }
229
230 let gamma = transcript.challenge_scalar(b"gamma");
231
232 prover_state.apply_fold_scalars(&gamma);
235
236 #[cfg(feature = "zk")]
237 let scalar_product_proof = if Mo::BLINDING {
238 Some(prover_state.scalar_product_proof(transcript))
239 } else {
240 None
241 };
242
243 let final_message = if Mo::BLINDING {
246 None
247 } else {
248 let msg = prover_state.compute_final_message();
249 transcript.append_serde(b"final_e1", &msg.e1);
250 transcript.append_serde(b"final_e2", &msg.e2);
251 Some(msg)
252 };
253
254 let _d = transcript.challenge_scalar(b"d");
255
256 let proof = DoryProof {
257 vmv_message,
258 first_messages,
259 second_messages,
260 final_message,
261 nu,
262 sigma,
263 #[cfg(feature = "zk")]
264 e2: zk_e2,
265 #[cfg(feature = "zk")]
266 y_com: zk_y_com,
267 #[cfg(feature = "zk")]
268 sigma1_proof: zk_sigma1,
269 #[cfg(feature = "zk")]
270 sigma2_proof: zk_sigma2,
271 #[cfg(feature = "zk")]
272 scalar_product_proof,
273 };
274 assert!(
275 proof.mode().is_ok(),
276 "prover constructed a malformed proof shape"
277 );
278 #[cfg(feature = "zk")]
279 return Ok((proof, zk_r_y));
280 #[cfg(not(feature = "zk"))]
281 Ok((proof, None))
282}
283
284#[tracing::instrument(skip_all, name = "verify_evaluation_proof")]
320pub fn verify_evaluation_proof<F, E, M1, M2, T>(
321 commitment: E::GT,
322 evaluation: F,
323 point: &[F],
324 proof: &DoryProof<E::G1, E::G2, E::GT>,
325 setup: VerifierSetup<E>,
326 transcript: &mut T,
327) -> Result<(), DoryError>
328where
329 F: Field,
330 E: PairingCurve,
331 E::G1: Group<Scalar = F>,
332 E::G2: Group<Scalar = F>,
333 E::GT: Group<Scalar = F>,
334 M1: DoryRoutines<E::G1>,
335 M2: DoryRoutines<E::G2>,
336 T: Transcript<Curve = E>,
337{
338 let nu = proof.nu;
339 let sigma = proof.sigma;
340
341 if point.len() != nu + sigma {
342 return Err(DoryError::InvalidPointDimension {
343 expected: nu + sigma,
344 actual: point.len(),
345 });
346 }
347
348 if nu > sigma {
349 return Err(DoryError::InvalidSize {
350 expected: sigma,
351 actual: nu,
352 });
353 }
354
355 let mode = proof.mode()?;
359
360 let vmv_message = &proof.vmv_message;
361 transcript.append_serde(b"vmv_c", &vmv_message.c);
362 transcript.append_serde(b"vmv_d2", &vmv_message.d2);
363 transcript.append_serde(b"vmv_e1", &vmv_message.e1);
364
365 #[cfg(feature = "zk")]
369 let (e2, zk_final) = match mode {
370 ProofMode::Zk {
371 e2,
372 y_com,
373 sigma1,
374 sigma2,
375 scalar_product,
376 } => {
377 use crate::reduce_and_fold::{absorb_sigma2_proof, verify_sigma1_proof};
378 transcript.append_serde(b"vmv_e2", e2);
379 transcript.append_serde(b"vmv_y_com", y_com);
380 verify_sigma1_proof::<E, T>(e2, y_com, sigma1, &setup, transcript)?;
381 let sigma2_c = absorb_sigma2_proof::<E, T>(sigma2, transcript);
382 (*e2, Some((scalar_product, sigma2, sigma2_c)))
383 }
384 ProofMode::Transparent(..) => (setup.g2_0.scale(&evaluation), None),
385 };
386 #[cfg(not(feature = "zk"))]
387 let e2 = setup.g2_0.scale(&evaluation);
388
389 let num_rounds = sigma;
392
393 let max_rounds = setup.max_log_n / 2;
395 if num_rounds > max_rounds
396 || proof.first_messages.len() != num_rounds
397 || proof.second_messages.len() != num_rounds
398 {
399 return Err(DoryError::InvalidProof);
400 }
401
402 let s1_coords: Vec<F> = point[..sigma].to_vec();
407 let mut s2_coords: Vec<F> = vec![F::zero(); sigma];
411 s2_coords[..nu].copy_from_slice(&point[sigma..sigma + nu]);
412
413 let mut verifier_state = DoryVerifierState::new(
414 vmv_message.c, commitment, vmv_message.d2, vmv_message.e1, e2, s1_coords, s2_coords, num_rounds,
422 setup.clone(),
423 );
424
425 for round in 0..num_rounds {
426 let first_msg = &proof.first_messages[round];
427 let second_msg = &proof.second_messages[round];
428
429 transcript.append_serde(b"d1_left", &first_msg.d1_left);
430 transcript.append_serde(b"d1_right", &first_msg.d1_right);
431 transcript.append_serde(b"d2_left", &first_msg.d2_left);
432 transcript.append_serde(b"d2_right", &first_msg.d2_right);
433 transcript.append_serde(b"e1_beta", &first_msg.e1_beta);
434 transcript.append_serde(b"e2_beta", &first_msg.e2_beta);
435 let beta = transcript.challenge_scalar(b"beta");
436
437 transcript.append_serde(b"c_plus", &second_msg.c_plus);
438 transcript.append_serde(b"c_minus", &second_msg.c_minus);
439 transcript.append_serde(b"e1_plus", &second_msg.e1_plus);
440 transcript.append_serde(b"e1_minus", &second_msg.e1_minus);
441 transcript.append_serde(b"e2_plus", &second_msg.e2_plus);
442 transcript.append_serde(b"e2_minus", &second_msg.e2_minus);
443 let alpha = transcript.challenge_scalar(b"alpha");
444
445 verifier_state.process_round(first_msg, second_msg, &alpha, &beta)?;
446 }
447
448 let gamma = transcript.challenge_scalar(b"gamma");
449
450 #[cfg(feature = "zk")]
453 if let Some((sp, sigma2, sigma2_c)) = zk_final {
454 use crate::reduce_and_fold::absorb_scalar_product_proof;
455 let sigma_c = absorb_scalar_product_proof::<E, T>(sp, transcript);
456 let d = transcript.challenge_scalar(b"d");
457 return verifier_state.verify_final(
458 FinalCheck::Zk {
459 scalar_product: sp,
460 sigma_c,
461 sigma2,
462 sigma2_c,
463 },
464 &gamma,
465 &d,
466 );
467 }
468
469 let msg = match mode {
471 ProofMode::Transparent(msg, _) => msg,
472 #[cfg(feature = "zk")]
473 ProofMode::Zk { .. } => return Err(DoryError::InvalidProof),
474 };
475 transcript.append_serde(b"final_e1", &msg.e1);
476 transcript.append_serde(b"final_e2", &msg.e2);
477 let d = transcript.challenge_scalar(b"d");
478
479 verifier_state.verify_final(FinalCheck::Transparent(msg), &gamma, &d)
480}