use crate::{Cow, String, Vec};
use core::{
borrow::Borrow,
fmt::Debug,
ops::{AddAssign, MulAssign, SubAssign},
};
use rand_core::RngCore;
pub use snarkvm_algorithms::fft::DensePolynomial as Polynomial;
use snarkvm_errors::serialization::SerializationError;
use snarkvm_models::curves::Field;
use snarkvm_utilities::{
bytes::{FromBytes, ToBytes},
error as error_fn,
serialize::*,
};
pub type PolynomialLabel = String;
pub trait PCUniversalParams: CanonicalSerialize + CanonicalDeserialize + Clone + Debug + ToBytes + FromBytes {
fn max_degree(&self) -> usize;
}
pub trait PCCommitterKey: CanonicalSerialize + CanonicalDeserialize + Clone + Debug {
fn max_degree(&self) -> usize;
fn supported_degree(&self) -> usize;
}
pub trait PCVerifierKey: CanonicalSerialize + CanonicalDeserialize + Clone + Debug {
fn max_degree(&self) -> usize;
fn supported_degree(&self) -> usize;
}
pub trait PCCommitment: CanonicalDeserialize + CanonicalSerialize + Clone + Debug + ToBytes {
fn empty() -> Self;
fn has_degree_bound(&self) -> bool;
fn is_in_correct_subgroup_assuming_on_curve(&self) -> bool;
}
pub trait PCRandomness: CanonicalSerialize + CanonicalDeserialize + Clone {
fn empty() -> Self;
fn rand<R: RngCore>(num_queries: usize, has_degree_bound: bool, rng: &mut R) -> Self;
}
pub trait PCProof: CanonicalSerialize + CanonicalDeserialize + Clone + ToBytes {}
#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct LabeledPolynomial<'a, F: Field> {
label: PolynomialLabel,
polynomial: Cow<'a, Polynomial<F>>,
degree_bound: Option<usize>,
hiding_bound: Option<usize>,
}
impl<'a, F: Field> core::ops::Deref for LabeledPolynomial<'a, F> {
type Target = Polynomial<F>;
fn deref(&self) -> &Self::Target {
&self.polynomial
}
}
impl<'a, F: Field> LabeledPolynomial<'a, F> {
pub fn new_owned(
label: PolynomialLabel,
polynomial: Polynomial<F>,
degree_bound: Option<usize>,
hiding_bound: Option<usize>,
) -> Self {
Self {
label,
polynomial: Cow::Owned(polynomial),
degree_bound,
hiding_bound,
}
}
pub fn new(
label: PolynomialLabel,
polynomial: &'a Polynomial<F>,
degree_bound: Option<usize>,
hiding_bound: Option<usize>,
) -> Self {
Self {
label,
polynomial: Cow::Borrowed(polynomial),
degree_bound,
hiding_bound,
}
}
pub fn label(&self) -> &String {
&self.label
}
pub fn polynomial(&self) -> &Polynomial<F> {
&self.polynomial
}
pub fn evaluate(&self, point: F) -> F {
self.polynomial.evaluate(point)
}
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, CanonicalSerialize)]
pub struct LabeledCommitment<C: PCCommitment> {
label: PolynomialLabel,
commitment: C,
degree_bound: Option<usize>,
}
impl<C: PCCommitment> ToBytes for LabeledCommitment<C> {
fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
CanonicalSerialize::serialize(&self.commitment, &mut writer).map_err(|_| error_fn("could not serialize struct"))
}
}
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 {
matches!(self, LCTerm::One)
}
}
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,
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,
}
}
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> {
#[allow(clippy::suspicious_op_assign_impl)]
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> {
#[allow(clippy::suspicious_op_assign_impl)]
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
}
}
#[macro_export]
macro_rules! impl_bytes {
($ty: ident) => {
impl<E: PairingEngine> FromBytes for $ty<E> {
fn read<R: Read>(mut reader: R) -> io::Result<Self> {
CanonicalDeserialize::deserialize(&mut reader).map_err(|_| error("could not deserialize struct"))
}
}
impl<E: PairingEngine> ToBytes for $ty<E> {
fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
CanonicalSerialize::serialize(self, &mut writer).map_err(|_| error("could not serialize struct"))
}
}
};
}