1use crate::util::ops::{ subw };
20
21pub struct Fe25519 {
23 pub v: [u32; 32],
24}
25
26#[inline]
27pub fn make_fe25519() -> Fe25519 {
28 Fe25519 { v: [0; 32] }
29}
30
31#[inline]
32pub fn make_copy_fe25519(x: &Fe25519) -> Fe25519 {
33 let mut copy = make_fe25519();
34 copy.v.copy_from_slice(&x.v);
35 copy
36}
37
38#[inline]
39pub fn fe25519_cp(r: &mut Fe25519, x: &Fe25519) {
40 r.v.copy_from_slice(&x.v);
41}
42
43#[inline]
46fn equal(a: u32, b: u32) -> u32 {
47 let mut x = a ^ b; x = subw!( x, 1 as u32 ); x >>= 31; x
51}
52
53#[inline]
56fn ge(a: u32, b: u32) -> u32 {
57 let mut x = a;
58 x = subw!( x, b ); x >>= 31; x ^= 1; x
62}
63
64#[inline]
66fn times19(a: u32) -> u32 {
67 (a << 4) + (a << 1) + a
68}
69
70#[inline]
72fn times38(a: u32) -> u32 {
73 (a << 5) + (a << 2) + (a << 1)
74}
75
76fn reduce_add_sub(r: &mut Fe25519) {
78 for _ in 0..4 {
79 let mut t = r.v[31] >> 7;
80 r.v[31] &= 127;
81 t = times19(t);
82 r.v[0] += t;
83 for i in 0..31 {
84 t = r.v[i] >> 8;
85 r.v[i+1] += t;
86 r.v[i] &= 255;
87 }
88 }
89}
90
91fn reduce_mul(r: &mut Fe25519) {
93 for _ in 0..2 {
94 let mut t = r.v[31] >> 7;
95 r.v[31] &= 127;
96 t = times19(t);
97 r.v[0] += t;
98 for i in 0..31 {
99 t = r.v[i] >> 8;
100 r.v[i+1] += t;
101 r.v[i] &= 255;
102 }
103 }
104}
105
106fn fe25519_freeze(r: &mut Fe25519) {
109 let mut m = equal(r.v[31],127);
110 let mut i: usize = 30;
111 while i > 0 {
112 m &= equal(r.v[i],255);
113 i -= 1;
114 }
115 m &= ge(r.v[0],237);
116
117 m = 0 - m;
118
119 r.v[31] -= m&127;
120 i = 30;
121 while i > 0 {
122 r.v[i] -= m&255;
123 i -= 1;
124 }
125 r.v[0] -= m&237;
126}
127
128pub fn fe25519_unpack(r: &mut Fe25519, x: &[u8]) {
130 for i in 0..32 { r.v[i] = x[i] as u32; }
131 r.v[31] &= 127;
132}
133
134pub fn fe25519_pack(r: &mut [u8], x: &Fe25519) {
137 let mut y = make_copy_fe25519(x);
138 fe25519_freeze(&mut y);
139 for i in 0..32 { r[i] = y.v[i] as u8; }
140}
141
142pub fn fe25519_iseq_vartime(x: &Fe25519, y: &Fe25519) -> bool {
144 let mut t1 = make_copy_fe25519(x);
145 let mut t2 = make_copy_fe25519(y);
146 fe25519_freeze(&mut t1);
147 fe25519_freeze(&mut t2);
148 for i in 0..32 {
149 if t1.v[i] != t2.v[i] { return false; }
150 }
151 true
152}
153
154pub fn fe25519_cmov(r: &mut Fe25519, x: &Fe25519, b: u8) {
156 let mut mask: u32 = b as u32;
157 mask = subw!( 0 as u32, mask );
158 for i in 0..32 { r.v[i] ^= mask & (x.v[i] ^ r.v[i]); }
159}
160
161pub fn fe25519_getparity(x: &Fe25519) -> u8 {
163 let mut t = make_copy_fe25519(x);
164 fe25519_freeze(&mut t);
165 (t.v[0] & 1) as u8
166}
167
168pub fn fe25519_setone(r: &mut Fe25519) {
170 r.v[0] = 1;
171 for i in 1..32 { r.v[i] = 0; }
172}
173
174pub fn fe25519_setzero(r: &mut Fe25519) {
176 for i in 0..32 { r.v[i]=0; }
177}
178
179const ZERO_FE25519: Fe25519 = Fe25519 { v: [0; 32] };
180
181pub fn fe25519_neg(r: &mut Fe25519, x: &Fe25519) {
183 let t = make_copy_fe25519(x);
184 fe25519_sub(r, &ZERO_FE25519, &t);
185}
186
187pub fn fe25519_add(r: &mut Fe25519, x: &Fe25519, y: &Fe25519) {
189 for i in 0..32 { r.v[i] = x.v[i] + y.v[i]; }
190 reduce_add_sub(r);
191}
192
193pub fn fe25519_sub(r: &mut Fe25519, x: &Fe25519, y: &Fe25519) {
195 let mut t: [u32; 32] = [0; 32];
196 t[0] = x.v[0] + 0x1da;
197 t[31] = x.v[31] + 0xfe;
198 for i in 1..31 { t[i] = x.v[i] + 0x1fe; }
199 for i in 0..32 { r.v[i] = t[i] - y.v[i]; }
200 reduce_add_sub(r);
201}
202
203pub fn fe25519_mul(r: &mut Fe25519, x: &Fe25519, y: &Fe25519) {
205 let mut t: [u32; 63] = [0; 63];
206
207 for i in 0..32 {
208 for j in 0..32 {
209 t[i+j] += x.v[i] * y.v[j];
210 }
211 }
212
213 for i in 32..63 {
214 r.v[i-32] = t[i-32] + times38(t[i]);
215 }
216 r.v[31] = t[31]; reduce_mul(r);
219}
220
221#[inline]
223pub fn fe25519_square(r: &mut Fe25519, x: &Fe25519) {
224 fe25519_mul(r, x, x);
225}
226
227pub fn fe25519_invert(r: &mut Fe25519, x: &Fe25519) {
234 let mut z2 = make_fe25519();
235 let mut z9 = make_fe25519();
236 let mut z11 = make_fe25519();
237 let mut z2_5_0 = make_fe25519();
238 let mut z2_10_0 = make_fe25519();
239 let mut z2_20_0 = make_fe25519();
240 let mut z2_50_0 = make_fe25519();
241 let mut z2_100_0 = make_fe25519();
242 let mut t0 = make_fe25519();
243 let mut t1 = make_fe25519();
244
245 fe25519_square(&mut z2, x);
246 fe25519_square(&mut t1, &z2);
247 fe25519_square(&mut t0, &t1);
248 fe25519_mul(&mut z9, &t0, x);
249 fe25519_mul(&mut z11, &z9, &z2);
250 fe25519_square(&mut t0, &z11);
251 fe25519_mul(&mut z2_5_0, &t0, &z9);
252
253 fe25519_square(&mut t0, &z2_5_0);
254 fe25519_square(&mut t1, &t0);
255 fe25519_square(&mut t0, &t1);
256 fe25519_square(&mut t1, &t0);
257 fe25519_square(&mut t0, &t1);
258 fe25519_mul(&mut z2_10_0, &t0, &z2_5_0);
259
260 fe25519_square(&mut t0, &z2_10_0);
261 fe25519_square(&mut t1, &t0);
262 for _ in 1..5 { fe25519_square(&mut t0, &t1); fe25519_square(&mut t1, &t0); }
263 fe25519_mul(&mut z2_20_0, &t1, &z2_10_0);
264
265 fe25519_square(&mut t0, &z2_20_0);
266 fe25519_square(&mut t1, &t0);
267 for _ in 1..10 { fe25519_square(&mut t0, &t1); fe25519_square(&mut t1, &t0); }
268 fe25519_mul(&mut t0, &t1, &z2_20_0);
269
270 fe25519_square(&mut t1, &t0);
271 fe25519_square(&mut t0, &t1);
272 for _ in 1..5 { fe25519_square(&mut t1, &t0); fe25519_square(&mut t0, &t1); }
273 fe25519_mul(&mut z2_50_0, &t0, &z2_10_0);
274
275 fe25519_square(&mut t0, &z2_50_0);
276 fe25519_square(&mut t1, &t0);
277 for _ in 1..25 { fe25519_square(&mut t0, &t1); fe25519_square(&mut t1, &t0); }
278 fe25519_mul(&mut z2_100_0, &t1, &z2_50_0);
279
280 fe25519_square(&mut t1, &z2_100_0);
281 fe25519_square(&mut t0, &t1);
282 for _ in 1..50 { fe25519_square(&mut t1, &t0); fe25519_square(&mut t0, &t1); }
283 fe25519_mul(&mut t1, &t0, &z2_100_0);
284
285 fe25519_square(&mut t0, &t1);
286 fe25519_square(&mut t1, &t0);
287 for _ in 1..25 { fe25519_square(&mut t0, &t1); fe25519_square(&mut t1, &t0); }
288 fe25519_mul(&mut t0, &t1, &z2_50_0);
289
290 fe25519_square(&mut t1, &t0);
291 fe25519_square(&mut t0, &t1);
292 fe25519_square(&mut t1, &t0);
293 fe25519_square(&mut t0, &t1);
294 fe25519_square(&mut t1, &t0);
295 fe25519_mul(r, &t1, &z11);
296}
297
298pub fn fe25519_pow2523(r: &mut Fe25519, x: &Fe25519) {
300 let mut z2 = make_fe25519();
301 let mut z9 = make_fe25519();
302 let mut z11 = make_fe25519();
303 let mut z2_5_0 = make_fe25519();
304 let mut z2_10_0 = make_fe25519();
305 let mut z2_20_0 = make_fe25519();
306 let mut z2_50_0 = make_fe25519();
307 let mut z2_100_0 = make_fe25519();
308 let mut t = make_fe25519();
309 let mut t2 = make_fe25519();
310
311 fe25519_square(&mut z2, x);
312 fe25519_square(&mut t, &z2);
313 fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2);
314 fe25519_mul(&mut z9, &t, x);
315 fe25519_mul(&mut z11, &z9, &z2);
316 fe25519_square(&mut t, &z11);
317 fe25519_mul(&mut z2_5_0, &t, &z9);
318
319 fe25519_square(&mut t, &z2_5_0);
320 for _ in 1..5 { fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2); }
321 fe25519_mul(&mut z2_10_0, &t, &z2_5_0);
322
323 fe25519_square(&mut t, &z2_10_0);
324 for _ in 1..10 { fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2); }
325 fe25519_mul(&mut z2_20_0, &t, &z2_10_0);
326
327 fe25519_square(&mut t, &z2_20_0);
328 for _ in 1..20 { fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2); }
329 fe25519_mul(&mut t2, &t, &z2_20_0); fe25519_cp(&mut t, &t2);
330
331 fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2);
332 for _ in 1..10 { fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2); }
333 fe25519_mul(&mut z2_50_0, &t, &z2_10_0);
334
335 fe25519_square(&mut t, &z2_50_0);
336 for _ in 1..50 { fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2); }
337 fe25519_mul(&mut z2_100_0, &t, &z2_50_0);
338
339 fe25519_square(&mut t, &z2_100_0);
340 for _ in 1..100 { fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2); }
341 fe25519_mul(&mut t2, &t, &z2_100_0); fe25519_cp(&mut t, &t2);
342
343 fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2);
344 for _ in 1..50 { fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2); }
345 fe25519_mul(&mut t2, &t, &z2_50_0); fe25519_cp(&mut t, &t2);
346
347 fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2);
348 fe25519_square(&mut t2, &t); fe25519_cp(&mut t, &t2);
349 fe25519_mul(r, &t, x);
350}
351