Let us walk on the 3-isogeny graph
Loading...
Searching...
No Matches
ctidh_wombat_eval.c
Go to the documentation of this file.
1//*******************************//
2// //
3// here //
4// lives //
5// WOMBats //
6// //
7//_______________________________//
8
9#include <string.h>
10#include <assert.h>
11
12#include "ctidh.h"
13
14#include "../common/primes.h"
15#include "../common/int64mask.h"
16#include "../common/elligator.h"
17#include "../common/random.h"
18// #include "crypto_declassify.h"
19
20#ifdef ENABLE_CT_TESTING
21#include <valgrind/memcheck.h>
22#endif
23
24const public_key base = {.A = {0}, .seed = ELLIGATOR_SEED}; /* A = 0 */
25
26// static void fp_print(fp A)
27// {
28// uint8_t i;
29// printf("{");
30// for(i = 0; i < NUMBER_OF_WORDS; i++)
31// printf("0x%016lX,", A[i]);
32// printf("}\n");
33// }
34
35static void cmov(int64_t *r, const long long *a, int64_t b)
36{
37 uint64_t t;
38
39 t = (*r ^ *a) & b;
40 *r ^= t;
41}
42
43/* get priv[pos] in constant time */
44static int64_t lookup(int64_t pos, const long long *priv)
45{
46 int64_t b;
47 int64_t r;
48 for (long long i = 0; i < primes_num; i++)
49 {
50 b = int64mask_equal(i, pos);
51 cmov(&r, &priv[i], b);
52 }
53 return r;
54}
55
56static void clearpublicprimes(proj *P, const proj *A24)
57{
58 // clear powers of 2
59 for (int64_t i = 0; i < two_cofactor; i++)
60 {
61 xDBL(P, P, A24, 0);
62 }
63}
64
65static void multiples(proj Q[], proj const P, proj const A)
66{
67 int j;
68
69 proj_copy(&Q[0], &P);
70 for (j = 0; j < (int)primes_num; j++)
71 {
72 if (primes[j] == 3 || primes[j] == 5 || primes[j] == 7)
73 continue;
74
75 xMUL_dac(&Q[0], &A, 1, &Q[0], primes_dac[j], primes_daclen[j], primes_daclen[j]);
76 }
77
78 // --- multiplying by 3
79 xMUL_dac(&Q[1], &A, 1, &Q[0], 0, 0, 0);
80 xMUL_dac(&Q[1], &A, 1, &Q[1], 0, 0, 0);
81 // --- multiplying by 5
82 xMUL_dac(&Q[0], &A, 1, &Q[0], 0, 1, 1);
83 xMUL_dac(&Q[0], &A, 1, &Q[0], 0, 1, 1);
84 xMUL_dac(&Q[2], &A, 1, &Q[1], 0, 1, 1);
85 xMUL_dac(&Q[2], &A, 1, &Q[2], 0, 1, 1);
86 // --- multiplying by 7
87 xMUL_dac(&Q[0], &A, 1, &Q[0], 2, 2, 2);
88 xMUL_dac(&Q[0], &A, 1, &Q[0], 2, 2, 2);
89 xMUL_dac(&Q[1], &A, 1, &Q[1], 2, 2, 2);
90 xMUL_dac(&Q[1], &A, 1, &Q[1], 2, 2, 2);
91}
92
93// Obtaining points of full order
94void fulltorsion_points(fp u, fp const a)
95{
96 proj Tp, Tm, Pp[primes_num], Aux_Tp[3], Pm[primes_num], Aux_Tm[3], A;
97 int j;
98
99 // Convert curve to projective Montgomery form (A' + 2C : 4C)
100 fp_copy(A.x, a);
101 fp_set1(A.z);
102 fp_add(A.z, A.z, A.z); // 2C
103 fp_add(A.x, A.x, A.z); // A' + 2C
104 fp_add(A.z, A.z, A.z); // 4C
105
106 fp_set0(u); // u <- 0
107 uint8_t boolp = 0, boolm = 0;
108
109 do
110 {
111
112#ifdef ENABLE_CT_TESTING
113 VALGRIND_MAKE_MEM_DEFINED(Aux_Tp, sizeof(proj) * 3);
114 VALGRIND_MAKE_MEM_DEFINED(Aux_Tm, sizeof(proj) * 3);
115 VALGRIND_MAKE_MEM_DEFINED(&A, sizeof(proj));
116 VALGRIND_MAKE_MEM_DEFINED(&boolp, sizeof(uint8_t));
117 VALGRIND_MAKE_MEM_DEFINED(&boolm, sizeof(uint8_t));
118 VALGRIND_MAKE_MEM_DEFINED(&Tp, sizeof(proj));
119 VALGRIND_MAKE_MEM_DEFINED(Pp, sizeof(proj) * primes_num);
120 VALGRIND_MAKE_MEM_DEFINED(Pm, sizeof(proj) * primes_num);
121#endif
122
123 fp_add(u, u, fp_1); // u <- u + 1 ... Recall, 1 must be in Montgomery domain
124 elligator_seeded(&Tp, &Tm, &A, (const fp *)u);
125
126 clearpublicprimes(&Tp, &A);
127 clearpublicprimes(&Tm, &A);
128
129#ifdef ENABLE_CT_TESTING
130 memset(Aux_Tp, 0, sizeof(proj) * 3);
131#endif
132 multiples(Aux_Tp, Tp, A);
133 if (fp_iszero(Aux_Tp[0].z) | fp_iszero(Aux_Tp[1].z) | fp_iszero(Aux_Tp[2].z))
134 continue;
135
136#ifdef ENABLE_CT_TESTING
137 memset(Aux_Tm, 0, sizeof(proj) * 3);
138#endif
139 multiples(Aux_Tm, Tm, A);
140 if (fp_iszero(Aux_Tm[0].z) | fp_iszero(Aux_Tm[1].z) | fp_iszero(Aux_Tm[2].z))
141 continue;
142
143 // Checking if Tp is an order (p+1)/(2^e)
144 proj_copy(&Pp[0], &Tp);
145 cofactor_multiples(Pp, A, 0, primes_num);
146 boolp = 1;
147 boolp &= (1 - fp_iszero(Pp[0].z)) | (1 - fp_iszero(Aux_Tp[0].z));
148 boolp &= (1 - fp_iszero(Pp[1].z)) | (1 - fp_iszero(Aux_Tp[1].z));
149 boolp &= (1 - fp_iszero(Pp[2].z)) | (1 - fp_iszero(Aux_Tp[2].z));
150 for (j = 3; j < (int)primes_num; j++)
151 boolp &= (1 - fp_iszero(Pp[j].z));
152
153 if (1 - boolp)
154 continue;
155
156 // ---> This can be removed for wd1 style
157 // Checking if Tm is an order (p+1)/(2^e)
158 proj_copy(&Pm[0], &Tm);
159 cofactor_multiples(Pm, A, 0, primes_num);
160
161 boolm = 1;
162 boolm &= (1 - fp_iszero(Pm[0].z)) | (1 - fp_iszero(Aux_Tm[0].z));
163 boolm &= (1 - fp_iszero(Pm[1].z)) | (1 - fp_iszero(Aux_Tm[1].z));
164 boolm &= (1 - fp_iszero(Pm[2].z)) | (1 - fp_iszero(Aux_Tm[2].z));
165 for (j = 3; j < (int)primes_num; j++)
166 boolm &= (1 - fp_iszero(Pm[j].z));
167
168 if (1 - boolm)
169 continue;
170 // <---
171 } while ((1 - boolp) | (1 - boolm));
172
173 fp_dec(u, (uint64_t *const)u);
174}
175
176/* goal: constant time */
177void action(public_key *out, public_key const *in, private_key const *priv)
178{
179
180 init_counters();
181
182 proj A;
183 fp_copy(A.x, in->A);
184 fp_copy(A.z, fp_1);
185
186 proj A24;
187 xA24(&A24, &A);
188
189 proj Points[4];
190 fp seed;
191 fp_set(seed, in->seed);
192 fp_enc(seed, seed);
193 elligator_seeded(&Points[0], &Points[1], &A24, (const fp *)seed);
194
195 clearpublicprimes(&Points[0], &A24);
196 clearpublicprimes(&Points[1], &A24);
197
198 // clear ells not used in the keyspace
199 for (int16_t j = batch_stop[primes_batches - 1] + 1; j < primes_num; j++)
200 {
201 xMUL_dac(&Points[0], &A24, 0, &Points[0], primes_dac[j], primes_daclen[j], primes_daclen[j]);
202 xMUL_dac(&Points[1], &A24, 0, &Points[1], primes_dac[j], primes_daclen[j], primes_daclen[j]);
203 }
204
205 // collect primes not used in the key ...
206 int16_t unused[batch_stop[primes_batches - 1] + 1];
207 // int16_t unused[255] = {0};
208
209 int16_t u = 0;
210 int16_t e = 0;
211 int16_t w = 0;
212 for (e = 0; e <= batch_stop[primes_batches - 1]; e++)
213 {
214#ifdef ENABLE_CT_TESTING
215 VALGRIND_MAKE_MEM_DEFINED(&u, sizeof(int16_t));
216 VALGRIND_MAKE_MEM_DEFINED(&e, sizeof(int16_t));
217 VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(int16_t));
218#endif
219
220 unused[u] = e;
221
222 int64_t mov = -int64mask_equal((int64_t)e, (int64_t)priv->ells[w]);
223
224 fp t1, t2;
225 t1[0] = u;
226 t2[0] = u + 1;
227 fp_cmov(&t1, (const fp *)&t2, 1 - mov);
228 u = t1[0];
229
230 t1[0] = w;
231 t2[0] = w + 1;
232 fp_cmov(&t1, (const fp *)&t2, mov);
233 w = t1[0];
234 }
235
236 // ... and remove them from our points
237 int16_t tmp_b = 0;
238 for (u = 0; u <= batch_stop[primes_batches - 1] - WOMBATKEYS; u++)
239 {
240 int16_t t = unused[u];
241 if (t > batch_stop[tmp_b])
242 tmp_b++;
243
244 long long dac = lookup(t, primes_dac);
245 long long daclen = lookup(t, primes_daclen);
246
247 xMUL_dac(&Points[0], &A24, 0, &Points[0], dac, daclen, batch_maxdac[tmp_b]);
248 xMUL_dac(&Points[1], &A24, 0, &Points[1], dac, daclen, batch_maxdac[tmp_b]);
249 }
250
251 // ACTION!
252 // copy "outer" points
253 proj_copy(&Points[2], &Points[0]);
254 proj_copy(&Points[3], &Points[1]);
255
256 int16_t current_key = WOMBATKEYS - 1;
257 for (int16_t current_batch = primes_batches - 1; current_batch >= 0; current_batch--)
258 {
259 uint8_t inner_counter = 0;
260
261 // outer points are now the inner points
262 proj_copy(&Points[0], &Points[2]);
263 proj_copy(&Points[1], &Points[3]);
264
265 // remove degrees not in the batch
266 tmp_b = 0;
267 for (int16_t j = 0; j < batch_keybounds_start[current_batch]; j++)
268 {
269 if (j > batch_keybounds_stop[tmp_b])
270 tmp_b++;
271
272 long long dac = lookup(priv->ells[j], primes_dac);
273 long long daclen = lookup(priv->ells[j], primes_daclen);
274
275 xMUL_dac(&Points[0], &A24, 0, &Points[0], dac, daclen, batch_maxdac[tmp_b]);
276 xMUL_dac(&Points[1], &A24, 0, &Points[1], dac, daclen, batch_maxdac[tmp_b]);
277 }
278
279
280 for (; current_key >= batch_keybounds_start[current_batch]; current_key--)
281 {
282 uint16_t current_ell_index = priv->ells[current_key];
283 uint64_t current_ell = lookup(current_ell_index, primes);
284 // 0 -> dummy, 1 -> + direction, 2 -> - direction
285 int64_t direction = priv->directions[current_key];
286
287 uint64_t lowerend_ell = primes[batch_start[current_batch] + batch_numkeys[current_batch] - inner_counter - 1];
288 uint64_t upperend_ell = primes[batch_stop[current_batch] - inner_counter];
289 // printf("%3d: %2d - %4ld-isogeny to %ld for cost of (%4ld,%4ld)\n",
290 // current_key, current_batch, current_ell, direction, lowerend_ell, upperend_ell);
291
292 // multiply out other factors
293 proj K;
294 proj_cmov(&K, &Points[0], -int64mask_equal(direction, (int64_t)2));
295 proj_cmov(&K, &Points[1], 1 + int64mask_equal(direction, (int64_t)2));
296
297 // we skip the "last/already processed" and remove only the "other" degrees
298 for (int16_t j = batch_keybounds_start[current_batch]; j < batch_keybounds_stop[current_batch] - inner_counter; j++)
299 {
300 xMUL_dac(&K, &A24, 0, &K, lookup(priv->ells[j], primes_dac), lookup(priv->ells[j], primes_daclen), batch_maxdac[current_batch]);
301 }
302
303 // make a copy to trow away in the dummy case
304 proj A_;
305 proj Points_[4];
306 proj_copy(&Points_[0], &Points[0]);
307 proj_copy(&Points_[1], &Points[1]);
308 proj_copy(&Points_[2], &Points[2]);
309 proj_copy(&Points_[3], &Points[3]);
310 proj_copy(&A_, &A);
311 // we can now compute the isogeny
312 if (current_key == 0)
313 {
314 // this is the last isogeny we need to compute! so we don't need to push points
315 xISOG_matryoshka(&A_, Points_, 0, &K, current_ell, lowerend_ell, upperend_ell);
316 }
317 else if (current_key == batch_keybounds_start[current_batch])
318 {
319 // on the last isogeny of the batch, we only need to push the 2 "outer" points
320 xISOG_matryoshka(&A_, &Points_[2], 2, &K, current_ell, lowerend_ell, upperend_ell);
321 }
322 else if (current_batch == 0)
323 {
324 // on the last batch, we only need the inner points
325 xISOG_matryoshka(&A_, Points_, 2, &K, current_ell, lowerend_ell, upperend_ell);
326 }
327 else if (current_key == batch_keybounds_start[current_batch] + 1)
328 {
329 // on the second to last isogeny of a batch, we only need to push 3 points
330 // the one needed for the last isogeny of the batch + the two outer points
331 proj_cswap(&Points_[0], &Points_[1], -int64mask_equal(priv->directions[current_key - 1], (int64_t)2));
332 xISOG_matryoshka(&A_, &Points_[1], 3, &K, current_ell, lowerend_ell, upperend_ell);
333 proj_cswap(&Points_[0], &Points_[1], -int64mask_equal(priv->directions[current_key - 1], (int64_t)2));
334 }
335 else
336 {
337 xISOG_matryoshka(&A_, Points_, 4, &K, current_ell, lowerend_ell, upperend_ell);
338 }
339
340 // skip isogeny in case of dummy isog
341 proj_cmov(&A, &A_, -int64mask_nonzero(direction));
342 proj_cmov(&Points[0], &Points_[0], -int64mask_nonzero(direction));
343 proj_cmov(&Points[1], &Points_[1], -int64mask_nonzero(direction));
344 proj_cmov(&Points[2], &Points_[2], -int64mask_nonzero(direction));
345 proj_cmov(&Points[3], &Points_[3], -int64mask_nonzero(direction));
346
347 xA24(&A24, &A);
348
349
350 long long dac = lookup(current_ell_index, primes_dac);
351 long long daclen = lookup(current_ell_index, primes_daclen);
352
353 // needed to remove the order incase a dummy isogeny was used
354 if (current_key > batch_keybounds_start[current_batch])
355 {
356 // not needed for the inner points in the last round
357 if (current_key == batch_keybounds_start[current_batch] + 1)
358 {
359 proj_cswap(&Points[0], &Points[1], -int64mask_equal(priv->directions[current_key - 1], (int64_t)2));
360 xMUL_dac(&Points[1], &A24, 0, &Points[1], dac, daclen, batch_maxdac[current_batch]);
361 proj_cswap(&Points[0], &Points[1], -int64mask_equal(priv->directions[current_key - 1], (int64_t)2));
362 }
363 else
364 {
365 xMUL_dac(&Points[0], &A24, 0, &Points[0], dac, daclen, batch_maxdac[current_batch]);
366 xMUL_dac(&Points[1], &A24, 0, &Points[1], dac, daclen, batch_maxdac[current_batch]);
367 }
368 }
369
370 if (current_batch != 0)
371 {
372 xMUL_dac(&Points[2], &A24, 0, &Points[2], dac, daclen, batch_maxdac[current_batch]);
373 xMUL_dac(&Points[3], &A24, 0, &Points[3], dac, daclen, batch_maxdac[current_batch]);
374 }
375
376 inner_counter++;
377 }
378 }
379
380 fp_inv(A.z);
381 fp_mul2(&A.x, (const fp *)&A.z);
382 fp_copy(out->A, A.x);
383}
384
385/* includes public-key validation. */
386bool csidh(public_key *out, public_key const *in, private_key const *priv)
387{
388 if (!validate(in))
389 {
390 fp_random(out->A);
391 return false;
392 }
393 action(out, in, priv);
394 return true;
395}
396
397//
398//
399//
400// ,.--""""--.._
401// ." .' `-.
402// ; ; ;
403// ' ; )
404// / ' . ;
405// / ; `. `;
406// ,.' : . : )
407// ;|\' : `./|) \ ;/
408// ;| \" -,- "-./ |; ).;
409// /\/ \/ );
410// : \ ;
411// : _ _ ; )
412// `. \;\ /;/ ; /
413// ! : : ,/ ;
414// (`. : _ : ,/"" ;
415// \\\`"^" ` : ;
416// ( )
417// ////
418//
419//
420// by https://ascii.co.uk/art/wombat
#define validate
Definition ctidh.h:53
#define base
Definition ctidh.h:44
#define fulltorsion_points
Definition ctidh.h:57
#define action
Definition ctidh.h:54
#define csidh
Definition ctidh.h:51
#define cofactor_multiples
Definition ctidh.h:55
#define elligator_seeded
Definition elligator.h:8
uint64_t fp[NUMBER_OF_WORDS]
Definition fp-gmp.h:22
#define fp_1
Definition fp-gmp.h:48
#define fp_inv
Definition fp-gmp.h:88
#define fp_cmov
Definition fp-gmp.h:323
#define fp_add
Definition fp-gmp.h:64
#define fp_enc
Definition fp-gmp.h:55
#define fp_copy
Definition fp-gmp.h:79
#define fp_random
Definition fp-gmp.h:85
#define fp_dec
Definition fp-gmp.h:58
#define xA24
Definition mont.h:17
#define xMUL_dac
Definition mont.h:21
#define xISOG_matryoshka
Definition mont.h:24
#define xDBL
Definition mont.h:18
for i
for j
#define batch_keybounds_start
Definition primes.h:57
#define primes
Definition primes.h:51
#define batch_maxdac
Definition primes.h:60
#define batch_keybounds_stop
Definition primes.h:58
#define primes_dac
Definition primes.h:52
#define batch_start
Definition primes.h:55
#define primes_daclen
Definition primes.h:53
#define batch_numkeys
Definition primes.h:59
#define batch_stop
Definition primes.h:56
uint8_t ells[WOMBATKEYS]
Definition ctidh.h:32
uint8_t directions[WOMBATKEYS]
Definition ctidh.h:33
Definition proj.h:18
uint64_t seed
Definition ctidh.h:41
f a
Definition to_model.m:12