elliptic_curve/hash2curve/osswu.rs
1//! Optimized simplified Shallue-van de Woestijne-Ulas methods.
2//!
3//! <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-sswu>
4
5use ff::Field;
6use subtle::Choice;
7use subtle::ConditionallySelectable;
8use subtle::ConstantTimeEq;
9
10/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters
11pub struct OsswuMapParams<F>
12where
13 F: Field,
14{
15 /// The first constant term
16 pub c1: &'static [u64],
17 /// The second constant term
18 pub c2: F,
19 /// The ISO A variable or Curve A variable
20 pub map_a: F,
21 /// The ISO A variable or Curve A variable
22 pub map_b: F,
23 /// The Z parameter
24 pub z: F,
25}
26
27/// Trait for determining the parity of the field
28pub trait Sgn0 {
29 /// Return the parity of the field
30 /// 1 == negative
31 /// 0 == non-negative
32 fn sgn0(&self) -> Choice;
33}
34
35/// The optimized simplified Shallue-van de Woestijne-Ulas method
36/// for mapping elliptic curve scalars to affine points.
37pub trait OsswuMap: Field + Sgn0 {
38 /// The OSSWU parameters for mapping the field to affine points.
39 /// For Weierstrass curves having A==0 or B==0, the parameters
40 /// should be for isogeny where A≠0 and B≠0.
41 const PARAMS: OsswuMapParams<Self>;
42
43 /// Optimized sqrt_ratio for q = 3 mod 4.
44 fn sqrt_ratio_3mod4(u: Self, v: Self) -> (Choice, Self) {
45 // 1. tv1 = v^2
46 let tv1 = v.square();
47 // 2. tv2 = u * v
48 let tv2 = u * v;
49 // 3. tv1 = tv1 * tv2
50 let tv1 = tv1 * tv2;
51 // 4. y1 = tv1^c1
52 let y1 = tv1.pow_vartime(Self::PARAMS.c1);
53 // 5. y1 = y1 * tv2
54 let y1 = y1 * tv2;
55 // 6. y2 = y1 * c2
56 let y2 = y1 * Self::PARAMS.c2;
57 // 7. tv3 = y1^2
58 let tv3 = y1.square();
59 // 8. tv3 = tv3 * v
60 let tv3 = tv3 * v;
61 // 9. isQR = tv3 == u
62 let is_qr = tv3.ct_eq(&u);
63 // 10. y = CMOV(y2, y1, isQR)
64 let y = ConditionallySelectable::conditional_select(&y2, &y1, is_qr);
65 // 11. return (isQR, y)
66 (is_qr, y)
67 }
68
69 /// Convert this field element into an affine point on the elliptic curve
70 /// returning (X, Y). For Weierstrass curves having A==0 or B==0
71 /// the result is a point on an isogeny.
72 fn osswu(&self) -> (Self, Self) {
73 // 1. tv1 = u^2
74 let tv1 = self.square();
75 // 2. tv1 = Z * tv1
76 let tv1 = Self::PARAMS.z * tv1;
77 // 3. tv2 = tv1^2
78 let tv2 = tv1.square();
79 // 4. tv2 = tv2 + tv1
80 let tv2 = tv2 + tv1;
81 // 5. tv3 = tv2 + 1
82 let tv3 = tv2 + Self::ONE;
83 // 6. tv3 = B * tv3
84 let tv3 = Self::PARAMS.map_b * tv3;
85 // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
86 let tv4 = ConditionallySelectable::conditional_select(
87 &Self::PARAMS.z,
88 &-tv2,
89 !Field::is_zero(&tv2),
90 );
91 // 8. tv4 = A * tv4
92 let tv4 = Self::PARAMS.map_a * tv4;
93 // 9. tv2 = tv3^2
94 let tv2 = tv3.square();
95 // 10. tv6 = tv4^2
96 let tv6 = tv4.square();
97 // 11. tv5 = A * tv6
98 let tv5 = Self::PARAMS.map_a * tv6;
99 // 12. tv2 = tv2 + tv5
100 let tv2 = tv2 + tv5;
101 // 13. tv2 = tv2 * tv3
102 let tv2 = tv2 * tv3;
103 // 14. tv6 = tv6 * tv4
104 let tv6 = tv6 * tv4;
105 // 15. tv5 = B * tv6
106 let tv5 = Self::PARAMS.map_b * tv6;
107 // 16. tv2 = tv2 + tv5
108 let tv2 = tv2 + tv5;
109 // 17. x = tv1 * tv3
110 let x = tv1 * tv3;
111 // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
112 let (is_gx1_square, y1) = Self::sqrt_ratio_3mod4(tv2, tv6);
113 // 19. y = tv1 * u
114 let y = tv1 * self;
115 // 20. y = y * y1
116 let y = y * y1;
117 // 21. x = CMOV(x, tv3, is_gx1_square)
118 let x = ConditionallySelectable::conditional_select(&x, &tv3, is_gx1_square);
119 // 22. y = CMOV(y, y1, is_gx1_square)
120 let y = ConditionallySelectable::conditional_select(&y, &y1, is_gx1_square);
121 // 23. e1 = sgn0(u) == sgn0(y)
122 let e1 = self.sgn0().ct_eq(&y.sgn0());
123 // 24. y = CMOV(-y, y, e1)
124 let y = ConditionallySelectable::conditional_select(&-y, &y, e1);
125 // 25. x = x / tv4
126 let x = x * tv4.invert().unwrap();
127 // 26. return (x, y)
128 (x, y)
129 }
130}