@@ -4,6 +4,7 @@ use subtle::ConditionallySelectable;
44use subtle:: ConstantTimeEq ;
55
66use super :: { MontgomeryXpoint , ProjectiveMontgomeryXpoint } ;
7+ use crate :: AffinePoint ;
78use crate :: field:: { ConstMontyType , FieldElement } ;
89
910/// A point in Montgomery form including the y-coordinate.
@@ -74,6 +75,50 @@ impl From<MontgomeryPoint> for MontgomeryXpoint {
7475 }
7576}
7677
78+ impl From < & MontgomeryPoint > for AffinePoint {
79+ // https://www.rfc-editor.org/rfc/rfc7748#section-4.2
80+ fn from ( value : & MontgomeryPoint ) -> AffinePoint {
81+ let x = value. x ;
82+ let y = value. y ;
83+ let mut t0 = x. square ( ) ; // x^2
84+ let t1 = t0 + FieldElement :: ONE ; // x^2+1
85+ t0 -= FieldElement :: ONE ; // x^2-1
86+ let mut t2 = y. square ( ) ; // y^2
87+ t2 = t2. double ( ) ; // 2y^2
88+ let t3 = x. double ( ) ; // 2x
89+
90+ let mut t4 = t0 * y; // y(x^2-1)
91+ t4 = t4. double ( ) ; // 2y(x^2-1)
92+ let xNum = t4. double ( ) ; // xNum = 4y(x^2-1)
93+
94+ let mut t5 = t0. square ( ) ; // x^4-2x^2+1
95+ t4 = t5 + t2; // x^4-2x^2+1+2y^2
96+ let xDen = t4 + t2; // xDen = x^4-2x^2+1+4y^2
97+
98+ t5 *= x; // x^5-2x^3+x
99+ t4 = t2 * t3; // 4xy^2
100+ let yNum = t4 - t5; // yNum = -(x^5-2x^3+x-4xy^2)
101+
102+ t4 = t1 * t2; // 2x^2y^2+2y^2
103+ let yDen = t5 - t4; // yDen = x^5-2x^3+x-2x^2y^2-2y^2
104+
105+ let x = xNum * xDen. invert ( ) ;
106+ let y = yNum * yDen. invert ( ) ;
107+
108+ AffinePoint :: conditional_select (
109+ & AffinePoint { x, y } ,
110+ & AffinePoint :: IDENTITY ,
111+ value. ct_eq ( & MontgomeryPoint :: IDENTITY ) ,
112+ )
113+ }
114+ }
115+
116+ impl From < MontgomeryPoint > for AffinePoint {
117+ fn from ( value : MontgomeryPoint ) -> Self {
118+ ( & value) . into ( )
119+ }
120+ }
121+
77122/// A Projective point in Montgomery form including the y-coordinate.
78123#[ derive( Copy , Clone , Debug , Eq ) ]
79124pub struct ProjectiveMontgomeryPoint {
@@ -182,6 +227,35 @@ impl From<ProjectiveMontgomeryPoint> for MontgomeryXpoint {
182227#[ cfg( test) ]
183228mod tests {
184229 use super :: * ;
230+ use crate :: { EdwardsPoint , MontgomeryScalar } ;
231+
232+ #[ test]
233+ fn to_edwards ( ) {
234+ let scalar = MontgomeryScalar :: from ( 200u32 ) ;
235+
236+ // Montgomery scalar mul
237+ let montgomery_res = ProjectiveMontgomeryPoint :: GENERATOR * scalar * scalar;
238+ // Goldilocks scalar mul
239+ let goldilocks_point = EdwardsPoint :: GENERATOR * scalar. to_scalar ( ) * scalar. to_scalar ( ) ;
240+
241+ assert_eq ! ( goldilocks_point. to_montgomery( ) , montgomery_res. into( ) ) ;
242+ }
243+
244+ #[ test]
245+ fn identity_to_edwards ( ) {
246+ let edwards = AffinePoint :: IDENTITY ;
247+ let montgomery = MontgomeryPoint :: IDENTITY ;
248+
249+ assert_eq ! ( AffinePoint :: from( montgomery) , edwards) ;
250+ }
251+
252+ #[ test]
253+ fn identity_from_montgomery ( ) {
254+ let edwards = EdwardsPoint :: IDENTITY ;
255+ let montgomery = MontgomeryPoint :: IDENTITY ;
256+
257+ assert_eq ! ( edwards. to_montgomery( ) , montgomery) ;
258+ }
185259
186260 #[ test]
187261 fn to_projective_x ( ) {
0 commit comments