ark_poly_commit/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2//! A crate for polynomial commitment schemes.
3#![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
35/// Data structures used by a polynomial commitment scheme.
36pub mod data_structures;
37pub use data_structures::*;
38
39/// Useful functions
40pub(crate) mod utils;
41
42/// R1CS constraints for polynomial constraints.
43#[cfg(feature = "r1cs")]
44mod constraints;
45#[cfg(feature = "r1cs")]
46pub use constraints::*;
47
48/// Errors pertaining to query sets.
49pub mod error;
50use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
51pub use error::*;
52
53/// Univariate and multivariate polynomial commitment schemes
54/// which (optionally) enable hiding commitments by following
55/// the approach outlined in [[CHMMVW20, "Marlin"]][marlin].
56///
57/// [marlin]: https://eprint.iacr.org/2019/1047
58pub mod marlin;
59
60/// A random number generator that bypasses some limitations of the Rust borrow
61/// checker.
62pub 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}
74/// The core [[KZG10]][kzg] construction.
75///
76/// [kzg]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf
77pub mod kzg10;
78
79/// Polynomial commitment scheme from [[KZG10]][kzg] that enforces
80/// strict degree bounds and (optionally) enables hiding commitments by
81/// following the approach outlined in [[CHMMVW20, "Marlin"]][marlin].
82///
83/// [kzg]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf
84/// [marlin]: https://eprint.iacr.org/2019/1047
85pub use marlin::marlin_pc;
86
87/// Polynomial commitment scheme based on the construction in [[KZG10]][kzg],
88/// modified to obtain batching and to enforce strict
89/// degree bounds by following the approach outlined in [[MBKM19,
90/// “Sonic”]][sonic] (more precisely, via the variant in
91/// [[Gabizon19, “AuroraLight”]][al] that avoids negative G1 powers).
92///
93/// [kzg]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf
94/// [sonic]: https://eprint.iacr.org/2019/099
95/// [al]: https://eprint.iacr.org/2019/601
96/// [marlin]: https://eprint.iacr.org/2019/1047
97pub mod sonic_pc;
98
99/// A polynomial commitment scheme based on the hardness of the
100/// discrete logarithm problem in prime-order groups.
101/// The construction is detailed in [[BCMS20]][pcdas].
102///
103/// [pcdas]: https://eprint.iacr.org/2020/499
104pub mod ipa_pc;
105
106/// A multilinear polynomial commitment scheme that converts n-variate multilinear polynomial into
107/// n quotient UV polynomial. This scheme is based on hardness of the discrete logarithm
108/// in prime-order groups. Construction is detailed in [[XZZPD19]][xzzpd19] and [[ZGKPP18]][zgkpp18]
109///
110/// [xzzpd19]: https://eprint.iacr.org/2019/317
111/// [zgkpp]: https://ieeexplore.ieee.org/document/8418645
112pub mod multilinear_pc;
113
114use ark_crypto_primitives::sponge::{CryptographicSponge, FieldElementSize};
115/// Multivariate polynomial commitment based on the construction in
116/// [[PST13]][pst] with batching and (optional) hiding property inspired
117/// by the univariate scheme in [[CHMMVW20, "Marlin"]][marlin]
118///
119/// [pst]: https://eprint.iacr.org/2011/587.pdf
120/// [marlin]: https://eprint.iacr.org/2019/1047
121pub use marlin::marlin_pst13_pc;
122
123/// Streaming polynomial commitment based on the construction in
124/// [[BCHO22, "Gemini"]][gemini] with batching techniques inspired
125/// by [[BDFG20]][bdfg].
126///
127/// [gemini]:
128/// [bdfg]: https://eprint.iacr.org/2020/081.pdf
129pub mod streaming_kzg;
130
131/// Scheme based on the Ligero construction in [[Ligero]][ligero].
132///
133/// [ligero]: https://eprint.iacr.org/2022/1608
134/// [brakedown]: https://eprint.iacr.org/2021/1043.pdf
135pub mod linear_codes;
136
137/// A polynomial commitment scheme based on the hardness of the
138/// discrete logarithm problem in prime-order groups. This is a
139/// Fiat-Shamired version of the PCS described in the Hyrax paper
140/// [[WTsTW17]][hyrax], with the difference that, unlike in the
141/// cited reference, the evaluation of the polynomial at the point
142/// of interest is indeed revealed to the verifier at the end.
143///
144/// [hyrax]: https://eprint.iacr.org/2017/1132.pdf
145pub mod hyrax;
146
147/// `QuerySet` is the set of queries that are to be made to a set of labeled polynomials/equations
148/// `p` that have previously been committed to. Each element of a `QuerySet` is a pair of
149/// `(label, (point_label, point))`, where `label` is the label of a polynomial in `p`,
150/// `point_label` is the label for the point (e.g., "beta"), and  and `point` is the location
151/// that `p[label]` is to be queried at.
152pub type QuerySet<T> = BTreeSet<(String, (String, T))>;
153
154/// `Evaluations` is the result of querying a set of labeled polynomials or equations
155/// `p` at a `QuerySet` `Q`. It maps each element of `Q` to the resulting evaluation.
156/// That is, if `(label, query)` is an element of `Q`, then `evaluation.get((label, query))`
157/// should equal `p[label].evaluate(query)`.
158pub type Evaluations<T, F> = BTreeMap<(String, T), F>;
159
160/// Describes the interface for a polynomial commitment scheme that allows
161/// a sender to commit to multiple polynomials and later provide a succinct proof
162/// of evaluation for the corresponding commitments at a query set `Q`, while
163/// enforcing per-polynomial degree bounds.
164pub trait PolynomialCommitment<F: PrimeField, P: Polynomial<F>>: Sized {
165    /// The universal parameters for the commitment scheme. These are "trimmed"
166    /// down to `Self::CommitterKey` and `Self::VerifierKey` by `Self::trim`.
167    type UniversalParams: PCUniversalParams;
168    /// The committer key for the scheme; used to commit to a polynomial and then
169    /// open the commitment to produce an evaluation proof.
170    type CommitterKey: PCCommitterKey;
171    /// The verifier key for the scheme; used to check an evaluation proof.
172    type VerifierKey: PCVerifierKey;
173    /// The commitment to a polynomial.
174    type Commitment: PCCommitment + Default;
175    /// Auxiliary state of the commitment, output by the `commit` phase.
176    /// It contains information that can be reused by the committer
177    /// during the `open` phase, such as the commitment randomness.
178    /// Not to be shared with the verifier.
179    type CommitmentState: PCCommitmentState;
180    /// The evaluation proof for a single point.
181    type Proof: Clone;
182    /// The evaluation proof for a query set.
183    type BatchProof: Clone
184        + From<Vec<Self::Proof>>
185        + Into<Vec<Self::Proof>>
186        + CanonicalSerialize
187        + CanonicalDeserialize;
188    /// The error type for the scheme.
189    type Error: ark_std::error::Error + From<Error>;
190
191    /// Constructs public parameters when given as input the maximum degree `degree`
192    /// for the polynomial commitment scheme. `num_vars` specifies the number of
193    /// variables for multivariate setup
194    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    /// Specializes the public parameters for polynomials up to the given `supported_degree`
201    /// and for enforcing degree bounds in the range `1..=supported_degree`.
202    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    /// Outputs a list of commitments to `polynomials`. If `polynomials[i].is_hiding()`,
210    /// then the `i`-th commitment is hiding up to `polynomials.hiding_bound()` queries.
211    /// `rng` should not be `None` if `polynomials[i].is_hiding() == true` for any `i`.
212    ///
213    /// If for some `i`, `polynomials[i].is_hiding() == false`, then the
214    /// corresponding randomness is `Self::Randomness::empty()`.
215    ///
216    /// If for some `i`, `polynomials[i].degree_bound().is_some()`, then that
217    /// polynomial will have the corresponding degree bound enforced.
218    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    /// open but with individual challenges
233    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    /// check but with individual challenges
248    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    /// Open several polynomials at one or more points each (possibly different
261    /// for each polynomial). Each entry in the in the query set of points
262    /// contains the label of the polynomial which should be queried at that
263    /// point.
264    ///
265    /// Behaviour is undefined if `query_set` contains the entries with the
266    /// same point label but different actual points.
267    ///
268    /// The opening challenges are independent for each batch of polynomials.
269    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        // The default implementation achieves proceeds by rearranging the queries in
284        // order to gather (i.e. batch) all polynomials that should be queried at
285        // the same point, then opening their commitments simultaneously with a
286        // single call to `open` (per point)
287        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        // `label` is the label of the polynomial the query refers to
304        // `point_label` is the label of the point being queried
305        // `point` is the actual point
306        for (label, (point_label, point)) in query_set.iter() {
307            // For each point label in `query_set`, we define an entry in
308            // `query_to_labels_map` containing a pair whose first element is
309            // the actual point and the second one is the set of labels of the
310            // polynomials being queried at that point
311            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            // Constructing matching vectors with the polynomial, commitment
324            // randomness and actual commitment for each polynomial being
325            // queried at `point`
326            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            // Simultaneously opening the commitments of all polynomials that
340            // refer to the the current point using the plain `open` function
341            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    /// Verify opening proofs for several polynomials at one or more points
361    /// each (possibly different for each polynomial). Each entry in
362    /// the query set of points contains the label of the polynomial which
363    /// was queried at that point.
364    ///
365    /// Behaviour is undefined if `query_set` contains the entries with the
366    /// same point label but different points.
367    ///
368    /// Behaviour is also undefined if proofs are not ordered the same way as
369    /// queries in `query_to_labels_map` (this is the outcome of calling
370    /// `batch_open` for the same commitment list and query set).H
371    ///
372    /// The opening challenges are independent for each batch of polynomials.
373    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        // The default implementation proceeds by rearranging the queries in
386        // order to gather (i.e. batch) the proofs of all polynomials that should
387        // have been opened at the same point, then verifying those proofs
388        // simultaneously with a single call to `check` (per point).
389        let commitments: BTreeMap<_, _> = commitments.into_iter().map(|c| (c.label(), c)).collect();
390        let mut query_to_labels_map = BTreeMap::new();
391
392        // `label` is the label of the polynomial the query refers to
393        // `point_label` is the label of the point being queried
394        // `point` is the actual point
395        for (label, (point_label, point)) in query_set.iter() {
396            // For each point label in `query_set`, we define an entry in
397            // `query_to_labels_map` containing a pair whose first element is
398            // the actual point and the second one is the set of labels of the
399            // polynomials being queried at that point
400            let labels = query_to_labels_map
401                .entry(point_label)
402                .or_insert((point, BTreeSet::new()));
403            labels.1.insert(label);
404        }
405
406        // Implicit assumption: proofs are ordered in same manner as queries in
407        // `query_to_labels_map`.
408        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            // Constructing matching vectors with the commitment and claimed
415            // value of each polynomial being queried at `point`
416            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            // Verify all proofs referring to the current point simultaneously
436            // with a single call to `check`
437            result &= Self::check(vk, comms, &point, values, &proof, sponge, Some(rng))?;
438            end_timer!(proof_time);
439        }
440        Ok(result)
441    }
442
443    /// Open commitments to all polynomials involved in a number of linear
444    /// combinations (LC) simultaneously.
445    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        // The default implementation proceeds by batch-opening all polynomials
461        // appearing in those LC that are queried at the same point.
462        let linear_combinations: Vec<_> = linear_combinations.into_iter().collect();
463        let polynomials: Vec<_> = polynomials.into_iter().collect();
464
465        // Rearrange the information about queries on linear combinations into
466        // information about queries on individual polynomials.
467        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        // Batch-open all polynomials that refer to each individual point in `query_set`
472        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    /// Verify opening proofs for all polynomials involved in a number of
488    /// linear combinations (LC) simultaneously.
489    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        // The default implementation does this by batch-checking each
503        // batch-opening proof of polynomials appearing in those LC that were
504        // queried at the same point, then computing the evaluations of each LC
505        // using the proved polynomial evaluations.
506        let BatchLCProof { proof, evals } = proof;
507        let lc_s = BTreeMap::from_iter(linear_combinations.into_iter().map(|lc| (lc.label(), lc)));
508
509        // Rearrange the information about queries on linear combinations into
510        // information about queries on individual polynomials.
511        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                // Compute the value of the linear combination by adding the
536                // claimed value for each polynomial in it (to be proved later)
537                // scaled by the corresponding coefficient.
538                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                // Checking the computed evaluation matches the claimed one
552                if claimed_rhs != actual_rhs {
553                    eprintln!("Claimed evaluation of {} is incorrect", lc.label());
554                    return Ok(false);
555                }
556            }
557        }
558
559        // Verify the claimed evaluation for each polynomial appearing in the
560        // linear combinations, batched by point
561        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
579/// The size of opening challenges in bits.
580pub const CHALLENGE_SIZE: FieldElementSize = FieldElementSize::Truncated(128);
581
582/// Evaluate the given polynomials at `query_set`.
583pub 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
604// Separate the information about queries on linear combinations into
605// information about queries on individual polynomials.
606//
607// For instance, if `linear_combinations` is
608// [
609//  ("average", 1/2 * pol_1 + 1/2 * pol_2),
610//  ("weighted", 1/2 * pol_1 + 1/2 * pol_3)
611// ]
612// and `query_set` is
613// [
614//  ("average", ("three", 3))
615//  ("weighted", ("three", 3))
616// ],
617// then the output is
618// {
619//  ("pol_1", ("three", 3)),
620//  ("pol_2", ("three", 3)),
621//  ("pol_3", ("three", 3)),
622// }
623fn 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        // If testing multivariate polynomials, make the max degree lower
786        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            // Generate polynomials
810            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            // Construct query set
856            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        // If testing multivariate polynomials, make the max degree lower
927        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            // Generate polynomials
951            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's construct our equations
1000            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                        // Insert query
1032                        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    /// Generate default parameters for alpha = 17, state-size = 8
1390    ///
1391    /// WARNING: This poseidon parameter is not secure. Please generate
1392    /// your own parameters according the field you use.
1393    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}