Let us walk on the 3-isogeny graph
Loading...
Searching...
No Matches
fp2.c
Go to the documentation of this file.
1//
2// Quadratic field arithmetic assuming p = 3 mod 4: GF(p²)
3//
4
5#include <string.h>
6#include "fp2.h"
7#include "utilities.h"
8
9
10void fp2_add(fp2_t *output, fp2_t input_a, fp2_t input_b) {
11 fp_add(output->re, input_a.re, input_b.re);
12 fp_add(output->im, input_a.im, input_b.im);
13}
14
15
16void fp2_sub(fp2_t *output, fp2_t input_a, fp2_t input_b) {
17 fp_sub(output->re, input_a.re, input_b.re);
18 fp_sub(output->im, input_a.im, input_b.im);
19}
20
21void fp2_mul(fp2_t *output, fp2_t input_a, fp2_t input_b) {
22 fp_t z0, z1, z2, z3, tmp;
23 fp_add(z0, input_a.re, input_a.im);
24 fp_add(z1, input_b.re, input_b.im);
25 fp_mul(tmp, z0, z1);
26 fp_mul(z2, input_a.re, input_b.re);
27 fp_mul(z3, input_a.im, input_b.im);
28 fp_sub(output->re, z2, z3);
29 fp_sub(output->im, tmp, z2);
30 fp_sub(output->im, output->im, z3);
31}
32
33void fp2_sqr(fp2_t *output, fp2_t input) {
34 fp_t z0, z1, z2;
35 fp_add(z0, input.re, input.re);
36 fp_add(z1, input.re, input.im);
37 fp_sub(z2, input.re, input.im);
38 fp_mul(output->re, z1, z2);
39 fp_mul(output->im, z0, input.im);
40}
41
42
43void fp2_neg(fp2_t *output, fp2_t input) {
44 fp_neg(output->re, input.re);
45 fp_neg(output->im, input.im);
46}
47
48
49void fp2_set_to_one(fp2_t *output) {
50 fp_set_to_one(output->re);
51 fp_set_to_zero(output->im);
52}
53
54void fp2_set_to_zero(fp2_t *output) {
55 fp_set_to_zero(output->re);
56 fp_set_to_zero(output->im);
57}
58
59void fp2_copy(fp2_t *output, fp2_t input) {
60 fp_copy(output->re, input.re);
61 fp_copy(output->im, input.im);
62}
63
64
65void fp2_cswap(fp2_t *input_a, fp2_t *input_b, uint64_t input) {
66 // If input = 0 then a <- a and b <- b, else if input = 0xFF...FF then a <- b and b <- a
67 uint64_t temp;
68 unsigned int i;
69
70 for (i = 0; i < FIELD_64BITS_WORDS; i++) {
71 temp = input & (input_a->re[i] ^ input_b->re[i]);
72 input_a->re[i] = temp ^ input_a->re[i];
73 input_b->re[i] = temp ^ input_b->re[i];
74 temp = input & (input_a->im[i] ^ input_b->im[i]);
75 input_a->im[i] = temp ^ input_a->im[i];
76 input_b->im[i] = temp ^ input_b->im[i];
77 }
78}
79
80
81void fp2_cset(fp2_t *output, fp2_t input, uint64_t input_mask) {
82 // If mask = 0 then output is not modified, else if input = 0xFF...FF then output <- input
83 uint64_t temp;
84 unsigned int i;
85
86 for (i = 0; i < FIELD_64BITS_WORDS; i++) {
87 temp = input_mask & (output->re[i] ^ input.re[i]);
88 output->re[i] = temp ^ output->re[i];
89 temp = input_mask & (output->im[i] ^ input.im[i]);
90 output->im[i] = temp ^ output->im[i];
91 }
92}
93
94
95void fp2_inv(fp2_t *output, fp2_t input) {
96 fp_t N0, N1, S1, S2, zero = {0};
97 fp_sqr(N0, input.re);
98 fp_sqr(N1, input.im);
99 fp_add(S1, N0, N1);
100 fp_inv(S1, S1);
101 fp_sub(S2, zero, input.im);
102 fp_mul(output->re, S1, input.re);
103 fp_mul(output->im, S1, S2);
104}
105
106
107void fp2_half(fp2_t *output, fp2_t input) {
108 fp_half(output->re, input.re);
109 fp_half(output->im, input.im);
110}
111
112
113void fp2_to_mont(fp2_t *output, fp2_t input) {
114 fp_to_mont(output->re, input.re);
115 fp_to_mont(output->im, input.im);
116}
117
118
119void fp2_from_mont(fp2_t *output, fp2_t input) {
120 fp_from_mont(output->re, input.re);
121 fp_from_mont(output->im, input.im);
122}
123
124
125void fp2_conj(fp2_t *output, fp2_t input) {
126 fp_copy(output->re, input.re);
127 fp_neg(output->im, input.im);
128}
129
130
131void fp2_to_bytes(uint8_t *output, fp2_t input) {
132 fp2_t t;
133
134 fp2_from_mont(&t, input);
135 memcpy(output, t.re, FIELD_BYTES);
136 memcpy(&output[FIELD_BYTES], t.im, FIELD_BYTES);
137}
138
139
140void fp2_element_from_bytes(fp2_t *output, const uint8_t *input) {
141 output->re[FIELD_64BITS_WORDS - 1] = 0;
142 memcpy(output->re, input, FIELD_BYTES);
143 output->im[FIELD_64BITS_WORDS - 1] = 0;
144 memcpy(output->im, &input[FIELD_BYTES], FIELD_BYTES);
145 fp2_to_mont(output, *output);
146}
147
148
149int64_t fp2_is_zero(fp2_t input) {
150 return fp_is_zero(input.re) & fp_is_zero(input.im);
151}
152
153
154uint8_t fp2_is_equal(fp2_t input_a, fp2_t input_b) {
155 return fp_is_equal(input_a.re, input_b.re) & fp_is_equal(input_a.im, input_b.im);
156}
157
158
159void fp2_linear_pass_in(fp2_t *output, const fp2_t *input, uint8_t input_length, uint8_t input_index) {
160 // This function copies the ith entry of the input into the output
161 // At most 255-length lists
162 uint8_t i;
163 for(i = 0; i < input_length; i++) {
164 int64_t mask = (int64_t)input_index - (int64_t)i;
165 fp2_cset(output, input[i], ~((mask >> 63) | (-mask >> 63)));
166 }
167}
168
169
170void fp2_linear_pass_out(fp2_t *output, fp2_t input, uint8_t input_length, uint8_t input_index) {
171 // This function copies the input into the ith entry of the output
172 // At most 255-length lists
173 uint8_t i;
174 for(i = 0; i < input_length; i++) {
175 int64_t mask = (int64_t)input_index - (int64_t)i;
176 fp2_cset(&output[i], input, ~((mask >> 63) | (-mask >> 63)));
177 }
178}
179
180
181uint8_t fp2_locate_zero(const fp2_t *input, uint8_t input_length) {
182 // At most 255-length lists
183 uint8_t i;
184 int64_t index = 0;
185 for(i = 0; i < input_length; i++) {
186 index |= i & fp2_is_zero(input[i]);
187 }
188 return (uint8_t)index;
189}
190
191
192uint8_t fp2_is_square(fp2_t input) {
193 fp_t t0, t1;
194
195 fp_sqr(t0, input.re);
196 fp_sqr(t1, input.im);
197 fp_add(t0, t0, t1);
198 return fp_is_square(t0);
199}
200
201
202void fp2_batchinv(fp2_t *output_list, const fp2_t *input_list, uint8_t input_length) {
203 int i;
204 fp2_t tmp_list[input_length], inv, tmp;
205
206 fp2_copy(&tmp_list[0], input_list[0]);
207 for(i = 1; i < input_length; i++) { fp2_mul(&tmp_list[i], tmp_list[i - 1], input_list[i]); }
208 fp2_inv(&inv, tmp_list[input_length - 1]);
209 for(i = (input_length - 1); i > 0; i--) {
210 fp2_mul(&tmp, inv, tmp_list[i - 1]);
211 fp2_mul(&inv, inv, input_list[i]);
212 fp2_copy(&output_list[i], tmp);
213 }
214 fp2_copy(&output_list[0], inv);
215}
216
217#ifndef SSEC_KONG_ET_AL_S_ALGORITHM
218void fp2_sqrt_slow(fp2_t *output, fp2_t input) {
219 // Square root over Fq with q = p²: Adj and Rodríguez-Henríquez's algorithm (constant-time implementation). We assume p = 3 mod 4
220 // if input does NOT have square-root, then it returns zero
221
222 fp2_t input_1, alpha, ALPHA, alpha_conjugated, input_0, minus_one, x0, temp, choose_from[3];
223
224 fp2_set_to_zero(&alpha_conjugated);
225 fp2_set_to_one(&minus_one);
226 fp2_neg(&minus_one, minus_one);
227
228 int i, j, k;
229 uint64_t flag;
230
231 // input_1 <- input ^ ([p - 3] / 4)
232 fp2_set_to_one(&input_1);
233 fp2_copy(&temp, input);
234 for (i = 0, k = 0; i < FIELD_64BITS_WORDS && k < FIELD_BITS; i++, k++) {
235 flag = 1;
236 for (j = 0; j < 64; j++, k++) {
237 if ((flag & SQUARE_ROOT_EXPONENT_34[i]) != 0) {fp2_mul(&input_1, temp, input_1);}
238 fp2_sqr(&temp, temp);
239 flag <<= 1;
240 }
241 }
242
243 fp2_sqr(&alpha, input_1);
244 fp2_mul(&alpha, alpha, input);
245
246 fp2_conj(&alpha_conjugated, alpha);
247 fp2_mul(&input_0, alpha_conjugated, alpha);
248
249 // choose_from[2] stores zero when input does NOT have square-root
250 fp2_set_to_zero(&choose_from[2]);
251
252 // choose_from[1] stores the square root concerning alpha == -1
253 fp2_mul(&x0, input_1, input);
254 fp_neg(choose_from[1].re, x0.im);
255 fp_copy(choose_from[1].im, x0.re);
256
257 // choose_from[0] stores the square root concerning alpha != -1
258 fp2_sub(&ALPHA, alpha, minus_one);
259
260 // output <- ALPHA ^ ([p - 1] / 2)
261 fp2_set_to_one(&choose_from[0]);
262 fp2_copy(&temp, ALPHA);
263 for (i = 0, k = 0; i < FIELD_64BITS_WORDS && k < FIELD_BITS; i++, k++) {
264 flag = 1;
265 for (j = 0; j < 64; j++, k++) {
266 if ((flag & SQUARE_ROOT_EXPONENT_12[i]) != 0) {fp2_mul(&choose_from[0], temp, choose_from[0]);}
267 fp2_sqr(&temp, temp);
268 flag <<= 1;
269 }
270 }
271 fp2_mul(&choose_from[0], choose_from[0], x0);
272
273 // select the correct square-root output by linear pass (constant-time)
274 fp2_linear_pass_in(output, choose_from, 3, (fp2_is_equal(minus_one, input_0) << 1) ^ fp2_is_equal(minus_one, alpha));
275
276 // clear data
277 fp2_set_to_zero(&choose_from[0]);
278 fp2_set_to_zero(&choose_from[1]);
279 fp2_set_to_zero(&choose_from[2]);
280 fp2_set_to_zero(&temp);
281}
282#else
283void fp2_sqrt_slow(fp2_t *output, fp2_t input) {
284 // Square root over Fq with q = p²: Kong et al.'s algorithm. We assume p² = 9 mod 16 and p = 3 mod 4
285 // This function assumes the input has square-root
286
287 int i, j, k;
288 uint64_t flag;
289 fp_t one;
290 fp2_t a_double, b, b_square, c, r, temp, s[2], u;
291
292 fp_set_to_one(one);
293
294 fp2_set_to_one(&b);
295 fp2_add(&a_double, input, input);
296 fp2_copy(&temp, a_double);
297
298 for (i = 0, k = 0; i < 2 * FIELD_64BITS_WORDS && k < SQUARE_ROOT_EXPONENT_BITS; i++, k++) {
299 flag = 1;
300 for (j = 0; j < 64; j++, k++) {
301 if ((flag & SQUARE_ROOT_EXPONENT_916[i]) != 0) {fp2_mul(&b, temp, b);}
302 fp2_sqr(&temp, temp);
303 flag <<= 1;
304 }
305 }
306 fp2_sqr(&b_square, b);
307 fp2_mul(&c, a_double, b_square);
308 fp2_sqr(&r, c);
309 fp_sub(c.re, c.re, one); // c - 1
310
311 fp2_mul(&s[0], input, b);
312 fp2_mul(&s[0], s[0], c);
313 fp2_mul(&u, b, *((fp2_t *)&SQUARE_ROOT_CONSTANT_T));
314 fp2_mul(&s[1], u, *((fp2_t *)&SQUARE_ROOT_CONSTANT_D));
315
316 fp2_sqr(&c, s[1]);
317 fp2_mul(&c, c, input);
318 fp2_add(&c, c, c);
319 fp_sub(c.re, c.re, one); // c - 1
320 fp2_mul(&s[1], s[1], input);
321 fp2_mul(&s[1], s[1], c);
322
323 // select the correct square-root output by linear pass (constant-time)
324 fp2_linear_pass_in(output, s, 2, fp_is_equal(one, r.re) & fp_is_zero(r.im));
325
326 // clear data
327 fp2_set_to_zero(&s[0]);
328 fp2_set_to_zero(&s[1]);
329 fp2_set_to_zero(&temp);
330}
331#endif
332
333void fp2_sqrt_fast(fp2_t *output, fp2_t input) {
334 fp_t delta, x0, t0, x1, t1, temp;
335 uint64_t flag;
336
337 // x1 <- (a0^2 + a1^2)
338 fp_sqr(x0, input.re);
339 fp_sqr(x1, input.im);
340 fp_add(x1, x0, x1);
341
342 // alpha <- x1 ^ ([p + 1] / 4)
343 fp_set_to_one(delta);
344 fp_copy(temp, x1);
345 for (int i = 0; i < FIELD_64BITS_WORDS; i++) {
346 flag = 1;
347 for (int j = 0; j < 64; j++) {
348 if ((flag & SQUARE_ROOT_EXPONENT_14[i]) != 0)
349 fp_mul(delta, temp, delta);
350 fp_sqr(temp, temp);
351 flag <<= 1;
352 }
353 }
354
355 // x0 <- a0 + delta
356 fp_add(x0, input.re, delta);
357 // t0 <- 2 * x0
358 fp_add(t0, x0, x0);
359
360 // x1 <- t0 ^ ([p - 3] / 4)
361 fp_set_to_one(x1);
362 fp_copy(temp, t0);
363 for (int i = 0; i < FIELD_64BITS_WORDS; i++) {
364 flag = 1;
365 for (int j = 0; j < 64; j++) {
366 if ((flag & SQUARE_ROOT_EXPONENT_34[i]) != 0)
367 fp_mul(x1, temp, x1);
368 fp_sqr(temp, temp);
369 flag <<= 1;
370 }
371 }
372
373 // x0 <- x0 * x1
374 fp_mul(x0, x0, x1);
375 // x1 <- a1 * x1
376 fp_mul(x1, input.im, x1);
377
378 // t1 <- (2 * x0)^2
379 fp_add(t1, x0, x0);
380 fp_sqr(t1, t1);
381
382 fp_t uno, zero;
383 fp_set_to_one(uno);
384 fp_set_to_zero(zero);
385
386 uint8_t selector = -fp_is_equal(t1, t0);
387
388 fp_neg(temp, x0);
389 fp_copy(t0, x1);
390 fp_copy(t1, temp);
391
392 constant_time_conditional_mov((uint8_t *)&t0, (uint8_t *)&x0, FIELD_64BITS_WORDS * 8, selector);
393 constant_time_conditional_mov((uint8_t *)&t1, (uint8_t *)&x1, FIELD_64BITS_WORDS * 8, selector);
394
395 fp_copy(output->re, t0);
396 fp_copy(output->im, t1);
397}
398
399void fp2_curt(fp2_t *output, fp2_t input) {
400 // This function assumes the input has cube-root
401 int i, j, k;
402 uint64_t flag;
403 fp2_t temp, aux;
404 fp2_set_to_one(&aux);
405 fp2_copy(&temp, input);
406
407 for (i = 0, k = 0; i < 2 * FIELD_64BITS_WORDS && k < CUBE_ROOT_EXPONENT_BITS; i++, k++) {
408 flag = 1;
409 for (j = 0; j < 64; j++, k++) {
410 if ((flag & CUBE_ROOT_EXPONENT[i]) != 0) {fp2_mul(&aux, temp, aux);}
411 fp2_sqr(&temp, temp);
412 flag <<= 1;
413 }
414 }
415
416 fp2_copy(output, aux);
417}
void fp2_to_bytes(uint8_t *output, fp2_t input)
Definition fp2.c:131
void fp2_sqrt_slow(fp2_t *output, fp2_t input)
Definition fp2.c:283
uint8_t fp2_is_equal(fp2_t input_a, fp2_t input_b)
Definition fp2.c:154
void fp2_linear_pass_out(fp2_t *output, fp2_t input, uint8_t input_length, uint8_t input_index)
Definition fp2.c:170
void fp2_conj(fp2_t *output, fp2_t input)
Definition fp2.c:125
void fp2_batchinv(fp2_t *output_list, const fp2_t *input_list, uint8_t input_length)
Definition fp2.c:202
void fp2_linear_pass_in(fp2_t *output, const fp2_t *input, uint8_t input_length, uint8_t input_index)
Definition fp2.c:159
void fp2_set_to_zero(fp2_t *output)
Definition fp2.c:54
void fp2_cset(fp2_t *output, fp2_t input, uint64_t input_mask)
Definition fp2.c:81
int64_t fp2_is_zero(fp2_t input)
Definition fp2.c:149
void fp2_sqrt_fast(fp2_t *output, fp2_t input)
Definition fp2.c:333
void fp2_half(fp2_t *output, fp2_t input)
Definition fp2.c:107
void fp2_from_mont(fp2_t *output, fp2_t input)
Definition fp2.c:119
void fp2_to_mont(fp2_t *output, fp2_t input)
Definition fp2.c:113
void fp2_curt(fp2_t *output, fp2_t input)
Definition fp2.c:399
uint8_t fp2_is_square(fp2_t input)
Definition fp2.c:192
uint8_t fp2_locate_zero(const fp2_t *input, uint8_t input_length)
Definition fp2.c:181
void fp2_cswap(fp2_t *input_a, fp2_t *input_b, uint64_t input)
Definition fp2.c:65
void fp2_element_from_bytes(fp2_t *output, const uint8_t *input)
Definition fp2.c:140
void fp2_set_to_one(fp2_t *output)
Definition fp2.c:49
#define fp_sqr
Definition fp-gmp.h:73
#define fp_sub
Definition fp-gmp.h:67
#define fp_mul
Definition fp-gmp.h:70
#define fp_inv
Definition fp-gmp.h:88
#define fp_add
Definition fp-gmp.h:64
#define fp_copy
Definition fp-gmp.h:79
int64_t fp_is_zero(const fp_t input)
Definition fp.c:112
void fp_to_mont(fp_t output, const fp_t input)
Definition fp.c:99
void fp_neg(fp_t output, const fp_t input)
Definition fp.c:9
uint8_t fp_is_equal(const fp_t input_a, const fp_t input_b)
Definition fp.c:122
void fp_set_to_zero(fp_t input_output)
Definition fp.c:19
void fp_half(fp_t output, const fp_t input)
Definition fp.c:84
void fp_from_mont(fp_t output, const fp_t input)
Definition fp.c:104
void fp_set_to_one(fp_t input_output)
Definition fp.c:14
uint8_t fp_is_square(const fp_t input)
Definition fp.c:148
uint64_t fp_t[FIELD_64BITS_WORDS]
Definition fp.h:12
#define FIELD_BYTES
Definition p254.h:8
#define FIELD_64BITS_WORDS
Definition p254.h:9
#define FIELD_BITS
Definition p254.h:7
#define CUBE_ROOT_EXPONENT_BITS
Definition p254.h:59
#define SQUARE_ROOT_EXPONENT_BITS
Definition p255.h:72
for i
for j
Definition fp2.h:10
fp_t re
Definition fp2.h:11
fp_t im
Definition fp2.h:12
void constant_time_conditional_mov(uint8_t *output, const uint8_t *input, uint64_t input_length, uint8_t input_selector)
Definition utilities.c:74