use crate::{Polynomial, String, Vec};
use ark_ff::{Field, PrimeField, ToConstraintField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::rand::RngCore;
use ark_std::{
borrow::Borrow,
marker::PhantomData,
ops::{AddAssign, MulAssign, SubAssign},
};
pub type PolynomialLabel = String;
pub trait PCUniversalParams:
Clone + core::fmt::Debug + CanonicalSerialize + CanonicalDeserialize
{
fn max_degree(&self) -> usize;
}
pub trait PCCommitterKey:
Clone + core::fmt::Debug + CanonicalSerialize + CanonicalDeserialize
{
fn max_degree(&self) -> usize;
fn supported_degree(&self) -> usize;
}
pub trait PCVerifierKey:
Clone + core::fmt::Debug + CanonicalSerialize + CanonicalDeserialize
{
fn max_degree(&self) -> usize;
fn supported_degree(&self) -> usize;
}
pub trait PCPreparedVerifierKey<Unprepared: PCVerifierKey> {
fn prepare(vk: &Unprepared) -> Self;
}
pub trait PCCommitment: Clone + CanonicalSerialize + CanonicalDeserialize {
fn empty() -> Self;
fn has_degree_bound(&self) -> bool;
}
pub trait PCPreparedCommitment<UNPREPARED: PCCommitment>: Clone {
fn prepare(comm: &UNPREPARED) -> Self;
}
pub trait PCRandomness: Clone + CanonicalSerialize + CanonicalDeserialize {
fn empty() -> Self;
fn rand<R: RngCore>(
num_queries: usize,
has_degree_bound: bool,
num_vars: Option<usize>,
rng: &mut R,
) -> Self;
}
#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct BatchLCProof<F: PrimeField, T: Clone + CanonicalSerialize + CanonicalDeserialize> {
pub proof: T,
pub evals: Option<Vec<F>>,
}
#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct LabeledPolynomial<F: Field, P: Polynomial<F>> {
label: PolynomialLabel,
polynomial: P,
degree_bound: Option<usize>,
hiding_bound: Option<usize>,
_field: PhantomData<F>,
}
impl<'a, F: Field, P: Polynomial<F>> core::ops::Deref for LabeledPolynomial<F, P> {
type Target = P;
fn deref(&self) -> &Self::Target {
&self.polynomial
}
}
impl<'a, F: Field, P: Polynomial<F>> LabeledPolynomial<F, P> {
pub fn new(
label: PolynomialLabel,
polynomial: P,
degree_bound: Option<usize>,
hiding_bound: Option<usize>,
) -> Self {
Self {
label,
polynomial: polynomial,
degree_bound,
hiding_bound,
_field: PhantomData,
}
}
pub fn label(&self) -> &String {
&self.label
}
pub fn polynomial(&self) -> &P {
&self.polynomial
}
pub fn polynomial_mut(&mut self) -> &mut P {
&mut self.polynomial
}
pub fn evaluate(&self, point: &P::Point) -> F {
self.polynomial.evaluate(point)
}
pub fn degree(&self) -> usize {
self.polynomial.degree()
}
pub fn degree_bound(&self) -> Option<usize> {
self.degree_bound
}
pub fn is_hiding(&self) -> bool {
self.hiding_bound.is_some()
}
pub fn hiding_bound(&self) -> Option<usize> {
self.hiding_bound
}
}
#[derive(Clone)]
pub struct LabeledCommitment<C: PCCommitment> {
label: PolynomialLabel,
commitment: C,
degree_bound: Option<usize>,
}
impl<F: Field, C: PCCommitment + ToConstraintField<F>> ToConstraintField<F>
for LabeledCommitment<C>
{
fn to_field_elements(&self) -> Option<Vec<F>> {
self.commitment.to_field_elements()
}
}
impl<C: PCCommitment> LabeledCommitment<C> {
pub fn new(label: PolynomialLabel, commitment: C, degree_bound: Option<usize>) -> Self {
Self {
label,
commitment,
degree_bound,
}
}
pub fn label(&self) -> &String {
&self.label
}
pub fn commitment(&self) -> &C {
&self.commitment
}
pub fn degree_bound(&self) -> Option<usize> {
self.degree_bound
}
}
#[derive(Hash, Ord, PartialOrd, Clone, Eq, PartialEq, Debug)]
pub enum LCTerm {
One,
PolyLabel(String),
}
impl LCTerm {
#[inline]
pub fn is_one(&self) -> bool {
if let LCTerm::One = self {
true
} else {
false
}
}
}
impl From<PolynomialLabel> for LCTerm {
fn from(other: PolynomialLabel) -> Self {
Self::PolyLabel(other)
}
}
impl<'a> From<&'a str> for LCTerm {
fn from(other: &str) -> Self {
Self::PolyLabel(other.into())
}
}
impl core::convert::TryInto<PolynomialLabel> for LCTerm {
type Error = ();
fn try_into(self) -> Result<PolynomialLabel, ()> {
match self {
Self::One => Err(()),
Self::PolyLabel(l) => Ok(l),
}
}
}
impl<'a> core::convert::TryInto<&'a PolynomialLabel> for &'a LCTerm {
type Error = ();
fn try_into(self) -> Result<&'a PolynomialLabel, ()> {
match self {
LCTerm::One => Err(()),
LCTerm::PolyLabel(l) => Ok(l),
}
}
}
impl<B: Borrow<String>> PartialEq<B> for LCTerm {
fn eq(&self, other: &B) -> bool {
match self {
Self::One => false,
Self::PolyLabel(l) => l == other.borrow(),
}
}
}
#[derive(Clone, Debug)]
pub struct LinearCombination<F> {
pub label: String,
pub terms: Vec<(F, LCTerm)>,
}
impl<F: Field> LinearCombination<F> {
pub fn empty(label: impl Into<String>) -> Self {
Self {
label: label.into(),
terms: Vec::new(),
}
}
pub fn new(label: impl Into<String>, terms: Vec<(F, impl Into<LCTerm>)>) -> Self {
let terms = terms.into_iter().map(|(c, t)| (c, t.into())).collect();
Self {
label: label.into(),
terms: terms,
}
}
pub fn label(&self) -> &String {
&self.label
}
pub fn is_empty(&self) -> bool {
self.terms.is_empty()
}
pub fn push(&mut self, term: (F, LCTerm)) -> &mut Self {
self.terms.push(term);
self
}
}
impl<'a, F: Field> AddAssign<(F, &'a LinearCombination<F>)> for LinearCombination<F> {
fn add_assign(&mut self, (coeff, other): (F, &'a LinearCombination<F>)) {
self.terms
.extend(other.terms.iter().map(|(c, t)| (coeff * c, t.clone())));
}
}
impl<'a, F: Field> SubAssign<(F, &'a LinearCombination<F>)> for LinearCombination<F> {
fn sub_assign(&mut self, (coeff, other): (F, &'a LinearCombination<F>)) {
self.terms
.extend(other.terms.iter().map(|(c, t)| (-coeff * c, t.clone())));
}
}
impl<'a, F: Field> AddAssign<&'a LinearCombination<F>> for LinearCombination<F> {
fn add_assign(&mut self, other: &'a LinearCombination<F>) {
self.terms.extend(other.terms.iter().cloned());
}
}
impl<'a, F: Field> SubAssign<&'a LinearCombination<F>> for LinearCombination<F> {
fn sub_assign(&mut self, other: &'a LinearCombination<F>) {
self.terms
.extend(other.terms.iter().map(|(c, t)| (-*c, t.clone())));
}
}
impl<F: Field> AddAssign<F> for LinearCombination<F> {
fn add_assign(&mut self, coeff: F) {
self.terms.push((coeff, LCTerm::One));
}
}
impl<F: Field> SubAssign<F> for LinearCombination<F> {
fn sub_assign(&mut self, coeff: F) {
self.terms.push((-coeff, LCTerm::One));
}
}
impl<F: Field> MulAssign<F> for LinearCombination<F> {
fn mul_assign(&mut self, coeff: F) {
self.terms.iter_mut().for_each(|(c, _)| *c *= coeff);
}
}
impl<F: Field> core::ops::Deref for LinearCombination<F> {
type Target = [(F, LCTerm)];
fn deref(&self) -> &Self::Target {
&self.terms
}
}