1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! Optimized simplified Shallue-van de Woestijne-Ulas methods.
//!
//! <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>
where
F: Field,
{
/// The first constant term
pub c1: &'static [u64],
/// The second constant term
pub c2: F,
/// The ISO A variable or Curve A variable
pub map_a: F,
/// The ISO A variable or Curve A variable
pub map_b: F,
/// The Z parameter
pub z: F,
}
/// Trait for determining the parity of the field
pub trait Sgn0 {
/// Return the parity of the field
/// 1 == negative
/// 0 == non-negative
fn sgn0(&self) -> Choice;
}
/// The optimized simplified Shallue-van de Woestijne-Ulas method
/// for mapping elliptic curve scalars to affine points.
pub trait OsswuMap: Field + Sgn0 {
/// The OSSWU parameters for mapping the field to affine points.
/// For Weierstrass curves having A==0 or B==0, the parameters
/// 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) {
// 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)
}
}