Skip to content

Commit

Permalink
Polynomial.rs improvements (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
feltroidprime authored Aug 19, 2024
1 parent c344b09 commit d2011dc
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 59 deletions.
12 changes: 9 additions & 3 deletions hydra/garaga/hints/ecip.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,8 +679,14 @@ def build_cairo1_tests_derive_ec_point_from_X(x: int, curve_id: CurveID, idx: in

t0 = time.time()
ZZ = zk_ecip_hint(Bs, ss, use_rust=False)
print(f"Time taken py : {time.time()-t0}")
time_taken_py = time.time() - t0
print(f"Time taken py : {time_taken_py}")

t0 = time.time()
ZZ = zk_ecip_hint(Bs, ss, use_rust=True)
print(f"Time taken rs : {time.time()-t0}")
ZZ_rs = zk_ecip_hint(Bs, ss, use_rust=True)
time_taken_rs = time.time() - t0
print(f"Time taken rs : {time_taken_rs}")

print(f"Ratio: {time_taken_py / time_taken_rs}")

assert ZZ == ZZ_rs
10 changes: 5 additions & 5 deletions tools/garaga_rs/src/ecip/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ fn construct_function<F: IsPrimeField + CurveParamsProvider<F>>(ps: Vec<G1Point<
let product = a_num_b_num * line_ab;
let num = product.reduce();
let den = (line(a.clone(), a.neg()) * line(b.clone(), b.neg())).to_poly();
let d = num.div_by_poly(den);
let d = num.div_by_poly(&den);
xs2.push((a.add(b), d));
}

Expand Down Expand Up @@ -505,16 +505,16 @@ fn dlog<F: IsPrimeField + CurveParamsProvider<F>>(d: FF<F>) -> FunctionFelt<F> {

FunctionFelt {
a: RationalFunction::new(
a_num.scale_by_coeff(den.leading_coefficient().inv().unwrap()),
a_num.scale_by_coeff(&den.leading_coefficient().inv().unwrap()),
a_den
.clone()
.scale_by_coeff(a_den.leading_coefficient().inv().unwrap()),
.scale_by_coeff(&a_den.leading_coefficient().inv().unwrap()),
),
b: RationalFunction::new(
b_num.scale_by_coeff(den.leading_coefficient().inv().unwrap()),
b_num.scale_by_coeff(&den.leading_coefficient().inv().unwrap()),
b_den
.clone()
.scale_by_coeff(b_den.leading_coefficient().inv().unwrap()),
.scale_by_coeff(&b_den.leading_coefficient().inv().unwrap()),
),
}
}
16 changes: 8 additions & 8 deletions tools/garaga_rs/src/ecip/ff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ impl<F: IsPrimeField + CurveParamsProvider<F>> FF<F> {

for (i, poly) in self.coeffs.iter().enumerate().skip(2) {
if i % 2 == 0 {
deg_0_coeff = deg_0_coeff + poly.clone() * y2.clone();
deg_0_coeff = deg_0_coeff + poly * &y2;
} else {
deg_1_coeff = deg_1_coeff + poly.clone() * y2.clone();
y2 = y2.clone() * y2.clone();
deg_1_coeff = deg_1_coeff + poly * &y2;

y2 = &y2 * &y2;
}
}

Expand All @@ -85,7 +86,7 @@ impl<F: IsPrimeField + CurveParamsProvider<F>> FF<F> {
coeffs: self
.coeffs
.iter()
.map(|c| c.clone().scale_by_coeff(inv_coeff.clone()))
.map(|c| c.scale_by_coeff(&inv_coeff))
.collect(),
y2: self.y2.clone(),
}
Expand All @@ -96,12 +97,11 @@ impl<F: IsPrimeField + CurveParamsProvider<F>> FF<F> {
self.coeffs[0].clone()
}

pub fn div_by_poly(&self, poly: Polynomial<F>) -> FF<F> {
// println!("Starting div_by_poly with poly: {:?}", poly);
pub fn div_by_poly(&self, poly: &Polynomial<F>) -> FF<F> {
let coeffs: Vec<Polynomial<F>> = self
.coeffs
.iter()
.map(|c| c.clone().div_with_ref(&poly.clone()))
.map(|c| c.clone().div_with_ref(poly))
.collect();

// println!("Final coefficients after division: {:?}", coeffs);
Expand Down Expand Up @@ -168,7 +168,7 @@ impl<F: IsPrimeField + CurveParamsProvider<F>> Mul for FF<F> {

for (i, self_poly) in self.coeffs.iter().enumerate() {
for (j, other_poly) in other.coeffs.iter().enumerate() {
let product = self_poly.clone() * other_poly.clone();
let product = self_poly * other_poly;
coeffs[i + j] = coeffs[i + j].clone() + product;
}
}
Expand Down
126 changes: 87 additions & 39 deletions tools/garaga_rs/src/ecip/polynomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ impl<F: IsPrimeField> Polynomial<F> {
Polynomial::new(vec![FieldElement::<F>::zero()])
}

pub fn mul_with_ref(&self, other: &Polynomial<F>) -> Polynomial<F> {
if self.degree() == -1 || other.degree() == -1 {
return Polynomial::zero();
}
let mut result_coeffs =
vec![FieldElement::<F>::zero(); self.coefficients.len() + other.coefficients.len() - 1];

for (i, self_coeff) in self.coefficients.iter().enumerate() {
for (j, other_coeff) in other.coefficients.iter().enumerate() {
result_coeffs[i + j] += self_coeff * other_coeff;
}
}

Polynomial::new(result_coeffs)
}

pub fn divmod(self, denominator: &Self) -> (Self, Self) {
let den_deg = denominator.degree();
if den_deg == -1 {
Expand All @@ -97,13 +113,12 @@ impl<F: IsPrimeField> Polynomial<F> {
let mut rem_deg = num_deg;
while rem_deg >= den_deg {
let shift = rem_deg - den_deg;
let coefficient =
remainder.coefficients[rem_deg as usize].clone() * denom_lead_inv.clone();
let coefficient = &remainder.coefficients[rem_deg as usize] * &denom_lead_inv;
quotient_coeffs[shift as usize] = coefficient.clone();

let mut subtractee_coeffs = vec![FieldElement::<F>::zero(); (shift) as usize];
subtractee_coeffs.push(coefficient);
let subtractee = Polynomial::new(subtractee_coeffs) * denominator.clone();
let subtractee = Polynomial::new(subtractee_coeffs).mul_with_ref(denominator);
remainder = remainder - subtractee;
rem_deg = remainder.degree();
}
Expand All @@ -126,8 +141,8 @@ impl<F: IsPrimeField> Polynomial<F> {

for (i, coeff) in self.coefficients.iter().enumerate().skip(1) {
let u_64 = i as u64;
let degree = FieldElement::<F>::from(u_64);
new_coeffs[i - 1] = coeff.clone() * degree;
let degree = &FieldElement::<F>::from(u_64);
new_coeffs[i - 1] = *(&coeff) * degree;
}
Polynomial::new(new_coeffs)
}
Expand All @@ -148,24 +163,24 @@ impl<F: IsPrimeField> Polynomial<F> {
while r.degree() != -1 {
let quotient = old_r.clone().div_with_ref(&r);

let new_r = old_r - quotient.clone() * r.clone();
let new_r = old_r - quotient.clone().mul_with_ref(&r);
old_r = r;
r = new_r;

let new_s = old_s - quotient.clone() * s.clone();
let new_s = old_s - quotient.clone().mul_with_ref(&s);
old_s = s;
s = new_s;

let new_t = old_t - quotient.clone() * t.clone();
let new_t = old_t - quotient.clone().mul_with_ref(&t);
old_t = t;
t = new_t;
}

let lcinv = old_r.leading_coefficient().inv().unwrap();
(
old_s.scale_by_coeff(lcinv.clone()),
old_t.scale_by_coeff(lcinv.clone()),
old_r.scale_by_coeff(lcinv.clone()),
old_s.scale_by_coeff(&lcinv),
old_t.scale_by_coeff(&lcinv),
old_r.scale_by_coeff(&lcinv),
)
}

Expand All @@ -174,13 +189,39 @@ impl<F: IsPrimeField> Polynomial<F> {
quotient
}

pub fn scale_by_coeff(&self, coeff: FieldElement<F>) -> Polynomial<F> {
Polynomial::new(
self.coefficients
.iter()
.map(|c| c.clone() * coeff.clone())
.collect(),
)
pub fn scale_by_coeff(&self, coeff: &FieldElement<F>) -> Polynomial<F> {
Polynomial::new(self.coefficients.iter().map(|c| c * coeff).collect())
}
}

pub fn pad_with_zero_coefficients_to_length<F: IsPrimeField>(pa: &mut Polynomial<F>, n: usize) {
pa.coefficients.resize(n, FieldElement::zero());
}
pub fn pad_with_zero_coefficients<F: IsPrimeField>(
pa: &Polynomial<F>,
pb: &Polynomial<F>,
) -> (Polynomial<F>, Polynomial<F>) {
let mut pa = pa.clone();
let mut pb = pb.clone();

if pa.coefficients.len() > pb.coefficients.len() {
pad_with_zero_coefficients_to_length(&mut pb, pa.coefficients.len());
} else {
pad_with_zero_coefficients_to_length(&mut pa, pb.coefficients.len());
}
(pa, pb)
}

impl<F: IsPrimeField> std::ops::Add<&Polynomial<F>> for &Polynomial<F> {
type Output = Polynomial<F>;

fn add(self, a_polynomial: &Polynomial<F>) -> Self::Output {
let (pa, pb) = pad_with_zero_coefficients(self, a_polynomial);
let iter_coeff_pa = pa.coefficients.iter();
let iter_coeff_pb = pb.coefficients.iter();
let new_coefficients = iter_coeff_pa.zip(iter_coeff_pb).map(|(x, y)| x + y);
let new_coefficients_vec = new_coefficients.collect::<Vec<FieldElement<F>>>();
Polynomial::new(new_coefficients_vec)
}
}

Expand Down Expand Up @@ -221,27 +262,6 @@ impl<F: IsPrimeField> std::ops::Sub for Polynomial<F> {
}
}

impl<F: IsPrimeField> std::ops::Mul for Polynomial<F> {
type Output = Polynomial<F>;

fn mul(self, other: Polynomial<F>) -> Polynomial<F> {
if self.degree() == -1 || other.degree() == -1 {
return Polynomial::zero();
}
let mut result_coeffs =
vec![FieldElement::<F>::zero(); self.coefficients.len() + other.coefficients.len() - 1];

for (i, self_coeff) in self.coefficients.iter().enumerate() {
for (j, other_coeff) in other.coefficients.iter().enumerate() {
result_coeffs[i + j] =
result_coeffs[i + j].clone() + self_coeff.clone() * other_coeff.clone();
}
}

Polynomial::new(result_coeffs)
}
}

impl<F: IsPrimeField> PartialEq for Polynomial<F> {
fn eq(&self, other: &Self) -> bool {
if self.coefficients.len() != other.coefficients.len() {
Expand All @@ -257,3 +277,31 @@ impl<F: IsPrimeField> PartialEq for Polynomial<F> {
true
}
}

impl<F: IsPrimeField> std::ops::Mul<&Polynomial<F>> for &Polynomial<F> {
type Output = Polynomial<F>;
fn mul(self, factor: &Polynomial<F>) -> Polynomial<F> {
self.mul_with_ref(factor)
}
}

impl<F: IsPrimeField> std::ops::Mul<Polynomial<F>> for Polynomial<F> {
type Output = Polynomial<F>;
fn mul(self, factor: Polynomial<F>) -> Polynomial<F> {
&self * &factor
}
}

impl<F: IsPrimeField> std::ops::Mul<Polynomial<F>> for &Polynomial<F> {
type Output = Polynomial<F>;
fn mul(self, factor: Polynomial<F>) -> Polynomial<F> {
self * &factor
}
}

impl<F: IsPrimeField> std::ops::Mul<&Polynomial<F>> for Polynomial<F> {
type Output = Polynomial<F>;
fn mul(self, factor: &Polynomial<F>) -> Polynomial<F> {
&self * factor
}
}
8 changes: 4 additions & 4 deletions tools/garaga_rs/src/ecip/rational_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ impl<F: IsPrimeField> RationalFunction<F> {
}

pub fn simplify(&self) -> RationalFunction<F> {
let (_, _, gcd) = self.numerator.clone().xgcd(&self.denominator);
let (_, _, gcd) = self.numerator.xgcd(&self.denominator);
let num_simplified = self.numerator.clone().div_with_ref(&gcd);
let den_simplified = self.denominator.clone().div_with_ref(&gcd);

RationalFunction::new(
num_simplified.scale_by_coeff(self.denominator.leading_coefficient().inv().unwrap()),
den_simplified.scale_by_coeff(den_simplified.leading_coefficient().inv().unwrap()),
num_simplified.scale_by_coeff(&self.denominator.leading_coefficient().inv().unwrap()),
den_simplified.scale_by_coeff(&den_simplified.leading_coefficient().inv().unwrap()),
)
}

Expand All @@ -32,7 +32,7 @@ impl<F: IsPrimeField> RationalFunction<F> {

pub fn scale_by_coeff(&self, coeff: FieldElement<F>) -> RationalFunction<F> {
RationalFunction::new(
self.numerator.clone().scale_by_coeff(coeff),
self.numerator.scale_by_coeff(&coeff),
self.denominator.clone(),
)
}
Expand Down

0 comments on commit d2011dc

Please sign in to comment.