1use crate::arithmetic::{best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt};
7use crate::helpers::CurveRead;
8use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier};
9use crate::poly::ipa::msm::MSMIPA;
10use crate::poly::{Coeff, LagrangeCoeff, Polynomial};
11
12use group::{Curve, Group};
13use std::marker::PhantomData;
14
15mod prover;
16mod verifier;
17
18pub use prover::create_proof;
19pub use verifier::verify_proof;
20
21use std::io;
22
23#[derive(Debug, Clone)]
25pub struct ParamsIPA<C: CurveAffine> {
26 pub(crate) k: u32,
27 pub(crate) n: u64,
28 pub(crate) g: Vec<C>,
29 pub(crate) g_lagrange: Vec<C>,
30 pub(crate) w: C,
31 pub(crate) u: C,
32}
33
34#[derive(Debug)]
36pub struct IPACommitmentScheme<C: CurveAffine> {
37 _marker: PhantomData<C>,
38}
39
40impl<C: CurveAffine> CommitmentScheme for IPACommitmentScheme<C> {
41 type Scalar = C::ScalarExt;
42 type Curve = C;
43
44 type ParamsProver = ParamsIPA<C>;
45 type ParamsVerifier = ParamsVerifierIPA<C>;
46
47 fn new_params(k: u32) -> Self::ParamsProver {
48 ParamsIPA::new(k)
49 }
50
51 fn read_params<R: io::Read>(reader: &mut R) -> io::Result<Self::ParamsProver> {
52 ParamsIPA::read(reader)
53 }
54}
55
56pub type ParamsVerifierIPA<C> = ParamsIPA<C>;
58
59impl<'params, C: CurveAffine> ParamsVerifier<'params, C> for ParamsIPA<C> {}
60
61impl<'params, C: CurveAffine> Params<'params, C> for ParamsIPA<C> {
62 type MSM = MSMIPA<'params, C>;
63
64 fn k(&self) -> u32 {
65 self.k
66 }
67
68 fn n(&self) -> u64 {
69 self.n
70 }
71
72 fn downsize(&mut self, k: u32) {
73 assert!(k <= self.k);
74
75 self.k = k;
76 self.n = 1 << k;
77 self.g.truncate(self.n as usize);
78 self.g_lagrange = g_to_lagrange(self.g.iter().map(|g| g.to_curve()).collect(), k);
79 }
80
81 fn empty_msm(&'params self) -> MSMIPA<C> {
82 MSMIPA::new(self)
83 }
84
85 fn commit_lagrange(
89 &self,
90 poly: &Polynomial<C::Scalar, LagrangeCoeff>,
91 r: Blind<C::Scalar>,
92 ) -> C::Curve {
93 let mut tmp_scalars = Vec::with_capacity(poly.len() + 1);
94 let mut tmp_bases = Vec::with_capacity(poly.len() + 1);
95
96 tmp_scalars.extend(poly.iter());
97 tmp_scalars.push(r.0);
98
99 tmp_bases.extend(self.g_lagrange.iter());
100 tmp_bases.push(self.w);
101
102 best_multiexp::<C>(&tmp_scalars, &tmp_bases)
103 }
104
105 fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
107 writer.write_all(&self.k.to_le_bytes())?;
108 for g_element in &self.g {
109 writer.write_all(g_element.to_bytes().as_ref())?;
110 }
111 for g_lagrange_element in &self.g_lagrange {
112 writer.write_all(g_lagrange_element.to_bytes().as_ref())?;
113 }
114 writer.write_all(self.w.to_bytes().as_ref())?;
115 writer.write_all(self.u.to_bytes().as_ref())?;
116
117 Ok(())
118 }
119
120 fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
122 let mut k = [0u8; 4];
123 reader.read_exact(&mut k[..])?;
124 let k = u32::from_le_bytes(k);
125
126 let n: u64 = 1 << k;
127
128 let g: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?;
129 let g_lagrange: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?;
130
131 let w = C::read(reader)?;
132 let u = C::read(reader)?;
133
134 Ok(Self {
135 k,
136 n,
137 g,
138 g_lagrange,
139 w,
140 u,
141 })
142 }
143}
144
145impl<'params, C: CurveAffine> ParamsProver<'params, C> for ParamsIPA<C> {
146 type ParamsVerifier = ParamsVerifierIPA<C>;
147
148 fn verifier_params(&'params self) -> &'params Self::ParamsVerifier {
149 self
150 }
151
152 fn new(k: u32) -> Self {
155 assert!(k < 32);
158
159 let n: u64 = 1 << k;
162
163 let g_projective = {
164 let mut g = Vec::with_capacity(n as usize);
165 g.resize(n as usize, C::Curve::identity());
166
167 parallelize(&mut g, move |g, start| {
168 let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters");
169
170 for (i, g) in g.iter_mut().enumerate() {
171 let i = (i + start) as u32;
172
173 let mut message = [0u8; 5];
174 message[1..5].copy_from_slice(&i.to_le_bytes());
175
176 *g = hasher(&message);
177 }
178 });
179
180 g
181 };
182
183 let g = {
184 let mut g = vec![C::identity(); n as usize];
185 parallelize(&mut g, |g, starts| {
186 C::Curve::batch_normalize(&g_projective[starts..(starts + g.len())], g);
187 });
188 g
189 };
190
191 let g_lagrange = g_to_lagrange(g_projective, k);
194
195 let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters");
196 let w = hasher(&[1]).to_affine();
197 let u = hasher(&[2]).to_affine();
198
199 ParamsIPA {
200 k,
201 n,
202 g,
203 g_lagrange,
204 w,
205 u,
206 }
207 }
208
209 fn commit(&self, poly: &Polynomial<C::Scalar, Coeff>, r: Blind<C::Scalar>) -> C::Curve {
213 let mut tmp_scalars = Vec::with_capacity(poly.len() + 1);
214 let mut tmp_bases = Vec::with_capacity(poly.len() + 1);
215
216 tmp_scalars.extend(poly.iter());
217 tmp_scalars.push(r.0);
218
219 tmp_bases.extend(self.g.iter());
220 tmp_bases.push(self.w);
221
222 best_multiexp::<C>(&tmp_scalars, &tmp_bases)
223 }
224
225 fn get_g(&self) -> &[C] {
226 &self.g
227 }
228}
229
230#[cfg(test)]
231mod test {
232 use crate::poly::commitment::ParamsProver;
233 use crate::poly::commitment::{Blind, Params, MSM};
234 use crate::poly::ipa::commitment::{create_proof, verify_proof, ParamsIPA};
235 use crate::poly::ipa::msm::MSMIPA;
236
237 use ff::Field;
238 use group::Curve;
239
240 #[test]
241 fn test_commit_lagrange_epaffine() {
242 const K: u32 = 6;
243
244 use rand_core::OsRng;
245
246 use crate::poly::EvaluationDomain;
247 use halo2curves::pasta::{EpAffine, Fq};
248
249 let params = ParamsIPA::<EpAffine>::new(K);
250 let domain = EvaluationDomain::new(1, K);
251
252 let mut a = domain.empty_lagrange();
253
254 for (i, a) in a.iter_mut().enumerate() {
255 *a = Fq::from(i as u64);
256 }
257
258 let b = domain.lagrange_to_coeff(a.clone());
259
260 let alpha = Blind(Fq::random(OsRng));
261
262 assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha));
263 }
264
265 #[test]
266 fn test_commit_lagrange_eqaffine() {
267 const K: u32 = 6;
268
269 use rand_core::OsRng;
270
271 use crate::poly::EvaluationDomain;
272 use halo2curves::pasta::{EqAffine, Fp};
273
274 let params: ParamsIPA<EqAffine> = ParamsIPA::<EqAffine>::new(K);
275 let domain = EvaluationDomain::new(1, K);
276
277 let mut a = domain.empty_lagrange();
278
279 for (i, a) in a.iter_mut().enumerate() {
280 *a = Fp::from(i as u64);
281 }
282
283 let b = domain.lagrange_to_coeff(a.clone());
284
285 let alpha = Blind(Fp::random(OsRng));
286
287 assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha));
288 }
289
290 #[test]
291 fn test_opening_proof() {
292 const K: u32 = 6;
293
294 use ff::Field;
295 use rand_core::OsRng;
296
297 use super::super::commitment::{Blind, Params};
298 use crate::arithmetic::eval_polynomial;
299 use crate::halo2curves::pasta::{EpAffine, Fq};
300 use crate::poly::EvaluationDomain;
301 use crate::transcript::{
302 Blake2bRead, Blake2bWrite, Challenge255, Transcript, TranscriptRead, TranscriptWrite,
303 };
304
305 use crate::transcript::TranscriptReadBuffer;
306 use crate::transcript::TranscriptWriterBuffer;
307
308 let rng = OsRng;
309
310 let params = ParamsIPA::<EpAffine>::new(K);
311 let mut params_buffer = vec![];
312 <ParamsIPA<_> as Params<_>>::write(¶ms, &mut params_buffer).unwrap();
313 let params: ParamsIPA<EpAffine> = Params::read::<_>(&mut ¶ms_buffer[..]).unwrap();
314
315 let domain = EvaluationDomain::new(1, K);
316
317 let mut px = domain.empty_coeff();
318
319 for (i, a) in px.iter_mut().enumerate() {
320 *a = Fq::from(i as u64);
321 }
322
323 let blind = Blind(Fq::random(rng));
324
325 let p = params.commit(&px, blind).to_affine();
326
327 let mut transcript =
328 Blake2bWrite::<Vec<u8>, EpAffine, Challenge255<EpAffine>>::init(vec![]);
329 transcript.write_point(p).unwrap();
330 let x = transcript.squeeze_challenge_scalar::<()>();
331 let v = eval_polynomial(&px, *x);
333 transcript.write_scalar(v).unwrap();
334
335 let (proof, ch_prover) = {
336 create_proof(¶ms, rng, &mut transcript, &px, blind, *x).unwrap();
337 let ch_prover = transcript.squeeze_challenge();
338 (transcript.finalize(), ch_prover)
339 };
340
341 let mut transcript =
343 Blake2bRead::<&[u8], EpAffine, Challenge255<EpAffine>>::init(&proof[..]);
344 let p_prime = transcript.read_point().unwrap();
345 assert_eq!(p, p_prime);
346 let x_prime = transcript.squeeze_challenge_scalar::<()>();
347 assert_eq!(*x, *x_prime);
348 let v_prime = transcript.read_scalar().unwrap();
349 assert_eq!(v, v_prime);
350
351 let mut commitment_msm = MSMIPA::new(¶ms);
352 commitment_msm.append_term(Fq::one(), p.into());
353
354 let guard = verify_proof(¶ms, commitment_msm, &mut transcript, *x, v).unwrap();
355 let ch_verifier = transcript.squeeze_challenge();
356 assert_eq!(*ch_prover, *ch_verifier);
357
358 {
360 let msm_challenges = guard.clone().use_challenges();
362 assert!(msm_challenges.check());
363
364 let g = guard.compute_g();
366 let (msm_g, _accumulator) = guard.clone().use_g(g);
367 assert!(msm_g.check());
368 }
369 }
370}