Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 84 additions & 41 deletions elliptic-curve/src/hash2curve/osswu.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! Optimized simplified Shallue-van de Woestijne-Ulas methods.
//!
//! <https://eprint.iacr.org/2009/340.pdf>
//! <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-sswu>

use ff::Field;
use subtle::Choice;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;

/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters
pub struct OsswuMapParams<F>
Expand Down Expand Up @@ -38,50 +40,91 @@ pub trait OsswuMap: Field + Sgn0 {
/// should be for isogeny where A≠0 and B≠0.
const PARAMS: OsswuMapParams<Self>;

/// 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)
}
}