|
10 | 10 |
|
11 | 11 | #![allow(non_snake_case)]
|
12 | 12 |
|
13 |
| -// use crate::constants::A_PLUS_TWO_OVER_FOUR; |
14 |
| -use crate::EdwardsScalar; |
15 |
| -use crate::edwards::extended::EdwardsPoint; |
16 |
| -use crate::field::FieldElement; |
17 |
| -use core::fmt; |
18 |
| -use core::ops::Mul; |
19 |
| -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; |
| 13 | +mod x; |
20 | 14 |
|
21 |
| -// Low order points on Curve448 and it's twist |
22 |
| -const LOW_A: MontgomeryXpoint = MontgomeryXpoint([ |
23 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
24 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
25 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
26 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
27 |
| -]); |
28 |
| -const LOW_B: MontgomeryXpoint = MontgomeryXpoint([ |
29 |
| - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
30 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
31 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
32 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
33 |
| -]); |
34 |
| -const LOW_C: MontgomeryXpoint = MontgomeryXpoint([ |
35 |
| - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
36 |
| - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, |
37 |
| - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
38 |
| - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
39 |
| -]); |
40 |
| - |
41 |
| -/// A point in Montgomery form |
42 |
| -#[derive(Copy, Clone)] |
43 |
| -pub struct MontgomeryXpoint(pub [u8; 56]); |
44 |
| - |
45 |
| -impl Default for MontgomeryXpoint { |
46 |
| - fn default() -> MontgomeryXpoint { |
47 |
| - Self([0u8; 56]) |
48 |
| - } |
49 |
| -} |
50 |
| - |
51 |
| -impl elliptic_curve::zeroize::DefaultIsZeroes for MontgomeryXpoint {} |
52 |
| - |
53 |
| -impl fmt::Debug for MontgomeryXpoint { |
54 |
| - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
55 |
| - self.0[..].fmt(formatter) |
56 |
| - } |
57 |
| -} |
58 |
| - |
59 |
| -impl ConstantTimeEq for MontgomeryXpoint { |
60 |
| - fn ct_eq(&self, other: &MontgomeryXpoint) -> Choice { |
61 |
| - self.0.ct_eq(&other.0) |
62 |
| - } |
63 |
| -} |
64 |
| - |
65 |
| -impl PartialEq for MontgomeryXpoint { |
66 |
| - fn eq(&self, other: &MontgomeryXpoint) -> bool { |
67 |
| - self.ct_eq(other).into() |
68 |
| - } |
69 |
| -} |
70 |
| -impl Eq for MontgomeryXpoint {} |
71 |
| - |
72 |
| -/// A Projective point in Montgomery form |
73 |
| -#[derive(Copy, Clone, Debug)] |
74 |
| -pub struct ProjectiveMontgomeryXpoint { |
75 |
| - U: FieldElement, |
76 |
| - W: FieldElement, |
77 |
| -} |
78 |
| - |
79 |
| -impl Mul<&EdwardsScalar> for &MontgomeryXpoint { |
80 |
| - type Output = MontgomeryXpoint; |
81 |
| - |
82 |
| - #[allow(clippy::suspicious_arithmetic_impl)] |
83 |
| - fn mul(self, scalar: &EdwardsScalar) -> MontgomeryXpoint { |
84 |
| - // Algorithm 8 of Costello-Smith 2017 |
85 |
| - let affine_u = FieldElement::from_bytes(&self.0); |
86 |
| - let mut x0 = ProjectiveMontgomeryXpoint::identity(); |
87 |
| - let mut x1 = ProjectiveMontgomeryXpoint { |
88 |
| - U: affine_u, |
89 |
| - W: FieldElement::ONE, |
90 |
| - }; |
91 |
| - |
92 |
| - let bits = scalar.bits(); |
93 |
| - let mut swap = 0; |
94 |
| - for s in (0..448).rev() { |
95 |
| - let bit = bits[s] as u8; |
96 |
| - let choice: u8 = swap ^ bit; |
97 |
| - |
98 |
| - ProjectiveMontgomeryXpoint::conditional_swap(&mut x0, &mut x1, Choice::from(choice)); |
99 |
| - differential_add_and_double(&mut x0, &mut x1, &affine_u); |
100 |
| - |
101 |
| - swap = bit; |
102 |
| - } |
103 |
| - |
104 |
| - x0.to_affine() |
105 |
| - } |
106 |
| -} |
107 |
| - |
108 |
| -impl Mul<&MontgomeryXpoint> for &EdwardsScalar { |
109 |
| - type Output = MontgomeryXpoint; |
110 |
| - |
111 |
| - fn mul(self, point: &MontgomeryXpoint) -> MontgomeryXpoint { |
112 |
| - point * self |
113 |
| - } |
114 |
| -} |
115 |
| - |
116 |
| -impl MontgomeryXpoint { |
117 |
| - /// Returns the generator specified in RFC7748 |
118 |
| - pub const GENERATOR: Self = Self([ |
119 |
| - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
120 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
121 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
122 |
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
123 |
| - ]); |
124 |
| - |
125 |
| - /// Convert this point to an [`EdwardsPoint`] |
126 |
| - pub fn to_edwards(&self, _sign: u8) -> Option<EdwardsPoint> { |
127 |
| - // We use the 4-isogeny to map to the Ed448. |
128 |
| - // This is different to Curve25519, where we use a birational map. |
129 |
| - todo!() |
130 |
| - } |
131 |
| - |
132 |
| - /// Returns true if the point is one of the low order points |
133 |
| - pub fn is_low_order(&self) -> bool { |
134 |
| - (*self == LOW_A) || (*self == LOW_B) || (*self == LOW_C) |
135 |
| - } |
136 |
| - |
137 |
| - /// View the point as a byte slice |
138 |
| - pub fn as_bytes(&self) -> &[u8; 56] { |
139 |
| - &self.0 |
140 |
| - } |
141 |
| - |
142 |
| - /// Convert the point to a ProjectiveMontgomeryPoint |
143 |
| - pub fn to_projective(&self) -> ProjectiveMontgomeryXpoint { |
144 |
| - ProjectiveMontgomeryXpoint { |
145 |
| - U: FieldElement::from_bytes(&self.0), |
146 |
| - W: FieldElement::ONE, |
147 |
| - } |
148 |
| - } |
149 |
| -} |
150 |
| - |
151 |
| -impl ConditionallySelectable for ProjectiveMontgomeryXpoint { |
152 |
| - fn conditional_select( |
153 |
| - a: &ProjectiveMontgomeryXpoint, |
154 |
| - b: &ProjectiveMontgomeryXpoint, |
155 |
| - choice: Choice, |
156 |
| - ) -> ProjectiveMontgomeryXpoint { |
157 |
| - ProjectiveMontgomeryXpoint { |
158 |
| - U: FieldElement::conditional_select(&a.U, &b.U, choice), |
159 |
| - W: FieldElement::conditional_select(&a.W, &b.W, choice), |
160 |
| - } |
161 |
| - } |
162 |
| -} |
163 |
| - |
164 |
| -fn differential_add_and_double( |
165 |
| - P: &mut ProjectiveMontgomeryXpoint, |
166 |
| - Q: &mut ProjectiveMontgomeryXpoint, |
167 |
| - affine_PmQ: &FieldElement, |
168 |
| -) { |
169 |
| - let t0 = P.U + P.W; |
170 |
| - let t1 = P.U - P.W; |
171 |
| - let t2 = Q.U + Q.W; |
172 |
| - let t3 = Q.U - Q.W; |
173 |
| - |
174 |
| - let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 |
175 |
| - let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 |
176 |
| - |
177 |
| - let t6 = t4 - t5; // 4 U_P W_P |
178 |
| - |
179 |
| - let t7 = t0 * t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q |
180 |
| - let t8 = t1 * t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q |
181 |
| - |
182 |
| - let t9 = t7 + t8; // 2 (U_P U_Q - W_P W_Q) |
183 |
| - let t10 = t7 - t8; // 2 (W_P U_Q - U_P W_Q) |
184 |
| - |
185 |
| - let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 |
186 |
| - let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 |
187 |
| - let t13 = FieldElement::A_PLUS_TWO_OVER_FOUR * t6; // (A + 2) U_P U_Q |
188 |
| - |
189 |
| - let t14 = t4 * t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 |
190 |
| - let t15 = t13 + t5; // (U_P - W_P)^2 + (A + 2) U_P W_P |
191 |
| - |
192 |
| - let t16 = t6 * t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) |
193 |
| - let t17 = *affine_PmQ * t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 |
194 |
| - let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 |
195 |
| - |
196 |
| - P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 |
197 |
| - P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) |
198 |
| - Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 |
199 |
| - Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 |
200 |
| -} |
201 |
| - |
202 |
| -impl ProjectiveMontgomeryXpoint { |
203 |
| - /// The identity element of the group: the point at infinity. |
204 |
| - pub fn identity() -> ProjectiveMontgomeryXpoint { |
205 |
| - ProjectiveMontgomeryXpoint { |
206 |
| - U: FieldElement::ONE, |
207 |
| - W: FieldElement::ZERO, |
208 |
| - } |
209 |
| - } |
210 |
| - |
211 |
| - /// Convert the point to affine form |
212 |
| - pub fn to_affine(&self) -> MontgomeryXpoint { |
213 |
| - let x = self.U * self.W.invert(); |
214 |
| - MontgomeryXpoint(x.to_bytes()) |
215 |
| - } |
216 |
| -} |
217 |
| - |
218 |
| -#[cfg(test)] |
219 |
| -mod tests { |
220 |
| - |
221 |
| - use super::*; |
222 |
| - |
223 |
| - #[test] |
224 |
| - fn test_montgomery_edwards() { |
225 |
| - let scalar = EdwardsScalar::from(200u32); |
226 |
| - use crate::GOLDILOCKS_BASE_POINT as bp; |
227 |
| - |
228 |
| - // Montgomery scalar mul |
229 |
| - let montgomery_bp = bp.to_montgomery_x(); |
230 |
| - let montgomery_res = &montgomery_bp * &scalar; |
231 |
| - |
232 |
| - // Goldilocks scalar mul |
233 |
| - let goldilocks_point = bp.scalar_mul(&scalar); |
234 |
| - assert_eq!(goldilocks_point.to_montgomery_x(), montgomery_res); |
235 |
| - } |
236 |
| -} |
| 15 | +pub use x::{MontgomeryXpoint, ProjectiveMontgomeryXpoint}; |
0 commit comments