Skip to content

Commit 2ef2027

Browse files
committed
perf: switch SW_EC to projective coordinates - guest-libs (INT-6136)
1 parent 9e856e4 commit 2ef2027

File tree

10 files changed

+76
-42
lines changed

10 files changed

+76
-42
lines changed

guest-libs/k256/src/internal.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::ops::{Add, Neg};
1+
use core::ops::Add;
22

33
use hex_literal::hex;
44
use openvm_algebra_guest::IntMod;
@@ -41,6 +41,7 @@ impl CyclicGroup for Secp256k1Point {
4141
y: Secp256k1Coord::from_const_bytes(hex!(
4242
"B8D410FB8FD0479C195485A648B417FDA808110EFCFBA45D65C4A32677DA3A48"
4343
)),
44+
z: Secp256k1Coord::from_const_u8(1),
4445
};
4546
const NEG_GENERATOR: Self = Secp256k1Point {
4647
x: Secp256k1Coord::from_const_bytes(hex!(
@@ -49,6 +50,7 @@ impl CyclicGroup for Secp256k1Point {
4950
y: Secp256k1Coord::from_const_bytes(hex!(
5051
"7727EF046F2FB863E6AB7A59B74BE80257F7EEF103045BA29A3B5CD98825C5B7"
5152
)),
53+
z: Secp256k1Coord::from_const_u8(1),
5254
};
5355
}
5456

@@ -74,10 +76,12 @@ impl IntrinsicCurve for Secp256k1 {
7476

7577
impl Secp256k1Point {
7678
pub fn x_be_bytes(&self) -> [u8; 32] {
77-
<Self as WeierstrassPoint>::x(self).to_be_bytes()
79+
let n = self.normalize();
80+
<Self as WeierstrassPoint>::x(&n).to_be_bytes()
7881
}
7982

8083
pub fn y_be_bytes(&self) -> [u8; 32] {
81-
<Self as WeierstrassPoint>::y(self).to_be_bytes()
84+
let n = self.normalize();
85+
<Self as WeierstrassPoint>::y(&n).to_be_bytes()
8286
}
8387
}

guest-libs/k256/src/point.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ impl AffineCoordinates for Secp256k1Point {
4545
type FieldRepr = FieldBytes;
4646

4747
fn x(&self) -> FieldBytes {
48-
*FieldBytes::from_slice(&<Self as WeierstrassPoint>::x(self).to_be_bytes())
48+
let n = self.normalize();
49+
*FieldBytes::from_slice(&<Self as WeierstrassPoint>::x(&n).to_be_bytes())
4950
}
5051

5152
fn y_is_odd(&self) -> Choice {
52-
(self.y().as_le_bytes()[0] & 1).into()
53+
let n = self.normalize();
54+
(n.y().as_le_bytes()[0] & 1).into()
5355
}
5456
}
5557

@@ -61,21 +63,26 @@ impl ConditionallySelectable for Secp256k1Point {
6163
b: &Secp256k1Point,
6264
choice: Choice,
6365
) -> Secp256k1Point {
64-
Secp256k1Point::from_xy_unchecked(
66+
Secp256k1Point::from_xyz_unchecked(
6567
Secp256k1Coord::conditional_select(
6668
<Self as WeierstrassPoint>::x(a),
6769
<Self as WeierstrassPoint>::x(b),
6870
choice,
6971
),
7072
Secp256k1Coord::conditional_select(a.y(), b.y(), choice),
73+
Secp256k1Coord::conditional_select(a.z(), b.z(), choice),
7174
)
7275
}
7376
}
7477

7578
impl ConstantTimeEq for Secp256k1Point {
7679
fn ct_eq(&self, other: &Secp256k1Point) -> Choice {
77-
<Self as WeierstrassPoint>::x(self).ct_eq(<Self as WeierstrassPoint>::x(other))
78-
& self.y().ct_eq(other.y())
80+
// Projective equivalence: (X1*Z2 == X2*Z1) && (Y1*Z2 == Y2*Z1)
81+
let x1z2 = <Self as WeierstrassPoint>::x(self) * other.z();
82+
let x2z1 = <Self as WeierstrassPoint>::x(other) * self.z();
83+
let y1z2 = self.y() * other.z();
84+
let y2z1 = other.y() * self.z();
85+
x1z2.ct_eq(&x2z1) & y1z2.ct_eq(&y2z1)
7986
}
8087
}
8188

@@ -164,7 +171,7 @@ impl elliptic_curve::group::Curve for Secp256k1Point {
164171
type AffineRepr = Secp256k1Point;
165172

166173
fn to_affine(&self) -> Secp256k1Point {
167-
*self
174+
self.normalize()
168175
}
169176
}
170177

@@ -219,10 +226,11 @@ impl FromEncodedPoint<Secp256k1> for Secp256k1Point {
219226

220227
impl ToEncodedPoint<Secp256k1> for Secp256k1Point {
221228
fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
229+
let n = self.normalize();
222230
EncodedPoint::conditional_select(
223231
&EncodedPoint::from_affine_coordinates(
224-
&<Self as WeierstrassPoint>::x(self).to_be_bytes().into(),
225-
&<Self as WeierstrassPoint>::y(self).to_be_bytes().into(),
232+
&<Self as WeierstrassPoint>::x(&n).to_be_bytes().into(),
233+
&<Self as WeierstrassPoint>::y(&n).to_be_bytes().into(),
226234
compress,
227235
),
228236
&EncodedPoint::identity(),

guest-libs/k256/tests/lib.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,23 +303,25 @@ mod host_tests {
303303

304304
// Generic add can handle equal or unequal points.
305305
#[allow(clippy::op_ref)]
306-
let p3 = &p1 + &p2;
306+
let p3 = (&p1 + &p2).normalize();
307307
if p3.x() != &x3 || p3.y() != &y3 {
308308
panic!();
309309
}
310310
#[allow(clippy::op_ref)]
311-
let p4 = &p2 + &p2;
311+
let p4 = (&p2 + &p2).normalize();
312312
if p4.x() != &x4 || p4.y() != &y4 {
313313
panic!();
314314
}
315315

316316
// Add assign and double assign
317317
p1 += &p2;
318-
if p1.x() != &x3 || p1.y() != &y3 {
318+
let p1n = p1.normalize();
319+
if p1n.x() != &x3 || p1n.y() != &y3 {
319320
panic!();
320321
}
321322
p2.double_assign();
322-
if p2.x() != &x4 || p2.y() != &y4 {
323+
let p2n = p2.normalize();
324+
if p2n.x() != &x4 || p2n.y() != &y4 {
323325
panic!();
324326
}
325327

@@ -333,7 +335,7 @@ mod host_tests {
333335
let y5 = Secp256k1Coord::from_le_bytes_unchecked(&hex!(
334336
"9E272F746DA7BED171E522610212B6AEEAAFDB2AD9F4B530B8E1B27293B19B2C"
335337
));
336-
let result = msm(&[scalar], &[p1]);
338+
let result = msm(&[scalar], &[p1]).normalize();
337339
if result.x() != &x5 || result.y() != &y5 {
338340
panic!();
339341
}

guest-libs/p256/src/internal.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::ops::{Add, Neg};
1+
use core::ops::Add;
22

33
use hex_literal::hex;
44
use openvm_algebra_guest::IntMod;
@@ -42,6 +42,7 @@ impl CyclicGroup for P256Point {
4242
y: P256Coord::from_const_bytes(hex!(
4343
"f551bf376840b6cbce5e316b5733ce2b169e0f7c4aebe78e9b7f1afee242e34f"
4444
)),
45+
z: P256Coord::from_const_u8(1),
4546
};
4647
const NEG_GENERATOR: Self = P256Point {
4748
x: P256Coord::from_const_bytes(hex!(
@@ -50,6 +51,7 @@ impl CyclicGroup for P256Point {
5051
y: P256Coord::from_const_bytes(hex!(
5152
"0aae40c897bf493431a1ce94a9cc31d4e961f083b51418716580e5011cbd1cb0"
5253
)),
54+
z: P256Coord::from_const_u8(1),
5355
};
5456
}
5557

@@ -74,10 +76,12 @@ impl IntrinsicCurve for NistP256 {
7476

7577
impl P256Point {
7678
pub fn x_be_bytes(&self) -> [u8; 32] {
77-
<Self as WeierstrassPoint>::x(self).to_be_bytes()
79+
let n = self.normalize();
80+
<Self as WeierstrassPoint>::x(&n).to_be_bytes()
7881
}
7982

8083
pub fn y_be_bytes(&self) -> [u8; 32] {
81-
<Self as WeierstrassPoint>::y(self).to_be_bytes()
84+
let n = self.normalize();
85+
<Self as WeierstrassPoint>::y(&n).to_be_bytes()
8286
}
8387
}

guest-libs/p256/src/point.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,33 +45,40 @@ impl AffineCoordinates for P256Point {
4545
type FieldRepr = FieldBytes;
4646

4747
fn x(&self) -> FieldBytes {
48-
*FieldBytes::from_slice(&<Self as WeierstrassPoint>::x(self).to_be_bytes())
48+
let n = self.normalize();
49+
*FieldBytes::from_slice(&<Self as WeierstrassPoint>::x(&n).to_be_bytes())
4950
}
5051

5152
fn y_is_odd(&self) -> Choice {
52-
(self.y().as_le_bytes()[0] & 1).into()
53+
let n = self.normalize();
54+
(n.y().as_le_bytes()[0] & 1).into()
5355
}
5456
}
5557

5658
impl Copy for P256Point {}
5759

5860
impl ConditionallySelectable for P256Point {
5961
fn conditional_select(a: &P256Point, b: &P256Point, choice: Choice) -> P256Point {
60-
P256Point::from_xy_unchecked(
62+
P256Point::from_xyz_unchecked(
6163
P256Coord::conditional_select(
6264
<Self as WeierstrassPoint>::x(a),
6365
<Self as WeierstrassPoint>::x(b),
6466
choice,
6567
),
6668
P256Coord::conditional_select(a.y(), b.y(), choice),
69+
P256Coord::conditional_select(a.z(), b.z(), choice),
6770
)
6871
}
6972
}
7073

7174
impl ConstantTimeEq for P256Point {
7275
fn ct_eq(&self, other: &P256Point) -> Choice {
73-
<Self as WeierstrassPoint>::x(self).ct_eq(<Self as WeierstrassPoint>::x(other))
74-
& self.y().ct_eq(other.y())
76+
// Projective equivalence: (X1*Z2 == X2*Z1) && (Y1*Z2 == Y2*Z1)
77+
let x1z2 = <Self as WeierstrassPoint>::x(self) * other.z();
78+
let x2z1 = <Self as WeierstrassPoint>::x(other) * self.z();
79+
let y1z2 = self.y() * other.z();
80+
let y2z1 = other.y() * self.z();
81+
x1z2.ct_eq(&x2z1) & y1z2.ct_eq(&y2z1)
7582
}
7683
}
7784

@@ -160,7 +167,7 @@ impl elliptic_curve::group::Curve for P256Point {
160167
type AffineRepr = P256Point;
161168

162169
fn to_affine(&self) -> P256Point {
163-
*self
170+
self.normalize()
164171
}
165172
}
166173

@@ -214,10 +221,11 @@ impl FromEncodedPoint<NistP256> for P256Point {
214221

215222
impl ToEncodedPoint<NistP256> for P256Point {
216223
fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
224+
let n = self.normalize();
217225
EncodedPoint::conditional_select(
218226
&EncodedPoint::from_affine_coordinates(
219-
&<Self as WeierstrassPoint>::x(self).to_be_bytes().into(),
220-
&<Self as WeierstrassPoint>::y(self).to_be_bytes().into(),
227+
&<Self as WeierstrassPoint>::x(&n).to_be_bytes().into(),
228+
&<Self as WeierstrassPoint>::y(&n).to_be_bytes().into(),
221229
compress,
222230
),
223231
&EncodedPoint::identity(),

guest-libs/p256/tests/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,18 +287,20 @@ mod host_tests {
287287

288288
// Generic add can handle equal or unequal points.
289289
#[allow(clippy::op_ref)]
290-
let p3 = &p1 + &p2;
290+
let p3 = (&p1 + &p2).normalize();
291291
#[allow(clippy::op_ref)]
292-
let p4 = &p2 + &p2;
292+
let p4 = (&p2 + &p2).normalize();
293293

294294
// Add assign and double assign
295295
let mut sum = P256Point::from_xy(x1, y1).unwrap();
296296
sum += &p2;
297+
let sum = sum.normalize();
297298
if sum.x() != p3.x() || sum.y() != p3.y() {
298299
panic!();
299300
}
300301
let mut double = P256Point::from_xy(x2, y2).unwrap();
301302
double.double_assign();
303+
let double = double.normalize();
302304
if double.x() != p4.x() || double.y() != p4.y() {
303305
panic!();
304306
}
@@ -307,8 +309,8 @@ mod host_tests {
307309
let p1 = P256Point::from_xy(x1, y1).unwrap();
308310
let scalar = P256Scalar::from_u32(3);
309311
#[allow(clippy::op_ref)]
310-
let p2 = &p1.double() + &p1;
311-
let result = msm(&[scalar], &[p1]);
312+
let p2 = (&p1.double() + &p1).normalize();
313+
let result = msm(&[scalar], &[p1]).normalize();
312314
if result.x() != p2.x() || result.y() != p2.y() {
313315
panic!();
314316
}

guest-libs/pairing/src/bls12_381/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
extern crate alloc;
22

3-
use core::ops::Neg;
4-
53
use openvm_algebra_guest::IntMod;
64
use openvm_algebra_moduli_macros::moduli_declare;
75
use openvm_ecc_guest::{weierstrass::IntrinsicCurve, CyclicGroup, Group};
@@ -53,6 +51,7 @@ impl CyclicGroup for G1Affine {
5351
y: Bls12_381Fp::from_const_bytes(hex!(
5452
"E1E7C5462923AA0CE48A88A244C73CD0EDB3042CCB18DB00F60AD0D595E0F5FCE48A1D74ED309EA0F1A0AAE381F4B308"
5553
)),
54+
z: Bls12_381Fp::from_const_u8(1),
5655
};
5756
const NEG_GENERATOR: Self = G1Affine {
5857
x: Bls12_381Fp::from_const_bytes(hex!(
@@ -61,6 +60,7 @@ impl CyclicGroup for G1Affine {
6160
y: Bls12_381Fp::from_const_bytes(hex!(
6261
"CAC239B9D6DC54AD1B75CB0EBA386F4E3642ACCAD5B95566C907B51DEF6A8167F2212ECFC8767DAAA845D555681D4D11"
6362
)),
63+
z: Bls12_381Fp::from_const_u8(1),
6464
};
6565
}
6666

@@ -80,14 +80,13 @@ impl IntrinsicCurve for Bls12_381 {
8080
mod g2 {
8181
use openvm_algebra_guest::Field;
8282
use openvm_ecc_guest::{
83-
impl_sw_affine, impl_sw_group_ops, weierstrass::WeierstrassPoint, AffinePoint, Group,
83+
impl_sw_group_ops, impl_sw_proj, weierstrass::WeierstrassPoint, Group,
8484
};
8585

8686
use super::{Fp, Fp2};
8787

88-
const THREE: Fp2 = Fp2::new(Fp::from_const_u8(3), Fp::ZERO);
8988
const B: Fp2 = Fp2::new(Fp::from_const_u8(4), Fp::from_const_u8(4));
90-
impl_sw_affine!(G2Affine, Fp2, THREE, B);
89+
impl_sw_proj!(G2Affine, Fp2, B);
9190
impl_sw_group_ops!(G2Affine, Fp2);
9291
}
9392

guest-libs/pairing/src/bls12_381/tests.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,10 @@ fn test_bls12381_g2_affine() {
256256
(expected_neg, r_neg),
257257
(expected_double, r_double),
258258
] {
259-
assert_eq!(convert_g2_affine_halo2_to_openvm(expected), actual);
259+
assert_eq!(
260+
convert_g2_affine_halo2_to_openvm(expected),
261+
actual.normalize()
262+
);
260263
}
261264
}
262265
}

guest-libs/pairing/src/bn254/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extern crate alloc;
22

3-
use core::ops::{Add, Neg};
3+
use core::ops::Add;
44

55
use hex_literal::hex;
66
use openvm_algebra_guest::IntMod;
@@ -47,12 +47,14 @@ impl CyclicGroup for G1Affine {
4747
const GENERATOR: Self = G1Affine {
4848
x: Bn254Fp::from_const_u8(1),
4949
y: Bn254Fp::from_const_u8(2),
50+
z: Bn254Fp::from_const_u8(1),
5051
};
5152
const NEG_GENERATOR: Self = G1Affine {
5253
x: Bn254Fp::from_const_u8(1),
5354
y: Bn254Fp::from_const_bytes(hex!(
5455
"45FD7CD8168C203C8DCA7168916A81975D588181B64550B829A031E1724E6430"
5556
)),
57+
z: Bn254Fp::from_const_u8(1),
5658
};
5759
}
5860

@@ -62,12 +64,11 @@ mod g2 {
6264
use hex_literal::hex;
6365
use openvm_algebra_guest::Field;
6466
use openvm_ecc_guest::{
65-
impl_sw_affine, impl_sw_group_ops, weierstrass::WeierstrassPoint, AffinePoint, Group,
67+
impl_sw_group_ops, impl_sw_proj, weierstrass::WeierstrassPoint, Group,
6668
};
6769

6870
use super::{Fp, Fp2};
6971

70-
const THREE: Fp2 = Fp2::new(Fp::from_const_u8(3), Fp::ZERO);
7172
// 3 / (9 + u)
7273
// validated by a test below
7374
const B: Fp2 = Fp2::new(
@@ -78,7 +79,7 @@ mod g2 {
7879
"d215c38506bda2e452182de584a04fa7f4fdd8eeadaf2ccdd4fef03ab0139700"
7980
)),
8081
);
81-
impl_sw_affine!(G2Affine, Fp2, THREE, B);
82+
impl_sw_proj!(G2Affine, Fp2, B);
8283
impl_sw_group_ops!(G2Affine, Fp2);
8384

8485
#[test]

guest-libs/pairing/src/bn254/tests.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,10 @@ fn test_bn254_g2_affine() {
243243
(expected_neg, r_neg),
244244
(expected_double, r_double),
245245
] {
246-
assert_eq!(convert_g2_affine_halo2_to_openvm(expected), actual);
246+
assert_eq!(
247+
convert_g2_affine_halo2_to_openvm(expected),
248+
actual.normalize()
249+
);
247250
}
248251
}
249252
}

0 commit comments

Comments
 (0)