Skip to content

Commit 2384c41

Browse files
authored
k256: IDENTITY and GENERATOR point constants (#511)
Adds inherent constants to `AffinePoint` and `ProjectivePoint` representing the identity and generator points. This should make it possible to write `const fn`s that produce things like precomputed basepoint tables (see #508). Deprecates the previous inherent methods on `ProjectivePoint` for returning these constants.
1 parent fb38001 commit 2384c41

File tree

7 files changed

+164
-136
lines changed

7 files changed

+164
-136
lines changed

k256/bench/scalar.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ fn test_scalar_y() -> Scalar {
2828
}
2929

3030
fn bench_point_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) {
31-
let p = ProjectivePoint::generator();
31+
let p = ProjectivePoint::GENERATOR;
3232
let m = hex!("AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522");
3333
let s = Scalar::from_repr(m.into()).unwrap();
3434
group.bench_function("point-scalar mul", |b| b.iter(|| &p * &s));
3535
}
3636

3737
fn bench_point_lincomb<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) {
38-
let p = ProjectivePoint::generator();
38+
let p = ProjectivePoint::GENERATOR;
3939
let m = hex!("AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522");
4040
let s = Scalar::from_repr(m.into()).unwrap();
4141
group.bench_function("lincomb via mul+add", |b| b.iter(|| &p * &s + &p * &s));

k256/src/arithmetic/affine.rs

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ use super::{FieldElement, ProjectivePoint, CURVE_EQUATION_B};
66
use crate::{CompressedPoint, EncodedPoint, FieldBytes, Scalar, Secp256k1};
77
use core::ops::{Mul, Neg};
88
use elliptic_curve::{
9-
ff::Field,
10-
generic_array::arr,
119
group::{prime::PrimeCurveAffine, GroupEncoding},
1210
sec1::{self, FromEncodedPoint, ToEncodedPoint},
1311
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
@@ -39,9 +37,46 @@ use elliptic_curve::serde::{de, ser, Deserialize, Serialize};
3937
#[derive(Clone, Copy, Debug)]
4038
#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
4139
pub struct AffinePoint {
40+
/// x-coordinate
4241
pub(crate) x: FieldElement,
42+
43+
/// y-coordinate
4344
pub(crate) y: FieldElement,
44-
pub(super) infinity: Choice,
45+
46+
/// Is this point the point at infinity? 0 = no, 1 = yes
47+
///
48+
/// This is a proxy for [`Choice`], but uses `u8` instead to permit `const`
49+
/// constructors for `IDENTITY` and `GENERATOR`.
50+
pub(super) infinity: u8,
51+
}
52+
53+
impl AffinePoint {
54+
/// Additive identity of the group: the point at infinity.
55+
pub const IDENTITY: Self = Self {
56+
x: FieldElement::ZERO,
57+
y: FieldElement::ZERO,
58+
infinity: 1,
59+
};
60+
61+
/// Base point of secp256k1.
62+
///
63+
/// ```text
64+
/// Gₓ = 79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9 59f2815b 16f81798
65+
/// Gᵧ = 483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419 9c47d08f fb10d4b8
66+
/// ```
67+
pub const GENERATOR: Self = Self {
68+
x: FieldElement::from_bytes_unchecked(&[
69+
0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87,
70+
0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b,
71+
0x16, 0xf8, 0x17, 0x98,
72+
]),
73+
y: FieldElement::from_bytes_unchecked(&[
74+
0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11,
75+
0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, 0x8f,
76+
0xfb, 0x10, 0xd4, 0xb8,
77+
]),
78+
infinity: 0,
79+
};
4580
}
4681

4782
impl PrimeCurveAffine for AffinePoint {
@@ -50,38 +85,17 @@ impl PrimeCurveAffine for AffinePoint {
5085

5186
/// Returns the identity of the group: the point at infinity.
5287
fn identity() -> Self {
53-
Self {
54-
x: FieldElement::zero(),
55-
y: FieldElement::zero(),
56-
infinity: Choice::from(1),
57-
}
88+
Self::IDENTITY
5889
}
5990

60-
/// Returns the base point of SECP256k1.
91+
/// Returns the base point of secp256k1.
6192
fn generator() -> Self {
62-
// SECP256k1 basepoint in affine coordinates:
63-
// x = 79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9 59f2815b 16f81798
64-
// y = 483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419 9c47d08f fb10d4b8
65-
AffinePoint {
66-
x: FieldElement::from_bytes(&arr![u8;
67-
0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87,
68-
0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b,
69-
0x16, 0xf8, 0x17, 0x98
70-
])
71-
.unwrap(),
72-
y: FieldElement::from_bytes(&arr![u8;
73-
0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11,
74-
0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, 0x8f,
75-
0xfb, 0x10, 0xd4, 0xb8
76-
])
77-
.unwrap(),
78-
infinity: Choice::from(0),
79-
}
93+
Self::GENERATOR
8094
}
8195

8296
/// Is this point the identity point?
8397
fn is_identity(&self) -> Choice {
84-
self.infinity
98+
Choice::from(self.infinity)
8599
}
86100

87101
/// Convert to curve representation.
@@ -101,7 +115,7 @@ impl ConditionallySelectable for AffinePoint {
101115
AffinePoint {
102116
x: FieldElement::conditional_select(&a.x, &b.x, choice),
103117
y: FieldElement::conditional_select(&a.y, &b.y, choice),
104-
infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
118+
infinity: u8::conditional_select(&a.infinity, &b.infinity, choice),
105119
}
106120
}
107121
}
@@ -116,7 +130,7 @@ impl ConstantTimeEq for AffinePoint {
116130

117131
impl Default for AffinePoint {
118132
fn default() -> Self {
119-
Self::identity()
133+
Self::IDENTITY
120134
}
121135
}
122136

@@ -146,7 +160,7 @@ impl DecompressPoint<Secp256k1> for AffinePoint {
146160
Self {
147161
x,
148162
y: y.normalize(),
149-
infinity: Choice::from(0),
163+
infinity: 0,
150164
}
151165
})
152166
})
@@ -189,7 +203,7 @@ impl FromEncodedPoint<Secp256k1> for AffinePoint {
189203
/// `None` value if `encoded_point` is not on the secp256k1 curve.
190204
fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption<Self> {
191205
match encoded_point.coordinates() {
192-
sec1::Coordinates::Identity => CtOption::new(Self::identity(), 1.into()),
206+
sec1::Coordinates::Identity => CtOption::new(Self::IDENTITY, 1.into()),
193207
sec1::Coordinates::Compact { .. } => {
194208
// TODO(tarcieri): add decompaction support
195209
CtOption::new(Self::default(), 0.into())
@@ -206,11 +220,7 @@ impl FromEncodedPoint<Secp256k1> for AffinePoint {
206220
// Check that the point is on the curve
207221
let lhs = (y * &y).negate(1);
208222
let rhs = x * &x * &x + &CURVE_EQUATION_B;
209-
let point = AffinePoint {
210-
x,
211-
y,
212-
infinity: Choice::from(0),
213-
};
223+
let point = AffinePoint { x, y, infinity: 0 };
214224
CtOption::new(point, (lhs + &rhs).normalizes_to_zero())
215225
})
216226
})
@@ -228,7 +238,7 @@ impl ToEncodedPoint<Secp256k1> for AffinePoint {
228238
compress,
229239
),
230240
&EncodedPoint::identity(),
231-
self.infinity,
241+
self.is_identity(),
232242
)
233243
}
234244
}
@@ -369,16 +379,16 @@ mod tests {
369379

370380
#[test]
371381
fn affine_negation() {
372-
let basepoint = AffinePoint::generator();
382+
let basepoint = AffinePoint::GENERATOR;
373383
assert_eq!((-(-basepoint)), basepoint);
374384
}
375385

376386
#[test]
377387
fn identity_encoding() {
378388
// This is technically an invalid SEC1 encoding, but is preferable to panicking.
379-
assert_eq!([0; 33], AffinePoint::identity().to_bytes().as_slice());
389+
assert_eq!([0; 33], AffinePoint::IDENTITY.to_bytes().as_slice());
380390
assert!(bool::from(
381-
AffinePoint::from_bytes(&AffinePoint::identity().to_bytes())
391+
AffinePoint::from_bytes(&AffinePoint::IDENTITY.to_bytes())
382392
.unwrap()
383393
.is_identity()
384394
))

k256/src/arithmetic/mul.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl LookupTable {
101101
let xabs = (x + xmask) ^ xmask;
102102

103103
// Get an array element in constant time
104-
let mut t = ProjectivePoint::identity();
104+
let mut t = ProjectivePoint::IDENTITY;
105105
for j in 1..9 {
106106
let c = (xabs as u8).ct_eq(&(j as u8));
107107
t.conditional_assign(&self.0[j - 1], c);
@@ -278,7 +278,7 @@ fn lincomb_generic<const N: usize>(xs: &[ProjectivePoint; N], ks: &[Scalar; N])
278278
Radix16Decomposition::default(),
279279
);
280280

281-
let mut acc = ProjectivePoint::identity();
281+
let mut acc = ProjectivePoint::IDENTITY;
282282
for component in 0..N {
283283
acc += &tables1[component].select(digits1[component].0[32]);
284284
acc += &tables2[component].select(digits2[component].0[32]);

0 commit comments

Comments
 (0)