Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kzg #69

Merged
merged 14 commits into from
May 21, 2024
305 changes: 16 additions & 289 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 0 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@ version ="0.1.0"

[dependencies]
rand ="0.8.5"
num-bigint={ version="0.4.5", default-features=false }
ark-std ={ version="0.4.0", default-features=false }
ark-bn254 ="0.4.0"
ark-poly ="0.4.0"
ark-ff ="0.4.0"
ark-ec ="0.4.0"
Comment on lines -13 to -17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3


[dev-dependencies]
rstest ="0.19.0"
Expand Down
28 changes: 25 additions & 3 deletions src/curve/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Elliptic curve operations and types.

use self::field::prime::PlutoScalarField;
use super::*;

pub mod pairing;
Expand Down Expand Up @@ -93,6 +94,12 @@ impl<C: EllipticCurve> AddAssign for AffinePoint<C> {
fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; }
}

impl<C: EllipticCurve> Sum for AffinePoint<C> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(|x, y| x + y).unwrap_or(AffinePoint::Infinity)
}
}

impl<C: EllipticCurve> Neg for AffinePoint<C> {
type Output = AffinePoint<C>;

Expand All @@ -105,15 +112,16 @@ impl<C: EllipticCurve> Neg for AffinePoint<C> {
}
}

// TODO: This should likely use a `Self::ScalarField` instead of `u32`.
/// Scalar multiplication on the rhs: P*(u32)
/// This is the niave implementation of scalar multiplication
/// There is a faster way to do this but this is simpler to reason about for now
#[allow(clippy::suspicious_arithmetic_impl)]
impl<C: EllipticCurve> Mul<u32> for AffinePoint<C> {
type Output = AffinePoint<C>;

fn mul(mut self, scalar: u32) -> Self::Output {
if scalar == 0 {
return AffinePoint::Infinity;
}
let val = self;
for _ in 1..scalar {
self += val;
Expand All @@ -122,12 +130,26 @@ impl<C: EllipticCurve> Mul<u32> for AffinePoint<C> {
}
}

/// Scalar multiplication on the Lhs (u32)*P
impl<C: EllipticCurve> Sub for AffinePoint<C> {
type Output = AffinePoint<C>;

fn sub(self, rhs: Self) -> Self::Output { self + -rhs }
}

impl<C: EllipticCurve> Mul<PlutoScalarField> for AffinePoint<C> {
type Output = AffinePoint<C>;

fn mul(self, scalar: PlutoScalarField) -> Self::Output { scalar.value as u32 * self }
}

#[allow(clippy::suspicious_arithmetic_impl)]
impl<C: EllipticCurve> std::ops::Mul<AffinePoint<C>> for u32 {
type Output = AffinePoint<C>;

fn mul(self, val: AffinePoint<C>) -> Self::Output {
if self == 0 {
return AffinePoint::Infinity;
}
let mut out = val;
for _ in 1..self {
out += val;
Expand Down
32 changes: 32 additions & 0 deletions src/curve/pairing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,36 @@ mod tests {

assert_eq!(result.pow(17), PlutoBaseFieldExtension::ONE);
}

// test the bilinearity of the pairing
#[test]
fn bilinearity() {
let a = PlutoScalarField::new(3);
let b = PlutoScalarField::new(5);

let p = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::generator());
let cube_root_of_unity = PlutoBaseFieldExtension::primitive_root_of_unity(3);
let q = if let AffinePoint::<PlutoBaseCurve>::Point(x, y) =
AffinePoint::<PlutoBaseCurve>::generator()
{
AffinePoint::<PlutoExtendedCurve>::new(
cube_root_of_unity * PlutoBaseFieldExtension::from(x),
PlutoBaseFieldExtension::from(y),
)
} else {
panic!("Generator is not a point");
};

let a_p = p * a;
let b_q = q * b;

let lhs = pairing::<PlutoExtendedCurve, 17>(a_p, b_q);
let ab = a * b;
let rhs = pairing::<PlutoExtendedCurve, 17>(p, q).pow(ab.value);

println!("LHS: {:?}", lhs);
println!("RHS: {:?}", rhs);

assert_eq!(lhs, rhs);
}
}
2 changes: 1 addition & 1 deletion src/field/prime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub type PlutoScalarField = PrimeField<{ PlutoPrime::Scalar as usize }>;
/// by a prime number `P`, and the elements are integers modulo `P`.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, PartialOrd)]
pub struct PrimeField<const P: usize> {
value: usize,
pub(crate) value: usize,
}

impl<const P: usize> PrimeField<P> {
Expand Down
139 changes: 0 additions & 139 deletions src/kzg.rs

This file was deleted.

7 changes: 7 additions & 0 deletions src/kzg/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! KZG implementation for polynomial commitments
pub mod setup;
#[cfg(test)] mod tests;

pub use setup::*;

use super::*;
112 changes: 112 additions & 0 deletions src/kzg/setup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//! Does the SRS setup for the KZG10 scheme.

use self::{curve::pairing::pairing, field::prime::PlutoScalarField};
use super::*;

/// simple setup to get params.
#[allow(dead_code, clippy::type_complexity)]
pub fn setup() -> (Vec<AffinePoint<PlutoExtendedCurve>>, Vec<AffinePoint<PlutoExtendedCurve>>) {
// NOTE: For demonstration purposes only.

// This is just tau from plonk by hand, it is not actually secure
let tau: PlutoScalarField = PlutoScalarField::new(2);

let g1 = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::generator());
let g2 = AffinePoint::<PlutoExtendedCurve>::generator();
// NOTE: Just sample the d of both for now.
// - g1 and g2 SRS have variable sizes for diff kzg uses
// - in eth blobs, g1 is 4096 elements, g2 is 16 elements
// - in plonk, we need d+5 g1 elements and one g2 element
let mut srs_g1_points: Vec<AffinePoint<PlutoExtendedCurve>> = vec![];
let mut srs_g2_points: Vec<AffinePoint<PlutoExtendedCurve>> = vec![];
for i in 0..7 {
// G1 Group

// degree seven commitment poly
// g1srs = {g1^tau^0, g1^tau^1, g1^tau^2, g1^tau^3, g1^tau^4, g1^tau^5, g1^tau^6}
let result = g1 * tau.pow(i);

srs_g1_points.push(result);
// G2 Group

// degree two divisor poly
if i < 2 {
// g2srs = {g2^tau^0, g2^tau^1}
let result = g2 * tau.pow(i);
srs_g2_points.push(result);
}
}

(srs_g1_points, srs_g2_points)
}

/// kzg poly commit
/// Both binding and hiding commitment
#[allow(dead_code)]
pub fn commit(
coefs: Vec<PlutoScalarField>,
g1_srs: Vec<AffinePoint<PlutoExtendedCurve>>,
) -> AffinePoint<PlutoExtendedCurve> {
// check srs is longer than coefs
assert!(g1_srs.len() >= coefs.len());
// SUM_{i=0}^{n} (g1^tau^i * coef_i)
g1_srs.into_iter().zip(coefs).map(|(g1, coef)| g1 * coef).sum::<AffinePoint<PlutoExtendedCurve>>()
}

/// Open the commitment
pub fn open(
coefs: Vec<PlutoScalarField>,
eval_point: PlutoScalarField,
g1_srs: Vec<AffinePoint<PlutoExtendedCurve>>,
) -> AffinePoint<PlutoExtendedCurve> {
let poly = Polynomial::<Monomial, PlutoScalarField>::new(coefs.clone());
let divisor =
Polynomial::<Monomial, PlutoScalarField>::new(vec![-eval_point, PlutoScalarField::ONE]);

let result = poly.div(divisor).coefficients;
println!("resulting polynomial {:?}", result);

commit(result, g1_srs)
}

/// Verify the polynomial evaluation.
pub fn check(
p: AffinePoint<PlutoExtendedCurve>,
q: AffinePoint<PlutoExtendedCurve>,
point: PlutoScalarField,
value: PlutoScalarField,
g1_srs: Vec<AffinePoint<PlutoExtendedCurve>>,
g2_srs: Vec<AffinePoint<PlutoExtendedCurve>>,
) -> bool {
let g1 = *g1_srs.first().expect("has g1 srs");

// This was the seeming bug, It now works for all polynomials, but am not sure why yet.
let g2 = g2_srs[1];

// e(pi, g2 - gen * point)
let lhs = pairing::<PlutoExtendedCurve, 17>(
q,
g2 - AffinePoint::<PlutoExtendedCurve>::generator() * point,
);

// e(p - g1 * value, gen)
let rhs = pairing::<PlutoExtendedCurve, 17>(
p - g1 * value,
AffinePoint::<PlutoExtendedCurve>::generator(),
);
println!("lhs {:?}", lhs);
println!("rhs {:?}", rhs);

lhs == rhs
}

// p = 101
// k = 2 (embedding degree, determines your extension field)
// base field = GF_101
// base scaler is 17 (number of points in the group)
// pairing output is in Extension field = GF_101^2?
// (all petals are in this base extension field: has two cyclic groups of order 17)

// Asymmetric means G1 and G2 are different subgroups
// This is a little confusing teminology because all pairing friendly subgroups are isomorphic
// Symmetric means G1 and G2 are the same subgroup
Loading