use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup, VariableBaseMSM};
use ark_ff::{Field, One, PrimeField, Zero};
use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial};
use ark_serialize::{CanonicalSerialize, Compress};
#[cfg(not(feature = "std"))]
use ark_std::vec::Vec;
use ark_std::{
borrow::Borrow,
fmt,
ops::{Add, Mul},
};
mod data_structures;
mod space;
mod time;
pub use data_structures::*;
pub use space::CommitterKeyStream;
pub use time::CommitterKey;
#[cfg(test)]
#[allow(missing_docs)]
pub mod tests;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Commitment<E: Pairing>(pub(crate) E::G1Affine);
impl<E: Pairing> Commitment<E> {
pub fn size_in_bytes(&self) -> usize {
E::G1Affine::zero().serialized_size(Compress::Yes)
}
}
#[inline]
fn msm<E: Pairing>(bases: &[E::G1Affine], scalars: &[E::ScalarField]) -> E::G1Affine {
let scalars = scalars.iter().map(|x| x.into_bigint()).collect::<Vec<_>>();
let sp = <E::G1 as VariableBaseMSM>::msm_bigint(bases, &scalars);
sp.into_affine()
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EvaluationProof<E: Pairing>(pub E::G1Affine);
impl<E: Pairing> Add for EvaluationProof<E> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
EvaluationProof((self.0 + rhs.0).into_affine())
}
}
impl<E: Pairing> core::iter::Sum for EvaluationProof<E> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let zero = EvaluationProof(E::G1Affine::zero());
iter.fold(zero, |x, y| x + y)
}
}
#[derive(Debug, Clone)]
pub struct VerificationError;
impl fmt::Display for VerificationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error in stream.")
}
}
pub(crate) type VerificationResult = Result<(), VerificationError>;
#[derive(Debug, PartialEq, Eq)]
pub struct VerifierKey<E: Pairing> {
powers_of_g: Vec<E::G1Affine>,
powers_of_g2: Vec<E::G2Affine>,
}
impl<E: Pairing> VerifierKey<E> {
pub fn verify(
&self,
commitment: &Commitment<E>,
&alpha: &E::ScalarField,
evaluation: &E::ScalarField,
proof: &EvaluationProof<E>,
) -> VerificationResult {
let scalars = [(-alpha).into_bigint(), E::ScalarField::one().into_bigint()];
let ep = <E::G2 as VariableBaseMSM>::msm_bigint(&self.powers_of_g2, &scalars);
let lhs = commitment.0.into_group() - self.powers_of_g[0].mul(evaluation);
let g2 = self.powers_of_g2[0];
if E::pairing(lhs, g2) == E::pairing(proof.0, ep) {
Ok(())
} else {
Err(VerificationError)
}
}
pub fn verify_multi_points(
&self,
commitments: &[Commitment<E>],
eval_points: &[E::ScalarField],
evaluations: &[Vec<E::ScalarField>],
proof: &EvaluationProof<E>,
open_chal: &E::ScalarField,
) -> VerificationResult {
let zeros = vanishing_polynomial(eval_points);
let zeros_repr = zeros.iter().map(|x| x.into_bigint()).collect::<Vec<_>>();
let zeros = <E::G2 as VariableBaseMSM>::msm_bigint(&self.powers_of_g2, &zeros_repr);
let mut sca_inverse = Vec::new();
for (j, x_j) in eval_points.iter().enumerate() {
let mut sca = E::ScalarField::one();
for (k, x_k) in eval_points.iter().enumerate() {
if j == k {
continue;
}
sca *= *x_j - x_k;
}
sca = sca.inverse().unwrap();
sca_inverse.push(sca);
}
let mut lang = Vec::new();
for (j, _x_j) in eval_points.iter().enumerate() {
let mut l_poly = DensePolynomial::from_coefficients_vec(vec![E::ScalarField::one()]);
for (k, x_k) in eval_points.iter().enumerate() {
if j == k {
continue;
}
let tmp_poly =
DensePolynomial::from_coefficients_vec(vec![-(*x_k), E::ScalarField::one()]);
l_poly = l_poly.mul(&tmp_poly);
}
lang.push(l_poly);
}
let etas = powers(*open_chal, evaluations.len());
let interpolated_polynomials = evaluations
.iter()
.map(|e| interpolate_poly::<E>(eval_points, e, &sca_inverse, &lang).coeffs)
.collect::<Vec<_>>();
let i_poly = linear_combination(&interpolated_polynomials[..], &etas).unwrap();
let i_comm = msm::<E>(&self.powers_of_g, &i_poly);
let comm_vec = commitments.iter().map(|x| x.0).collect::<Vec<_>>();
let etas_repr = etas.iter().map(|e| e.into_bigint()).collect::<Vec<_>>();
let f_comm = <E::G1 as VariableBaseMSM>::msm_bigint(&comm_vec, &etas_repr);
let g2 = self.powers_of_g2[0];
if E::pairing(f_comm - i_comm.into_group(), g2) == E::pairing(proof.0, zeros) {
Ok(())
} else {
Err(VerificationError)
}
}
}
fn interpolate_poly<E: Pairing>(
eval_points: &[E::ScalarField],
evals: &[E::ScalarField],
sca_inverse: &[E::ScalarField],
lang: &[DensePolynomial<E::ScalarField>],
) -> DensePolynomial<E::ScalarField> {
let mut res = DensePolynomial::from_coefficients_vec(vec![E::ScalarField::zero()]);
for (j, (_x_j, y_j)) in eval_points.iter().zip(evals.iter()).enumerate() {
let l_poly = (&lang[j]).mul(sca_inverse[j] * y_j);
res = (&res).add(&l_poly);
}
res
}
pub(crate) fn vanishing_polynomial<F: Field>(points: &[F]) -> DensePolynomial<F> {
let one = DensePolynomial::from_coefficients_vec(vec![F::one()]);
points
.iter()
.map(|&point| DensePolynomial::from_coefficients_vec(vec![-point, F::one()]))
.fold(one, |x, y| x.naive_mul(&y))
}
pub(crate) fn linear_combination<F: Field, PP>(
polynomials: &[PP],
challenges: &[F],
) -> Option<Vec<F>>
where
PP: Borrow<Vec<F>>,
{
polynomials
.iter()
.zip(challenges.iter())
.map(|(p, &c)| &DensePolynomial::from_coefficients_vec(p.borrow().to_vec()) * c)
.reduce(|x, y| x + y)?
.coeffs
.into()
}
pub(crate) fn powers<F: Field>(element: F, len: usize) -> Vec<F> {
let mut powers = vec![F::one(); len];
for i in 1..len {
powers[i] = element * powers[i - 1];
}
powers
}