Skip to content

Commit 5110c47

Browse files
committed
Implement group traits for affine forms
1 parent ab9a3d1 commit 5110c47

File tree

5 files changed

+263
-114
lines changed

5 files changed

+263
-114
lines changed

ed448-goldilocks/src/curve/twedwards/affine.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![allow(dead_code)]
2+
use crate::TWISTED_EDWARDS_BASE_POINT;
23
use crate::curve::twedwards::{extended::ExtendedPoint, extensible::ExtensiblePoint};
34
use crate::field::FieldElement;
45
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
@@ -30,6 +31,12 @@ impl AffinePoint {
3031
y: FieldElement::ONE,
3132
};
3233

34+
/// Identity element
35+
pub(crate) const GENERATOR: AffinePoint = AffinePoint {
36+
x: TWISTED_EDWARDS_BASE_POINT.X,
37+
y: TWISTED_EDWARDS_BASE_POINT.Y,
38+
};
39+
3340
/// Checks if the AffinePoint is on the TwistedEdwards curve
3441
pub(crate) fn is_on_curve(&self) -> Choice {
3542
let xx = self.x.square();
@@ -140,7 +147,6 @@ mod tests {
140147

141148
#[test]
142149
fn test_negation() {
143-
use crate::TWISTED_EDWARDS_BASE_POINT;
144150
let a = TWISTED_EDWARDS_BASE_POINT.to_extensible().to_affine();
145151
assert_eq!(a.is_on_curve().unwrap_u8(), 1);
146152

ed448-goldilocks/src/decaf/affine.rs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use crate::curve::twedwards::affine::AffinePoint as InnerAffinePoint;
2+
use crate::decaf::points::DecafPointRepr;
23
use crate::field::FieldElement;
34
use crate::{Decaf448FieldBytes, DecafPoint, DecafScalar, ORDER};
4-
use core::ops::Mul;
5+
use core::ops::{Mul, Neg};
56
use elliptic_curve::{
67
Error,
8+
group::{GroupEncoding, prime::PrimeCurveAffine},
79
point::{AffineCoordinates, NonIdentity},
810
zeroize::DefaultIsZeroes,
911
};
10-
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
12+
use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq, CtOption};
1113

1214
/// Affine point on the twisted curve
1315
#[derive(Copy, Clone, Debug, Default)]
@@ -70,9 +72,82 @@ impl AffineCoordinates for AffinePoint {
7072

7173
impl DefaultIsZeroes for AffinePoint {}
7274

75+
impl GroupEncoding for AffinePoint {
76+
type Repr = DecafPointRepr;
77+
78+
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
79+
Self::from_bytes_unchecked(bytes)
80+
}
81+
82+
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
83+
let s = FieldElement::from_bytes(&bytes.0);
84+
//XX: Check for canonical encoding and sign,
85+
// Copied this check from Dalek: The From_bytes function does not throw an error, if the bytes exceed the prime.
86+
// However, to_bytes reduces the Field element before serialising
87+
// So we can use to_bytes -> from_bytes and if the representations are the same, then the element was already in reduced form
88+
let s_bytes_check = s.to_bytes();
89+
let s_encoding_is_canonical = s_bytes_check[..].ct_eq(&bytes.0);
90+
let s_is_negative = s.is_negative();
91+
// if s_encoding_is_canonical.unwrap_u8() == 0u8 || s.is_negative().unwrap_u8() == 1u8 {
92+
// return None;
93+
// }
94+
95+
let ss = s.square();
96+
let u1 = FieldElement::ONE - ss;
97+
let u2 = FieldElement::ONE + ss;
98+
let u1_sqr = u1.square();
99+
100+
let v = ss * (FieldElement::NEG_FOUR_TIMES_TWISTED_D) + u1_sqr; // XXX: constantify please
101+
102+
let (I, ok) = (v * u1_sqr).inverse_square_root();
103+
104+
let Dx = I * u1;
105+
let Dxs = s.double() * Dx;
106+
107+
let mut x = (Dxs * I) * v;
108+
let k = Dxs * FieldElement::DECAF_FACTOR;
109+
x.conditional_negate(k.is_negative());
110+
111+
let y = Dx * u2;
112+
let pt = InnerAffinePoint { x, y };
113+
114+
CtOption::new(
115+
Self(pt),
116+
ok & pt.is_on_curve() & s_encoding_is_canonical & !s_is_negative,
117+
)
118+
}
119+
120+
fn to_bytes(&self) -> Self::Repr {
121+
self.to_decaf().to_bytes()
122+
}
123+
}
124+
125+
impl PrimeCurveAffine for AffinePoint {
126+
type Scalar = DecafScalar;
127+
type Curve = DecafPoint;
128+
129+
fn identity() -> Self {
130+
Self::IDENTITY
131+
}
132+
133+
fn generator() -> Self {
134+
Self::GENERATOR
135+
}
136+
137+
fn is_identity(&self) -> Choice {
138+
self.ct_eq(&Self::IDENTITY)
139+
}
140+
141+
fn to_curve(&self) -> Self::Curve {
142+
self.to_decaf()
143+
}
144+
}
145+
73146
impl AffinePoint {
74147
/// The identity point
75148
pub const IDENTITY: Self = Self(InnerAffinePoint::IDENTITY);
149+
/// The generator point
150+
pub const GENERATOR: Self = Self(InnerAffinePoint::GENERATOR);
76151

77152
/// Convert to DecafPoint
78153
pub fn to_decaf(&self) -> DecafPoint {
@@ -115,3 +190,23 @@ impl Mul<&DecafScalar> for &AffinePoint {
115190
}
116191

117192
define_mul_variants!(LHS = AffinePoint, RHS = DecafScalar, Output = DecafPoint);
193+
194+
impl Neg for AffinePoint {
195+
type Output = Self;
196+
197+
fn neg(self) -> Self::Output {
198+
Self(self.0.negate())
199+
}
200+
}
201+
202+
#[cfg(test)]
203+
mod test {
204+
use super::*;
205+
use elliptic_curve::CurveGroup;
206+
207+
#[test]
208+
fn generator() {
209+
assert_eq!(AffinePoint::GENERATOR.to_decaf(), DecafPoint::GENERATOR);
210+
assert_eq!(DecafPoint::GENERATOR.to_affine(), AffinePoint::GENERATOR);
211+
}
212+
}

ed448-goldilocks/src/decaf/points.rs

Lines changed: 56 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ use elliptic_curve::{
66
CurveGroup, Error, Group,
77
array::Array,
88
consts::U56,
9-
group::{GroupEncoding, cofactor::CofactorGroup, prime::PrimeGroup},
9+
group::{
10+
GroupEncoding,
11+
cofactor::CofactorGroup,
12+
prime::{PrimeCurve, PrimeGroup},
13+
},
1014
ops::LinearCombination,
1115
point::NonIdentity,
1216
};
@@ -239,6 +243,10 @@ impl CofactorGroup for DecafPoint {
239243

240244
impl PrimeGroup for DecafPoint {}
241245

246+
impl PrimeCurve for DecafPoint {
247+
type Affine = DecafAffinePoint;
248+
}
249+
242250
impl<const N: usize> LinearCombination<[(DecafPoint, DecafScalar); N]> for DecafPoint {}
243251

244252
impl LinearCombination<[(DecafPoint, DecafScalar)]> for DecafPoint {}
@@ -535,43 +543,7 @@ impl CompressedDecaf {
535543

536544
/// Decompress a point if it is valid
537545
pub fn decompress(&self) -> CtOption<DecafPoint> {
538-
let s = FieldElement::from_bytes(&self.0);
539-
//XX: Check for canonical encoding and sign,
540-
// Copied this check from Dalek: The From_bytes function does not throw an error, if the bytes exceed the prime.
541-
// However, to_bytes reduces the Field element before serialising
542-
// So we can use to_bytes -> from_bytes and if the representations are the same, then the element was already in reduced form
543-
let s_bytes_check = s.to_bytes();
544-
let s_encoding_is_canonical = s_bytes_check[..].ct_eq(&self.0);
545-
let s_is_negative = s.is_negative();
546-
// if s_encoding_is_canonical.unwrap_u8() == 0u8 || s.is_negative().unwrap_u8() == 1u8 {
547-
// return None;
548-
// }
549-
550-
let ss = s.square();
551-
let u1 = FieldElement::ONE - ss;
552-
let u2 = FieldElement::ONE + ss;
553-
let u1_sqr = u1.square();
554-
555-
let v = ss * (FieldElement::NEG_FOUR_TIMES_TWISTED_D) + u1_sqr; // XXX: constantify please
556-
557-
let (I, ok) = (v * u1_sqr).inverse_square_root();
558-
559-
let Dx = I * u1;
560-
let Dxs = s.double() * Dx;
561-
562-
let mut X = (Dxs * I) * v;
563-
let k = Dxs * FieldElement::DECAF_FACTOR;
564-
X.conditional_negate(k.is_negative());
565-
566-
let Y = Dx * u2;
567-
let Z = FieldElement::ONE;
568-
let T = X * Y;
569-
let pt = ExtendedPoint { X, Y, Z, T };
570-
571-
CtOption::new(
572-
DecafPoint(pt),
573-
ok & pt.is_on_curve() & s_encoding_is_canonical & !s_is_negative,
574-
)
546+
DecafAffinePoint::from_bytes((&self.0).into()).map(|pt| pt.to_decaf())
575547
}
576548

577549
/// Get the bytes of this compressed point
@@ -633,109 +605,118 @@ mod test {
633605
#[test]
634606
fn test_vectors_lib_decaf() {
635607
// Testing small multiples of basepoint. Taken from reference implementation.
636-
let compressed = [
608+
const COMPRESSED: [DecafPointBytes; 16] = [
637609
// Taken from libdecaf, where they were computed using SAGE script
638-
CompressedDecaf([
610+
[
639611
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
640612
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
641-
]),
642-
CompressedDecaf([
613+
],
614+
[
643615
102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
644616
102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 51, 51, 51, 51, 51, 51,
645617
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
646618
51,
647-
]),
648-
CompressedDecaf([
619+
],
620+
[
649621
200, 152, 235, 79, 135, 249, 124, 86, 76, 111, 214, 31, 199, 228, 150, 137, 49, 74,
650622
31, 129, 142, 200, 94, 235, 59, 213, 81, 74, 200, 22, 211, 135, 120, 246, 158, 243,
651623
71, 168, 159, 202, 129, 126, 102, 222, 253, 237, 206, 23, 140, 124, 199, 9, 178,
652624
17, 110, 117,
653-
]),
654-
CompressedDecaf([
625+
],
626+
[
655627
160, 192, 155, 242, 186, 114, 8, 253, 160, 244, 191, 227, 208, 245, 178, 154, 84,
656628
48, 18, 48, 109, 67, 131, 27, 90, 220, 111, 231, 248, 89, 111, 163, 8, 118, 61,
657629
177, 84, 104, 50, 59, 17, 207, 110, 74, 235, 140, 24, 254, 68, 103, 143, 68, 84,
658630
90, 105, 188,
659-
]),
660-
CompressedDecaf([
631+
],
632+
[
661633
180, 111, 24, 54, 170, 40, 124, 10, 90, 86, 83, 240, 236, 94, 249, 233, 3, 244, 54,
662634
226, 28, 21, 112, 194, 154, 217, 229, 245, 150, 218, 151, 238, 175, 23, 21, 10,
663635
227, 11, 203, 49, 116, 208, 75, 194, 215, 18, 200, 199, 120, 157, 124, 180, 253,
664636
161, 56, 244,
665-
]),
666-
CompressedDecaf([
637+
],
638+
[
667639
28, 91, 190, 207, 71, 65, 223, 170, 231, 157, 183, 45, 250, 206, 0, 234, 170, 197,
668640
2, 194, 6, 9, 52, 182, 234, 174, 202, 106, 32, 189, 61, 169, 224, 190, 135, 119,
669641
247, 208, 32, 51, 209, 177, 88, 132, 35, 34, 129, 164, 31, 199, 248, 14, 237, 4,
670642
175, 94,
671-
]),
672-
CompressedDecaf([
643+
],
644+
[
673645
134, 255, 1, 130, 212, 15, 127, 158, 219, 120, 98, 81, 88, 33, 189, 103, 191, 214,
674646
22, 90, 60, 68, 222, 149, 215, 223, 121, 184, 119, 156, 207, 100, 96, 227, 198,
675647
139, 112, 193, 106, 170, 40, 15, 45, 123, 63, 34, 215, 69, 185, 122, 137, 144, 108,
676648
252, 71, 108,
677-
]),
678-
CompressedDecaf([
649+
],
650+
[
679651
80, 43, 203, 104, 66, 235, 6, 240, 228, 144, 50, 186, 232, 124, 85, 76, 3, 29, 109,
680652
77, 45, 118, 148, 239, 191, 156, 70, 141, 72, 34, 12, 80, 248, 202, 40, 132, 51,
681653
100, 215, 12, 238, 146, 214, 254, 36, 110, 97, 68, 143, 157, 185, 128, 139, 59, 36,
682654
8,
683-
]),
684-
CompressedDecaf([
655+
],
656+
[
685657
12, 152, 16, 241, 226, 235, 211, 137, 202, 167, 137, 55, 77, 120, 0, 121, 116, 239,
686658
77, 23, 34, 115, 22, 244, 14, 87, 139, 51, 104, 39, 218, 63, 107, 72, 42, 71, 148,
687659
235, 106, 57, 117, 185, 113, 181, 225, 56, 143, 82, 233, 30, 162, 241, 188, 176,
688660
249, 18,
689-
]),
690-
CompressedDecaf([
661+
],
662+
[
691663
32, 212, 29, 133, 161, 141, 86, 87, 162, 150, 64, 50, 21, 99, 187, 208, 76, 47,
692664
251, 208, 163, 122, 123, 164, 58, 79, 125, 38, 60, 226, 111, 175, 78, 31, 116, 249,
693665
244, 181, 144, 198, 146, 41, 174, 87, 31, 227, 127, 166, 57, 181, 184, 235, 72,
694666
189, 154, 85,
695-
]),
696-
CompressedDecaf([
667+
],
668+
[
697669
230, 180, 184, 244, 8, 199, 1, 13, 6, 1, 231, 237, 160, 195, 9, 161, 164, 39, 32,
698670
214, 208, 107, 87, 89, 253, 196, 225, 239, 226, 45, 7, 109, 108, 68, 212, 47, 80,
699671
141, 103, 190, 70, 41, 20, 210, 139, 142, 220, 227, 46, 112, 148, 48, 81, 100, 175,
700672
23,
701-
]),
702-
CompressedDecaf([
673+
],
674+
[
703675
190, 136, 187, 184, 108, 89, 193, 61, 142, 157, 9, 171, 152, 16, 95, 105, 194, 209,
704676
221, 19, 77, 188, 211, 176, 134, 54, 88, 245, 49, 89, 219, 100, 192, 225, 57, 209,
705677
128, 243, 200, 155, 130, 150, 208, 174, 50, 68, 25, 192, 111, 168, 127, 199, 218,
706678
175, 52, 193,
707-
]),
708-
CompressedDecaf([
679+
],
680+
[
709681
164, 86, 249, 54, 151, 105, 232, 240, 137, 2, 18, 74, 3, 20, 199, 160, 101, 55,
710682
160, 110, 50, 65, 31, 79, 147, 65, 89, 80, 161, 123, 173, 250, 116, 66, 182, 33,
711683
116, 52, 163, 160, 94, 244, 91, 229, 241, 11, 215, 178, 239, 142, 160, 12, 67, 30,
712684
222, 197,
713-
]),
714-
CompressedDecaf([
685+
],
686+
[
715687
24, 110, 69, 44, 68, 102, 170, 67, 131, 180, 192, 2, 16, 213, 46, 121, 34, 219,
716688
249, 119, 30, 139, 71, 226, 41, 169, 183, 183, 60, 141, 16, 253, 126, 240, 182,
717689
228, 21, 48, 249, 31, 36, 163, 237, 154, 183, 31, 163, 139, 152, 178, 254, 71, 70,
718690
213, 29, 104,
719-
]),
720-
CompressedDecaf([
691+
],
692+
[
721693
74, 231, 253, 202, 233, 69, 63, 25, 90, 142, 173, 92, 190, 26, 123, 150, 153, 103,
722694
59, 82, 196, 10, 178, 121, 39, 70, 72, 135, 190, 83, 35, 127, 127, 58, 33, 185, 56,
723695
212, 13, 14, 201, 225, 91, 29, 81, 48, 177, 63, 254, 216, 19, 115, 165, 62, 43, 67,
724-
]),
725-
CompressedDecaf([
696+
],
697+
[
726698
132, 25, 129, 195, 191, 238, 195, 246, 12, 254, 202, 117, 217, 216, 220, 23, 244,
727699
108, 240, 16, 111, 36, 34, 181, 154, 236, 88, 10, 88, 243, 66, 39, 46, 58, 94, 87,
728700
90, 5, 93, 219, 5, 19, 144, 197, 76, 36, 198, 236, 177, 224, 172, 235, 7, 95, 96,
729701
86,
730-
]),
702+
],
731703
];
732704
let mut point = DecafPoint::IDENTITY;
733705
let generator = DecafPoint::GENERATOR;
734-
for compressed_point in compressed.iter() {
735-
assert_eq!(&point.compress(), compressed_point);
706+
for compressed_point in COMPRESSED.iter() {
707+
assert_eq!(&point.to_bytes().0, compressed_point);
708+
assert_eq!(&point.to_affine().to_bytes().0, compressed_point);
736709
point += generator;
737-
let decompressed_point = compressed_point.decompress();
738-
assert_eq!(decompressed_point.is_some().unwrap_u8(), 1u8);
710+
assert!(
711+
DecafPoint::from_bytes(compressed_point.into())
712+
.into_option()
713+
.is_some()
714+
);
715+
assert!(
716+
DecafAffinePoint::from_bytes(compressed_point.into())
717+
.into_option()
718+
.is_some()
719+
);
739720
}
740721
}
741722

0 commit comments

Comments
 (0)