Skip to content

Commit a94edb1

Browse files
authored
Implement CofactorGroup for all relevant curves (#1394)
- `DecafPoint` is always in the subgroup - Impelement `CofactorGroup` for `primeorder` curves - Use `CofactorGroup` for `MapToCurve`
1 parent c9f8b22 commit a94edb1

File tree

10 files changed

+62
-47
lines changed

10 files changed

+62
-47
lines changed

ed448-goldilocks/src/decaf/points.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,11 @@ impl CofactorGroup for DecafPoint {
226226
type Subgroup = DecafPoint;
227227

228228
fn clear_cofactor(&self) -> Self::Subgroup {
229-
self.double().double()
229+
*self
230230
}
231231

232232
fn into_subgroup(self) -> CtOption<Self::Subgroup> {
233-
CtOption::new(self.clear_cofactor(), self.is_torsion_free())
233+
CtOption::new(self, Choice::from(1))
234234
}
235235

236236
fn is_torsion_free(&self) -> Choice {

ed448-goldilocks/src/field/element.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use elliptic_curve::{
1616
consts::{U56, U64, U84, U88},
1717
modular::ConstMontyParams,
1818
},
19-
group::cofactor::CofactorGroup,
2019
zeroize::DefaultIsZeroes,
2120
};
2221
use hash2curve::MapToCurve;
@@ -199,10 +198,6 @@ impl MapToCurve for Ed448 {
199198
fn map_to_curve(element: FieldElement) -> EdwardsPoint {
200199
element.map_to_curve_elligator2().isogeny().to_edwards()
201200
}
202-
203-
fn map_to_subgroup(point: EdwardsPoint) -> EdwardsPoint {
204-
point.clear_cofactor()
205-
}
206201
}
207202

208203
impl MapToCurve for Decaf448 {
@@ -213,10 +208,6 @@ impl MapToCurve for Decaf448 {
213208
fn map_to_curve(element: FieldElement) -> DecafPoint {
214209
DecafPoint(element.map_to_curve_decaf448())
215210
}
216-
217-
fn map_to_subgroup(point: DecafPoint) -> DecafPoint {
218-
point
219-
}
220211
}
221212

222213
impl Sum for FieldElement {

hash2curve/src/group_digest.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! Traits for handling hash to curve.
22
33
use super::{ExpandMsg, MapToCurve, hash_to_field};
4-
use elliptic_curve::{ProjectivePoint, array::typenum::Unsigned};
4+
use elliptic_curve::ProjectivePoint;
5+
use elliptic_curve::array::typenum::Unsigned;
6+
use elliptic_curve::group::cofactor::CofactorGroup;
57

68
/// Hash arbitrary byte sequences to a valid group element.
79
pub trait GroupDigest: MapToCurve {
@@ -38,7 +40,7 @@ pub trait GroupDigest: MapToCurve {
3840
let [u0, u1] = hash_to_field::<2, X, _, Self::FieldElement, Self::FieldLength>(msg, dst)?;
3941
let q0 = Self::map_to_curve(u0);
4042
let q1 = Self::map_to_curve(u1);
41-
Ok(Self::add_and_map_to_subgroup(q0, q1))
43+
Ok((q0 + q1).clear_cofactor())
4244
}
4345

4446
/// Computes the encode to curve routine.
@@ -67,7 +69,7 @@ pub trait GroupDigest: MapToCurve {
6769
{
6870
let [u] = hash_to_field::<1, X, _, Self::FieldElement, Self::FieldLength>(msg, dst)?;
6971
let q0 = Self::map_to_curve(u);
70-
Ok(Self::map_to_subgroup(q0))
72+
Ok(q0.clear_cofactor())
7173
}
7274

7375
/// Computes the hash to field routine according to

hash2curve/src/map2curve.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22
33
use elliptic_curve::array::typenum::NonZero;
44
use elliptic_curve::array::{Array, ArraySize};
5+
use elliptic_curve::group::cofactor::CofactorGroup;
56
use elliptic_curve::ops::Reduce;
67
use elliptic_curve::{CurveArithmetic, ProjectivePoint};
78

89
/// Trait for converting field elements into a point via a mapping method like
910
/// Simplified Shallue-van de Woestijne-Ulas or Elligator.
10-
pub trait MapToCurve: CurveArithmetic<Scalar: Reduce<Array<u8, Self::ScalarLength>>> {
11+
pub trait MapToCurve:
12+
CurveArithmetic<
13+
ProjectivePoint: CofactorGroup<Subgroup = Self::ProjectivePoint>,
14+
Scalar: Reduce<Array<u8, Self::ScalarLength>>,
15+
>
16+
{
1117
/// The field element representation for a group value with multiple elements.
1218
type FieldElement: Reduce<Array<u8, Self::FieldLength>> + Default + Copy;
1319
/// The `L` parameter as specified in the [RFC](https://www.rfc-editor.org/rfc/rfc9380.html#section-5-6) for field elements.
@@ -17,17 +23,4 @@ pub trait MapToCurve: CurveArithmetic<Scalar: Reduce<Array<u8, Self::ScalarLengt
1723

1824
/// Map a field element into a curve point.
1925
fn map_to_curve(element: Self::FieldElement) -> ProjectivePoint<Self>;
20-
21-
/// Map a curve point to a point in the curve subgroup.
22-
/// This is usually done by clearing the cofactor, if necessary.
23-
fn map_to_subgroup(point: ProjectivePoint<Self>) -> ProjectivePoint<Self>;
24-
25-
/// Combine two curve points into a point in the curve subgroup.
26-
/// This is usually done by clearing the cofactor of the sum.
27-
fn add_and_map_to_subgroup(
28-
lhs: ProjectivePoint<Self>,
29-
rhs: ProjectivePoint<Self>,
30-
) -> ProjectivePoint<Self> {
31-
Self::map_to_subgroup(lhs + rhs)
32-
}
3326
}

k256/src/arithmetic/hash2curve.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,6 @@ impl MapToCurve for Secp256k1 {
143143
}
144144
.into()
145145
}
146-
147-
fn map_to_subgroup(point: ProjectivePoint) -> ProjectivePoint {
148-
point
149-
}
150146
}
151147

152148
impl Reduce<Array<u8, U48>> for Scalar {
@@ -267,6 +263,7 @@ mod tests {
267263
array::Array,
268264
bigint::{ArrayEncoding, NonZero, U384},
269265
consts::U48,
266+
group::cofactor::CofactorGroup,
270267
ops::Reduce,
271268
};
272269
use hash2curve::{GroupDigest, MapToCurve};
@@ -374,7 +371,7 @@ mod tests {
374371
assert_eq!(aq1.x.to_bytes().as_slice(), test_vector.q1_x);
375372
assert_eq!(aq1.y.to_bytes().as_slice(), test_vector.q1_y);
376373

377-
let p = Secp256k1::add_and_map_to_subgroup(q0, q1);
374+
let p = (q0 + q1).clear_cofactor();
378375
let ap = p.to_affine();
379376
assert_eq!(ap.x.to_bytes().as_slice(), test_vector.p_x);
380377
assert_eq!(ap.y.to_bytes().as_slice(), test_vector.p_y);

k256/src/arithmetic/projective.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use elliptic_curve::{
1212
BatchNormalize, CurveGroup, Error, Result,
1313
group::{
1414
Group, GroupEncoding,
15+
cofactor::CofactorGroup,
1516
prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
1617
},
1718
rand_core::TryRngCore,
@@ -451,6 +452,22 @@ impl GroupEncoding for ProjectivePoint {
451452
}
452453
}
453454

455+
impl CofactorGroup for ProjectivePoint {
456+
type Subgroup = ProjectivePoint;
457+
458+
fn clear_cofactor(&self) -> Self::Subgroup {
459+
*self
460+
}
461+
462+
fn into_subgroup(self) -> CtOption<Self::Subgroup> {
463+
CtOption::new(self, Choice::from(1))
464+
}
465+
466+
fn is_torsion_free(&self) -> Choice {
467+
Choice::from(1)
468+
}
469+
}
470+
454471
impl PrimeGroup for ProjectivePoint {}
455472

456473
impl CurveGroup for ProjectivePoint {

p256/src/arithmetic/hash2curve.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ impl MapToCurve for NistP256 {
7070
.unwrap()
7171
.into()
7272
}
73-
74-
fn map_to_subgroup(point: ProjectivePoint) -> ProjectivePoint {
75-
point
76-
}
7773
}
7874

7975
impl Reduce<Array<u8, U48>> for Scalar {

p384/src/arithmetic/hash2curve.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ impl MapToCurve for NistP384 {
7272
.unwrap()
7373
.into()
7474
}
75-
76-
fn map_to_subgroup(point: ProjectivePoint) -> ProjectivePoint {
77-
point
78-
}
7975
}
8076

8177
impl Reduce<Array<u8, U72>> for Scalar {
@@ -107,6 +103,7 @@ mod tests {
107103
array::Array,
108104
bigint::{ArrayEncoding, CheckedSub, NonZero, U384, U576},
109105
consts::U72,
106+
group::cofactor::CofactorGroup,
110107
ops::Reduce,
111108
sec1::{self, ToEncodedPoint},
112109
};
@@ -239,7 +236,7 @@ mod tests {
239236
let q1 = NistP384::map_to_curve(u[1]);
240237
assert_point_eq!(q1, test_vector.q1_x, test_vector.q1_y);
241238

242-
let p = NistP384::add_and_map_to_subgroup(q0, q1);
239+
let p = (q0 + q1).clear_cofactor();
243240
assert_point_eq!(p, test_vector.p_x, test_vector.p_y);
244241

245242
// complete run

p521/src/arithmetic/hash2curve.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,6 @@ impl MapToCurve for NistP521 {
7575
.unwrap()
7676
.into()
7777
}
78-
79-
fn map_to_subgroup(point: ProjectivePoint) -> ProjectivePoint {
80-
point
81-
}
8278
}
8379

8480
impl Reduce<Array<u8, U98>> for Scalar {
@@ -110,6 +106,7 @@ mod tests {
110106
array::Array,
111107
bigint::{ArrayEncoding, CheckedSub, NonZero, U576, U896},
112108
consts::U98,
109+
group::cofactor::CofactorGroup,
113110
ops::Reduce,
114111
sec1::{self, ToEncodedPoint},
115112
};
@@ -242,7 +239,7 @@ mod tests {
242239
let q1 = NistP521::map_to_curve(u[1]);
243240
assert_point_eq!(q1, test_vector.q1_x, test_vector.q1_y);
244241

245-
let p = NistP521::add_and_map_to_subgroup(q0, q1);
242+
let p = (q0 + q1).clear_cofactor();
246243
assert_point_eq!(p, test_vector.p_x, test_vector.p_y);
247244

248245
// complete run

primeorder/src/projective.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use elliptic_curve::{
1616
bigint::{ArrayEncoding, ByteArray},
1717
group::{
1818
Group, GroupEncoding,
19+
cofactor::CofactorGroup,
1920
prime::{PrimeCurve, PrimeGroup},
2021
},
2122
ops::{BatchInvert, LinearCombination},
@@ -274,6 +275,30 @@ where
274275
}
275276
}
276277

278+
impl<C> CofactorGroup for ProjectivePoint<C>
279+
where
280+
C: PrimeCurveParams,
281+
CompressedPoint<C>: Send + Sync,
282+
FieldBytes<C>: Copy,
283+
FieldBytesSize<C>: ModulusSize,
284+
CompressedPoint<C>: Copy,
285+
<UncompressedPointSize<C> as ArraySize>::ArrayType<u8>: Copy,
286+
{
287+
type Subgroup = ProjectivePoint<C>;
288+
289+
fn clear_cofactor(&self) -> Self::Subgroup {
290+
*self
291+
}
292+
293+
fn into_subgroup(self) -> CtOption<Self::Subgroup> {
294+
CtOption::new(self, Choice::from(1))
295+
}
296+
297+
fn is_torsion_free(&self) -> Choice {
298+
Choice::from(1)
299+
}
300+
}
301+
277302
impl<C> CurveGroup for ProjectivePoint<C>
278303
where
279304
C: PrimeCurveParams,

0 commit comments

Comments
 (0)