halo2_axiom/poly/ipa/multiopen/
prover.rs1use super::{construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4};
2use crate::arithmetic::{eval_polynomial, kate_division, CurveAffine};
3use crate::poly::commitment::ParamsProver;
4use crate::poly::commitment::{Blind, Prover};
5use crate::poly::ipa::commitment::{self, IPACommitmentScheme, ParamsIPA};
6use crate::poly::query::ProverQuery;
7use crate::poly::{Coeff, Polynomial};
8use crate::transcript::{EncodedChallenge, TranscriptWrite};
9
10use ff::Field;
11use group::Curve;
12use rand_core::RngCore;
13use std::io;
14use std::marker::PhantomData;
15
16#[derive(Debug)]
18pub struct ProverIPA<'params, C: CurveAffine> {
19 pub(crate) params: &'params ParamsIPA<C>,
20}
21
22impl<'params, C: CurveAffine> Prover<'params, IPACommitmentScheme<C>> for ProverIPA<'params, C> {
23 const QUERY_INSTANCE: bool = true;
24
25 fn new(params: &'params ParamsIPA<C>) -> Self {
26 Self { params }
27 }
28
29 fn create_proof<'com, Z: EncodedChallenge<C>, T: TranscriptWrite<C, Z>, R, I>(
31 &self,
32 mut rng: R,
33 transcript: &mut T,
34 queries: I,
35 ) -> io::Result<()>
36 where
37 I: IntoIterator<Item = ProverQuery<'com, C>> + Clone,
38 R: RngCore,
39 {
40 let x_1: ChallengeX1<_> = transcript.squeeze_challenge_scalar();
41 let x_2: ChallengeX2<_> = transcript.squeeze_challenge_scalar();
42
43 let (poly_map, point_sets) = construct_intermediate_sets(queries).ok_or_else(|| {
44 io::Error::new(
45 io::ErrorKind::InvalidInput,
46 "queries iterator contains mismatching evaluations",
47 )
48 })?;
49
50 let mut q_polys: Vec<Option<Polynomial<C::Scalar, Coeff>>> = vec![None; point_sets.len()];
53 let mut q_blinds = vec![Blind(C::Scalar::ZERO); point_sets.len()];
54
55 {
56 let mut accumulate = |set_idx: usize,
57 new_poly: &Polynomial<C::Scalar, Coeff>,
58 blind: Blind<C::Scalar>| {
59 if let Some(poly) = &q_polys[set_idx] {
60 q_polys[set_idx] = Some(poly.clone() * *x_1 + new_poly);
61 } else {
62 q_polys[set_idx] = Some(new_poly.clone());
63 }
64 q_blinds[set_idx] *= *x_1;
65 q_blinds[set_idx] += blind;
66 };
67
68 for commitment_data in poly_map.into_iter() {
69 accumulate(
70 commitment_data.set_index, commitment_data.commitment.poly, commitment_data.commitment.blind, );
74 }
75 }
76
77 let q_prime_poly = point_sets
78 .iter()
79 .zip(q_polys.iter())
80 .fold(None, |q_prime_poly, (points, poly)| {
81 let mut poly = points
82 .iter()
83 .fold(poly.clone().unwrap().values, |poly, point| {
84 kate_division(&poly, *point)
85 });
86 poly.resize(self.params.n as usize, C::Scalar::ZERO);
87 let poly = Polynomial {
88 values: poly,
89 _marker: PhantomData,
90 };
91
92 if q_prime_poly.is_none() {
93 Some(poly)
94 } else {
95 q_prime_poly.map(|q_prime_poly| q_prime_poly * *x_2 + &poly)
96 }
97 })
98 .unwrap();
99
100 let q_prime_blind = Blind(C::Scalar::random(&mut rng));
101 let q_prime_commitment = self.params.commit(&q_prime_poly, q_prime_blind).to_affine();
102
103 transcript.write_point(q_prime_commitment)?;
104
105 let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar();
106
107 for q_i_poly in &q_polys {
110 transcript.write_scalar(eval_polynomial(q_i_poly.as_ref().unwrap(), *x_3))?;
111 }
112
113 let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar();
114
115 let (p_poly, p_poly_blind) = q_polys.into_iter().zip(q_blinds).fold(
116 (q_prime_poly, q_prime_blind),
117 |(q_prime_poly, q_prime_blind), (poly, blind)| {
118 (
119 q_prime_poly * *x_4 + &poly.unwrap(),
120 Blind((q_prime_blind.0 * &(*x_4)) + &blind.0),
121 )
122 },
123 );
124
125 commitment::create_proof(self.params, rng, transcript, &p_poly, p_poly_blind, *x_3)
126 }
127}