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

Optimize add_assign operation for Projective coordinates in Short Weierstrass model #784

Open
tcoratger opened this issue Feb 17, 2024 · 0 comments

Comments

@tcoratger
Copy link
Contributor

At the moment, the add_assign operation between two points in projective coordinates in the short weierstrass model implements the generic method (without any assumption over Z1 and Z2) here:

fn add_assign(&mut self, other: &'a Self) {
if self.is_zero() {
*self = *other;
return;
}
if other.is_zero() {
return;
}
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
// Works for all curves.
// Z1Z1 = Z1^2
let z1z1 = self.z.square();
// Z2Z2 = Z2^2
let z2z2 = other.z.square();
// U1 = X1*Z2Z2
let mut u1 = self.x;
u1 *= &z2z2;
// U2 = X2*Z1Z1
let mut u2 = other.x;
u2 *= &z1z1;
// S1 = Y1*Z2*Z2Z2
let mut s1 = self.y;
s1 *= &other.z;
s1 *= &z2z2;
// S2 = Y2*Z1*Z1Z1
let mut s2 = other.y;
s2 *= &self.z;
s2 *= &z1z1;
if u1 == u2 && s1 == s2 {
if s1 == s2 {
// The two points are equal, so we double.
self.double_in_place();
} else {
// a + (-a) = 0
*self = Self::zero();
}
} else {
// H = U2-U1
let mut h = u2;
h -= &u1;
// I = (2*H)^2
let mut i = h;
i.double_in_place().square_in_place();
// J = -H*I
let mut j = h;
j.neg_in_place();
j *= &i;
// r = 2*(S2-S1)
let mut r = s2;
r -= &s1;
r.double_in_place();
// V = U1*I
let mut v = u1;
v *= &i;
// X3 = r^2 + J - 2*V
self.x = r;
self.x.square_in_place();
self.x += &j;
self.x -= &(v.double());
// Y3 = r*(V - X3) + 2*S1*J
v -= &self.x;
self.y = s1;
self.y.double_in_place();
self.y = P::BaseField::sum_of_products(&[r, self.y], &[v, j]);
// Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H
// This is equal to Z3 = 2 * Z1 * Z2 * H, and computing it this way is faster.
self.z *= other.z;
self.z.double_in_place();
self.z *= &h;
}
}

This corresponds to the following logic: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl

with a cost of 11M + 5S + 9add + 4*2.

If Z1 = Z2 assumption holds, this cost can be reduced to 5M + 2S + 9add (following https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-zadd-2007-m).

Would it not be wise to also implement this variant in the add_assign inside a if self.z == other.z condition, in order to reduce the calculation cost of all operations satisfying this assumption, which can occur for several use cases.

  • For example when we simply add a and b which are initially in affine coordinates and transformed into projective coordinates for the occasion, z = 1 for both because the transformation from affine to projective coordinates is done with z = 1.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant