diff --git a/elliptic-curve/src/hash2curve/osswu.rs b/elliptic-curve/src/hash2curve/osswu.rs index 60796ebe5..3c3669ac3 100644 --- a/elliptic-curve/src/hash2curve/osswu.rs +++ b/elliptic-curve/src/hash2curve/osswu.rs @@ -1,9 +1,11 @@ //! Optimized simplified Shallue-van de Woestijne-Ulas methods. //! -//! +//! use ff::Field; use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; /// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters pub struct OsswuMapParams @@ -38,50 +40,91 @@ pub trait OsswuMap: Field + Sgn0 { /// should be for isogeny where A≠0 and B≠0. const PARAMS: OsswuMapParams; + /// Optimized sqrt_ratio for q = 3 mod 4. + fn sqrt_ratio_3mod4(u: Self, v: Self) -> (Choice, Self) { + // 1. tv1 = v^2 + let tv1 = v.square(); + // 2. tv2 = u * v + let tv2 = u * v; + // 3. tv1 = tv1 * tv2 + let tv1 = tv1 * tv2; + // 4. y1 = tv1^c1 + let y1 = tv1.pow_vartime(Self::PARAMS.c1); + // 5. y1 = y1 * tv2 + let y1 = y1 * tv2; + // 6. y2 = y1 * c2 + let y2 = y1 * Self::PARAMS.c2; + // 7. tv3 = y1^2 + let tv3 = y1.square(); + // 8. tv3 = tv3 * v + let tv3 = tv3 * v; + // 9. isQR = tv3 == u + let is_qr = tv3.ct_eq(&u); + // 10. y = CMOV(y2, y1, isQR) + let y = ConditionallySelectable::conditional_select(&y2, &y1, is_qr); + // 11. return (isQR, y) + (is_qr, y) + } + /// Convert this field element into an affine point on the elliptic curve /// returning (X, Y). For Weierstrass curves having A==0 or B==0 /// the result is a point on an isogeny. fn osswu(&self) -> (Self, Self) { - let tv1 = self.square(); // u^2 - let tv3 = Self::PARAMS.z * tv1; // Z * u^2 - let mut tv2 = tv3.square(); // tv3^2 - let mut xd = tv2 + tv3; // tv3^2 + tv3 - let x1n = Self::PARAMS.map_b * (xd + Self::ONE); // B * (xd + 1) - xd *= -Self::PARAMS.map_a; // -A * xd - - let tv = Self::PARAMS.z * Self::PARAMS.map_a; - xd.conditional_assign(&tv, xd.is_zero()); - - tv2 = xd.square(); //xd^2 - let gxd = tv2 * xd; // xd^3 - tv2 *= Self::PARAMS.map_a; // A * tv2 - - let mut gx1 = x1n * (tv2 + x1n.square()); //x1n *(tv2 + x1n^2) - tv2 = gxd * Self::PARAMS.map_b; // B * gxd - gx1 += tv2; // gx1 + tv2 - - let mut tv4 = gxd.square(); // gxd^2 - tv2 = gx1 * gxd; // gx1 * gxd - tv4 *= tv2; - - let y1 = tv4.pow_vartime(Self::PARAMS.c1) * tv2; // tv4^C1 * tv2 - let x2n = tv3 * x1n; // tv3 * x1n - - let y2 = y1 * Self::PARAMS.c2 * tv1 * self; // y1 * c2 * tv1 * u - - tv2 = y1.square() * gxd; //y1^2 * gxd - - let e2 = tv2.ct_eq(&gx1); - - // if e2 , x = x1, else x = x2 - let mut x = Self::conditional_select(&x2n, &x1n, e2); - // xn / xd - x *= xd.invert().unwrap(); - - // if e2, y = y1, else y = y2 - let mut y = Self::conditional_select(&y2, &y1, e2); - - y.conditional_assign(&-y, self.sgn0() ^ y.sgn0()); + // 1. tv1 = u^2 + let tv1 = self.square(); + // 2. tv1 = Z * tv1 + let tv1 = Self::PARAMS.z * tv1; + // 3. tv2 = tv1^2 + let tv2 = tv1.square(); + // 4. tv2 = tv2 + tv1 + let tv2 = tv2 + tv1; + // 5. tv3 = tv2 + 1 + let tv3 = tv2 + Self::ONE; + // 6. tv3 = B * tv3 + let tv3 = Self::PARAMS.map_b * tv3; + // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + let tv4 = ConditionallySelectable::conditional_select( + &Self::PARAMS.z, + &-tv2, + !Field::is_zero(&tv2), + ); + // 8. tv4 = A * tv4 + let tv4 = Self::PARAMS.map_a * tv4; + // 9. tv2 = tv3^2 + let tv2 = tv3.square(); + // 10. tv6 = tv4^2 + let tv6 = tv4.square(); + // 11. tv5 = A * tv6 + let tv5 = Self::PARAMS.map_a * tv6; + // 12. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 13. tv2 = tv2 * tv3 + let tv2 = tv2 * tv3; + // 14. tv6 = tv6 * tv4 + let tv6 = tv6 * tv4; + // 15. tv5 = B * tv6 + let tv5 = Self::PARAMS.map_b * tv6; + // 16. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 17. x = tv1 * tv3 + let x = tv1 * tv3; + // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + let (is_gx1_square, y1) = Self::sqrt_ratio_3mod4(tv2, tv6); + // 19. y = tv1 * u + let y = tv1 * self; + // 20. y = y * y1 + let y = y * y1; + // 21. x = CMOV(x, tv3, is_gx1_square) + let x = ConditionallySelectable::conditional_select(&x, &tv3, is_gx1_square); + // 22. y = CMOV(y, y1, is_gx1_square) + let y = ConditionallySelectable::conditional_select(&y, &y1, is_gx1_square); + // 23. e1 = sgn0(u) == sgn0(y) + let e1 = self.sgn0().ct_eq(&y.sgn0()); + // 24. y = CMOV(-y, y, e1) + let y = ConditionallySelectable::conditional_select(&-y, &y, e1); + // 25. x = x / tv4 + let x = x * tv4.invert().unwrap(); + // 26. return (x, y) (x, y) } }