Skip to content

Commit 060dbf6

Browse files
Add new unchecked (#1024)
* add new_uncheckes for short weiestrass * remove unused files * use unchecked for stark curve generator * revert changes for vesta curve * add missing comment * make the point field private * fix clippy * add safety comments and rename function --------- Co-authored-by: Nicole <nicole.graus@lambdaclass.com>
1 parent 74c7253 commit 060dbf6

File tree

6 files changed

+1950
-1932
lines changed

6 files changed

+1950
-1932
lines changed

crates/crypto/src/hash/pedersen/constants.rs

Lines changed: 1891 additions & 1891 deletions
Large diffs are not rendered by default.

crates/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/curve.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,10 @@ impl ShortWeierstrassProjectivePoint<BLS12377Curve> {
8989
/// Returns 𝜙(P) = (𝑥, 𝑦) ⇒ (𝛽𝑥, 𝑦), where 𝛽 is the Cube Root of Unity in the base prime field
9090
/// https://eprint.iacr.org/2022/352.pdf 2 Preliminaries
9191
fn phi(&self) -> Self {
92-
let mut a = self.clone();
93-
a.0.value[0] = a.x() * CUBE_ROOT_OF_UNITY_G1;
94-
a
92+
let [x, y, z] = self.coordinates();
93+
let new_x = x * CUBE_ROOT_OF_UNITY_G1;
94+
// SAFETY: The value `x` is computed correctly, so the point is in the curve.
95+
Self::new_unchecked([new_x, y.clone(), z.clone()])
9596
}
9697

9798
/// 𝜙(P) = −𝑢²P

crates/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/curve.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ impl ShortWeierstrassProjectivePoint<BLS12381Curve> {
8282
/// Returns 𝜙(P) = (𝑥, 𝑦) ⇒ (𝛽𝑥, 𝑦), where 𝛽 is the Cube Root of Unity in the base prime field
8383
/// https://eprint.iacr.org/2022/352.pdf 2 Preliminaries
8484
fn phi(&self) -> Self {
85-
// This clone is unsightly
86-
let mut a = self.clone();
87-
a.0.value[0] = a.x() * CUBE_ROOT_OF_UNITY_G1;
88-
a
85+
let [x, y, z] = self.coordinates();
86+
let new_x = x * CUBE_ROOT_OF_UNITY_G1;
87+
// SAFETY: The value `x` is computed correctly, so the point is in the curve.
88+
Self::new_unchecked([new_x, y.clone(), z.clone()])
8989
}
9090

9191
/// 𝜙(P) = −𝑢²P

crates/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/pairing.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ fn double_accumulate_line(
159159
let x1_sq_3 = three * x1.square();
160160
let [x1_sq_30, x1_sq_31] = x1_sq_3.value();
161161

162-
t.0.value = [x3, y3, z3];
162+
// SAFETY: The values `x_3, y_3, z_3` are computed correctly to be on the curve.
163+
t.set_unchecked([x3, y3, z3]);
163164

164165
// (a0 + a2w2 + a4w4 + a1w + a3w3 + a5w5) * (b0 + b2 w2 + b3 w3) =
165166
// (a0b0 + r (a3b3 + a4b2)) w0 + (a1b0 + r (a4b3 + a5b2)) w
@@ -213,7 +214,8 @@ fn add_accumulate_line(
213214
let y3 = &theta * (g - h) - i;
214215
let z3 = z1 * e;
215216

216-
t.0.value = [x3, y3, z3];
217+
// SAFETY: The values `x_3, y_3, z_3` are computed correctly to be on the curve.
218+
t.set_unchecked([x3, y3, z3]);
217219

218220
let [lambda0, lambda1] = lambda.value();
219221
let [theta0, theta1] = theta.value();

crates/math/src/elliptic_curve/short_weierstrass/curves/stark_curve.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::{
22
elliptic_curve::{
3-
point::ProjectivePoint,
43
short_weierstrass::{point::ShortWeierstrassProjectivePoint, traits::IsShortWeierstrass},
54
traits::IsEllipticCurve,
65
},
@@ -13,15 +12,18 @@ use crate::{
1312
pub struct StarkCurve;
1413

1514
impl StarkCurve {
16-
pub const fn from_affine_hex_string(
15+
pub const fn from_affine_hex_string_unchecked(
1716
x_hex: &str,
1817
y_hex: &str,
1918
) -> ShortWeierstrassProjectivePoint<Self> {
20-
ShortWeierstrassProjectivePoint(ProjectivePoint::new([
19+
// SAFETY: The values `x_hex, y_hex` must represent valid coordinates that satisfy
20+
// the curve equation. Invalid coordinates violate the invariant and produce
21+
// silently incorrect results in subsequent operations.
22+
ShortWeierstrassProjectivePoint::new_unchecked([
2123
FieldElement::<Stark252PrimeField>::from_hex_unchecked(x_hex),
2224
FieldElement::<Stark252PrimeField>::from_hex_unchecked(y_hex),
2325
FieldElement::<Stark252PrimeField>::from_hex_unchecked("1"),
24-
]))
26+
])
2527
}
2628
}
2729

@@ -32,17 +34,15 @@ impl IsEllipticCurve for StarkCurve {
3234
fn generator() -> Self::PointRepresentation {
3335
// SAFETY:
3436
// - The generator point is mathematically verified to be a valid point on the curve.
35-
// - `unwrap()` is safe because the provided coordinates satisfy the curve equation.
36-
let point = Self::PointRepresentation::new([
37+
Self::PointRepresentation::new_unchecked([
3738
FieldElement::<Self::BaseField>::from_hex_unchecked(
3839
"1EF15C18599971B7BECED415A40F0C7DEACFD9B0D1819E03D723D8BC943CFCA",
3940
),
4041
FieldElement::<Self::BaseField>::from_hex_unchecked(
4142
"5668060AA49730B7BE4801DF46EC62DE53ECD11ABE43A32873000C36E8DC1F",
4243
),
4344
FieldElement::one(),
44-
]);
45-
point.unwrap()
45+
])
4646
}
4747
}
4848

crates/math/src/elliptic_curve/short_weierstrass/point.rs

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@ use crate::traits::AsBytes;
1717
use alloc::vec::Vec;
1818

1919
#[derive(Clone, Debug)]
20-
pub struct ShortWeierstrassProjectivePoint<E: IsEllipticCurve>(pub ProjectivePoint<E>);
20+
pub struct ShortWeierstrassProjectivePoint<E: IsEllipticCurve>(ProjectivePoint<E>);
2121

2222
impl<E: IsShortWeierstrass> ShortWeierstrassProjectivePoint<E> {
2323
/// Creates an elliptic curve point giving the projective [x: y: z] coordinates.
2424
pub fn new(value: [FieldElement<E::BaseField>; 3]) -> Result<Self, EllipticCurveError> {
2525
let (x, y, z) = (&value[0], &value[1], &value[2]);
26-
2726
if z != &FieldElement::<E::BaseField>::zero()
2827
&& E::defining_equation_projective(x, y, z) == FieldElement::<E::BaseField>::zero()
2928
{
@@ -43,6 +42,22 @@ impl<E: IsShortWeierstrass> ShortWeierstrassProjectivePoint<E> {
4342
}
4443
}
4544

45+
/// Creates an elliptic curve point giving the projective [x: y: z] coordinates without
46+
/// checking that the point satisfies the curve equation.
47+
pub const fn new_unchecked(value: [FieldElement<E::BaseField>; 3]) -> Self {
48+
// SAFETY: The caller MUST ensure that [x:y:z] represents valid point on the
49+
// curve. Passing arbitrary coordinates here can violate the invariant
50+
// and produce silently incorrect results in subsequent operations.
51+
Self(ProjectivePoint::new(value))
52+
}
53+
54+
/// Changes the point coordinates without checking that it satisfies the curve equation.
55+
pub fn set_unchecked(&mut self, value: [FieldElement<E::BaseField>; 3]) {
56+
// SAFETY: The caller MUST ensure that the provided coordinates represent a valid curve
57+
// point. Setting invalid coordinates may lead to silently incorrect computations later on.
58+
self.0.value = value
59+
}
60+
4661
/// Returns the `x` coordinate of the point.
4762
pub fn x(&self) -> &FieldElement<E::BaseField> {
4863
self.0.x()
@@ -111,8 +126,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassProjectivePoint<E> {
111126
);
112127
// SAFETY: The values `x_p, y_p, z_p` are computed correctly to be on the curve.
113128
// The assertion above verifies that the resulting point is valid.
114-
let point = Self::new([xp, yp, zp]);
115-
point.unwrap()
129+
Self::new_unchecked([xp, yp, zp])
116130
}
117131
// https://hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/madd-1998-cmo
118132
/// More efficient than operate_with, but must ensure that other is in affine form
@@ -132,12 +146,11 @@ impl<E: IsShortWeierstrass> ShortWeierstrassProjectivePoint<E> {
132146
if u == *py {
133147
if v != *px || *py == FieldElement::zero() {
134148
// SAFETY: The point (0, 1, 0) is defined as the point at infinity.
135-
return Self::new([
149+
return Self::new_unchecked([
136150
FieldElement::zero(),
137151
FieldElement::one(),
138152
FieldElement::zero(),
139-
])
140-
.unwrap();
153+
]);
141154
} else {
142155
return self.double();
143156
}
@@ -161,8 +174,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassProjectivePoint<E> {
161174
);
162175
// SAFETY: The values `x, y, z` are computed correctly to be on the curve.
163176
// The assertion above verifies that the resulting point is valid.
164-
let point = Self::new([x, y, z]);
165-
point.unwrap()
177+
Self::new_unchecked([x, y, z])
166178
}
167179
}
168180

@@ -189,13 +201,11 @@ impl<E: IsShortWeierstrass> IsGroup for ShortWeierstrassProjectivePoint<E> {
189201
fn neutral_element() -> Self {
190202
// SAFETY:
191203
// - `(0, 1, 0)` is **mathematically valid** as the neutral element.
192-
// - `unwrap()` is safe because this is **a known valid point**.
193-
Self::new([
204+
Self::new_unchecked([
194205
FieldElement::zero(),
195206
FieldElement::one(),
196207
FieldElement::zero(),
197208
])
198-
.unwrap()
199209
}
200210

201211
fn is_neutral_element(&self) -> bool {
@@ -245,7 +255,7 @@ impl<E: IsShortWeierstrass> IsGroup for ShortWeierstrassProjectivePoint<E> {
245255
);
246256
// SAFETY: The values `x_p, y_p, z_p` are computed correctly to be on the curve.
247257
// The assertion above verifies that the resulting point is valid.
248-
Self::new([xp, yp, zp]).unwrap()
258+
Self::new_unchecked([xp, yp, zp])
249259
}
250260
}
251261
}
@@ -255,8 +265,7 @@ impl<E: IsShortWeierstrass> IsGroup for ShortWeierstrassProjectivePoint<E> {
255265
let [px, py, pz] = self.coordinates();
256266
// SAFETY:
257267
// - Negating `y` maintains the curve structure.
258-
// - `unwraps()` is safe because negation **is always valid**.
259-
Self::new([px.clone(), -py, pz.clone()]).unwrap()
268+
Self::new_unchecked([px.clone(), -py, pz.clone()])
260269
}
261270
}
262271

@@ -454,6 +463,15 @@ impl<E: IsShortWeierstrass> ShortWeierstrassJacobianPoint<E> {
454463
}
455464
}
456465

466+
/// Creates an elliptic curve point giving the projective [x: y: z] coordinates without
467+
/// checking that the point satisfies the curve equation.
468+
pub const fn new_unchecked(value: [FieldElement<E::BaseField>; 3]) -> Self {
469+
// SAFETY: The caller MUST ensure that [x:y:z] represents either a valid point on the
470+
// curve. Passing arbitrary coordinates here can violate the invariant
471+
// and produce silently incorrect results in subsequent operations.
472+
Self(JacobianPoint::new(value))
473+
}
474+
457475
/// Returns the `x` coordinate of the point.
458476
pub fn x(&self) -> &FieldElement<E::BaseField> {
459477
self.0.x()
@@ -508,7 +526,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassJacobianPoint<E> {
508526
);
509527
// SAFETY: The values `x_3, y_3, z_3` are computed correctly to be on the curve.
510528
// The assertion above verifies that the resulting point is valid.
511-
Self::new([x3, y3, z3]).unwrap()
529+
Self::new_unchecked([x3, y3, z3])
512530
} else {
513531
// http://www.hyperelliptic.org/EFD/g1p/data/shortw/jacobian-0/doubling/dbl-2009-alnr
514532
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
@@ -528,7 +546,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassJacobianPoint<E> {
528546
);
529547
// SAFETY: The values `x_3, y_3, z_3` are computed correctly to be on the curve.
530548
// The assertion above verifies that the resulting point is valid.
531-
Self::new([x3, y3, z3]).unwrap()
549+
Self::new_unchecked([x3, y3, z3])
532550
}
533551
}
534552

@@ -572,7 +590,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassJacobianPoint<E> {
572590
);
573591
// SAFETY: The values `x_3, y_3, z_3` are computed correctly to be on the curve.
574592
// The assertion above verifies that the resulting point is valid.
575-
Self::new([x3, y3, z3]).unwrap()
593+
Self::new_unchecked([x3, y3, z3])
576594
}
577595
}
578596
}
@@ -600,14 +618,11 @@ impl<E: IsShortWeierstrass> IsGroup for ShortWeierstrassJacobianPoint<E> {
600618
fn neutral_element() -> Self {
601619
// SAFETY:
602620
// - `(1, 1, 0)` is **mathematically valid** as the neutral element.
603-
// - `unwrap()` is safe because this is **a known valid point**.
604-
605-
Self::new([
621+
Self::new_unchecked([
606622
FieldElement::one(),
607623
FieldElement::one(),
608624
FieldElement::zero(),
609625
])
610-
.unwrap()
611626
}
612627

613628
fn is_neutral_element(&self) -> bool {
@@ -677,7 +692,7 @@ impl<E: IsShortWeierstrass> IsGroup for ShortWeierstrassJacobianPoint<E> {
677692
);
678693
// SAFETY: The values `x_3, y_3, z_3` are computed correctly to be on the curve.
679694
// The assertion above verifies that the resulting point is valid.
680-
Self::new([x3, y3, z3]).unwrap()
695+
Self::new_unchecked([x3, y3, z3])
681696
}
682697

683698
/// Returns the additive inverse of the jacobian point `p`
@@ -686,7 +701,7 @@ impl<E: IsShortWeierstrass> IsGroup for ShortWeierstrassJacobianPoint<E> {
686701
// SAFETY:
687702
// - The negation formula for Short Weierstrass curves is well-defined.
688703
// - The result remains a valid curve point.
689-
Self::new([x.clone(), -y, z.clone()]).unwrap()
704+
Self::new_unchecked([x.clone(), -y, z.clone()])
690705
}
691706
}
692707

0 commit comments

Comments
 (0)