@@ -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 {
@@ -188,6 +233,35 @@ impl From<ProjectiveMontgomeryPoint> for MontgomeryXpoint {
188233#[ cfg( test) ]
189234mod tests {
190235 use super :: * ;
236+ use crate :: { EdwardsPoint , MontgomeryScalar } ;
237+
238+ #[ test]
239+ fn to_edwards ( ) {
240+ let scalar = MontgomeryScalar :: from ( 200u32 ) ;
241+
242+ // Montgomery scalar mul
243+ let montgomery_res = ProjectiveMontgomeryPoint :: GENERATOR * scalar * scalar;
244+ // Goldilocks scalar mul
245+ let goldilocks_point = EdwardsPoint :: GENERATOR * scalar. to_scalar ( ) * scalar. to_scalar ( ) ;
246+
247+ assert_eq ! ( goldilocks_point. to_montgomery( ) , montgomery_res. into( ) ) ;
248+ }
249+
250+ #[ test]
251+ fn identity_to_edwards ( ) {
252+ let edwards = AffinePoint :: IDENTITY ;
253+ let montgomery = MontgomeryPoint :: IDENTITY ;
254+
255+ assert_eq ! ( AffinePoint :: from( montgomery) , edwards) ;
256+ }
257+
258+ #[ test]
259+ fn identity_from_montgomery ( ) {
260+ let edwards = EdwardsPoint :: IDENTITY ;
261+ let montgomery = MontgomeryPoint :: IDENTITY ;
262+
263+ assert_eq ! ( edwards. to_montgomery( ) , montgomery) ;
264+ }
191265
192266 #[ test]
193267 fn to_projective_x ( ) {
0 commit comments