use ark_ff::FftField;
use ark_poly::{EvaluationDomain, GeneralEvaluationDomain};
use ark_serialize::CanonicalSerialize;
use rs_merkle::{Hasher, MerkleTree};
use crate::{
folding::{reduce_polynomial, FoldedEvaluations},
rng::ReseedableRng,
utils::{to_polynomial, AssertPowerOfTwo, HasherExt, MerkleTreeExt},
};
#[derive(Clone)]
pub(crate) struct FriLayer<const N: usize, F, H: Hasher> {
tree: MerkleTree<H>,
evaluations: FoldedEvaluations<N, F>,
}
impl<const N: usize, F, H: Hasher> FriLayer<N, F, H> {
pub fn new(evaluations: &[F]) -> Self
where
F: CanonicalSerialize + Clone,
{
let evaluations = FoldedEvaluations::new(evaluations);
let tree = MerkleTree::from_evaluations(evaluations.as_ref());
Self { tree, evaluations }
}
pub const fn tree(&self) -> &MerkleTree<H> {
&self.tree
}
pub const fn evaluations(&self) -> &FoldedEvaluations<N, F> {
&self.evaluations
}
}
#[derive(Clone)]
pub struct FriCommitments<const N: usize, F, H: Hasher> {
layers: Vec<FriLayer<N, F, H>>,
remainder: Vec<F>,
}
impl<const N: usize, F: FftField, H: Hasher> FriCommitments<N, F, H> {
pub fn new<R>(
mut evaluations: Vec<F>,
mut rng: R,
blowup_factor: usize,
remainder_degree_plus_one: usize,
) -> Self
where
R: ReseedableRng<Seed = H::Hash>,
{
let _: () = AssertPowerOfTwo::<N>::OK;
let degree_bound = evaluations.len() / blowup_factor;
debug_assert!(
(degree_bound.ilog2() - remainder_degree_plus_one.ilog2()) % N.ilog2() == 0,
"Invalid remainder degree {} for polynomial of degree {} and folding factor {N} (would result in degree truncation)",
remainder_degree_plus_one - 1,
degree_bound - 1
);
let mut layers = Vec::with_capacity(
((degree_bound.ilog2() - remainder_degree_plus_one.ilog2()) / N.ilog2()) as usize,
);
let domain = GeneralEvaluationDomain::<F>::new(N).unwrap();
while evaluations.len() > remainder_degree_plus_one * blowup_factor {
let layer = FriLayer::new(&evaluations);
rng.reseed(layer.tree().root().expect("cannot get tree root"));
evaluations =
reduce_polynomial::<N, _>(layer.evaluations(), rng.draw_alpha(), Some(&domain));
layers.push(layer);
}
let poly = to_polynomial(evaluations, remainder_degree_plus_one);
rng.reseed(H::hash_item(&poly));
Self {
layers,
remainder: poly,
}
}
pub(crate) fn layers(&self) -> &[FriLayer<N, F, H>] {
&self.layers
}
pub(crate) fn remainder(self) -> Vec<F> {
self.remainder
}
}