1#![cfg_attr(not(feature = "std"), no_std)]
2#![deny(unused_import_braces, unused_qualifications, trivial_casts)]
4#![deny(trivial_numeric_casts, variant_size_differences)]
5#![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)]
6#![deny(unused_attributes, unused_mut)]
7#![deny(missing_docs)]
8#![deny(unused_imports)]
9#![deny(renamed_and_removed_lints, stable_features, unused_allocation)]
10#![deny(unused_comparisons, bare_trait_objects, unused_must_use)]
11#![forbid(unsafe_code)]
12#![doc = include_str!("../README.md")]
13
14#[allow(unused)]
15#[macro_use]
16extern crate derivative;
17#[macro_use]
18extern crate ark_std;
19
20use ark_ff::{Field, PrimeField};
21pub use ark_poly::{DenseUVPolynomial, Polynomial};
22use ark_std::{
23 collections::{BTreeMap, BTreeSet},
24 fmt::Debug,
25 hash::Hash,
26 iter::FromIterator,
27 rand::RngCore,
28};
29#[cfg(not(feature = "std"))]
30use ark_std::{
31 string::{String, ToString},
32 vec::Vec,
33};
34
35pub mod data_structures;
37pub use data_structures::*;
38
39pub(crate) mod utils;
41
42#[cfg(feature = "r1cs")]
44mod constraints;
45#[cfg(feature = "r1cs")]
46pub use constraints::*;
47
48pub mod error;
50use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
51pub use error::*;
52
53pub mod marlin;
59
60pub mod optional_rng;
63
64#[cfg(not(feature = "std"))]
65macro_rules! eprintln {
66 () => {};
67 ($($arg: tt)*) => {};
68}
69#[cfg(all(test, not(feature = "std")))]
70macro_rules! println {
71 () => {};
72 ($($arg: tt)*) => {};
73}
74pub mod kzg10;
78
79pub use marlin::marlin_pc;
86
87pub mod sonic_pc;
98
99pub mod ipa_pc;
105
106pub mod multilinear_pc;
113
114use ark_crypto_primitives::sponge::{CryptographicSponge, FieldElementSize};
115pub use marlin::marlin_pst13_pc;
122
123pub mod streaming_kzg;
130
131pub mod linear_codes;
136
137pub mod hyrax;
146
147pub type QuerySet<T> = BTreeSet<(String, (String, T))>;
153
154pub type Evaluations<T, F> = BTreeMap<(String, T), F>;
159
160pub trait PolynomialCommitment<F: PrimeField, P: Polynomial<F>>: Sized {
165 type UniversalParams: PCUniversalParams;
168 type CommitterKey: PCCommitterKey;
171 type VerifierKey: PCVerifierKey;
173 type Commitment: PCCommitment + Default;
175 type CommitmentState: PCCommitmentState;
180 type Proof: Clone;
182 type BatchProof: Clone
184 + From<Vec<Self::Proof>>
185 + Into<Vec<Self::Proof>>
186 + CanonicalSerialize
187 + CanonicalDeserialize;
188 type Error: ark_std::error::Error + From<Error>;
190
191 fn setup<R: RngCore>(
195 max_degree: usize,
196 num_vars: Option<usize>,
197 rng: &mut R,
198 ) -> Result<Self::UniversalParams, Self::Error>;
199
200 fn trim(
203 pp: &Self::UniversalParams,
204 supported_degree: usize,
205 supported_hiding_bound: usize,
206 enforced_degree_bounds: Option<&[usize]>,
207 ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error>;
208
209 fn commit<'a>(
219 ck: &Self::CommitterKey,
220 polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F, P>>,
221 rng: Option<&mut dyn RngCore>,
222 ) -> Result<
223 (
224 Vec<LabeledCommitment<Self::Commitment>>,
225 Vec<Self::CommitmentState>,
226 ),
227 Self::Error,
228 >
229 where
230 P: 'a;
231
232 fn open<'a>(
234 ck: &Self::CommitterKey,
235 labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F, P>>,
236 commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>,
237 point: &'a P::Point,
238 sponge: &mut impl CryptographicSponge,
239 states: impl IntoIterator<Item = &'a Self::CommitmentState>,
240 rng: Option<&mut dyn RngCore>,
241 ) -> Result<Self::Proof, Self::Error>
242 where
243 P: 'a,
244 Self::CommitmentState: 'a,
245 Self::Commitment: 'a;
246
247 fn check<'a>(
249 vk: &Self::VerifierKey,
250 commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>,
251 point: &'a P::Point,
252 values: impl IntoIterator<Item = F>,
253 proof: &Self::Proof,
254 sponge: &mut impl CryptographicSponge,
255 rng: Option<&mut dyn RngCore>,
256 ) -> Result<bool, Self::Error>
257 where
258 Self::Commitment: 'a;
259
260 fn batch_open<'a>(
270 ck: &Self::CommitterKey,
271 labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F, P>>,
272 commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>,
273 query_set: &QuerySet<P::Point>,
274 sponge: &mut impl CryptographicSponge,
275 states: impl IntoIterator<Item = &'a Self::CommitmentState>,
276 rng: Option<&mut dyn RngCore>,
277 ) -> Result<Self::BatchProof, Self::Error>
278 where
279 P: 'a,
280 Self::CommitmentState: 'a,
281 Self::Commitment: 'a,
282 {
283 let rng = &mut optional_rng::OptionalRng(rng);
288 let poly_st_comm: BTreeMap<_, _> = labeled_polynomials
289 .into_iter()
290 .zip(states)
291 .zip(commitments.into_iter())
292 .map(|((poly, st), comm)| (poly.label(), (poly, st, comm)))
293 .collect();
294
295 let open_time = start_timer!(|| format!(
296 "Opening {} polynomials at query set of size {}",
297 poly_st_comm.len(),
298 query_set.len(),
299 ));
300
301 let mut query_to_labels_map = BTreeMap::new();
302
303 for (label, (point_label, point)) in query_set.iter() {
307 let labels = query_to_labels_map
312 .entry(point_label)
313 .or_insert((point, BTreeSet::new()));
314 labels.1.insert(label);
315 }
316
317 let mut proofs = Vec::new();
318 for (_point_label, (point, labels)) in query_to_labels_map.into_iter() {
319 let mut query_polys: Vec<&'a LabeledPolynomial<_, _>> = Vec::new();
320 let mut query_states: Vec<&'a Self::CommitmentState> = Vec::new();
321 let mut query_comms: Vec<&'a LabeledCommitment<Self::Commitment>> = Vec::new();
322
323 for label in labels {
327 let (polynomial, state, comm) =
328 poly_st_comm.get(label).ok_or(Error::MissingPolynomial {
329 label: label.to_string(),
330 })?;
331
332 query_polys.push(polynomial);
333 query_states.push(state);
334 query_comms.push(comm);
335 }
336
337 let proof_time = start_timer!(|| "Creating proof");
338
339 let proof = Self::open(
342 ck,
343 query_polys,
344 query_comms,
345 &point,
346 sponge,
347 query_states,
348 Some(rng),
349 )?;
350
351 end_timer!(proof_time);
352
353 proofs.push(proof);
354 }
355 end_timer!(open_time);
356
357 Ok(proofs.into())
358 }
359
360 fn batch_check<'a, R: RngCore>(
374 vk: &Self::VerifierKey,
375 commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>,
376 query_set: &QuerySet<P::Point>,
377 evaluations: &Evaluations<P::Point, F>,
378 proof: &Self::BatchProof,
379 sponge: &mut impl CryptographicSponge,
380 rng: &mut R,
381 ) -> Result<bool, Self::Error>
382 where
383 Self::Commitment: 'a,
384 {
385 let commitments: BTreeMap<_, _> = commitments.into_iter().map(|c| (c.label(), c)).collect();
390 let mut query_to_labels_map = BTreeMap::new();
391
392 for (label, (point_label, point)) in query_set.iter() {
396 let labels = query_to_labels_map
401 .entry(point_label)
402 .or_insert((point, BTreeSet::new()));
403 labels.1.insert(label);
404 }
405
406 let proofs: Vec<_> = proof.clone().into();
409 assert_eq!(proofs.len(), query_to_labels_map.len());
410
411 let mut result = true;
412 for ((_point_label, (point, labels)), proof) in query_to_labels_map.into_iter().zip(proofs)
413 {
414 let mut comms: Vec<&'_ LabeledCommitment<_>> = Vec::new();
417 let mut values = Vec::new();
418 for label in labels.into_iter() {
419 let commitment = commitments.get(label).ok_or(Error::MissingPolynomial {
420 label: label.to_string(),
421 })?;
422
423 let v_i = evaluations.get(&(label.clone(), point.clone())).ok_or(
424 Error::MissingEvaluation {
425 label: label.to_string(),
426 },
427 )?;
428
429 comms.push(commitment);
430 values.push(*v_i);
431 }
432
433 let proof_time = start_timer!(|| "Checking per-query proof");
434
435 result &= Self::check(vk, comms, &point, values, &proof, sponge, Some(rng))?;
438 end_timer!(proof_time);
439 }
440 Ok(result)
441 }
442
443 fn open_combinations<'a>(
446 ck: &Self::CommitterKey,
447 linear_combinations: impl IntoIterator<Item = &'a LinearCombination<F>>,
448 polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F, P>>,
449 commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>,
450 query_set: &QuerySet<P::Point>,
451 sponge: &mut impl CryptographicSponge,
452 states: impl IntoIterator<Item = &'a Self::CommitmentState>,
453 rng: Option<&mut dyn RngCore>,
454 ) -> Result<BatchLCProof<F, Self::BatchProof>, Self::Error>
455 where
456 Self::CommitmentState: 'a,
457 Self::Commitment: 'a,
458 P: 'a,
459 {
460 let linear_combinations: Vec<_> = linear_combinations.into_iter().collect();
463 let polynomials: Vec<_> = polynomials.into_iter().collect();
464
465 let poly_query_set =
468 lc_query_set_to_poly_query_set(linear_combinations.iter().copied(), query_set);
469 let poly_evals = evaluate_query_set(polynomials.iter().copied(), &poly_query_set);
470
471 let proof = Self::batch_open(
473 ck,
474 polynomials,
475 commitments,
476 &poly_query_set,
477 sponge,
478 states,
479 rng,
480 )?;
481 Ok(BatchLCProof {
482 proof,
483 evals: Some(poly_evals.values().copied().collect()),
484 })
485 }
486
487 fn check_combinations<'a, R: RngCore>(
490 vk: &Self::VerifierKey,
491 linear_combinations: impl IntoIterator<Item = &'a LinearCombination<F>>,
492 commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>,
493 eqn_query_set: &QuerySet<P::Point>,
494 eqn_evaluations: &Evaluations<P::Point, F>,
495 proof: &BatchLCProof<F, Self::BatchProof>,
496 sponge: &mut impl CryptographicSponge,
497 rng: &mut R,
498 ) -> Result<bool, Self::Error>
499 where
500 Self::Commitment: 'a,
501 {
502 let BatchLCProof { proof, evals } = proof;
507 let lc_s = BTreeMap::from_iter(linear_combinations.into_iter().map(|lc| (lc.label(), lc)));
508
509 let poly_query_set = lc_query_set_to_poly_query_set(lc_s.values().copied(), eqn_query_set);
512 let sorted_by_poly_and_query_label: BTreeSet<_> = poly_query_set
513 .clone()
514 .into_iter()
515 .map(|(poly_label, v)| ((poly_label.clone(), v.1), v.0))
516 .collect();
517
518 let poly_evals = Evaluations::from_iter(
519 sorted_by_poly_and_query_label
520 .into_iter()
521 .zip(evals.clone().unwrap())
522 .map(|(((poly_label, point), _query_label), eval)| ((poly_label, point), eval)),
523 );
524
525 for &(ref lc_label, (_, ref point)) in eqn_query_set {
526 if let Some(lc) = lc_s.get(lc_label) {
527 let claimed_rhs = *eqn_evaluations
528 .get(&(lc_label.clone(), point.clone()))
529 .ok_or(Error::MissingEvaluation {
530 label: lc_label.to_string(),
531 })?;
532
533 let mut actual_rhs = F::zero();
534
535 for (coeff, label) in lc.iter() {
539 let eval = match label {
540 LCTerm::One => F::one(),
541 LCTerm::PolyLabel(l) => *poly_evals
542 .get(&(l.clone().into(), point.clone()))
543 .ok_or(Error::MissingEvaluation {
544 label: format!("{}-{:?}", l.clone(), point.clone()),
545 })?,
546 };
547
548 actual_rhs += &(*coeff * eval);
549 }
550
551 if claimed_rhs != actual_rhs {
553 eprintln!("Claimed evaluation of {} is incorrect", lc.label());
554 return Ok(false);
555 }
556 }
557 }
558
559 let pc_result = Self::batch_check(
562 vk,
563 commitments,
564 &poly_query_set,
565 &poly_evals,
566 proof,
567 sponge,
568 rng,
569 )?;
570 if !pc_result {
571 eprintln!("Evaluation proofs failed to verify");
572 return Ok(false);
573 }
574
575 Ok(true)
576 }
577}
578
579pub const CHALLENGE_SIZE: FieldElementSize = FieldElementSize::Truncated(128);
581
582pub fn evaluate_query_set<'a, F, P, T>(
584 polys: impl IntoIterator<Item = &'a LabeledPolynomial<F, P>>,
585 query_set: &QuerySet<T>,
586) -> Evaluations<T, F>
587where
588 F: Field,
589 P: 'a + Polynomial<F, Point = T>,
590 T: Clone + Debug + Hash + Ord + Sync,
591{
592 let polys = BTreeMap::from_iter(polys.into_iter().map(|p| (p.label(), p)));
593 let mut evaluations = Evaluations::new();
594 for (label, (_, point)) in query_set {
595 let poly = polys
596 .get(label)
597 .expect("polynomial in evaluated lc is not found");
598 let eval = poly.evaluate(&point);
599 evaluations.insert((label.clone(), point.clone()), eval);
600 }
601 evaluations
602}
603
604fn lc_query_set_to_poly_query_set<'a, F: Field, T: Clone + Ord>(
624 linear_combinations: impl IntoIterator<Item = &'a LinearCombination<F>>,
625 query_set: &QuerySet<T>,
626) -> QuerySet<T> {
627 let mut poly_query_set = QuerySet::<T>::new();
628 let lc_s = linear_combinations.into_iter().map(|lc| (lc.label(), lc));
629 let linear_combinations = BTreeMap::from_iter(lc_s);
630 for (lc_label, (point_label, point)) in query_set {
631 if let Some(lc) = linear_combinations.get(lc_label) {
632 for (_, poly_label) in lc.iter().filter(|(_, l)| !l.is_one()) {
633 if let LCTerm::PolyLabel(l) = poly_label {
634 poly_query_set.insert((l.into(), (point_label.clone(), point.clone())));
635 }
636 }
637 }
638 }
639 poly_query_set
640}
641
642#[cfg(test)]
643pub mod tests {
644 #![allow(missing_docs)]
645 use crate::*;
646 use ark_crypto_primitives::sponge::poseidon::{PoseidonConfig, PoseidonSponge};
647 use ark_std::rand::{
648 distributions::{Distribution, Uniform},
649 Rng, SeedableRng,
650 };
651 use ark_std::test_rng;
652 use rand_chacha::ChaCha20Rng;
653
654 struct TestInfo<F: PrimeField, P: Polynomial<F>, S: CryptographicSponge> {
655 num_iters: usize,
656 max_degree: Option<usize>,
657 supported_degree: Option<usize>,
658 num_vars: Option<usize>,
659 num_polynomials: usize,
660 enforce_degree_bounds: bool,
661 max_num_queries: usize,
662 num_equations: Option<usize>,
663 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
664 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
665 sponge: fn() -> S,
666 }
667
668 pub fn bad_degree_bound_test<F, P, PC, S>(
669 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
670 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
671 sponge: fn() -> S,
672 ) -> Result<(), PC::Error>
673 where
674 F: PrimeField,
675 P: Polynomial<F>,
676 PC: PolynomialCommitment<F, P>,
677 S: CryptographicSponge,
678 {
679 let sponge = sponge();
680
681 let rng = &mut ChaCha20Rng::from_rng(test_rng()).unwrap();
682 let max_degree = 100;
683 let pp = PC::setup(max_degree, None, rng)?;
684 for _ in 0..10 {
685 let supported_degree = Uniform::from(1..=max_degree).sample(rng);
686 assert!(
687 max_degree >= supported_degree,
688 "max_degree < supported_degree"
689 );
690
691 let mut labels = Vec::new();
692 let mut polynomials = Vec::new();
693 let mut degree_bounds = Vec::new();
694
695 for i in 0..10 {
696 let label = format!("Test{}", i);
697 labels.push(label.clone());
698 let degree_bound = 1usize;
699 let hiding_bound = Some(1);
700 degree_bounds.push(degree_bound);
701
702 polynomials.push(LabeledPolynomial::new(
703 label,
704 rand_poly(supported_degree, None, rng),
705 Some(degree_bound),
706 hiding_bound,
707 ));
708 }
709
710 let supported_hiding_bound = polynomials
711 .iter()
712 .map(|p| p.hiding_bound().unwrap_or(0))
713 .max()
714 .unwrap_or(0);
715 println!("supported degree: {:?}", supported_degree);
716 println!("supported hiding bound: {:?}", supported_hiding_bound);
717 let (ck, vk) = PC::trim(
718 &pp,
719 supported_degree,
720 supported_hiding_bound,
721 Some(degree_bounds.as_slice()),
722 )?;
723 println!("Trimmed");
724
725 let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?;
726
727 let mut query_set = QuerySet::new();
728 let mut values = Evaluations::new();
729 let point = rand_point(None, rng);
730 for (i, label) in labels.iter().enumerate() {
731 query_set.insert((label.clone(), (format!("{}", i), point.clone())));
732 let value = polynomials[i].evaluate(&point);
733 values.insert((label.clone(), point.clone()), value);
734 }
735 println!("Generated query set");
736
737 let proof = PC::batch_open(
738 &ck,
739 &polynomials,
740 &comms,
741 &query_set,
742 &mut (sponge.clone()),
743 &rands,
744 Some(rng),
745 )?;
746 let result = PC::batch_check(
747 &vk,
748 &comms,
749 &query_set,
750 &values,
751 &proof,
752 &mut (sponge.clone()),
753 rng,
754 )?;
755 assert!(result, "proof was incorrect, Query set: {:#?}", query_set);
756 }
757
758 Ok(())
759 }
760
761 fn test_template<F, P, PC, S>(info: TestInfo<F, P, S>) -> Result<(), PC::Error>
762 where
763 F: PrimeField,
764 P: Polynomial<F>,
765 PC: PolynomialCommitment<F, P>,
766 S: CryptographicSponge,
767 {
768 let TestInfo {
769 num_iters,
770 max_degree,
771 supported_degree,
772 num_vars,
773 num_polynomials,
774 enforce_degree_bounds,
775 max_num_queries,
776 num_equations: _,
777 rand_poly,
778 rand_point,
779 sponge,
780 } = info;
781
782 let sponge = sponge();
783
784 let rng = &mut ChaCha20Rng::from_rng(test_rng()).unwrap();
785 let max_degree = match num_vars {
787 Some(_) => max_degree.unwrap_or(Uniform::from(2..=10).sample(rng)),
788 None => max_degree.unwrap_or(Uniform::from(2..=64).sample(rng)),
789 };
790 let pp = PC::setup(max_degree, num_vars, rng)?;
791
792 for _ in 0..num_iters {
793 let supported_degree =
794 supported_degree.unwrap_or(Uniform::from(1..=max_degree).sample(rng));
795 assert!(
796 max_degree >= supported_degree,
797 "max_degree < supported_degree"
798 );
799 let mut polynomials: Vec<LabeledPolynomial<F, P>> = Vec::new();
800 let mut degree_bounds = if enforce_degree_bounds {
801 Some(Vec::new())
802 } else {
803 None
804 };
805
806 let mut labels = Vec::new();
807 println!("Sampled supported degree");
808
809 let num_points_in_query_set = Uniform::from(1..=max_num_queries).sample(rng);
811 for i in 0..num_polynomials {
812 let label = format!("Test{}", i);
813 labels.push(label.clone());
814 let degree = Uniform::from(1..=supported_degree).sample(rng);
815 let degree_bound = if let Some(degree_bounds) = &mut degree_bounds {
816 let range = Uniform::from(degree..=supported_degree);
817 let degree_bound = range.sample(rng);
818 degree_bounds.push(degree_bound);
819 Some(degree_bound)
820 } else {
821 None
822 };
823
824 let hiding_bound = if num_points_in_query_set >= degree {
825 Some(degree)
826 } else {
827 Some(num_points_in_query_set)
828 };
829
830 polynomials.push(LabeledPolynomial::new(
831 label,
832 rand_poly(degree, num_vars, rng).into(),
833 degree_bound,
834 hiding_bound,
835 ))
836 }
837 let supported_hiding_bound = polynomials
838 .iter()
839 .map(|p| p.hiding_bound().unwrap_or(0))
840 .max()
841 .unwrap_or(0);
842 println!("supported degree: {:?}", supported_degree);
843 println!("supported hiding bound: {:?}", supported_hiding_bound);
844 println!("num_points_in_query_set: {:?}", num_points_in_query_set);
845 let (ck, vk) = PC::trim(
846 &pp,
847 supported_degree,
848 supported_hiding_bound,
849 degree_bounds.as_ref().map(|s| s.as_slice()),
850 )?;
851 println!("Trimmed");
852
853 let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?;
854
855 let mut query_set = QuerySet::new();
857 let mut values = Evaluations::new();
858 for _ in 0..num_points_in_query_set {
859 let point = rand_point(num_vars, rng);
860 for (i, label) in labels.iter().enumerate() {
861 query_set.insert((label.clone(), (format!("{}", i), point.clone())));
862 let value = polynomials[i].evaluate(&point);
863 values.insert((label.clone(), point.clone()), value);
864 }
865 }
866 println!("Generated query set");
867
868 let proof = PC::batch_open(
869 &ck,
870 &polynomials,
871 &comms,
872 &query_set,
873 &mut (sponge.clone()),
874 &rands,
875 Some(rng),
876 )?;
877 let result = PC::batch_check(
878 &vk,
879 &comms,
880 &query_set,
881 &values,
882 &proof,
883 &mut (sponge.clone()),
884 rng,
885 )?;
886 if !result {
887 println!(
888 "Failed with {} polynomials, num_points_in_query_set: {:?}",
889 num_polynomials, num_points_in_query_set
890 );
891 println!("Degree of polynomials:",);
892 for poly in polynomials {
893 println!("Degree: {:?}", poly.degree());
894 }
895 }
896 assert!(result, "proof was incorrect, Query set: {:#?}", query_set);
897 }
898
899 Ok(())
900 }
901
902 fn equation_test_template<F, P, PC, S>(info: TestInfo<F, P, S>) -> Result<(), PC::Error>
903 where
904 F: PrimeField,
905 P: Polynomial<F>,
906 PC: PolynomialCommitment<F, P>,
907 S: CryptographicSponge,
908 {
909 let TestInfo {
910 num_iters,
911 max_degree,
912 supported_degree,
913 num_vars,
914 num_polynomials,
915 enforce_degree_bounds,
916 max_num_queries,
917 num_equations,
918 rand_poly,
919 rand_point,
920 sponge,
921 } = info;
922
923 let sponge = sponge();
924
925 let rng = &mut ChaCha20Rng::from_rng(test_rng()).unwrap();
926 let max_degree = match num_vars {
928 Some(_) => max_degree.unwrap_or(Uniform::from(2..=10).sample(rng)),
929 None => max_degree.unwrap_or(Uniform::from(2..=64).sample(rng)),
930 };
931 let pp = PC::setup(max_degree, num_vars, rng)?;
932
933 for _ in 0..num_iters {
934 let supported_degree =
935 supported_degree.unwrap_or(Uniform::from(1..=max_degree).sample(rng));
936 assert!(
937 max_degree >= supported_degree,
938 "max_degree < supported_degree"
939 );
940 let mut polynomials = Vec::new();
941 let mut degree_bounds = if enforce_degree_bounds {
942 Some(Vec::new())
943 } else {
944 None
945 };
946
947 let mut labels = Vec::new();
948 println!("Sampled supported degree");
949
950 let num_points_in_query_set = Uniform::from(1..=max_num_queries).sample(rng);
952 for i in 0..num_polynomials {
953 let label = format!("Test{}", i);
954 labels.push(label.clone());
955 let degree = Uniform::from(1..=supported_degree).sample(rng);
956 let degree_bound = if let Some(degree_bounds) = &mut degree_bounds {
957 if rng.gen() {
958 let range = Uniform::from(degree..=supported_degree);
959 let degree_bound = range.sample(rng);
960 degree_bounds.push(degree_bound);
961 Some(degree_bound)
962 } else {
963 None
964 }
965 } else {
966 None
967 };
968
969 let hiding_bound = if num_points_in_query_set >= degree {
970 Some(degree)
971 } else {
972 Some(num_points_in_query_set)
973 };
974 println!("Hiding bound: {:?}", hiding_bound);
975
976 polynomials.push(LabeledPolynomial::new(
977 label,
978 rand_poly(degree, num_vars, rng),
979 degree_bound,
980 hiding_bound,
981 ))
982 }
983 println!("supported degree: {:?}", supported_degree);
984 println!("num_points_in_query_set: {:?}", num_points_in_query_set);
985 println!("{:?}", degree_bounds);
986 println!("{}", num_polynomials);
987 println!("{}", enforce_degree_bounds);
988
989 let (ck, vk) = PC::trim(
990 &pp,
991 supported_degree,
992 supported_degree,
993 degree_bounds.as_ref().map(|s| s.as_slice()),
994 )?;
995 println!("Trimmed");
996
997 let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?;
998
999 let mut linear_combinations = Vec::new();
1001 let mut query_set = QuerySet::new();
1002 let mut values = Evaluations::new();
1003 for i in 0..num_points_in_query_set {
1004 let point = rand_point(num_vars, rng);
1005 for j in 0..num_equations.unwrap() {
1006 let label = format!("query {} eqn {}", i, j);
1007 let mut lc = LinearCombination::empty(label.clone());
1008
1009 let mut value = F::zero();
1010 let should_have_degree_bounds: bool = rng.gen();
1011 for (k, label) in labels.iter().enumerate() {
1012 if should_have_degree_bounds {
1013 value += &polynomials[k].evaluate(&point);
1014 lc.push((F::one(), label.to_string().into()));
1015 break;
1016 } else {
1017 let poly = &polynomials[k];
1018 if poly.degree_bound().is_some() {
1019 continue;
1020 } else {
1021 assert!(poly.degree_bound().is_none());
1022 let coeff = F::rand(rng);
1023 value += &(coeff * poly.evaluate(&point));
1024 lc.push((coeff, label.to_string().into()));
1025 }
1026 }
1027 }
1028 values.insert((label.clone(), point.clone()), value);
1029 if !lc.is_empty() {
1030 linear_combinations.push(lc);
1031 query_set.insert((label.clone(), (format!("{}", i), point.clone())));
1033 }
1034 }
1035 }
1036 if linear_combinations.is_empty() {
1037 continue;
1038 }
1039 println!("Generated query set");
1040 println!("Linear combinations: {:?}", linear_combinations);
1041
1042 let proof = PC::open_combinations(
1043 &ck,
1044 &linear_combinations,
1045 &polynomials,
1046 &comms,
1047 &query_set,
1048 &mut (sponge.clone()),
1049 &rands,
1050 Some(rng),
1051 )?;
1052 println!("Generated proof");
1053 let result = PC::check_combinations(
1054 &vk,
1055 &linear_combinations,
1056 &comms,
1057 &query_set,
1058 &values,
1059 &proof,
1060 &mut (sponge.clone()),
1061 rng,
1062 )?;
1063 if !result {
1064 println!(
1065 "Failed with {} polynomials, num_points_in_query_set: {:?}",
1066 num_polynomials, num_points_in_query_set
1067 );
1068 println!("Degree of polynomials:",);
1069 for poly in polynomials {
1070 println!("Degree: {:?}", poly.degree());
1071 }
1072 }
1073 assert!(
1074 result,
1075 "proof was incorrect, equations: {:#?}",
1076 linear_combinations
1077 );
1078 }
1079
1080 Ok(())
1081 }
1082
1083 pub fn single_poly_test<F, P, PC, S>(
1084 num_vars: Option<usize>,
1085 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1086 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1087 sponge: fn() -> S,
1088 ) -> Result<(), PC::Error>
1089 where
1090 F: PrimeField,
1091 P: Polynomial<F>,
1092 PC: PolynomialCommitment<F, P>,
1093 S: CryptographicSponge,
1094 {
1095 let info = TestInfo {
1096 num_iters: 100,
1097 max_degree: None,
1098 supported_degree: None,
1099 num_vars,
1100 num_polynomials: 1,
1101 enforce_degree_bounds: false,
1102 max_num_queries: 1,
1103 num_equations: None,
1104 rand_poly,
1105 rand_point,
1106 sponge,
1107 };
1108 test_template::<F, P, PC, S>(info)
1109 }
1110
1111 pub fn linear_poly_degree_bound_test<F, P, PC, S>(
1112 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1113 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1114 sponge: fn() -> S,
1115 ) -> Result<(), PC::Error>
1116 where
1117 F: PrimeField,
1118 P: Polynomial<F>,
1119 PC: PolynomialCommitment<F, P>,
1120 S: CryptographicSponge,
1121 {
1122 let info = TestInfo {
1123 num_iters: 100,
1124 max_degree: Some(2),
1125 supported_degree: Some(1),
1126 num_vars: None,
1127 num_polynomials: 1,
1128 enforce_degree_bounds: true,
1129 max_num_queries: 1,
1130 num_equations: None,
1131 rand_poly,
1132 rand_point,
1133 sponge,
1134 };
1135 test_template::<F, P, PC, S>(info)
1136 }
1137
1138 pub fn single_poly_degree_bound_test<F, P, PC, S>(
1139 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1140 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1141 sponge: fn() -> S,
1142 ) -> Result<(), PC::Error>
1143 where
1144 F: PrimeField,
1145 P: Polynomial<F>,
1146 PC: PolynomialCommitment<F, P>,
1147 S: CryptographicSponge,
1148 {
1149 let info = TestInfo {
1150 num_iters: 100,
1151 max_degree: None,
1152 supported_degree: None,
1153 num_vars: None,
1154 num_polynomials: 1,
1155 enforce_degree_bounds: true,
1156 max_num_queries: 1,
1157 num_equations: None,
1158 rand_poly,
1159 rand_point,
1160 sponge,
1161 };
1162 test_template::<F, P, PC, S>(info)
1163 }
1164
1165 pub fn quadratic_poly_degree_bound_multiple_queries_test<F, P, PC, S>(
1166 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1167 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1168 sponge: fn() -> S,
1169 ) -> Result<(), PC::Error>
1170 where
1171 F: PrimeField,
1172 P: Polynomial<F>,
1173 PC: PolynomialCommitment<F, P>,
1174 S: CryptographicSponge,
1175 {
1176 let info = TestInfo {
1177 num_iters: 100,
1178 max_degree: Some(3),
1179 supported_degree: Some(2),
1180 num_vars: None,
1181 num_polynomials: 1,
1182 enforce_degree_bounds: true,
1183 max_num_queries: 2,
1184 num_equations: None,
1185 rand_poly,
1186 rand_point,
1187 sponge,
1188 };
1189 test_template::<F, P, PC, S>(info)
1190 }
1191
1192 pub fn single_poly_degree_bound_multiple_queries_test<F, P, PC, S>(
1193 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1194 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1195 sponge: fn() -> S,
1196 ) -> Result<(), PC::Error>
1197 where
1198 F: PrimeField,
1199 P: Polynomial<F>,
1200 PC: PolynomialCommitment<F, P>,
1201 S: CryptographicSponge,
1202 {
1203 let info = TestInfo {
1204 num_iters: 100,
1205 max_degree: None,
1206 supported_degree: None,
1207 num_vars: None,
1208 num_polynomials: 1,
1209 enforce_degree_bounds: true,
1210 max_num_queries: 2,
1211 num_equations: None,
1212 rand_poly,
1213 rand_point,
1214 sponge,
1215 };
1216 test_template::<F, P, PC, S>(info)
1217 }
1218
1219 pub fn two_polys_degree_bound_single_query_test<F, P, PC, S>(
1220 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1221 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1222 sponge: fn() -> S,
1223 ) -> Result<(), PC::Error>
1224 where
1225 F: PrimeField,
1226 P: Polynomial<F>,
1227 PC: PolynomialCommitment<F, P>,
1228 S: CryptographicSponge,
1229 {
1230 let info = TestInfo {
1231 num_iters: 100,
1232 max_degree: None,
1233 supported_degree: None,
1234 num_vars: None,
1235 num_polynomials: 2,
1236 enforce_degree_bounds: true,
1237 max_num_queries: 1,
1238 num_equations: None,
1239 rand_poly,
1240 rand_point,
1241 sponge,
1242 };
1243 test_template::<F, P, PC, S>(info)
1244 }
1245
1246 pub fn full_end_to_end_test<F, P, PC, S>(
1247 num_vars: Option<usize>,
1248 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1249 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1250 sponge: fn() -> S,
1251 ) -> Result<(), PC::Error>
1252 where
1253 F: PrimeField,
1254 P: Polynomial<F>,
1255 PC: PolynomialCommitment<F, P>,
1256 S: CryptographicSponge,
1257 {
1258 let info = TestInfo {
1259 num_iters: 100,
1260 max_degree: None,
1261 supported_degree: None,
1262 num_vars,
1263 num_polynomials: 10,
1264 enforce_degree_bounds: true,
1265 max_num_queries: 5,
1266 num_equations: None,
1267 rand_poly,
1268 rand_point,
1269 sponge,
1270 };
1271 test_template::<F, P, PC, S>(info)
1272 }
1273
1274 pub fn full_end_to_end_equation_test<F, P, PC, S>(
1275 num_vars: Option<usize>,
1276 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1277 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1278 sponge: fn() -> S,
1279 ) -> Result<(), PC::Error>
1280 where
1281 F: PrimeField,
1282 P: Polynomial<F>,
1283 PC: PolynomialCommitment<F, P>,
1284 S: CryptographicSponge,
1285 {
1286 let info = TestInfo {
1287 num_iters: 100,
1288 max_degree: None,
1289 supported_degree: None,
1290 num_vars,
1291 num_polynomials: 10,
1292 enforce_degree_bounds: true,
1293 max_num_queries: 5,
1294 num_equations: Some(10),
1295 rand_poly,
1296 rand_point,
1297 sponge,
1298 };
1299 equation_test_template::<F, P, PC, S>(info)
1300 }
1301
1302 pub fn single_equation_test<F, P, PC, S>(
1303 num_vars: Option<usize>,
1304 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1305 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1306 sponge: fn() -> S,
1307 ) -> Result<(), PC::Error>
1308 where
1309 F: PrimeField,
1310 P: Polynomial<F>,
1311 PC: PolynomialCommitment<F, P>,
1312 S: CryptographicSponge,
1313 {
1314 let info = TestInfo {
1315 num_iters: 100,
1316 max_degree: None,
1317 supported_degree: None,
1318 num_vars,
1319 num_polynomials: 1,
1320 enforce_degree_bounds: false,
1321 max_num_queries: 1,
1322 num_equations: Some(1),
1323 rand_poly,
1324 rand_point,
1325 sponge,
1326 };
1327 equation_test_template::<F, P, PC, S>(info)
1328 }
1329
1330 pub fn two_equation_test<F, P, PC, S>(
1331 num_vars: Option<usize>,
1332 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1333 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1334 sponge: fn() -> S,
1335 ) -> Result<(), PC::Error>
1336 where
1337 F: PrimeField,
1338 P: Polynomial<F>,
1339 PC: PolynomialCommitment<F, P>,
1340 S: CryptographicSponge,
1341 {
1342 let info = TestInfo {
1343 num_iters: 100,
1344 max_degree: None,
1345 supported_degree: None,
1346 num_vars,
1347 num_polynomials: 2,
1348 enforce_degree_bounds: false,
1349 max_num_queries: 1,
1350 num_equations: Some(2),
1351 rand_poly,
1352 rand_point,
1353 sponge,
1354 };
1355 equation_test_template::<F, P, PC, S>(info)
1356 }
1357
1358 pub fn two_equation_degree_bound_test<F, P, PC, S>(
1359 rand_poly: fn(usize, Option<usize>, &mut ChaCha20Rng) -> P,
1360 rand_point: fn(Option<usize>, &mut ChaCha20Rng) -> P::Point,
1361 sponge: fn() -> S,
1362 ) -> Result<(), PC::Error>
1363 where
1364 F: PrimeField,
1365 P: Polynomial<F>,
1366 PC: PolynomialCommitment<F, P>,
1367 S: CryptographicSponge,
1368 {
1369 let info = TestInfo {
1370 num_iters: 100,
1371 max_degree: None,
1372 supported_degree: None,
1373 num_vars: None,
1374 num_polynomials: 2,
1375 enforce_degree_bounds: true,
1376 max_num_queries: 1,
1377 num_equations: Some(2),
1378 rand_poly,
1379 rand_point,
1380 sponge,
1381 };
1382 equation_test_template::<F, P, PC, S>(info)
1383 }
1384
1385 pub(crate) fn poseidon_sponge_for_test<F: PrimeField>() -> PoseidonSponge<F> {
1386 PoseidonSponge::new(&poseidon_parameters_for_test())
1387 }
1388
1389 pub(crate) fn poseidon_parameters_for_test<F: PrimeField>() -> PoseidonConfig<F> {
1394 let full_rounds = 8;
1395 let partial_rounds = 31;
1396 let alpha = 17;
1397
1398 let mds = vec![
1399 vec![F::one(), F::zero(), F::one()],
1400 vec![F::one(), F::one(), F::zero()],
1401 vec![F::zero(), F::one(), F::one()],
1402 ];
1403
1404 let mut ark = Vec::new();
1405 let mut ark_rng = test_rng();
1406
1407 for _ in 0..(full_rounds + partial_rounds) {
1408 let mut res = Vec::new();
1409
1410 for _ in 0..3 {
1411 res.push(F::rand(&mut ark_rng));
1412 }
1413 ark.push(res);
1414 }
1415 PoseidonConfig::new(full_rounds, partial_rounds, alpha, mds, ark, 2, 1)
1416 }
1417}