Skip to main content

starkom_pcs/
fri.rs

1use crate::hash::Hash;
2use crate::utils;
3use anyhow::{Result, anyhow};
4use ff::{Field, PrimeField};
5use starkom_bluesky::Scalar;
6use starkom_poly;
7use std::marker::PhantomData;
8use std::sync::LazyLock;
9
10type Polynomial = starkom_poly::Polynomial<Scalar>;
11
12/// Domain separator tag used when hashing the leaves of a Merkle tree.
13static LEAF_DST: LazyLock<Scalar> = LazyLock::new(|| utils::hash_to_scalar(b"starkom/fri/leaf"));
14
15/// Domain separator tag used in (internal) Merkle tree hashes.
16static TREE_DST: LazyLock<Scalar> = LazyLock::new(|| utils::hash_to_scalar(b"starkom/fri/tree"));
17
18/// Domain separator tag used when deriving the Fiat-Shamir challenge for FRI folding.
19static FOLD_DST: LazyLock<Scalar> = LazyLock::new(|| utils::hash_to_scalar(b"starkom/fri/fold"));
20
21/// The modular inverse of the multiplicative generator, used to correct the coset shift in the FRI
22/// fold formula: the standard formula divides by `x = g * omega^i`, so the fold coefficient is
23/// `alpha * g^{-1} * omega^{-i}`.
24static GENERATOR_INV: LazyLock<Scalar> =
25    LazyLock::new(|| Scalar::MULTIPLICATIVE_GENERATOR.invert().unwrap());
26
27/// Hashes a leaf of a Merkle tree.
28fn hash_leaf<H: Hash<Scalar>>(values: &[Scalar]) -> Scalar {
29    H::hash_many(
30        std::iter::once(*LEAF_DST)
31            .chain(std::iter::once(Scalar::from(values.len() as u64)))
32            .chain(values.iter().cloned())
33            .collect::<Vec<Scalar>>()
34            .as_slice(),
35    )
36}
37
38/// Computes all Merkle hashes of a vector of values up to the root.
39///
40/// `n` is the number of values and must be a power of two.
41///
42/// The full Merkle tree is stored inline in the `values` vector as follows:
43///
44///   * the first `n` elements are the values of the original vector,
45///   * the next `n / 2` elements are the hashes of the second-last layer of the tree,
46///   * the next `n / 4` elements are the hashes of the third-last layer of the tree,
47///   * ...
48///   * the last stored element is the Merkle root.
49///
50/// It's the caller's responsibility to ensure the `values` array has at least `n * 2 - 1` slots so
51/// that the full tree can be stored.
52///
53/// Note that the Merkle root will be at index `(n - 1) * 2`.
54///
55/// Note about usage: the Merkle trees we use in this module have scalar *vectors* for leaves, not
56/// just scalars.
57pub fn merklify<H: Hash<Scalar>>(mut values: &mut [Scalar], mut n: usize) {
58    assert!(n.is_power_of_two());
59    while n > 1 {
60        let m = n / 2;
61        for j in 0..m {
62            values[n + j] = H::hash_raw(*TREE_DST, values[j * 2], values[j * 2 + 1]);
63        }
64        values = &mut values[n..];
65        n = m;
66    }
67}
68
69/// Stores the Merkle root hashes of a FRI commitment.
70///
71/// Note that for low-degree testing these are *less* than log2(N), with N being the number of
72/// committed evaluations. Once the folding process has reduced all polynomials to degree-0 ones
73/// (that is, single constants) all subsequent folds would be identical, so we don't store them.
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct Commitment {
76    /// The first element in the array is the root of the main Merkle tree, the second one is the
77    /// root of the Merkle tree from the first folding round, and so on until the last element which
78    /// is the value of the last folding round.
79    roots: Vec<Scalar>,
80}
81
82impl Commitment {
83    /// Returns the number of stored roots, equivalent to the number of folding rounds and therefore
84    /// to the log2 of the degree bound plus one. For example, if the user commits 4 evaluations
85    /// `len()` will return 3.
86    pub fn len(&self) -> usize {
87        self.roots.len()
88    }
89
90    /// Returns the Merkle roots of all folding rounds.
91    ///
92    /// The returned slice has `len()` elements.
93    pub fn roots(&self) -> &[Scalar] {
94        self.roots.as_slice()
95    }
96
97    /// Returns the Merkle root hash of the committed polynomial, which is the first hash stored in
98    /// the commitment.
99    pub fn root(&self) -> Scalar {
100        *self.roots.first().unwrap()
101    }
102}
103
104/// A Merkle proof.
105///
106/// A FRI `Query` uses several of these: two from the main Merkle tree and two for each folding
107/// round.
108///
109/// NOTE: this object only stores the sister hashes of the Merkle path and the opened leaf values,
110/// it doesn't store the lookup key and the root hash anywhere because those pieces of information
111/// are reconstructed separately during the verification of a whole `Query`. In particular, all root
112/// hashes are stored in the `Commitment`.
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct LeafProof<H: Hash<Scalar>> {
115    leaf: Vec<Scalar>,
116    path: Vec<Scalar>,
117    _data: PhantomData<H>,
118}
119
120impl<H: Hash<Scalar>> LeafProof<H> {
121    /// Returns a reference to the leaf values (one for every committed polynomial).
122    pub fn leaf(&self) -> &[Scalar] {
123        self.leaf.as_slice()
124    }
125
126    /// Checks the leaf of this proof against the provided slice.
127    ///
128    /// The two must match or an error is returned.
129    pub fn check_leaf(&self, expected: &[Scalar]) -> Result<()> {
130        if expected.len() != self.leaf.len()
131            || self
132                .leaf
133                .iter()
134                .zip(expected.iter())
135                .any(|(&value1, &value2)| value1 != value2)
136        {
137            return Err(anyhow!("leaf value mismatch"));
138        }
139        Ok(())
140    }
141
142    /// Returns the length of the Merkle path, corresponding to the height of the tree minus 1 (the
143    /// root hash is not included in this count).
144    pub fn len(&self) -> usize {
145        self.path.len()
146    }
147
148    /// Verifies the proof against the given root hash.
149    pub fn verify(&self, mut index: usize, root_hash: Scalar) -> Result<()> {
150        let mut hash = hash_leaf::<H>(self.leaf.as_slice());
151        for sibling in &self.path {
152            hash = if index & 1 != 0 {
153                H::hash_raw(*TREE_DST, *sibling, hash)
154            } else {
155                H::hash_raw(*TREE_DST, hash, *sibling)
156            };
157            index >>= 1;
158        }
159        if index != 0 {
160            return Err(anyhow!("invalid index"));
161        }
162        if hash != root_hash {
163            return Err(anyhow!(
164                "root hash mismatch (got {}, want {})",
165                hash,
166                root_hash
167            ));
168        }
169        Ok(())
170    }
171
172    /// Indicates whether or not the committed polynomials are constant.
173    ///
174    /// This is used in low degree testing to check when the folding process collapses to degree-0
175    /// polynomials.
176    ///
177    /// Note that some polynomials may collapse earlier than others, and this function returns false
178    /// if one or more haven't collapsed yet. So it returns true if and only if all have collapsed.
179    pub fn is_constant(&self) -> bool {
180        let mut hash = hash_leaf::<H>(self.leaf.as_slice());
181        for &sibling in &self.path {
182            if sibling != hash {
183                return false;
184            }
185            hash = H::hash_raw(*TREE_DST, hash, hash);
186        }
187        true
188    }
189}
190
191/// A Merkle tree whose leaves are multiple polynomial evaluations.
192///
193/// The tree has N leaf in total, with N being the size of the extended domain, and each leaf has K
194/// polynomial evaluations, with K being the number of committed polynomials.
195///
196/// The internal nodes are single hashes.
197#[derive(Debug, Clone)]
198pub struct Tree<H: Hash<Scalar>> {
199    /// Number of polynomials in the tree. This is the number of values in each leaf.
200    num_polys: usize,
201    /// The leaves of the tree (N leaves with K evaluations each).
202    leaves: Vec<Vec<Scalar>>,
203    /// The internal nodes of the tree. There are 2*N-1 nodes in this array, with N = number of
204    /// leaves. The nodes of the bottom layer are the hashes of the corresponding leaves.
205    hashes: Vec<Scalar>,
206    _data: PhantomData<H>,
207}
208
209impl<H: Hash<Scalar>> Tree<H> {
210    /// Constructs a Merkle tree from a matrix of polynomial evaluations.
211    ///
212    /// More than one polynomial can be batched in the same tree because we our tree leaves are
213    /// vectors rather than single scalars. The only requirement is that all polynomials have the
214    /// same number of evaluations (not necessarily the same degree).
215    ///
216    /// The provided `leaves` array has one entry for each leaf, and each leaf is a vector of K
217    /// polynomial evaluations, with K = number of batched polynomials.
218    ///
219    /// Neither the outer array nor the inner arrays can be empty.
220    pub fn from_leaves(leaves: Vec<Vec<Scalar>>) -> Self {
221        let num_polys = leaves[0].len();
222        assert!(num_polys > 0);
223        let n = leaves.len();
224        assert!(n.is_power_of_two());
225        let mut hashes = vec![Scalar::ZERO; n * 2 - 1];
226        for i in 0..n {
227            let leaf = leaves[i].as_slice();
228            assert_eq!(leaf.len(), num_polys);
229            hashes[i] = hash_leaf::<H>(leaf);
230        }
231        merklify::<H>(hashes.as_mut_slice(), n);
232        Self {
233            num_polys,
234            leaves,
235            hashes,
236            _data: Default::default(),
237        }
238    }
239
240    /// Constructs a Merkle tree from a matrix of polynomial evaluations.
241    ///
242    /// The outer array of `values` contains one entry per committed polynomial, and each of the
243    /// inner arrays represents the evaluations of a polynomial.
244    ///
245    /// Therefore `values` has as many elements as the number of polynomials being committed and the
246    /// length of the inner arrays must equal the size of the (extended) evaluation domain.
247    ///
248    /// Note that the only difference between `new` and `from_leaves` is that the dimensions of the
249    /// provided matrix are inverted.
250    ///
251    /// Neither the outer array nor the inner arrays can be empty.
252    pub fn new(values: Vec<Vec<Scalar>>) -> Self {
253        let k = values.len();
254        assert!(k > 0);
255        let n = values[0].len();
256        let leaves: Vec<Vec<Scalar>> = (0..n)
257            .map(|i| {
258                (0..k)
259                    .map(|j| {
260                        assert_eq!(n, values[j].len());
261                        values[j][i]
262                    })
263                    .collect()
264            })
265            .collect();
266        Self::from_leaves(leaves)
267    }
268
269    /// Returns the number of polynomials stored in the tree.
270    ///
271    /// Each leaf of the tree has this number of values.
272    pub fn num_polys(&self) -> usize {
273        self.num_polys
274    }
275
276    /// Returns the number of leaves in the tree, corresponding to the size of the evaluation domain
277    /// (always a power of 2).
278    pub fn num_leaves(&self) -> usize {
279        self.leaves.len()
280    }
281
282    /// Returns the root hash of the Merkle tree.
283    pub fn root_hash(&self) -> Scalar {
284        let n = self.leaves.len();
285        self.hashes[(n - 1) * 2]
286    }
287
288    /// Returns a reference to the i-th leaf.
289    ///
290    /// Note that the leaf contains k elements, one for every committed polynomial.
291    pub fn leaf(&self, index: usize) -> &[Scalar] {
292        self.leaves[index].as_slice()
293    }
294
295    /// Returns a Merkle proof for the leaf at `index`.
296    pub fn query(&self, mut index: usize) -> LeafProof<H> {
297        let mut n = self.leaves.len();
298        assert!(n.is_power_of_two());
299        assert!(index < n);
300        let leaf = self.leaves[index].clone();
301        let mut path = Vec::with_capacity(n.trailing_zeros() as usize);
302        let mut hashes = self.hashes.as_slice();
303        while n > 1 {
304            path.push(hashes[index ^ 1]);
305            hashes = &hashes[n..];
306            n /= 2;
307            index >>= 1;
308        }
309        LeafProof {
310            leaf,
311            path,
312            _data: Default::default(),
313        }
314    }
315
316    /// Performs one FRI folding round, returning the new folded tree.
317    fn fold(&self) -> Self {
318        let n = self.leaves.len();
319        assert!(n.is_power_of_two());
320
321        let alpha = H::hash_raw(*FOLD_DST, self.hashes[(n - 1) * 2], Scalar::ZERO) * *GENERATOR_INV;
322
323        let k = n.trailing_zeros();
324        let omega_inv = Scalar::ROOT_OF_UNITY_INV.pow_vartime([1u64 << (Scalar::S - k), 0, 0, 0]);
325
326        let m = n / 2;
327        let mut omega_inv_i = Scalar::ONE;
328
329        let mut leaves = Vec::with_capacity(m);
330        for i in 0..m {
331            let pos = self.leaves[i].as_slice();
332            let neg = self.leaves[i + m].as_slice();
333            leaves.push(
334                pos.iter()
335                    .cloned()
336                    .zip(neg.iter().cloned())
337                    .map(|(pos, neg)| {
338                        (pos + neg + alpha * omega_inv_i * (pos - neg)) * Scalar::TWO_INV
339                    })
340                    .collect::<Vec<Scalar>>(),
341            );
342            omega_inv_i *= omega_inv;
343        }
344
345        Self::from_leaves(leaves)
346    }
347
348    /// Performs `times` FRI folding and returns an array of `times+1` trees.
349    ///
350    /// The first element is `self` (N leaves), the second element is the tree from the first
351    /// folding round (N/2 leaves), the third element is the tree from the second folding round (N/4
352    /// leaves), and so on.
353    fn fold_all(self, times: usize) -> Vec<Self> {
354        let mut trees = Vec::with_capacity(times + 1);
355        let mut tree = self;
356        for _ in 0..times {
357            let folded = tree.fold();
358            trees.push(tree);
359            tree = folded;
360        }
361        trees.push(tree);
362        trees
363    }
364}
365
366#[derive(Debug, Clone)]
367pub struct Query<H: Hash<Scalar>> {
368    /// The number of committed evaluations.
369    n: usize,
370    /// The index of the element we're opening (the partner index is inferred automatically).
371    index: usize,
372    /// Proves a pair of "partner" values at each folding round with one `LeafProof` pair for every
373    /// round. The pair at `folds[0]` proves the opened values (stored in `values`).
374    folds: Vec<(LeafProof<H>, LeafProof<H>)>,
375    _data: PhantomData<H>,
376}
377
378impl<H: Hash<Scalar>> Query<H> {
379    /// Returns the two opened indices.
380    pub fn indices(&self) -> (usize, usize) {
381        (self.index, (self.index + self.n / 2) % self.n)
382    }
383
384    /// Returns the opened domain element, that is the X-coordinate of the evaluation.
385    ///
386    /// This is the element corresponding to the first value returned by `indices`, while the
387    /// partner element can be obtained by simply negating this one.
388    ///
389    /// Note that we use `Polynomial::shifted_lde2` when committing polynomials, so the element
390    /// returned here is a shifted power of an N-th root of unity, with
391    /// `N = degree_bound * 2^blowup_factor`. The shift consists of multiplying the actual domain
392    /// element by `Scalar::MULTIPLICATIVE_GENERATOR`, consistently with `shifted_lde2`.
393    pub fn x(&self) -> Scalar {
394        Polynomial::coset_element2(self.index, self.n)
395    }
396
397    /// Returns the opened evaluations, one for every committed polynomial.
398    ///
399    /// The first component of the returned tuple contains the evaluations at the first index
400    /// returned by `indices`, while the second component contains those at the second index.
401    pub fn values(&self) -> (&[Scalar], &[Scalar]) {
402        (self.folds[0].0.leaf(), self.folds[0].1.leaf())
403    }
404
405    /// Returns the number of folding rounds.
406    ///
407    /// In general these are log2(d), with `d` being the degree bound of the committed polynomial.
408    /// Note that for low-degree testing `d` is strictly less than the number of committed
409    /// evaluations `N`.
410    pub fn len(&self) -> usize {
411        return self.folds.len();
412    }
413
414    /// Verifies this proof against the given commitment.
415    ///
416    /// NOTE: for low-degree testing you also need to check that `len()` returns the log2 of the
417    /// expected degree bound. This function only verifies the opened value pair across the folding
418    /// structure.
419    pub fn verify(&self, commitment: &Commitment) -> Result<()> {
420        assert!(self.n.is_power_of_two());
421        assert!(self.index < self.n);
422        let k = self.n.trailing_zeros();
423
424        let folds = self.folds.as_slice();
425
426        let h = folds.len();
427        if h > k as usize + 1 {
428            return Err(anyhow!("invalid proof size"));
429        }
430        if commitment.len() != h {
431            return Err(anyhow!("wrong number of folding rounds"));
432        }
433
434        let mut m = self.n;
435        let mut index = self.index;
436        let mut pos = self.folds[0].0.leaf().to_vec();
437        let mut step = Scalar::ROOT_OF_UNITY_INV.pow_vartime([1u64 << (Scalar::S - k), 0, 0, 0]);
438
439        for r in 0..h {
440            let (left, right) = &folds[r];
441            let root_hash = commitment.roots()[r];
442            let alpha = H::hash_raw(*FOLD_DST, root_hash, Scalar::ZERO) * *GENERATOR_INV;
443            let neg = right.leaf();
444
445            if 1usize << left.len() != m {
446                return Err(anyhow!(
447                    "invalid left-hand side Merkle proof height (got {}, want {})",
448                    left.len(),
449                    m.trailing_zeros()
450                ));
451            }
452            if 1usize << right.len() != m {
453                return Err(anyhow!(
454                    "invalid right-hand side Merkle proof height (got {}, want {})",
455                    right.len(),
456                    m.trailing_zeros()
457                ));
458            }
459
460            left.check_leaf(pos.as_slice())?;
461            left.verify(index, root_hash)?;
462            right.verify((index + m / 2) % m, root_hash)?;
463
464            let omega_inv_i = step.pow_vartime([index as u64, 0, 0, 0]);
465            m /= 2;
466            index %= m;
467
468            for i in 0..pos.len() {
469                pos[i] =
470                    (pos[i] + neg[i] + alpha * omega_inv_i * (pos[i] - neg[i])) * Scalar::TWO_INV;
471            }
472            step = step.square();
473        }
474
475        let (left, right) = folds.last().unwrap();
476        if !left.is_constant() || !right.is_constant() {
477            return Err(anyhow!("final folded polynomial is not constant"));
478        }
479
480        Ok(())
481    }
482}
483
484/// A FRI prover.
485///
486/// The struct contains the main Merkle tree built on the committed polynomial(s) and the Merkle
487/// trees of all folded polynomials up to and including the one where all polynomials have been
488/// folded into constant ones. Note that the final Merkle tree still has more than one leaf due to
489/// the low-degree extension.
490#[derive(Debug, Clone)]
491pub struct Prover<H: Hash<Scalar>> {
492    /// The degree bound of the committed polynomials. This is the highest degree among the
493    /// committed polynomials, plus one.
494    degree_bound: usize,
495    /// The base-2 logarithm of the blowup factor.
496    blowup_log2: usize,
497    /// The Merkle trees, one for the original polynomials plus one for every folding round.
498    /// `trees[0]` is the tree built over the original polynomial evaluations, `trees[1]` is the
499    /// tree resulting from the first folding round, etc.
500    trees: Vec<Tree<H>>,
501}
502
503impl<H: Hash<Scalar>> Prover<H> {
504    pub fn new(polynomials: Vec<Polynomial>, degree_bound: usize, blowup_log2: usize) -> Self {
505        assert!(degree_bound.is_power_of_two());
506        assert!(
507            polynomials
508                .iter()
509                .all(|polynomial| degree_bound >= polynomial.degree_bound())
510        );
511
512        let n = degree_bound << blowup_log2;
513        assert!(n as u64 <= 1u64 << Scalar::S);
514
515        let main_tree = Tree::<H>::new(
516            polynomials
517                .into_iter()
518                .map(|polynomial| polynomial.shifted_lde2(n))
519                .collect(),
520        );
521        let trees = main_tree.fold_all(degree_bound.trailing_zeros() as usize);
522
523        Self {
524            degree_bound,
525            blowup_log2,
526            trees,
527        }
528    }
529
530    /// Returns the degree bound of the committed polynomials (always a power of 2).
531    ///
532    /// NOTE: the actual degree of the original polynomials is often even lower than this value
533    /// because it was rounded up to the next power of 2 in order to run the FFT and FRI algorithms.
534    pub fn degree_bound(&self) -> usize {
535        self.degree_bound
536    }
537
538    /// Returns the size of the extended domain, equal to `degree_bound * 2^blowup_log2`.
539    pub fn extended_domain_size(&self) -> usize {
540        self.degree_bound << self.blowup_log2
541    }
542
543    /// Alias for `extended_domain_size`.
544    pub fn size(&self) -> usize {
545        self.degree_bound << self.blowup_log2
546    }
547
548    /// Returns the Merkle root hash of the committed polynomials.
549    ///
550    /// This is equivalent to the first root stored in the commiment returned by `commit()`.
551    pub fn root_hash(&self) -> Scalar {
552        self.trees[0].root_hash()
553    }
554
555    /// Creates the FRI commitment for the batched polynomials.
556    pub fn commit(&self) -> Commitment {
557        Commitment {
558            roots: self.trees.iter().map(|tree| tree.root_hash()).collect(),
559        }
560    }
561
562    /// Builds a FRI `Query` for the value at the specified index of the evaluation domain.
563    ///
564    /// NOTE: `index` is relative to the *inflated* evaluation domain, so for example if you
565    /// committed to 4 evaluations with a blowup factor of 8 the range for `index` is [0, 32).
566    pub fn query(&self, index: usize) -> Query<H> {
567        let d = self.degree_bound;
568        assert!(d.is_power_of_two());
569
570        let n = self.degree_bound << self.blowup_log2;
571        assert!(index < n);
572
573        let mut m = n;
574        let mut i = index;
575        let mut folds = vec![];
576        for tree in &self.trees {
577            folds.push((tree.query(i), tree.query((i + m / 2) % m)));
578            m /= 2;
579            i %= m;
580        }
581
582        {
583            let (left, right) = folds.last().unwrap();
584            assert!(left.is_constant());
585            assert!(right.is_constant());
586        }
587
588        Query {
589            n,
590            index,
591            folds,
592            _data: Default::default(),
593        }
594    }
595}
596
597#[cfg(test)]
598mod tests {
599    use super::*;
600    use crate::hash;
601    use crate::utils::parse_scalar;
602
603    type Poseidon2Hash = hash::Poseidon2Hash<Scalar>;
604    type Sha2Hash = hash::Sha2Hash<Scalar>;
605
606    #[test]
607    fn test_merklify_one_sha2() {
608        let mut values = vec![12.into()];
609        merklify::<Sha2Hash>(&mut values, 1);
610        assert_eq!(values, vec![12.into()]);
611    }
612
613    #[test]
614    fn test_merklify_one_poseidon2() {
615        let mut values = vec![12.into()];
616        merklify::<Poseidon2Hash>(&mut values, 1);
617        assert_eq!(values, vec![12.into()]);
618    }
619
620    #[test]
621    fn test_merklify_two_sha2() {
622        let mut values = vec![34.into(), 56.into()];
623        values.resize(3, 0.into());
624        merklify::<Sha2Hash>(&mut values, 2);
625        assert_eq!(
626            values,
627            vec![
628                34.into(),
629                56.into(),
630                parse_scalar("0x4e92e96500d26aa6e159670815c01b01c89f3385627027e52b20c3be995d9cb4")
631            ]
632        );
633    }
634
635    #[test]
636    fn test_merklify_two_poseidon2() {
637        let mut values = vec![34.into(), 56.into()];
638        values.resize(3, 0.into());
639        merklify::<Poseidon2Hash>(&mut values, 2);
640        assert_eq!(
641            values,
642            vec![
643                34.into(),
644                56.into(),
645                parse_scalar("0x460d694c3fc49199a27c631df8a837d5b64566c40075981ff5cb0396cf52a80b")
646            ]
647        );
648    }
649
650    #[test]
651    fn test_merklify_four_sha2() {
652        let mut values = vec![78.into(), 90.into(), 12.into(), 34.into()];
653        values.resize(7, 0.into());
654        merklify::<Sha2Hash>(&mut values, 4);
655        assert_eq!(
656            values,
657            vec![
658                78.into(),
659                90.into(),
660                12.into(),
661                34.into(),
662                parse_scalar("0x4ba5bb5405a8d200b4c1b2fe1240daa6be892eb58048020e0a03f5fb6e009dec"),
663                parse_scalar("0x1f4cbe6657a61b9852cb8c219f5bf3a42d6404902560ef5dd14f91a414fff307"),
664                parse_scalar("0x58d1fe70cb37a8e745391c570e3cda9e0c24e74464fb5119a29d01f2b64af357"),
665            ]
666        );
667    }
668
669    #[test]
670    fn test_merklify_four_poseidon2() {
671        let mut values = vec![78.into(), 90.into(), 12.into(), 34.into()];
672        values.resize(7, 0.into());
673        merklify::<Poseidon2Hash>(&mut values, 4);
674        assert_eq!(
675            values,
676            vec![
677                78.into(),
678                90.into(),
679                12.into(),
680                34.into(),
681                parse_scalar("0x09c10aba0c59772b51adb65ac6780471b94bf18f63aa121901fb3a428f171064"),
682                parse_scalar("0x2786758795737449218651c7a13e09e40159eb361293bbd7526c26a110f4b733"),
683                parse_scalar("0x183ba165b9bd525fddf2be1420f9087f9ebfbf0bedbdb9e3bf4ec7a785325b13"),
684            ]
685        );
686    }
687
688    fn test_merkle_tree<H: Hash<Scalar>>(leaves: Vec<Vec<Scalar>>, expected_root_hash: Scalar) {
689        let tree = Tree::<H>::from_leaves(leaves.clone());
690        assert_eq!(tree.num_polys(), leaves[0].len());
691        assert_eq!(tree.num_leaves(), leaves.len());
692        assert_eq!(tree.root_hash(), expected_root_hash);
693        for i in 0..leaves.len() {
694            let leaf = &leaves[i];
695            let proof = tree.query(i);
696            assert!(proof.verify(i, expected_root_hash).is_ok());
697            assert_eq!(proof.leaf().len(), leaf.len());
698            assert!(
699                proof
700                    .leaf()
701                    .iter()
702                    .zip(leaf.iter())
703                    .all(|(&lhs, &rhs)| lhs == rhs)
704            );
705        }
706    }
707
708    #[test]
709    fn test_merkle_tree_one_leaf_1() {
710        test_merkle_tree::<Sha2Hash>(
711            vec![vec![12.into()]],
712            parse_scalar("0x563171d1d29fc71a8e64c1996982ba9391b948c0f8e53c06f49dd50a935195bd"),
713        );
714        test_merkle_tree::<Poseidon2Hash>(
715            vec![vec![12.into()]],
716            parse_scalar("0x2cdc51a32dac2ed86403822d494776d4512920a3790544b4be3ebf2cbde92171"),
717        );
718    }
719
720    #[test]
721    fn test_merkle_tree_one_leaf_2() {
722        test_merkle_tree::<Sha2Hash>(
723            vec![vec![34.into()]],
724            parse_scalar("0x0a6461fb4b46a4cbf7855d0f8b2221b476c8fa54d510d03c5e0f1b7add3720d6"),
725        );
726        test_merkle_tree::<Poseidon2Hash>(
727            vec![vec![34.into()]],
728            parse_scalar("0x7bd38f78c7b116426eb1c3ce88929882f997ba95fd38128105171586b32a8db0"),
729        );
730    }
731
732    #[test]
733    fn test_merkle_tree_one_leaf_two_polynomials_1() {
734        test_merkle_tree::<Sha2Hash>(
735            vec![vec![12.into(), 34.into()]],
736            parse_scalar("0x12bca773e3d548e97bc3c09698887d8aa79a2a224741aca93ac1f748bf9d0a76"),
737        );
738        test_merkle_tree::<Poseidon2Hash>(
739            vec![vec![12.into(), 34.into()]],
740            parse_scalar("0x7266dbf17f81908d1abfcc37f1ac92cbdbbc0ddf8ed65dd8c56c6a7d4d6d23cf"),
741        );
742    }
743
744    #[test]
745    fn test_merkle_tree_one_leaf_two_polynomials_2() {
746        test_merkle_tree::<Sha2Hash>(
747            vec![vec![34.into(), 12.into()]],
748            parse_scalar("0x54ee34331f32bd339abb4fc82eb2779e696b593bf4c186ca2e993eb0cd3711c3"),
749        );
750        test_merkle_tree::<Poseidon2Hash>(
751            vec![vec![34.into(), 12.into()]],
752            parse_scalar("0x2b81b71d5988e82d27fb48f0b4b2c8f8ff3ba99751f2449997d840d7518dc11b"),
753        );
754    }
755
756    #[test]
757    fn test_merkle_tree_one_leaf_three_polynomials_1() {
758        test_merkle_tree::<Sha2Hash>(
759            vec![vec![12.into(), 34.into(), 56.into()]],
760            parse_scalar("0x285ebc787db855722846ffd14565aa60215c39953648ea0555d493d6d998c634"),
761        );
762        test_merkle_tree::<Poseidon2Hash>(
763            vec![vec![12.into(), 34.into(), 56.into()]],
764            parse_scalar("0x0c3b7d987cb1e3d95e6e0f95fcc37f64ebe76006c7d060cc88d2f6e77ac8ee9c"),
765        );
766    }
767
768    #[test]
769    fn test_merkle_tree_one_leaf_three_polynomials_2() {
770        test_merkle_tree::<Sha2Hash>(
771            vec![vec![34.into(), 12.into(), 78.into()]],
772            parse_scalar("0x54b1edfda64b33dacfd52f04514907c6692cceb22c85737851b192e1b6fc230e"),
773        );
774        test_merkle_tree::<Poseidon2Hash>(
775            vec![vec![34.into(), 12.into(), 78.into()]],
776            parse_scalar("0x06e1ad1622dcc06212ca8b23ca3fd56cdc4d8b065d987412a9cb9fdf1d0e155d"),
777        );
778    }
779
780    #[test]
781    fn test_merkle_tree_two_leaves_1() {
782        test_merkle_tree::<Sha2Hash>(
783            vec![vec![12.into()], vec![34.into()]],
784            parse_scalar("0x20e65b4345db52cd8249ed9c1797f859c4f3dff7c5d9374eb4b89118cd39b643"),
785        );
786        test_merkle_tree::<Poseidon2Hash>(
787            vec![vec![12.into()], vec![34.into()]],
788            parse_scalar("0x2f0c2ee238a5c8f3f9380fa9cdd59d4c1774ef7659554bf37d2e40b1bfda0f3d"),
789        );
790    }
791
792    #[test]
793    fn test_merkle_tree_two_leaves_2() {
794        test_merkle_tree::<Sha2Hash>(
795            vec![vec![34.into()], vec![56.into()]],
796            parse_scalar("0x1cc4e046101296f69bed2fc83482ce4056cd50d36b18cb4b08920225144bcaa6"),
797        );
798        test_merkle_tree::<Poseidon2Hash>(
799            vec![vec![34.into()], vec![56.into()]],
800            parse_scalar("0x14ff951575b5892afaf39760090ee44f2de980a45528a69700570aa0321338ab"),
801        );
802    }
803
804    #[test]
805    fn test_merkle_tree_two_leaves_two_polynomials_1() {
806        test_merkle_tree::<Sha2Hash>(
807            vec![vec![12.into(), 34.into()], vec![56.into(), 78.into()]],
808            parse_scalar("0x65a2f27eccdf81249652273e3df595841ac0d7398b1a866fce9bd6fe3c891dbc"),
809        );
810        test_merkle_tree::<Poseidon2Hash>(
811            vec![vec![12.into(), 34.into()], vec![56.into(), 78.into()]],
812            parse_scalar("0x3233da25a14a69d02937ebb8f7ca4831e1aa53a069c14bdbddb138d0488b3827"),
813        );
814    }
815
816    #[test]
817    fn test_merkle_tree_two_leaves_two_polynomials_2() {
818        test_merkle_tree::<Sha2Hash>(
819            vec![vec![78.into(), 56.into()], vec![34.into(), 12.into()]],
820            parse_scalar("0x40383f40f001699d6bec77a7ef72289ed6461d28659b94c1156d3d8cad226141"),
821        );
822        test_merkle_tree::<Poseidon2Hash>(
823            vec![vec![78.into(), 56.into()], vec![34.into(), 12.into()]],
824            parse_scalar("0x73b93dac865870e7515af085294a34ebf1bb2f1d86faf619013a9855df6caebb"),
825        );
826    }
827
828    fn test_prover_impl<H: Hash<Scalar>>(
829        polynomials: Vec<Polynomial>,
830        degree_bound: usize,
831        blowup_log2: usize,
832    ) {
833        let prover = Prover::<H>::new(polynomials, degree_bound, blowup_log2);
834        assert_eq!(prover.degree_bound(), degree_bound);
835        let n = degree_bound << blowup_log2;
836        assert_eq!(prover.extended_domain_size(), n);
837        let commitment = prover.commit();
838        for i in 0..n {
839            let query = prover.query(i);
840            assert_eq!(query.indices(), (i, (i + n / 2) % n));
841            assert_eq!(query.len(), degree_bound.trailing_zeros() as usize + 1);
842            assert!(query.verify(&commitment).is_ok());
843        }
844    }
845
846    fn test_prover(polynomials: Vec<Polynomial>, degree_bound: usize) {
847        test_prover_impl::<Sha2Hash>(polynomials.clone(), degree_bound, 1);
848        test_prover_impl::<Poseidon2Hash>(polynomials.clone(), degree_bound, 1);
849        test_prover_impl::<Sha2Hash>(polynomials.clone(), degree_bound, 2);
850        test_prover_impl::<Poseidon2Hash>(polynomials.clone(), degree_bound, 2);
851        test_prover_impl::<Sha2Hash>(polynomials.clone(), degree_bound, 3);
852        test_prover_impl::<Poseidon2Hash>(polynomials.clone(), degree_bound, 3);
853    }
854
855    #[test]
856    fn test_one_constant_polynomial() {
857        test_prover(vec![Polynomial::with_coefficients(vec![12.into()])], 1);
858        test_prover(vec![Polynomial::with_coefficients(vec![34.into()])], 1);
859    }
860
861    #[test]
862    fn test_two_constant_polynomials() {
863        test_prover(
864            vec![
865                Polynomial::with_coefficients(vec![12.into()]),
866                Polynomial::with_coefficients(vec![34.into()]),
867            ],
868            1,
869        );
870    }
871
872    #[test]
873    fn test_three_constant_polynomials() {
874        test_prover(
875            vec![
876                Polynomial::with_coefficients(vec![34.into()]),
877                Polynomial::with_coefficients(vec![56.into()]),
878                Polynomial::with_coefficients(vec![78.into()]),
879            ],
880            1,
881        );
882    }
883
884    #[test]
885    fn test_one_polynomial_degree_one() {
886        test_prover(
887            vec![Polynomial::with_coefficients(vec![12.into(), 34.into()])],
888            2,
889        );
890        test_prover(
891            vec![Polynomial::with_coefficients(vec![56.into(), 78.into()])],
892            2,
893        );
894    }
895
896    #[test]
897    fn test_two_polynomials_degree_one() {
898        test_prover(
899            vec![
900                Polynomial::with_coefficients(vec![12.into(), 34.into()]),
901                Polynomial::with_coefficients(vec![56.into(), 78.into()]),
902            ],
903            2,
904        );
905    }
906
907    #[test]
908    fn test_three_polynomials_degree_one() {
909        test_prover(
910            vec![
911                Polynomial::with_coefficients(vec![34.into(), 56.into()]),
912                Polynomial::with_coefficients(vec![56.into(), 78.into()]),
913                Polynomial::with_coefficients(vec![78.into(), 90.into()]),
914            ],
915            2,
916        );
917    }
918
919    #[test]
920    fn test_one_polynomial_degree_three() {
921        test_prover(
922            vec![Polynomial::with_coefficients(vec![
923                12.into(),
924                34.into(),
925                56.into(),
926                78.into(),
927            ])],
928            4,
929        );
930        test_prover(
931            vec![Polynomial::with_coefficients(vec![
932                42.into(),
933                43.into(),
934                44.into(),
935                45.into(),
936            ])],
937            4,
938        );
939    }
940
941    #[test]
942    fn test_two_polynomials_degree_three() {
943        test_prover(
944            vec![
945                Polynomial::with_coefficients(vec![12.into(), 34.into(), 56.into(), 78.into()]),
946                Polynomial::with_coefficients(vec![42.into(), 43.into(), 44.into(), 45.into()]),
947            ],
948            4,
949        );
950    }
951
952    #[test]
953    fn test_three_polynomials_degree_three() {
954        test_prover(
955            vec![
956                Polynomial::with_coefficients(vec![42.into(), 43.into(), 44.into(), 45.into()]),
957                Polynomial::with_coefficients(vec![12.into(), 34.into(), 56.into(), 78.into()]),
958                Polynomial::with_coefficients(vec![34.into(), 56.into(), 78.into(), 90.into()]),
959            ],
960            4,
961        );
962    }
963}