1use std::collections::{BTreeMap, BTreeSet};
7
8use super::*;
9use crate::{
10 arithmetic::{CurveAffine, FieldExt},
11 transcript::ChallengeScalar,
12};
13
14mod prover;
15mod verifier;
16
17pub use prover::create_proof;
18pub use verifier::verify_proof;
19
20#[derive(Clone, Copy, Debug)]
21struct X1 {}
22type ChallengeX1<F> = ChallengeScalar<F, X1>;
24
25#[derive(Clone, Copy, Debug)]
26struct X2 {}
27type ChallengeX2<F> = ChallengeScalar<F, X2>;
29
30#[derive(Clone, Copy, Debug)]
31struct X3 {}
32type ChallengeX3<F> = ChallengeScalar<F, X3>;
34
35#[derive(Clone, Copy, Debug)]
36struct X4 {}
37type ChallengeX4<F> = ChallengeScalar<F, X4>;
40
41#[derive(Debug, Clone)]
43pub struct ProverQuery<'a, C: CurveAffine> {
44 pub point: C::Scalar,
46 pub poly: &'a Polynomial<C::Scalar, Coeff>,
48 pub blind: commitment::Blind<C::Scalar>,
50}
51
52#[derive(Debug, Clone)]
54pub struct VerifierQuery<'r, 'params: 'r, C: CurveAffine> {
55 point: C::Scalar,
57 commitment: CommitmentReference<'r, 'params, C>,
59 eval: C::Scalar,
61}
62
63impl<'r, 'params: 'r, C: CurveAffine> VerifierQuery<'r, 'params, C> {
64 pub fn new_commitment(commitment: &'r C, point: C::Scalar, eval: C::Scalar) -> Self {
66 VerifierQuery {
67 point,
68 eval,
69 commitment: CommitmentReference::Commitment(commitment),
70 }
71 }
72
73 pub fn new_msm(
75 msm: &'r commitment::MSM<'params, C>,
76 point: C::Scalar,
77 eval: C::Scalar,
78 ) -> Self {
79 VerifierQuery {
80 point,
81 eval,
82 commitment: CommitmentReference::MSM(msm),
83 }
84 }
85}
86
87#[derive(Copy, Clone, Debug)]
88enum CommitmentReference<'r, 'params: 'r, C: CurveAffine> {
89 Commitment(&'r C),
90 MSM(&'r commitment::MSM<'params, C>),
91}
92
93impl<'r, 'params: 'r, C: CurveAffine> PartialEq for CommitmentReference<'r, 'params, C> {
94 fn eq(&self, other: &Self) -> bool {
95 match (self, other) {
96 (&CommitmentReference::Commitment(a), &CommitmentReference::Commitment(b)) => {
97 std::ptr::eq(a, b)
98 }
99 (&CommitmentReference::MSM(a), &CommitmentReference::MSM(b)) => std::ptr::eq(a, b),
100 _ => false,
101 }
102 }
103}
104
105#[derive(Debug)]
106struct CommitmentData<F, T: PartialEq> {
107 commitment: T,
108 set_index: usize,
109 point_indices: Vec<usize>,
110 evals: Vec<F>,
111}
112
113impl<F, T: PartialEq> CommitmentData<F, T> {
114 fn new(commitment: T) -> Self {
115 CommitmentData {
116 commitment,
117 set_index: 0,
118 point_indices: vec![],
119 evals: vec![],
120 }
121 }
122}
123
124trait Query<F>: Sized {
125 type Commitment: PartialEq + Copy;
126 type Eval: Clone + Default;
127
128 fn get_point(&self) -> F;
129 fn get_eval(&self) -> Self::Eval;
130 fn get_commitment(&self) -> Self::Commitment;
131}
132
133type IntermediateSets<F, Q> = (
134 Vec<CommitmentData<<Q as Query<F>>::Eval, <Q as Query<F>>::Commitment>>,
135 Vec<Vec<F>>,
136);
137
138fn construct_intermediate_sets<F: FieldExt, I, Q: Query<F>>(queries: I) -> IntermediateSets<F, Q>
139where
140 I: IntoIterator<Item = Q> + Clone,
141{
142 let mut commitment_map: Vec<CommitmentData<Q::Eval, Q::Commitment>> = vec![];
145
146 let mut point_index_map = BTreeMap::new();
149
150 for query in queries.clone() {
153 let num_points = point_index_map.len();
154 let point_idx = point_index_map
155 .entry(query.get_point())
156 .or_insert(num_points);
157
158 if let Some(pos) = commitment_map
159 .iter()
160 .position(|comm| comm.commitment == query.get_commitment())
161 {
162 commitment_map[pos].point_indices.push(*point_idx);
163 } else {
164 let mut tmp = CommitmentData::new(query.get_commitment());
165 tmp.point_indices.push(*point_idx);
166 commitment_map.push(tmp);
167 }
168 }
169
170 let mut inverse_point_index_map = BTreeMap::new();
172 for (&point, &point_index) in point_index_map.iter() {
173 inverse_point_index_map.insert(point_index, point);
174 }
175
176 let mut point_idx_sets = BTreeMap::new();
178 let mut commitment_set_map = Vec::new();
180
181 for commitment_data in commitment_map.iter() {
182 let mut point_index_set = BTreeSet::new();
183 for &point_index in commitment_data.point_indices.iter() {
185 point_index_set.insert(point_index);
186 }
187
188 commitment_set_map.push((commitment_data.commitment, point_index_set.clone()));
190
191 let num_sets = point_idx_sets.len();
192 point_idx_sets.entry(point_index_set).or_insert(num_sets);
193 }
194
195 for commitment_data in commitment_map.iter_mut() {
197 let len = commitment_data.point_indices.len();
198 commitment_data.evals = vec![Q::Eval::default(); len];
199 }
200
201 for query in queries {
203 let point_index = point_index_map.get(&query.get_point()).unwrap();
205
206 let mut point_index_set = BTreeSet::new();
208 for (commitment, point_idx_set) in commitment_set_map.iter() {
209 if query.get_commitment() == *commitment {
210 point_index_set = point_idx_set.clone();
211 }
212 }
213 assert!(!point_index_set.is_empty());
214
215 let set_index = point_idx_sets.get(&point_index_set).unwrap();
217 for commitment_data in commitment_map.iter_mut() {
218 if query.get_commitment() == commitment_data.commitment {
219 commitment_data.set_index = *set_index;
220 }
221 }
222 let point_index_set: Vec<usize> = point_index_set.iter().cloned().collect();
223
224 let point_index_in_set = point_index_set
226 .iter()
227 .position(|i| i == point_index)
228 .unwrap();
229
230 for commitment_data in commitment_map.iter_mut() {
231 if query.get_commitment() == commitment_data.commitment {
232 commitment_data.evals[point_index_in_set] = query.get_eval();
234 }
235 }
236 }
237
238 let mut point_sets: Vec<Vec<F>> = vec![Vec::new(); point_idx_sets.len()];
240 for (point_idx_set, &set_idx) in point_idx_sets.iter() {
241 for &point_idx in point_idx_set.iter() {
242 let point = inverse_point_index_map.get(&point_idx).unwrap();
243 point_sets[set_idx].push(*point);
244 }
245 }
246
247 (commitment_map, point_sets)
248}
249
250#[test]
251fn test_roundtrip() {
252 use group::Curve;
253 use rand_core::OsRng;
254
255 use super::commitment::{Blind, Params};
256 use crate::arithmetic::{eval_polynomial, FieldExt};
257 use crate::pasta::{EqAffine, Fp};
258 use crate::transcript::Challenge255;
259
260 const K: u32 = 4;
261
262 let params: Params<EqAffine> = Params::new(K);
263 let domain = EvaluationDomain::new(1, K);
264 let rng = OsRng;
265
266 let mut ax = domain.empty_coeff();
267 for (i, a) in ax.iter_mut().enumerate() {
268 *a = Fp::from(10 + i as u64);
269 }
270
271 let mut bx = domain.empty_coeff();
272 for (i, a) in bx.iter_mut().enumerate() {
273 *a = Fp::from(100 + i as u64);
274 }
275
276 let mut cx = domain.empty_coeff();
277 for (i, a) in cx.iter_mut().enumerate() {
278 *a = Fp::from(100 + i as u64);
279 }
280
281 let blind = Blind(Fp::random(rng));
282
283 let a = params.commit(&ax, blind).to_affine();
284 let b = params.commit(&bx, blind).to_affine();
285 let c = params.commit(&cx, blind).to_affine();
286
287 let x = Fp::random(rng);
288 let y = Fp::random(rng);
289 let avx = eval_polynomial(&ax, x);
290 let bvx = eval_polynomial(&bx, x);
291 let cvy = eval_polynomial(&cx, y);
292
293 let mut transcript = crate::transcript::Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
294 create_proof(
295 ¶ms,
296 rng,
297 &mut transcript,
298 std::iter::empty()
299 .chain(Some(ProverQuery {
300 point: x,
301 poly: &ax,
302 blind,
303 }))
304 .chain(Some(ProverQuery {
305 point: x,
306 poly: &bx,
307 blind,
308 }))
309 .chain(Some(ProverQuery {
310 point: y,
311 poly: &cx,
312 blind,
313 })),
314 )
315 .unwrap();
316 let proof = transcript.finalize();
317
318 {
319 let mut proof = &proof[..];
320 let mut transcript =
321 crate::transcript::Blake2bRead::<_, _, Challenge255<_>>::init(&mut proof);
322 let msm = params.empty_msm();
323
324 let guard = verify_proof(
325 ¶ms,
326 &mut transcript,
327 std::iter::empty()
328 .chain(Some(VerifierQuery::new_commitment(&a, x, avx)))
329 .chain(Some(VerifierQuery::new_commitment(&b, x, avx))) .chain(Some(VerifierQuery::new_commitment(&c, y, cvy))),
331 msm,
332 )
333 .unwrap();
334
335 assert!(!guard.use_challenges().eval());
337 }
338
339 {
340 let mut proof = &proof[..];
341
342 let mut transcript =
343 crate::transcript::Blake2bRead::<_, _, Challenge255<_>>::init(&mut proof);
344 let msm = params.empty_msm();
345
346 let guard = verify_proof(
347 ¶ms,
348 &mut transcript,
349 std::iter::empty()
350 .chain(Some(VerifierQuery::new_commitment(&a, x, avx)))
351 .chain(Some(VerifierQuery::new_commitment(&b, x, bvx)))
352 .chain(Some(VerifierQuery::new_commitment(&c, y, cvy))),
353 msm,
354 )
355 .unwrap();
356
357 assert!(guard.use_challenges().eval());
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::{construct_intermediate_sets, Query};
365 use crate::arithmetic::FieldExt;
366 use crate::pasta::Fp;
367
368 #[derive(Clone)]
369 struct MyQuery<F> {
370 commitment: usize,
371 point: F,
372 eval: F,
373 }
374
375 impl<F: Clone + Default> Query<F> for MyQuery<F> {
376 type Commitment = usize;
377 type Eval = F;
378
379 fn get_point(&self) -> F {
380 self.point.clone()
381 }
382 fn get_eval(&self) -> Self::Eval {
383 self.eval.clone()
384 }
385 fn get_commitment(&self) -> Self::Commitment {
386 self.commitment
387 }
388 }
389}
390
391#[cfg(test)]
392mod proptests {
393 use proptest::{
394 collection::vec,
395 prelude::*,
396 sample::{select, subsequence},
397 strategy::Strategy,
398 };
399
400 use super::construct_intermediate_sets;
401 use crate::poly::Rotation;
402 use pasta_curves::{arithmetic::FieldExt, Fp};
403
404 use std::collections::BTreeMap;
405 use std::convert::TryFrom;
406
407 #[derive(Debug, Clone)]
408 struct MyQuery<F> {
409 point: F,
410 eval: F,
411 commitment: usize,
412 }
413
414 impl super::Query<Fp> for MyQuery<Fp> {
415 type Commitment = usize;
416 type Eval = Fp;
417
418 fn get_point(&self) -> Fp {
419 self.point
420 }
421
422 fn get_eval(&self) -> Self::Eval {
423 self.eval
424 }
425
426 fn get_commitment(&self) -> Self::Commitment {
427 self.commitment
428 }
429 }
430
431 prop_compose! {
432 fn arb_point()(
433 bytes in vec(any::<u8>(), 64)
434 ) -> Fp {
435 Fp::from_bytes_wide(&<[u8; 64]>::try_from(bytes).unwrap())
436 }
437 }
438
439 prop_compose! {
440 fn arb_query(commitment: usize, point: Fp)(
441 eval in arb_point()
442 ) -> MyQuery<Fp> {
443 MyQuery {
444 point,
445 eval,
446 commitment
447 }
448 }
449 }
450
451 prop_compose! {
452 fn arb_queries_inner(num_points: usize, num_cols: usize, num_queries: usize)(
454 col_indices in vec(select((0..num_cols).collect::<Vec<_>>()), num_queries),
455 point_indices in vec(select((0..num_points).collect::<Vec<_>>()), num_queries)
456 ) -> Vec<(usize, usize)> {
457 col_indices.into_iter().zip(point_indices.into_iter()).collect()
458 }
459 }
460
461 prop_compose! {
462 fn compare_queries(
463 num_points: usize,
464 num_cols: usize,
465 num_queries: usize,
466 )(
467 points_1 in vec(arb_point(), num_points),
468 points_2 in vec(arb_point(), num_points),
469 mapping in arb_queries_inner(num_points, num_cols, num_queries)
470 )(
471 queries_1 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_1[*point_idx])).collect::<Vec<_>>(),
472 queries_2 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_2[*point_idx])).collect::<Vec<_>>(),
473 ) -> (
474 Vec<MyQuery<Fp>>,
475 Vec<MyQuery<Fp>>
476 ) {
477 (
478 queries_1,
479 queries_2,
480 )
481 }
482 }
483
484 proptest! {
485 #[test]
486 fn test_intermediate_sets(
487 (queries_1, queries_2) in compare_queries(8, 8, 16)
488 ) {
489 let (commitment_data, _point_sets) = construct_intermediate_sets(queries_1);
490 let set_indices = commitment_data.iter().map(|data| data.set_index).collect::<Vec<_>>();
491 let point_indices = commitment_data.iter().map(|data| data.point_indices.clone()).collect::<Vec<_>>();
492
493 let (new_commitment_data, _new_point_sets) = construct_intermediate_sets(queries_2);
496 let new_set_indices = new_commitment_data.iter().map(|data| data.set_index).collect::<Vec<_>>();
497 let new_point_indices = new_commitment_data.iter().map(|data| data.point_indices.clone()).collect::<Vec<_>>();
498
499 assert_eq!(set_indices, new_set_indices);
500 assert_eq!(point_indices, new_point_indices);
501 }
502 }
503}