1#![allow(non_snake_case)]
2
3use crate::ahp::indexer::*;
4use crate::ahp::verifier::*;
5use crate::ahp::*;
6
7use crate::ahp::constraint_systems::{
8 make_matrices_square_for_prover, pad_input_for_indexer_and_prover, unformat_public_input,
9};
10use crate::{ToString, Vec};
11use ark_ff::{Field, PrimeField, Zero};
12use ark_poly::{
13 univariate::DensePolynomial, EvaluationDomain, Evaluations as EvaluationsOnDomain,
14 GeneralEvaluationDomain, Polynomial, UVPolynomial,
15};
16use ark_relations::r1cs::{
17 ConstraintSynthesizer, ConstraintSystem, OptimizationGoal, SynthesisError,
18};
19use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError};
20use ark_std::rand::RngCore;
21use ark_std::{
22 cfg_into_iter, cfg_iter, cfg_iter_mut,
23 io::{Read, Write},
24};
25
26pub struct ProverState<'a, F: PrimeField> {
28 formatted_input_assignment: Vec<F>,
29 witness_assignment: Vec<F>,
30 z_a: Option<Vec<F>>,
32 z_b: Option<Vec<F>>,
34 zk_bound: usize,
36
37 w_poly: Option<LabeledPolynomial<F>>,
38 mz_polys: Option<(LabeledPolynomial<F>, LabeledPolynomial<F>)>,
39
40 index: &'a Index<F>,
41
42 verifier_first_msg: Option<VerifierFirstMsg<F>>,
44
45 mask_poly: Option<LabeledPolynomial<F>>,
47
48 domain_x: GeneralEvaluationDomain<F>,
50
51 domain_h: GeneralEvaluationDomain<F>,
53
54 domain_k: GeneralEvaluationDomain<F>,
56}
57
58impl<'a, F: PrimeField> ProverState<'a, F> {
59 pub fn public_input(&self) -> Vec<F> {
61 unformat_public_input(&self.formatted_input_assignment)
62 }
63}
64
65#[derive(Clone)]
67pub enum ProverMsg<F: Field> {
68 EmptyMessage,
71 FieldElements(Vec<F>),
73}
74
75impl<F: Field> ark_ff::ToBytes for ProverMsg<F> {
76 fn write<W: Write>(&self, w: W) -> ark_std::io::Result<()> {
77 match self {
78 ProverMsg::EmptyMessage => Ok(()),
79 ProverMsg::FieldElements(field_elems) => field_elems.write(w),
80 }
81 }
82}
83
84impl<F: Field> CanonicalSerialize for ProverMsg<F> {
85 fn serialize<W: Write>(&self, mut writer: W) -> Result<(), SerializationError> {
86 let res: Option<Vec<F>> = match self {
87 ProverMsg::EmptyMessage => None,
88 ProverMsg::FieldElements(v) => Some(v.clone()),
89 };
90 res.serialize(&mut writer)
91 }
92
93 fn serialized_size(&self) -> usize {
94 let res: Option<Vec<F>> = match self {
95 ProverMsg::EmptyMessage => None,
96 ProverMsg::FieldElements(v) => Some(v.clone()),
97 };
98 res.serialized_size()
99 }
100
101 fn serialize_unchecked<W: Write>(&self, mut writer: W) -> Result<(), SerializationError> {
102 let res: Option<Vec<F>> = match self {
103 ProverMsg::EmptyMessage => None,
104 ProverMsg::FieldElements(v) => Some(v.clone()),
105 };
106 res.serialize_unchecked(&mut writer)
107 }
108
109 fn serialize_uncompressed<W: Write>(&self, mut writer: W) -> Result<(), SerializationError> {
110 let res: Option<Vec<F>> = match self {
111 ProverMsg::EmptyMessage => None,
112 ProverMsg::FieldElements(v) => Some(v.clone()),
113 };
114 res.serialize_uncompressed(&mut writer)
115 }
116
117 fn uncompressed_size(&self) -> usize {
118 let res: Option<Vec<F>> = match self {
119 ProverMsg::EmptyMessage => None,
120 ProverMsg::FieldElements(v) => Some(v.clone()),
121 };
122 res.uncompressed_size()
123 }
124}
125
126impl<F: Field> CanonicalDeserialize for ProverMsg<F> {
127 fn deserialize<R: Read>(mut reader: R) -> Result<Self, SerializationError> {
128 let res = Option::<Vec<F>>::deserialize(&mut reader)?;
129
130 if let Some(res) = res {
131 Ok(ProverMsg::FieldElements(res))
132 } else {
133 Ok(ProverMsg::EmptyMessage)
134 }
135 }
136
137 fn deserialize_unchecked<R: Read>(mut reader: R) -> Result<Self, SerializationError> {
138 let res = Option::<Vec<F>>::deserialize_unchecked(&mut reader)?;
139
140 if let Some(res) = res {
141 Ok(ProverMsg::FieldElements(res))
142 } else {
143 Ok(ProverMsg::EmptyMessage)
144 }
145 }
146
147 fn deserialize_uncompressed<R: Read>(mut reader: R) -> Result<Self, SerializationError> {
148 let res = Option::<Vec<F>>::deserialize_uncompressed(&mut reader)?;
149
150 if let Some(res) = res {
151 Ok(ProverMsg::FieldElements(res))
152 } else {
153 Ok(ProverMsg::EmptyMessage)
154 }
155 }
156}
157
158pub struct ProverFirstOracles<F: Field> {
160 pub w: LabeledPolynomial<F>,
162 pub z_a: LabeledPolynomial<F>,
164 pub z_b: LabeledPolynomial<F>,
166 pub mask_poly: LabeledPolynomial<F>,
168}
169
170impl<F: Field> ProverFirstOracles<F> {
171 pub fn iter(&self) -> impl Iterator<Item = &LabeledPolynomial<F>> {
173 vec![&self.w, &self.z_a, &self.z_b, &self.mask_poly].into_iter()
174 }
175}
176
177pub struct ProverSecondOracles<F: Field> {
179 pub t: LabeledPolynomial<F>,
181 pub g_1: LabeledPolynomial<F>,
183 pub h_1: LabeledPolynomial<F>,
185}
186
187impl<F: Field> ProverSecondOracles<F> {
188 pub fn iter(&self) -> impl Iterator<Item = &LabeledPolynomial<F>> {
190 vec![&self.t, &self.g_1, &self.h_1].into_iter()
191 }
192}
193
194pub struct ProverThirdOracles<F: Field> {
196 pub g_2: LabeledPolynomial<F>,
198 pub h_2: LabeledPolynomial<F>,
200}
201
202impl<F: Field> ProverThirdOracles<F> {
203 pub fn iter(&self) -> impl Iterator<Item = &LabeledPolynomial<F>> {
205 vec![&self.g_2, &self.h_2].into_iter()
206 }
207}
208
209impl<F: PrimeField> AHPForR1CS<F> {
210 pub fn prover_init<'a, C: ConstraintSynthesizer<F>>(
212 index: &'a Index<F>,
213 c: C,
214 ) -> Result<ProverState<'a, F>, Error> {
215 let init_time = start_timer!(|| "AHP::Prover::Init");
216
217 let constraint_time = start_timer!(|| "Generating constraints and witnesses");
218 let pcs = ConstraintSystem::new_ref();
219 pcs.set_optimization_goal(OptimizationGoal::Weight);
220 pcs.set_mode(ark_relations::r1cs::SynthesisMode::Prove {
221 construct_matrices: true,
222 });
223 c.generate_constraints(pcs.clone())?;
224 end_timer!(constraint_time);
225
226 let padding_time = start_timer!(|| "Padding matrices to make them square");
227 pad_input_for_indexer_and_prover(pcs.clone());
228 pcs.finalize();
229 make_matrices_square_for_prover(pcs.clone());
230 end_timer!(padding_time);
231
232 let num_non_zero = index.index_info.num_non_zero;
233
234 let (formatted_input_assignment, witness_assignment, num_constraints) = {
235 let pcs = pcs.borrow().unwrap();
236 (
237 pcs.instance_assignment.as_slice().to_vec(),
238 pcs.witness_assignment.as_slice().to_vec(),
239 pcs.num_constraints,
240 )
241 };
242
243 let num_input_variables = formatted_input_assignment.len();
244 let num_witness_variables = witness_assignment.len();
245 if index.index_info.num_constraints != num_constraints
246 || num_input_variables + num_witness_variables != index.index_info.num_variables
247 {
248 return Err(Error::InstanceDoesNotMatchIndex);
249 }
250
251 if !Self::formatted_public_input_is_admissible(&formatted_input_assignment) {
252 return Err(Error::InvalidPublicInputLength);
253 }
254
255 let inner_prod_fn = |row: &[(F, usize)]| {
257 let mut acc = F::zero();
258 for &(ref coeff, i) in row {
259 let tmp = if i < num_input_variables {
260 formatted_input_assignment[i]
261 } else {
262 witness_assignment[i - num_input_variables]
263 };
264
265 acc += &(if coeff.is_one() { tmp } else { tmp * coeff });
266 }
267 acc
268 };
269
270 let eval_z_a_time = start_timer!(|| "Evaluating z_A");
271 let z_a = index.a.iter().map(|row| inner_prod_fn(row)).collect();
272 end_timer!(eval_z_a_time);
273
274 let eval_z_b_time = start_timer!(|| "Evaluating z_B");
275 let z_b = index.b.iter().map(|row| inner_prod_fn(row)).collect();
276 end_timer!(eval_z_b_time);
277
278 let zk_bound = 1; let domain_h = GeneralEvaluationDomain::new(num_constraints)
281 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
282
283 let domain_k = GeneralEvaluationDomain::new(num_non_zero)
284 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
285
286 let domain_x = GeneralEvaluationDomain::new(num_input_variables)
287 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
288
289 end_timer!(init_time);
290
291 Ok(ProverState {
292 formatted_input_assignment,
293 witness_assignment,
294 z_a: Some(z_a),
295 z_b: Some(z_b),
296 w_poly: None,
297 mz_polys: None,
298 zk_bound,
299 index,
300 verifier_first_msg: None,
301 mask_poly: None,
302 domain_h,
303 domain_k,
304 domain_x,
305 })
306 }
307
308 pub fn prover_first_round<'a, R: RngCore>(
310 mut state: ProverState<'a, F>,
311 rng: &mut R,
312 ) -> Result<(ProverMsg<F>, ProverFirstOracles<F>, ProverState<'a, F>), Error> {
313 let round_time = start_timer!(|| "AHP::Prover::FirstRound");
314 let domain_h = state.domain_h;
315 let zk_bound = state.zk_bound;
316
317 let v_H = domain_h.vanishing_polynomial().into();
318
319 let x_time = start_timer!(|| "Computing x polynomial and evals");
320 let domain_x = state.domain_x;
321 let x_poly = EvaluationsOnDomain::from_vec_and_domain(
322 state.formatted_input_assignment.clone(),
323 domain_x,
324 )
325 .interpolate();
326 let x_evals = domain_h.fft(&x_poly);
327 end_timer!(x_time);
328
329 let ratio = domain_h.size() / domain_x.size();
330
331 let mut w_extended = state.witness_assignment.clone();
332 w_extended.extend(vec![
333 F::zero();
334 domain_h.size()
335 - domain_x.size()
336 - state.witness_assignment.len()
337 ]);
338
339 let w_poly_time = start_timer!(|| "Computing w polynomial");
340 let w_poly_evals = cfg_into_iter!(0..domain_h.size())
341 .map(|k| {
342 if k % ratio == 0 {
343 F::zero()
344 } else {
345 w_extended[k - (k / ratio) - 1] - &x_evals[k]
346 }
347 })
348 .collect();
349
350 let w_poly = &EvaluationsOnDomain::from_vec_and_domain(w_poly_evals, domain_h)
351 .interpolate()
352 + &(&DensePolynomial::from_coefficients_slice(&[F::rand(rng)]) * &v_H);
353 let (w_poly, remainder) = w_poly.divide_by_vanishing_poly(domain_x).unwrap();
354 assert!(remainder.is_zero());
355 end_timer!(w_poly_time);
356
357 let z_a_poly_time = start_timer!(|| "Computing z_A polynomial");
358 let z_a = state.z_a.clone().unwrap();
359 let z_a_poly = &EvaluationsOnDomain::from_vec_and_domain(z_a, domain_h).interpolate()
360 + &(&DensePolynomial::from_coefficients_slice(&[F::rand(rng)]) * &v_H);
361 end_timer!(z_a_poly_time);
362
363 let z_b_poly_time = start_timer!(|| "Computing z_B polynomial");
364 let z_b = state.z_b.clone().unwrap();
365 let z_b_poly = &EvaluationsOnDomain::from_vec_and_domain(z_b, domain_h).interpolate()
366 + &(&DensePolynomial::from_coefficients_slice(&[F::rand(rng)]) * &v_H);
367 end_timer!(z_b_poly_time);
368
369 let mask_poly_time = start_timer!(|| "Computing mask polynomial");
370 let mask_poly_degree = 3 * domain_h.size() + 2 * zk_bound - 3;
371 let mut mask_poly = DensePolynomial::rand(mask_poly_degree, rng);
372 let scaled_sigma_1 = (mask_poly.divide_by_vanishing_poly(domain_h).unwrap().1)[0];
373 mask_poly[0] -= &scaled_sigma_1;
374 end_timer!(mask_poly_time);
375
376 let msg = ProverMsg::EmptyMessage;
377
378 assert!(w_poly.degree() < domain_h.size() - domain_x.size() + zk_bound);
379 assert!(z_a_poly.degree() < domain_h.size() + zk_bound);
380 assert!(z_b_poly.degree() < domain_h.size() + zk_bound);
381 assert!(mask_poly.degree() <= 3 * domain_h.size() + 2 * zk_bound - 3);
382
383 let w = LabeledPolynomial::new("w".to_string(), w_poly, None, Some(1));
384 let z_a = LabeledPolynomial::new("z_a".to_string(), z_a_poly, None, Some(1));
385 let z_b = LabeledPolynomial::new("z_b".to_string(), z_b_poly, None, Some(1));
386 let mask_poly =
387 LabeledPolynomial::new("mask_poly".to_string(), mask_poly.clone(), None, None);
388
389 let oracles = ProverFirstOracles {
390 w: w.clone(),
391 z_a: z_a.clone(),
392 z_b: z_b.clone(),
393 mask_poly: mask_poly.clone(),
394 };
395
396 state.w_poly = Some(w);
397 state.mz_polys = Some((z_a, z_b));
398 state.mask_poly = Some(mask_poly);
399 end_timer!(round_time);
400
401 Ok((msg, oracles, state))
402 }
403
404 fn calculate_t<'a>(
405 matrices: impl Iterator<Item = &'a Matrix<F>>,
406 matrix_randomizers: &[F],
407 input_domain: GeneralEvaluationDomain<F>,
408 domain_h: GeneralEvaluationDomain<F>,
409 r_alpha_x_on_h: Vec<F>,
410 ) -> DensePolynomial<F> {
411 let mut t_evals_on_h = vec![F::zero(); domain_h.size()];
412 for (matrix, eta) in matrices.zip(matrix_randomizers) {
413 for (r, row) in matrix.iter().enumerate() {
414 for (coeff, c) in row.iter() {
415 let index = domain_h.reindex_by_subdomain(input_domain, *c);
416 t_evals_on_h[index] += *eta * coeff * r_alpha_x_on_h[r];
417 }
418 }
419 }
420 EvaluationsOnDomain::from_vec_and_domain(t_evals_on_h, domain_h).interpolate()
421 }
422
423 pub fn prover_num_first_round_oracles() -> usize {
425 4
426 }
427
428 pub fn prover_first_round_degree_bounds(
430 _info: &IndexInfo<F>,
431 ) -> impl Iterator<Item = Option<usize>> {
432 vec![None; 4].into_iter()
433 }
434
435 pub fn prover_second_round<'a, R: RngCore>(
437 ver_message: &VerifierFirstMsg<F>,
438 mut state: ProverState<'a, F>,
439 _r: &mut R,
440 ) -> (ProverMsg<F>, ProverSecondOracles<F>, ProverState<'a, F>) {
441 let round_time = start_timer!(|| "AHP::Prover::SecondRound");
442
443 let domain_h = state.domain_h;
444 let zk_bound = state.zk_bound;
445
446 let mask_poly = state
447 .mask_poly
448 .as_ref()
449 .expect("ProverState should include mask_poly when prover_second_round is called");
450
451 let VerifierFirstMsg {
452 alpha,
453 eta_a,
454 eta_b,
455 eta_c,
456 } = *ver_message;
457
458 let summed_z_m_poly_time = start_timer!(|| "Compute z_m poly");
459 let (z_a_poly, z_b_poly) = state.mz_polys.as_ref().unwrap();
460 let z_c_poly = z_a_poly.polynomial() * z_b_poly.polynomial();
461
462 let mut summed_z_m_coeffs = z_c_poly.coeffs;
463 cfg_iter_mut!(summed_z_m_coeffs).for_each(|c| *c *= &eta_c);
467 cfg_iter_mut!(summed_z_m_coeffs)
468 .zip(&z_a_poly.polynomial().coeffs)
469 .zip(&z_b_poly.polynomial().coeffs)
470 .for_each(|((c, a), b)| *c += &(eta_a * a + &(eta_b * b)));
471
472 let summed_z_m = DensePolynomial::from_coefficients_vec(summed_z_m_coeffs);
473 end_timer!(summed_z_m_poly_time);
474
475 let r_alpha_x_evals_time = start_timer!(|| "Compute r_alpha_x evals");
476 let r_alpha_x_evals =
477 domain_h.batch_eval_unnormalized_bivariate_lagrange_poly_with_diff_inputs(alpha);
478 end_timer!(r_alpha_x_evals_time);
479
480 let r_alpha_poly_time = start_timer!(|| "Compute r_alpha_x poly");
481 let r_alpha_poly = DensePolynomial::from_coefficients_vec(domain_h.ifft(&r_alpha_x_evals));
482 end_timer!(r_alpha_poly_time);
483
484 let t_poly_time = start_timer!(|| "Compute t poly");
485 let t_poly = Self::calculate_t(
486 vec![&state.index.a, &state.index.b, &state.index.c].into_iter(),
487 &[eta_a, eta_b, eta_c],
488 state.domain_x,
489 state.domain_h,
490 r_alpha_x_evals.to_vec(),
491 );
492 end_timer!(t_poly_time);
493
494 let z_poly_time = start_timer!(|| "Compute z poly");
495
496 let domain_x = GeneralEvaluationDomain::new(state.formatted_input_assignment.len())
497 .ok_or(SynthesisError::PolynomialDegreeTooLarge)
498 .unwrap();
499 let x_poly = EvaluationsOnDomain::from_vec_and_domain(
500 state.formatted_input_assignment.clone(),
501 domain_x,
502 )
503 .interpolate();
504 let w_poly = state.w_poly.as_ref().unwrap();
505 let mut z_poly = w_poly.polynomial().mul_by_vanishing_poly(domain_x);
506 cfg_iter_mut!(z_poly.coeffs)
507 .zip(&x_poly.coeffs)
508 .for_each(|(z, x)| *z += x);
509 assert!(z_poly.degree() < domain_h.size() + zk_bound);
510
511 end_timer!(z_poly_time);
512
513 let q_1_time = start_timer!(|| "Compute q_1 poly");
514
515 let mul_domain_size = *[
516 mask_poly.len(),
517 r_alpha_poly.coeffs.len() + summed_z_m.coeffs.len(),
518 t_poly.coeffs.len() + z_poly.len(),
519 ]
520 .iter()
521 .max()
522 .unwrap();
523 let mul_domain = GeneralEvaluationDomain::new(mul_domain_size)
524 .expect("field is not smooth enough to construct domain");
525 let mut r_alpha_evals = r_alpha_poly.evaluate_over_domain_by_ref(mul_domain);
526 let summed_z_m_evals = summed_z_m.evaluate_over_domain_by_ref(mul_domain);
527 let z_poly_evals = z_poly.evaluate_over_domain_by_ref(mul_domain);
528 let t_poly_m_evals = t_poly.evaluate_over_domain_by_ref(mul_domain);
529
530 cfg_iter_mut!(r_alpha_evals.evals)
531 .zip(&summed_z_m_evals.evals)
532 .zip(&z_poly_evals.evals)
533 .zip(&t_poly_m_evals.evals)
534 .for_each(|(((a, b), &c), d)| {
535 *a *= b;
536 *a -= c * d;
537 });
538 let rhs = r_alpha_evals.interpolate();
539 let q_1 = mask_poly.polynomial() + &rhs;
540 end_timer!(q_1_time);
541
542 let sumcheck_time = start_timer!(|| "Compute sumcheck h and g polys");
543 let (h_1, x_g_1) = q_1.divide_by_vanishing_poly(domain_h).unwrap();
544 let g_1 = DensePolynomial::from_coefficients_slice(&x_g_1.coeffs[1..]);
545 end_timer!(sumcheck_time);
546
547 let msg = ProverMsg::EmptyMessage;
548
549 assert!(g_1.degree() <= domain_h.size() - 2);
550 assert!(h_1.degree() <= 2 * domain_h.size() + 2 * zk_bound - 2);
551
552 let oracles = ProverSecondOracles {
553 t: LabeledPolynomial::new("t".into(), t_poly, None, None),
554 g_1: LabeledPolynomial::new("g_1".into(), g_1, Some(domain_h.size() - 2), Some(1)),
555 h_1: LabeledPolynomial::new("h_1".into(), h_1, None, None),
556 };
557
558 state.w_poly = None;
559 state.verifier_first_msg = Some(*ver_message);
560 end_timer!(round_time);
561
562 (msg, oracles, state)
563 }
564
565 pub fn prover_num_second_round_oracles() -> usize {
567 3
568 }
569
570 pub fn prover_second_round_degree_bounds(
572 info: &IndexInfo<F>,
573 ) -> impl Iterator<Item = Option<usize>> {
574 let h_domain_size =
575 GeneralEvaluationDomain::<F>::compute_size_of_domain(info.num_constraints).unwrap();
576
577 vec![None, Some(h_domain_size - 2), None].into_iter()
578 }
579
580 pub fn prover_third_round<'a, R: RngCore>(
582 ver_message: &VerifierSecondMsg<F>,
583 prover_state: ProverState<'a, F>,
584 _r: &mut R,
585 ) -> Result<(ProverMsg<F>, ProverThirdOracles<F>), Error> {
586 let round_time = start_timer!(|| "AHP::Prover::ThirdRound");
587
588 let ProverState {
589 index,
590 verifier_first_msg,
591 domain_h,
592 domain_k,
593 ..
594 } = prover_state;
595
596 let VerifierFirstMsg {
597 eta_a,
598 eta_b,
599 eta_c,
600 alpha,
601 } = verifier_first_msg.expect(
602 "ProverState should include verifier_first_msg when prover_third_round is called",
603 );
604
605 let beta = ver_message.beta;
606
607 let v_H_at_alpha = domain_h.evaluate_vanishing_polynomial(alpha);
608 let v_H_at_beta = domain_h.evaluate_vanishing_polynomial(beta);
609
610 let (a_star, b_star, c_star) = (
611 &index.a_star_arith,
612 &index.b_star_arith,
613 &index.c_star_arith,
614 );
615
616 let f_evals_time = start_timer!(|| "Computing f evals on K");
617 let mut f_vals_on_K = Vec::with_capacity(domain_k.size());
618 let mut inverses_a = Vec::with_capacity(domain_k.size());
619 let mut inverses_b = Vec::with_capacity(domain_k.size());
620 let mut inverses_c = Vec::with_capacity(domain_k.size());
621
622 for i in 0..domain_k.size() {
623 inverses_a.push((beta - a_star.evals_on_K.row[i]) * (alpha - a_star.evals_on_K.col[i]));
624 inverses_b.push((beta - b_star.evals_on_K.row[i]) * (alpha - b_star.evals_on_K.col[i]));
625 inverses_c.push((beta - c_star.evals_on_K.row[i]) * (alpha - c_star.evals_on_K.col[i]));
626 }
627 ark_ff::batch_inversion(&mut inverses_a);
628 ark_ff::batch_inversion(&mut inverses_b);
629 ark_ff::batch_inversion(&mut inverses_c);
630
631 for i in 0..domain_k.size() {
632 let t = eta_a * a_star.evals_on_K.val[i] * inverses_a[i]
633 + eta_b * b_star.evals_on_K.val[i] * inverses_b[i]
634 + eta_c * c_star.evals_on_K.val[i] * inverses_c[i];
635 let f_at_kappa = v_H_at_beta * v_H_at_alpha * t;
636 f_vals_on_K.push(f_at_kappa);
637 }
638 end_timer!(f_evals_time);
639
640 let f_poly_time = start_timer!(|| "Computing f poly");
641 let f = EvaluationsOnDomain::from_vec_and_domain(f_vals_on_K, domain_k).interpolate();
642 end_timer!(f_poly_time);
643
644 let g_2 = DensePolynomial::from_coefficients_slice(&f.coeffs[1..]);
645
646 let domain_b = GeneralEvaluationDomain::<F>::new(3 * domain_k.size() - 3)
647 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
648
649 let denom_eval_time = start_timer!(|| "Computing denominator evals on B");
650 let a_denom: Vec<_> = cfg_iter!(a_star.evals_on_B.row.evals)
651 .zip(&a_star.evals_on_B.col.evals)
652 .zip(&a_star.row_col_evals_on_B.evals)
653 .map(|((&r, c), r_c)| beta * alpha - (r * alpha) - (beta * c) + r_c)
654 .collect();
655
656 let b_denom: Vec<_> = cfg_iter!(b_star.evals_on_B.row.evals)
657 .zip(&b_star.evals_on_B.col.evals)
658 .zip(&b_star.row_col_evals_on_B.evals)
659 .map(|((&r, c), r_c)| beta * alpha - (r * alpha) - (beta * c) + r_c)
660 .collect();
661
662 let c_denom: Vec<_> = cfg_iter!(c_star.evals_on_B.row.evals)
663 .zip(&c_star.evals_on_B.col.evals)
664 .zip(&c_star.row_col_evals_on_B.evals)
665 .map(|((&r, c), r_c)| beta * alpha - (r * alpha) - (beta * c) + r_c)
666 .collect();
667 end_timer!(denom_eval_time);
668
669 let a_evals_time = start_timer!(|| "Computing a evals on B");
670 let a_star_evals_on_B = &a_star.evals_on_B;
671 let b_star_evals_on_B = &b_star.evals_on_B;
672 let c_star_evals_on_B = &c_star.evals_on_B;
673 let a_poly_on_B = cfg_into_iter!(0..domain_b.size())
674 .map(|i| {
675 let t = eta_a * a_star_evals_on_B.val.evals[i] * b_denom[i] * c_denom[i]
676 + eta_b * b_star_evals_on_B.val.evals[i] * a_denom[i] * c_denom[i]
677 + eta_c * c_star_evals_on_B.val.evals[i] * a_denom[i] * b_denom[i];
678 v_H_at_beta * v_H_at_alpha * t
679 })
680 .collect();
681 end_timer!(a_evals_time);
682
683 let a_poly_time = start_timer!(|| "Computing a poly");
684 let a_poly = EvaluationsOnDomain::from_vec_and_domain(a_poly_on_B, domain_b).interpolate();
685 end_timer!(a_poly_time);
686
687 let b_evals_time = start_timer!(|| "Computing b evals on B");
688 let b_poly_on_B = cfg_into_iter!(0..domain_b.size())
689 .map(|i| a_denom[i] * b_denom[i] * c_denom[i])
690 .collect();
691 end_timer!(b_evals_time);
692
693 let b_poly_time = start_timer!(|| "Computing b poly");
694 let b_poly = EvaluationsOnDomain::from_vec_and_domain(b_poly_on_B, domain_b).interpolate();
695 end_timer!(b_poly_time);
696
697 let h_2_poly_time = start_timer!(|| "Computing sumcheck h poly");
698 let h_2 = (&a_poly - &(&b_poly * &f))
699 .divide_by_vanishing_poly(domain_k)
700 .unwrap()
701 .0;
702 end_timer!(h_2_poly_time);
703
704 let msg = ProverMsg::EmptyMessage;
705
706 assert!(g_2.degree() <= domain_k.size() - 2);
707 let oracles = ProverThirdOracles {
708 g_2: LabeledPolynomial::new("g_2".to_string(), g_2, Some(domain_k.size() - 2), None),
709 h_2: LabeledPolynomial::new("h_2".to_string(), h_2, None, None),
710 };
711 end_timer!(round_time);
712
713 Ok((msg, oracles))
714 }
715
716 pub fn prover_num_third_round_oracles() -> usize {
718 3
719 }
720
721 pub fn prover_third_round_degree_bounds(
723 info: &IndexInfo<F>,
724 ) -> impl Iterator<Item = Option<usize>> {
725 let num_non_zero = info.num_non_zero;
726 let k_size = GeneralEvaluationDomain::<F>::compute_size_of_domain(num_non_zero).unwrap();
727
728 vec![Some(k_size - 2), None].into_iter()
729 }
730}