use crate::error::Error;
use ark_ec::{
models::short_weierstrass::{Affine, SWCurveConfig},
AffineRepr, CurveGroup,
};
use ark_ff::{BigInteger, Field, PrimeField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{fmt::Debug, rand::RngCore, vec, vec::Vec, UniformRand};
use core::ops::{Add, Sub};
use dock_crypto_utils::commitment::PedersenCommitmentKey;
use zeroize::{Zeroize, ZeroizeOnDrop};
pub trait SWPoint: SWCurveConfig + Clone + Copy + PartialEq {}
impl<T: SWCurveConfig + Clone + Copy + PartialEq> SWPoint for T {}
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
pub struct CommitmentWithOpening<G: SWPoint> {
#[zeroize(skip)]
pub comm: Affine<G>,
pub value: G::ScalarField,
pub randomness: G::ScalarField,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, CanonicalSerialize, CanonicalDeserialize)]
pub struct PointCommitment<G: SWPoint> {
pub x: Affine<G>,
pub y: Affine<G>,
}
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
pub struct PointCommitmentWithOpening<G: SWPoint> {
pub x: G::ScalarField,
pub r_x: G::ScalarField,
pub y: G::ScalarField,
pub r_y: G::ScalarField,
#[zeroize(skip)]
pub comm: PointCommitment<G>,
}
impl<C: SWPoint> PointCommitmentWithOpening<C> {
pub fn new<R: RngCore, P: SWPoint>(
rng: &mut R,
point: &Affine<P>,
comm_key: &PedersenCommitmentKey<Affine<C>>,
) -> Result<Self, Error> {
let r_x = C::ScalarField::rand(rng);
let r_y = C::ScalarField::rand(rng);
Self::new_given_randomness(point, r_x, r_y, comm_key)
}
pub fn new_given_randomness<P: SWPoint>(
point: &Affine<P>,
r_x: C::ScalarField,
r_y: C::ScalarField,
comm_key: &PedersenCommitmentKey<Affine<C>>,
) -> Result<Self, Error> {
let (x, y) = point_coords_as_scalar_field_elements::<P, C>(point)?;
Ok(Self::new_given_randomness_and_coords(
x, y, r_x, r_y, comm_key,
))
}
pub fn new_given_randomness_and_coords(
x: C::ScalarField,
y: C::ScalarField,
r_x: C::ScalarField,
r_y: C::ScalarField,
comm_key: &PedersenCommitmentKey<Affine<C>>,
) -> Self {
let comm_x = comm_key.commit(&x, &r_x);
let comm_y = comm_key.commit(&y, &r_y);
Self {
x,
y,
r_x,
r_y,
comm: PointCommitment {
x: comm_x,
y: comm_y,
},
}
}
}
impl<G: SWPoint> Add for &PointCommitment<G> {
type Output = PointCommitment<G>;
fn add(self, rhs: Self) -> Self::Output {
PointCommitment {
x: (self.x + rhs.x).into_affine(),
y: (self.y + rhs.y).into_affine(),
}
}
}
impl<G: SWPoint> Sub for &PointCommitment<G> {
type Output = PointCommitment<G>;
fn sub(self, rhs: Self) -> Self::Output {
PointCommitment {
x: (self.x.into_group() - rhs.x).into_affine(),
y: (self.y.into_group() - rhs.y).into_affine(),
}
}
}
impl<G: SWPoint> Add for &PointCommitmentWithOpening<G> {
type Output = PointCommitmentWithOpening<G>;
fn add(self, rhs: Self) -> Self::Output {
PointCommitmentWithOpening {
x: self.x + rhs.x,
r_x: self.r_x + rhs.r_x,
y: self.y + rhs.y,
r_y: self.r_y + rhs.r_y,
comm: &self.comm + &rhs.comm,
}
}
}
impl<G: SWPoint> Sub for &PointCommitmentWithOpening<G> {
type Output = PointCommitmentWithOpening<G>;
fn sub(self, rhs: Self) -> Self::Output {
PointCommitmentWithOpening {
x: self.x - rhs.x,
r_x: self.r_x - rhs.r_x,
y: self.y - rhs.y,
r_y: self.r_y - rhs.r_y,
comm: &self.comm - &rhs.comm,
}
}
}
impl<G: SWPoint> CommitmentWithOpening<G> {
pub fn new<R: RngCore>(
rng: &mut R,
value: G::ScalarField,
comm_key: &PedersenCommitmentKey<Affine<G>>,
) -> Self {
let randomness = G::ScalarField::rand(rng);
let comm = comm_key.commit(&value, &randomness);
Self {
value,
randomness,
comm,
}
}
pub fn new_given_randomness(
value: G::ScalarField,
randomness: G::ScalarField,
comm_key: &PedersenCommitmentKey<Affine<G>>,
) -> Self {
let comm = comm_key.commit(&value, &randomness);
Self {
value,
randomness,
comm,
}
}
}
pub fn point_coords_as_scalar_field_elements<P: SWPoint, G: SWPoint>(
point: &Affine<P>,
) -> Result<(G::ScalarField, G::ScalarField), Error> {
if G::ScalarField::MODULUS.to_bytes_le()
!= <P::BaseField as Field>::BasePrimeField::MODULUS.to_bytes_le()
{
return Err(Error::ScalarFieldBaseFieldMismatch);
}
if P::BaseField::extension_degree() != 1 {
return Err(Error::CannotCommitToExtensionOfDegree(
P::BaseField::extension_degree(),
));
}
let xy = point.xy().ok_or(Error::PointAtInfinity)?;
let mut bytes = vec![];
let x = {
for b in xy.0.to_base_prime_field_elements() {
bytes = b.into_bigint().to_bytes_le();
}
G::ScalarField::from_le_bytes_mod_order(&bytes)
};
let y = {
for b in xy.1.to_base_prime_field_elements() {
bytes = b.into_bigint().to_bytes_le();
}
G::ScalarField::from_le_bytes_mod_order(&bytes)
};
Ok((x, y))
}
pub fn from_base_field_to_scalar_field<B: Field, S: PrimeField>(c: &B) -> S {
let mut bytes = vec![];
for b in c.to_base_prime_field_elements() {
bytes = b.into_bigint().to_bytes_le();
}
S::from_le_bytes_mod_order(&bytes)
}