1 /*
2 * Copyright (C) 2017 - This file is part of libecc project
3 *
4 * Authors:
5 * Ryad BENADJILA <ryadbenadjila@gmail.com>
6 * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7 * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8 *
9 * Contributors:
10 * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11 * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12 *
13 * This software is licensed under a dual BSD and GPL v2 license.
14 * See LICENSE file at the root folder of the project.
15 */
16 #include <libecc/libarith.h>
17 /* Include internal API as it is used in our tests */
18 #include "../nn/nn_div.h"
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <assert.h>
27
28 #ifdef WITH_ASSERT_BACKTRACE
29 #include <signal.h>
30 #include <execinfo.h>
31
32 #define BACKTRACE_SIZE 4096
33 static unsigned int backtrace_buffer_ptr = 0;
34 static char backtrace_buffer[BACKTRACE_SIZE];
35
36 /* assert trapping and backtracing */
assert_signal_handler(int sig)37 static void assert_signal_handler(int sig)
38 {
39 if (sig != SIGINT) {
40 raise(sig);
41 }
42 /* Print the recorded backtrace */
43 printf("**** BACKTRACE *****\n");
44 printf("(from old to most recent calls)\n");
45 printf("%s", backtrace_buffer);
46 exit(-1);
47 }
48
49 #define ADD_TO_BACKTRACE(...) do {\
50 int written_size;\
51 written_size = snprintf(backtrace_buffer + backtrace_buffer_ptr, BACKTRACE_SIZE - 1 - backtrace_buffer_ptr, __VA_ARGS__);\
52 backtrace_buffer_ptr += written_size;\
53 if(backtrace_buffer_ptr >= BACKTRACE_SIZE - 1){\
54 memset(backtrace_buffer, 0, sizeof(backtrace_buffer)-1);\
55 backtrace_buffer_ptr = 0;\
56 }\
57 } while(0)
58 #else
59
60 #define ADD_TO_BACKTRACE(...) do {\
61 } while(0)
62
63 #endif
64
65 /*
66 * Import integer number (found in hexadecimal form in hbuf buffer
67 * of length hbuflen) into already allocated out_nn. hbuflen is
68 * expected to be of even size. out_nn parameter is expected to
69 * have a large enough storage space (i.e. hbuflen / 2) to hold
70 * imported number.
71 */
nn_import_from_hexbuf(nn_t out_nn,const char * hbuf,u32 hbuflen)72 static int nn_import_from_hexbuf(nn_t out_nn, const char *hbuf, u32 hbuflen)
73 {
74 char buf[WORD_BYTES * 2 + 1];
75 const char *start;
76 u32 wlen;
77 u32 k;
78 int ret;
79
80 ret = nn_check_initialized(out_nn); EG(ret, err);
81 MUST_HAVE((hbuf != NULL), ret, err);
82 MUST_HAVE(((hbuflen / 2) / WORD_BYTES) == out_nn->wlen, ret, err);
83
84 wlen = (hbuflen + WORD_BYTES - 1) / (2 * WORD_BYTES);
85 for (k = wlen; k > 0; k--) {
86 /*
87 * Copy current hex encoded word into null terminated
88 * scratch buffer
89 */
90 memset(buf, 0, WORD_BYTES * 2 + 1);
91 start = hbuf + ((k - 1) * WORD_BYTES * 2);
92 memcpy(buf, start, WORD_BYTES * 2);
93
94 /* Let strtoull() convert the value for us */
95 out_nn->val[wlen - k] = strtoull(buf, NULL, 16);
96 }
97
98 for (k = NN_MAX_WORD_LEN; k > wlen; k--) {
99 out_nn->val[k - 1] = 0;
100 }
101
102 err:
103 return ret;
104 }
105
106 #define DISPATCH_TABLE_MAGIC "FEEDBABE"
107 struct dispatch_table {
108 const char magic[sizeof(DISPATCH_TABLE_MAGIC)];
109 const char *op_string;
110 const char *op_string_helper;
111 int (*fun) (const char *op, void **, int);
112 };
113
114 #define ADD_TO_DISPATCH_TABLE(fun, op_string, op_string_helper) \
115 static const struct dispatch_table entry_##fun \
116 ATTRIBUTE_SECTION("tests_dispatch_table_section") ATTRIBUTE_USED = \
117 { DISPATCH_TABLE_MAGIC, op_string, op_string_helper, fun };
118
119 #define FIND_IN_DISPATCH_TABLE(op, to_find, type) do {\
120 extern struct dispatch_table __start_tests_dispatch_table_section;\
121 extern struct dispatch_table __stop_tests_dispatch_table_section;\
122 struct dispatch_table *dt, *begin, *end;\
123 char *ptr;\
124 \
125 begin = &__start_tests_dispatch_table_section;\
126 end = &__stop_tests_dispatch_table_section;\
127 ptr = (char*)begin;\
128 \
129 to_find = NULL;\
130 \
131 while(ptr < (char*)end){\
132 dt = (struct dispatch_table*)ptr;\
133 /* Find the magic */\
134 while(memcmp(dt->magic, DISPATCH_TABLE_MAGIC, sizeof(DISPATCH_TABLE_MAGIC)) != 0){\
135 ptr++;\
136 dt = (struct dispatch_table*)ptr;\
137 }\
138 if(strcmp(dt->op_string, op) == 0){ \
139 to_find = dt->type;\
140 break;\
141 }\
142 ptr += sizeof(struct dispatch_table);\
143 }\
144 } while(0)
145
146 #define FIND_FUN_IN_DISPATCH_TABLE(op, function) FIND_IN_DISPATCH_TABLE(op, function, fun)
147
148 #define FIND_HELPER_IN_DISPATCH_TABLE(op, string_helper) FIND_IN_DISPATCH_TABLE(op, string_helper, op_string_helper)
149
150 /*****************/
151
152 #define GENERIC_TEST_FP_DECL_INIT0(name, ctx) \
153 fp_t name##_ptr[] = {NULL};
154
155 #define GENERIC_TEST_FP_DECL_INIT1(name, ctx) \
156 fp name##0; \
157 fp_t name##_ptr[] = { &name##0 };\
158 ret |= fp_init(&name##0, ctx);\
159
160 #define GENERIC_TEST_FP_DECL_INIT2(name, ctx) \
161 fp name##0, name##1;\
162 fp_t name##_ptr[] = { &name##0, &name##1 };\
163 ret |= fp_init(&name##0, ctx);\
164 ret |= fp_init(&name##1, ctx);\
165
166 #define GENERIC_TEST_FP_DECL_INIT3(name, ctx) \
167 fp name##0, name##1, name##2;\
168 fp_t name##_ptr[] = { &name##0, &name##1, &name##2 };\
169 ret |= fp_init(&name##0, ctx);\
170 ret |= fp_init(&name##1, ctx);\
171 ret |= fp_init(&name##2, ctx);\
172
173 #define GENERIC_TEST_FP_DECL_INIT4(name, ctx) \
174 fp name##0, name##1, name##2, name##3;\
175 fp_t name##_ptr[] = { &name##0, &name##1, &name##2, &name##3 };\
176 ret |= fp_init(&name##0, ctx);\
177 ret |= fp_init(&name##1, ctx);\
178 ret |= fp_init(&name##2, ctx);\
179 ret |= fp_init(&name##3, ctx);\
180
181 #define GENERIC_TEST_FP_DECL_INIT5(name, ctx) \
182 fp name##0, name##1, name##2, name##3, name##4;\
183 fp_t name##_ptr[] = { &name##0, &name##1, &name##2, &name##3, &name##4 };\
184 ret |= fp_init(&name##0, ctx);\
185 ret |= fp_init(&name##1, ctx);\
186 ret |= fp_init(&name##2, ctx);\
187 ret |= fp_init(&name##3, ctx);\
188 ret |= fp_init(&name##4, ctx);\
189
190 #define GENERIC_TEST_FP_DECL_INIT6(name, ctx) \
191 fp name##0, name##1, name##2, name##3, name##4, name##5;\
192 fp_t name##_ptr[] = { &name##0, &name##1, &name##2, &name##3, &name##4, &name##5 };\
193 ret |= fp_init(&name##0, ctx);\
194 ret |= fp_init(&name##1, ctx);\
195 ret |= fp_init(&name##2, ctx);\
196 ret |= fp_init(&name##3, ctx);\
197 ret |= fp_init(&name##4, ctx);\
198 ret |= fp_init(&name##5, ctx);\
199
200 #define GENERIC_TEST_NN_DECL_INIT0(name, size) \
201 nn_t name##_ptr[] = {NULL};
202
203 #define GENERIC_TEST_NN_DECL_INIT1(name, size) \
204 nn name##0; \
205 nn_t name##_ptr[] = { &name##0 }; \
206 ret |= nn_init(&name##0, size); \
207
208 #define GENERIC_TEST_NN_DECL_INIT2(name, size) \
209 nn name##0, name##1; \
210 nn_t name##_ptr[] = { &name##0, &name##1 }; \
211 ret |= nn_init(&name##0, size); \
212 ret |= nn_init(&name##1, size); \
213
214 #define GENERIC_TEST_NN_DECL_INIT3(name, size) \
215 nn name##0, name##1, name##2; \
216 nn_t name##_ptr[] = { &name##0, &name##1, &name##2 }; \
217 ret |= nn_init(&name##0, size); \
218 ret |= nn_init(&name##1, size); \
219 ret |= nn_init(&name##2, size); \
220
221 #define GENERIC_TEST_NN_DECL_INIT4(name, size) \
222 nn name##0, name##1, name##2, name##3; \
223 nn_t name##_ptr[] = { &name##0, &name##1, &name##2, &name##3 }; \
224 ret |= nn_init(&name##0, size); \
225 ret |= nn_init(&name##1, size); \
226 ret |= nn_init(&name##2, size); \
227 ret |= nn_init(&name##3, size); \
228
229 #define GENERIC_TEST_NN_DECL_INIT5(name, size) \
230 nn name##0, name##1, name##2, name##3, name##4; \
231 nn_t name##_ptr[] = { &name##0, &name##1, &name##2, &name##3, &name##4 };\
232 ret |= nn_init(&name##0, size); \
233 ret |= nn_init(&name##1, size); \
234 ret |= nn_init(&name##2, size); \
235 ret |= nn_init(&name##3, size); \
236 ret |= nn_init(&name##4, size); \
237
238 #define GENERIC_TEST_NN_DECL_INIT6(name, size) \
239 nn name##0, name##1, name##2, name##3, name##4, name##5; \
240 nn_t name##_ptr[] = { &name##0, &name##1, &name##2, &name##3, &name##4, &name##5 };\
241 ret |= nn_init(&name##0, size); \
242 ret |= nn_init(&name##1, size); \
243 ret |= nn_init(&name##2, size); \
244 ret |= nn_init(&name##3, size); \
245 ret |= nn_init(&name##4, size); \
246 ret |= nn_init(&name##5, size); \
247
248 #define GENERIC_TEST_FP_CLEAR0(name)
249
250 #define GENERIC_TEST_FP_CLEAR1(name) \
251 fp_uninit(&name##0);\
252
253 #define GENERIC_TEST_FP_CLEAR2(name) \
254 fp_uninit(&name##0);\
255 fp_uninit(&name##1);\
256
257 #define GENERIC_TEST_FP_CLEAR3(name) \
258 fp_uninit(&name##0);\
259 fp_uninit(&name##1);\
260 fp_uninit(&name##2);\
261
262 #define GENERIC_TEST_FP_CLEAR4(name) \
263 fp_uninit(&name##0);\
264 fp_uninit(&name##1);\
265 fp_uninit(&name##2);\
266 fp_uninit(&name##3);\
267
268 #define GENERIC_TEST_FP_CLEAR5(name) \
269 fp_uninit(&name##0);\
270 fp_uninit(&name##1);\
271 fp_uninit(&name##2);\
272 fp_uninit(&name##3);\
273 fp_uninit(&name##4);\
274
275 #define GENERIC_TEST_FP_CLEAR6(name) \
276 fp_uninit(&name##0);\
277 fp_uninit(&name##1);\
278 fp_uninit(&name##2);\
279 fp_uninit(&name##3);\
280 fp_uninit(&name##4);\
281 fp_uninit(&name##5);\
282
283 #define GENERIC_TEST_nn_uninit0(name)
284
285 #define GENERIC_TEST_nn_uninit1(name) \
286 nn_uninit(&name##0);\
287
288 #define GENERIC_TEST_nn_uninit2(name) \
289 nn_uninit(&name##0);\
290 nn_uninit(&name##1);\
291
292 #define GENERIC_TEST_nn_uninit3(name) \
293 nn_uninit(&name##0);\
294 nn_uninit(&name##1);\
295 nn_uninit(&name##2);\
296
297 #define GENERIC_TEST_nn_uninit4(name) \
298 nn_uninit(&name##0);\
299 nn_uninit(&name##1);\
300 nn_uninit(&name##2);\
301 nn_uninit(&name##3);\
302
303 #define GENERIC_TEST_nn_uninit5(name) \
304 nn_uninit(&name##0);\
305 nn_uninit(&name##1);\
306 nn_uninit(&name##2);\
307 nn_uninit(&name##3);\
308 nn_uninit(&name##4);\
309
310 #define GENERIC_TEST_nn_uninit6(name) \
311 nn_uninit(&name##0);\
312 nn_uninit(&name##1);\
313 nn_uninit(&name##2);\
314 nn_uninit(&name##3);\
315 nn_uninit(&name##4);\
316 nn_uninit(&name##5);\
317
318 #define FP_CTX_T_GENERIC_IN(num) ((fp_ctx_t)params[num])
319 #define FP_T_GENERIC_IN(num) ((fp_t)params[num])
320 #define NN_T_GENERIC_IN(num) ((nn_t)params[num])
321 #define UINT_GENERIC_IN(num) ((u64)*((u64*)params[num]))
322 #define WORD_T_GENERIC_IN(num) ((word_t)*((word_t*)params[num]))
323 #define INT_GENERIC_IN(num) ((int)*((int*)params[num]))
324
325 #define FP_T_GENERIC_OUT(num) (&fp_out##num)
326 #define NN_T_GENERIC_OUT(num) (&nn_out##num)
327 #define WORD_T_GENERIC_OUT(num) (&(word_out[num]))
328 #define INT_GENERIC_OUT(num) (&(int_out[num]))
329
330 #define CHECK_FUN_RET there_is_output = 1; fun_out_value = (int)
331
332 #define CHECK_FUN_NO_RET there_is_output = 0; fun_out_value = (int)
333
334 /* Number of pre-allocated */
335 #define NUM_PRE_ALLOCATED_NN 6
336 #define NUM_PRE_ALLOCATED_FP 6
337 #define MAX_PARAMS 6
338
339 #define GENERIC_TEST_NN_DECL_INIT_MAX(name, n) GENERIC_TEST_NN_DECL_INIT6(name, n)
340 #define GENERIC_TEST_FP_DECL_INIT_MAX(name, ctx) GENERIC_TEST_FP_DECL_INIT6(name, ctx)
341
342 /* Check that the string of parameters types only containes 'c', 'f', 'n' and 'u'
343 * Check that the string of parameters I/O only contains 'i', 'o' and 'O'
344 *
345 */
346 #define PARAMETERS_SANITY_CHECK(test_num, param_types, param_io) do {\
347 unsigned int i, real_output = 0;\
348 assert(sizeof(param_types) == sizeof(param_io));\
349 for(i = 0; i < sizeof(param_types)-1; i++){\
350 if((param_types[i] != 'c') && (param_types[i] != 'f') && (param_types[i] != 'n') && (param_types[i] != 'u') && (param_types[i] != 's')){ \
351 printf("Error: types parameters of test %d mismatch!\n", test_num);\
352 return 0;\
353 }\
354 if((param_io[i] != 'i') && (param_io[i] != 'o') && (param_io[i] != 'O')){\
355 printf("Error: I/O parameters of test %d mismatch!\n", test_num);\
356 return 0;\
357 }\
358 if((param_io[i] == 'O') && (param_types[i] != 'u') && (param_types[i] != 's')){\
359 printf("Error: types and I/O parameters of test %d mismatch!\n", test_num);\
360 return 0;\
361 }\
362 if(param_io[i] == 'O'){\
363 real_output++;\
364 }\
365 }\
366 /* Check that we only have one function output */\
367 if(real_output > 1){\
368 printf("Error: multiple function output defined in I/O parameters of test %d!\n", test_num);\
369 return 0;\
370 }\
371 } while(0);
372
373 #define SET_PARAMETER_PRETTY_NAME1(a) a
374 #define SET_PARAMETER_PRETTY_NAME2(a, b) SET_PARAMETER_PRETTY_NAME1(a) "\0" b
375 #define SET_PARAMETER_PRETTY_NAME3(a, b, c) SET_PARAMETER_PRETTY_NAME2(a, b) "\0" c
376 #define SET_PARAMETER_PRETTY_NAME4(a, b, c, d) SET_PARAMETER_PRETTY_NAME3(a, b, c) "\0" d
377 #define SET_PARAMETER_PRETTY_NAME5(a, b, c, d, e) SET_PARAMETER_PRETTY_NAME4(a, b, c, d) "\0" e
378 #define SET_PARAMETER_PRETTY_NAME6(a, b, c, d, e, f) SET_PARAMETER_PRETTY_NAME5(a, b, c, d, e) "\0" f
379
380 #define SET_PARAMETER_PRETTY_NAME(num, ...) SET_PARAMETER_PRETTY_NAME##num(__VA_ARGS__)
381
382 /* Parse the helper string to get the pretty print names */
383 #define GET_PARAMETER_PRETTY_NAME(parameters_string_names_, parameters_string_names, num, out) do {\
384 unsigned int cnt = 0;\
385 out = 0;\
386 \
387 /* Find the proper position */\
388 while(out < sizeof(parameters_string_names_)-1){\
389 if(cnt == num){\
390 break;\
391 }\
392 if(parameters_string_names[out] == '\0'){\
393 cnt++;\
394 }\
395 out++;\
396 }\
397 } while(0);
398
399 /* Print for a given test all the inputs, outpus and expected outputs */
400 #define PRINT_ALL(parameters_types, parameters_io, params, nn_out_ptr, fp_out_ptr, fun_output, there_is_output, parameters_string_names_, bad_num) do { \
401 unsigned int j;\
402 unsigned int nn_out_local_cnt = 0, fp_out_local_cnt = 0;\
403 unsigned int str_pos;\
404 const char parameters_string_names[] = parameters_string_names_;\
405 const char real[] = "Real ";\
406 const char expected[] = "Expected ";\
407 char expected_modified_string_names[sizeof(expected)+sizeof(parameters_string_names_)];\
408 char real_modified_string_names[sizeof(real)+sizeof(parameters_string_names_)];\
409 /* First print the inputs */\
410 for(j=0; j<sizeof(parameters_types)-1; j++){\
411 GET_PARAMETER_PRETTY_NAME(parameters_string_names_, parameters_string_names, j, str_pos);\
412 if(parameters_io[j] == 'i'){\
413 /* This is an input */\
414 if(parameters_types[j] == 'c'){\
415 nn_print(&(parameters_string_names[str_pos]), &(FP_CTX_T_GENERIC_IN(j)->p)); \
416 }\
417 if(parameters_types[j] == 'f'){\
418 nn_print(&(parameters_string_names[str_pos]), &(FP_T_GENERIC_IN(j)->fp_val)); \
419 }\
420 if(parameters_types[j] == 'n'){\
421 nn_print(&(parameters_string_names[str_pos]), NN_T_GENERIC_IN(j));\
422 }\
423 if(parameters_types[j] == 'u'){\
424 printf("%16s: 0x", &(parameters_string_names[str_pos])); \
425 printf(PRINTF_WORD_HEX_FMT, WORD_T_GENERIC_IN(j)); \
426 printf("\n"); \
427 }\
428 if(parameters_types[j] == 's'){\
429 printf("%16s:", &(parameters_string_names[str_pos])); \
430 printf("%d", INT_GENERIC_IN(j)); \
431 printf("\n"); \
432 }\
433 }\
434 }\
435 /* Then print the outputs */\
436 for(j=0; j<sizeof(parameters_types)-1; j++){\
437 GET_PARAMETER_PRETTY_NAME(parameters_string_names_, parameters_string_names, j, str_pos);\
438 memset(expected_modified_string_names, 0, sizeof(expected_modified_string_names));\
439 strcat(expected_modified_string_names, expected);\
440 strcat(expected_modified_string_names, &(parameters_string_names[str_pos]));\
441 memset(real_modified_string_names, 0, sizeof(real_modified_string_names));\
442 strcat(real_modified_string_names, real);\
443 strcat(real_modified_string_names, &(parameters_string_names[str_pos]));\
444 if(parameters_io[j] == 'o'){\
445 /* This is an input that is an output */\
446 if(parameters_types[j] == 'f'){\
447 nn_print(real_modified_string_names, &(fp_out_ptr[j]->fp_val)); \
448 nn_print(expected_modified_string_names, &(FP_T_GENERIC_IN(j)->fp_val)); \
449 fp_out_local_cnt++;\
450 }\
451 if(parameters_types[j] == 'n'){\
452 nn_print(real_modified_string_names, nn_out_ptr[j]);\
453 nn_print(expected_modified_string_names, NN_T_GENERIC_IN(j));\
454 nn_out_local_cnt++;\
455 }\
456 if(parameters_types[j] == 'u'){\
457 printf("%16s: 0x", real_modified_string_names); \
458 printf(PRINTF_WORD_HEX_FMT, *(WORD_T_GENERIC_OUT(j))); \
459 printf("\n"); \
460 printf("%16s: 0x", expected_modified_string_names); \
461 printf(PRINTF_WORD_HEX_FMT, WORD_T_GENERIC_IN(j)); \
462 printf("\n"); \
463 }\
464 if(parameters_types[j] == 's'){\
465 printf("%16s: ", real_modified_string_names); \
466 printf("%d", *(INT_GENERIC_OUT(j))); \
467 printf("\n"); \
468 printf("%16s: ", expected_modified_string_names); \
469 printf("%d", INT_GENERIC_IN(j)); \
470 printf("\n"); \
471 }\
472 }\
473 if((parameters_io[j] == 'O') && (there_is_output == 1)){\
474 /* This is a real function output */\
475 if(parameters_types[j] == 'u'){\
476 printf("%16s: 0x", real_modified_string_names); \
477 printf(PRINTF_WORD_HEX_FMT, (word_t)fun_output); \
478 printf("\n"); \
479 printf("%16s: 0x", expected_modified_string_names); \
480 printf(PRINTF_WORD_HEX_FMT, WORD_T_GENERIC_IN(j)); \
481 printf("\n"); \
482 }\
483 if(parameters_types[j] == 's'){\
484 printf("%16s: ", real_modified_string_names); \
485 printf("%d", (int)fun_output); \
486 printf("\n"); \
487 printf("%16s: ", expected_modified_string_names); \
488 printf("%d", INT_GENERIC_IN(j)); \
489 printf("\n"); \
490 }\
491 }\
492 }\
493 } while(0)
494
495 /* Generic testing framework. Seems ugly but does the job! */
496 #define GENERIC_TEST(test_name, operation_, given_string_helper, fun_name, parameters_types_, parameters_io_, parameters_string_names, fun_output, nn_out_num, fp_out_num, ...) \
497 int test_##test_name(const char ATTRIBUTE_UNUSED *op, void **params, int test_num);\
498 int test_##test_name(const char ATTRIBUTE_UNUSED *op, void **params, int test_num){\
499 unsigned int i;\
500 int ret = 0, cmp, mismatch = 0; \
501 const char *op_string = NULL;\
502 unsigned int n_len ATTRIBUTE_UNUSED = 0;\
503 int fun_out_value = 0;\
504 u8 there_is_output = 0;\
505 unsigned int nn_out_local_cnt = 0, fp_out_local_cnt = 0;\
506 fp_ctx_t fp_ctx_param ATTRIBUTE_UNUSED = NULL;\
507 int fp_ctx_initialized ATTRIBUTE_UNUSED = 0;\
508 \
509 const char parameters_types[] = parameters_types_;\
510 const char parameters_io[] = parameters_io_;\
511 \
512 const char operation[] = #operation_;\
513 \
514 /* Our words used as output of functions */\
515 word_t word_out[MAX_PARAMS] ATTRIBUTE_UNUSED = { 0 };\
516 int int_out[MAX_PARAMS] ATTRIBUTE_UNUSED = { 0 };\
517 \
518 assert(memcmp(operation, op, sizeof(operation)) == 0);\
519 \
520 /* Sanity check: check that the parameters passed from the file are the same as the ones declared in the test */\
521 if(memcmp(global_parameters, parameters_types, LOCAL_MIN(MAX_PARAMS, strlen(parameters_types))) != 0){\
522 printf("Error: parameters %s given in the test file differ from the test expected parameters (%s)\n", parameters_types, global_parameters);\
523 return -1;\
524 }\
525 \
526 PARAMETERS_SANITY_CHECK(test_num, parameters_types, parameters_io);\
527 \
528 /* If we find an fp or nn, assume its length is the common length. */\
529 for(i=0; i<sizeof(parameters_io)-1; i++){\
530 if((parameters_io[i] == 'o') && (parameters_types[i] == 'f')){\
531 n_len = (FP_T_GENERIC_IN(i))->fp_val.wlen;\
532 break;\
533 }\
534 if((parameters_io[i] == 'o') && (parameters_types[i] == 'n')){\
535 n_len = (NN_T_GENERIC_IN(i))->wlen;\
536 break;\
537 }\
538 }\
539 for(i=0; i<sizeof(parameters_io)-1; i++){\
540 if(parameters_types[i] == 'c'){\
541 fp_ctx_param = (FP_CTX_T_GENERIC_IN(i));\
542 fp_ctx_initialized = 1;\
543 break;\
544 }\
545 }\
546 GENERIC_TEST_NN_DECL_INIT##nn_out_num(nn_out, n_len * WORD_BYTES);\
547 assert(fp_out_num == 0 || fp_ctx_initialized != 0);\
548 GENERIC_TEST_FP_DECL_INIT##fp_out_num(fp_out, fp_ctx_param);\
549 if(ret){\
550 goto err;\
551 }\
552 \
553 CHECK_FUN_##fun_output fun_name(__VA_ARGS__);\
554 /* Check generic value return is 0 */\
555 if(there_is_output == 0){\
556 assert(fun_out_value == 0);\
557 }\
558 \
559 /* Check result is what we expect */\
560 FIND_HELPER_IN_DISPATCH_TABLE(operation, op_string);\
561 assert(op_string != NULL);\
562 \
563 for(i=0; i<sizeof(parameters_io)-1; i++){\
564 if(parameters_io[i] == 'o'){\
565 /* We have an input that is an output, check it */\
566 if (parameters_types[i] == 'f') {\
567 ret = fp_cmp(fp_out_ptr[i], FP_T_GENERIC_IN(i), &cmp); \
568 if(ret || cmp){\
569 printf("[-] Test %d (%s): result mismatch\n", test_num, op_string);\
570 /* Print the expected outputs */\
571 PRINT_ALL(parameters_types, parameters_io, params, nn_out_ptr, fp_out_ptr, fun_out_value, there_is_output, parameters_string_names, i);\
572 mismatch = 1;\
573 break;\
574 }\
575 fp_out_local_cnt++;\
576 }\
577 if (parameters_types[i] == 'n') {\
578 ret = nn_cmp(nn_out_ptr[i], NN_T_GENERIC_IN(i), &cmp); \
579 if(ret || cmp){\
580 printf("[-] Test %d (%s): result mismatch\n", test_num, op_string);\
581 /* Print the expected outputs */\
582 PRINT_ALL(parameters_types, parameters_io, params, nn_out_ptr, fp_out_ptr, fun_out_value, there_is_output, parameters_string_names, i);\
583 mismatch = 1;\
584 break;\
585 }\
586 nn_out_local_cnt++;\
587 }\
588 if (parameters_types[i] == 'u') {\
589 if((*(WORD_T_GENERIC_OUT(i))) != WORD_T_GENERIC_IN(i)){\
590 printf("[-] Test %d (%s): result mismatch\n", test_num, op_string);\
591 /* Print the expected outputs */\
592 PRINT_ALL(parameters_types, parameters_io, params, nn_out_ptr, fp_out_ptr, fun_out_value, there_is_output, parameters_string_names, i);\
593 mismatch = 1;\
594 break;\
595 }\
596 }\
597 if (parameters_types[i] == 's') {\
598 if((*(INT_GENERIC_OUT(i))) != INT_GENERIC_IN(i)){\
599 printf("[-] Test %d (%s): result mismatch\n", test_num, op_string);\
600 /* Print the expected outputs */\
601 PRINT_ALL(parameters_types, parameters_io, params, nn_out_ptr, fp_out_ptr, fun_out_value, there_is_output, parameters_string_names, i);\
602 mismatch = 1;\
603 break;\
604 }\
605 }\
606 }\
607 if(parameters_io[i] == 'O'){\
608 /* We have a function output, check it */\
609 if(fun_out_value != INT_GENERIC_IN(i)){\
610 printf("[-] Test %d (%s): result mismatch\n", test_num, op_string);\
611 /* Print the expected outputs */\
612 PRINT_ALL(parameters_types, parameters_io, params, nn_out_ptr, fp_out_ptr, fun_out_value, there_is_output, parameters_string_names, i);\
613 mismatch = 1;\
614 break;\
615 }\
616 }\
617 }\
618 \
619 GENERIC_TEST_nn_uninit##nn_out_num(nn_out);\
620 GENERIC_TEST_FP_CLEAR##fp_out_num(fp_out);\
621 \
622 return !mismatch;\
623 err:\
624 printf("[-] Error: general error when initializing variables ...\n");\
625 exit(-1);\
626 }\
627 ADD_TO_DISPATCH_TABLE(test_##test_name, #operation_, given_string_helper)
628
629 #define GENERIC_TEST_NN(test_name, operation_, given_string_helper, fun_name, parameters_types_, parameters_io_, parameters_string_names, fun_output, nn_out_num, ...) \
630 GENERIC_TEST(test_name, operation_, given_string_helper, fun_name, parameters_types_, parameters_io_, parameters_string_names, fun_output, nn_out_num, 0, __VA_ARGS__)
631
632 #define GENERIC_TEST_FP(test_name, operation_, given_string_helper, fun_name, parameters_types_, parameters_io_, parameters_string_names, fun_output, nn_out_num, ...) \
633 GENERIC_TEST(test_name, operation_, given_string_helper, fun_name, parameters_types_, parameters_io_, parameters_string_names, fun_output, nn_out_num, __VA_ARGS__)
634
635
636 /* Global variable to keep track of parameters */
637 static char global_parameters[MAX_PARAMS];
638
639 /*********** NN layer tests ************************************************/
640 /* Testing shifts and rotates */
641 GENERIC_TEST_NN(nn_lshift_fixedlen, NN_SHIFT_LEFT_FIXEDLEN, "(fixed)<<", nn_lshift_fixedlen, "nnu", "oii",
642 SET_PARAMETER_PRETTY_NAME(3, "output", "input", "fixed lshift"), NO_RET, 1,
643 NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1), (bitcnt_t)UINT_GENERIC_IN(2))
644 GENERIC_TEST_NN(nn_rshift_fixedlen, NN_SHIFT_RIGHT_FIXEDLEN, "(fixed)>>", nn_rshift_fixedlen, "nnu", "oii",
645 SET_PARAMETER_PRETTY_NAME(3, "output", "input", "fixed rshift"), NO_RET, 1,
646 NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1), (bitcnt_t)UINT_GENERIC_IN(2))
647 GENERIC_TEST_NN(nn_lshift, NN_SHIFT_LEFT, "<<", nn_lshift, "nnu", "oii",
648 SET_PARAMETER_PRETTY_NAME(3, "output", "input", "lshift"), NO_RET, 1,
649 NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1), (bitcnt_t)UINT_GENERIC_IN(2))
650 GENERIC_TEST_NN(nn_rshift, NN_SHIFT_RIGHT, ">>", nn_rshift, "nnu", "oii",
651 SET_PARAMETER_PRETTY_NAME(3, "output", "input", "rshift"), NO_RET, 1,
652 NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1), (bitcnt_t)UINT_GENERIC_IN(2))
653 GENERIC_TEST_NN(nn_lrot, NN_ROTATE_LEFT, "lrot", nn_lrot, "nnuu", "oiii",
654 SET_PARAMETER_PRETTY_NAME(4, "output", "input", "lrot", "bitlen_base"), NO_RET, 1,
655 NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1), (bitcnt_t)UINT_GENERIC_IN(2), (bitcnt_t)UINT_GENERIC_IN(3))
656 GENERIC_TEST_NN(nn_rrot, NN_ROTATE_RIGHT, "rrot", nn_rrot, "nnuu", "oiii",
657 SET_PARAMETER_PRETTY_NAME(4, "output", "input", "rrot", "bitlen_base"), NO_RET, 1,
658 NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1), (bitcnt_t)UINT_GENERIC_IN(2), (bitcnt_t)UINT_GENERIC_IN(3))
659
660
661 /* Testing xor, or, and, not */
662 GENERIC_TEST_NN(nn_xor, NN_XOR, "^", nn_xor, "nnn", "iio",
663 SET_PARAMETER_PRETTY_NAME(3, "input1", "input2", "output"), NO_RET, 3,
664 NN_T_GENERIC_OUT(2), NN_T_GENERIC_IN(0), NN_T_GENERIC_IN(1))
665 GENERIC_TEST_NN(nn_or, NN_OR, "|", nn_or, "nnn", "iio",
666 SET_PARAMETER_PRETTY_NAME(3, "input1", "input2", "output"), NO_RET, 3,
667 NN_T_GENERIC_OUT(2), NN_T_GENERIC_IN(0), NN_T_GENERIC_IN(1))
668 GENERIC_TEST_NN(nn_and, NN_AND, "&", nn_and, "nnn", "iio",
669 SET_PARAMETER_PRETTY_NAME(3, "input1", "input2", "output"), NO_RET, 3,
670 NN_T_GENERIC_OUT(2), NN_T_GENERIC_IN(0), NN_T_GENERIC_IN(1))
671 GENERIC_TEST_NN(nn_not, NN_NOT, "~", nn_not, "nn", "io",
672 SET_PARAMETER_PRETTY_NAME(2, "input", "output"), NO_RET, 2,
673 NN_T_GENERIC_OUT(1), NN_T_GENERIC_IN(0))
674
675 /* Testing add and sub */
676 GENERIC_TEST_NN(nn_add, NN_ADD, "+", nn_add, "nnn", "iio",
677 SET_PARAMETER_PRETTY_NAME(3, "input1", "input2", "output"),
678 NO_RET, 3, NN_T_GENERIC_OUT(2), NN_T_GENERIC_IN(0),
679 NN_T_GENERIC_IN(1))
680 GENERIC_TEST_NN(nn_sub, NN_SUB, "-", nn_sub, "nnn", "iio",
681 SET_PARAMETER_PRETTY_NAME(3, "input1", "input2", "output"),
682 NO_RET, 3, NN_T_GENERIC_OUT(2), NN_T_GENERIC_IN(0),
683 NN_T_GENERIC_IN(1))
684
685 /* Testing inc and dec */
686 GENERIC_TEST_NN(nn_inc, NN_INC, "++", nn_inc, "nn", "io",
687 SET_PARAMETER_PRETTY_NAME(2, "input", "output"), NO_RET, 2,
688 NN_T_GENERIC_OUT(1), NN_T_GENERIC_IN(0))
689 GENERIC_TEST_NN(nn_dec, NN_DEC, "--", nn_dec, "nn", "io",
690 SET_PARAMETER_PRETTY_NAME(2, "input", "output"), NO_RET, 2,
691 NN_T_GENERIC_OUT(1), NN_T_GENERIC_IN(0))
692
693 /* Testing modular add, sub, inc, dec, mul, exp (inputs are supposed < p except for exp) */
694 GENERIC_TEST_NN(nn_mod_add, NN_MOD_ADD, "+%", nn_mod_add, "nnnn", "iiio",
695 SET_PARAMETER_PRETTY_NAME(4, "input1", "input2", "modulo", "output"),
696 NO_RET, 4, NN_T_GENERIC_OUT(3), NN_T_GENERIC_IN(0),
697 NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2))
698 GENERIC_TEST_NN(nn_mod_sub, NN_MOD_SUB, "-%", nn_mod_sub, "nnnn", "iiio",
699 SET_PARAMETER_PRETTY_NAME(4, "input1", "input2", "modulo", "output"),
700 NO_RET, 4, NN_T_GENERIC_OUT(3), NN_T_GENERIC_IN(0),
701 NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2))
702 GENERIC_TEST_NN(nn_mod_inc, NN_MOD_INC, "++%", nn_mod_inc, "nnn", "iio",
703 SET_PARAMETER_PRETTY_NAME(3, "input1", "modulo", "output"),
704 NO_RET, 3, NN_T_GENERIC_OUT(2), NN_T_GENERIC_IN(0),
705 NN_T_GENERIC_IN(1))
706 GENERIC_TEST_NN(nn_mod_dec, NN_MOD_DEC, "--%", nn_mod_dec, "nnn", "iio",
707 SET_PARAMETER_PRETTY_NAME(3, "input1", "modulo", "output"),
708 NO_RET, 3, NN_T_GENERIC_OUT(2), NN_T_GENERIC_IN(0),
709 NN_T_GENERIC_IN(1))
710 GENERIC_TEST_NN(nn_mod_mul, NN_MOD_MUL, "*%", nn_mod_mul, "nnnn", "iiio",
711 SET_PARAMETER_PRETTY_NAME(4, "input1", "input2", "modulo", "output"),
712 NO_RET, 4, NN_T_GENERIC_OUT(3), NN_T_GENERIC_IN(0),
713 NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2))
714 GENERIC_TEST_NN(nn_mod_pow, NN_MOD_POW, "exp%", nn_mod_pow, "nnnn", "iiio",
715 SET_PARAMETER_PRETTY_NAME(4, "base", "exp", "modulo", "output"),
716 NO_RET, 4, NN_T_GENERIC_OUT(3), NN_T_GENERIC_IN(0),
717 NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2))
718
719
720 /* Testing mul */
721 GENERIC_TEST_NN(nn_mul, NN_MUL, "*", nn_mul, "nnn", "oii",
722 SET_PARAMETER_PRETTY_NAME(3, "output1", "input1", "input2"),
723 NO_RET, 1, NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1),
724 NN_T_GENERIC_IN(2))
725 GENERIC_TEST_NN(nn_sqr, NN_SQR, "(^2)", nn_sqr, "nn", "oi",
726 SET_PARAMETER_PRETTY_NAME(2, "output1", "input1"),
727 NO_RET, 1, NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1))
728
729 /* Testing division */
730 GENERIC_TEST_NN(nn_divrem, NN_DIVREM, "/", nn_divrem, "nnnn", "ooii",
731 SET_PARAMETER_PRETTY_NAME(4, "quotient", "remainder", "input1", "input2"),
732 NO_RET, 2, NN_T_GENERIC_OUT(0), NN_T_GENERIC_OUT(1),
733 NN_T_GENERIC_IN(2), NN_T_GENERIC_IN(3))
734 GENERIC_TEST_NN(nn_xgcd, NN_XGCD, "xgcd", nn_xgcd, "nnnnns", "oooiio",
735 SET_PARAMETER_PRETTY_NAME(6, "xgcd", "u", "v", "input1", "input2", "sign"),
736 NO_RET, 3, NN_T_GENERIC_OUT(0), NN_T_GENERIC_OUT(1), NN_T_GENERIC_OUT(2),
737 NN_T_GENERIC_IN(3), NN_T_GENERIC_IN(4), INT_GENERIC_OUT(5))
738 GENERIC_TEST_NN(nn_gcd, NN_GCD, "gcd", nn_gcd, "nnns", "oiio",
739 SET_PARAMETER_PRETTY_NAME(4, "gcd", "input1", "input2", "sign"),
740 NO_RET, 1, NN_T_GENERIC_OUT(0),
741 NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2), INT_GENERIC_OUT(3))
742 GENERIC_TEST_NN(nn_mod, NN_MOD, "%", nn_mod, "nnn", "oii",
743 SET_PARAMETER_PRETTY_NAME(3, "output", "input1", "input2"),
744 NO_RET, 1, NN_T_GENERIC_OUT(0),
745 NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2))
746
747 /* Testing modular inversion */
748 GENERIC_TEST_NN(nn_modinv, NN_MODINV, "(^-1%)", nn_modinv, "nnns", "oiiO",
749 SET_PARAMETER_PRETTY_NAME(4, "output", "input1", "input2", "ret"),
750 RET, 1, NN_T_GENERIC_OUT(0),
751 NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2))
752
753 /* Testing modular inversion modulo a 2**n */
754 GENERIC_TEST_NN(nn_modinv_2exp, NN_MODINV_2EXP, "(^-1%)(2exp)", nn_modinv_2exp, "nnus", "oiio",
755 SET_PARAMETER_PRETTY_NAME(4, "output", "input1", "input2", "isodd"),
756 NO_RET, 1, NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1),
757 UINT_GENERIC_IN(2), INT_GENERIC_OUT(3))
758
759 /* Check Montgomery multiplication redcify primitives */
760 GENERIC_TEST_NN(nn_compute_redc1_coefs, NN_COEF_REDC1, "coef_redc1", nn_compute_redc1_coefs, "nnnu", "ooio",
761 SET_PARAMETER_PRETTY_NAME(4, "r", "r_square", "p", "mpinv"),
762 NO_RET, 3, NN_T_GENERIC_OUT(0), NN_T_GENERIC_OUT(1), NN_T_GENERIC_IN(2), WORD_T_GENERIC_OUT(3))
763 GENERIC_TEST_NN(nn_compute_div_coefs, NN_COEF_DIV, "coef_div", nn_compute_div_coefs, "nuun", "oooi",
764 SET_PARAMETER_PRETTY_NAME(4, "p_normalized", "p_shift", "p_reciprocal", "p"),
765 NO_RET, 3, NN_T_GENERIC_OUT(0), WORD_T_GENERIC_OUT(1), WORD_T_GENERIC_OUT(2), NN_T_GENERIC_IN(3))
766 GENERIC_TEST_NN(nn_mul_redc1, NN_MUL_REDC1, "*_redc1", nn_mul_redc1, "nnnnu", "oiiii",
767 SET_PARAMETER_PRETTY_NAME(5, "output", "input1", "input2", "p", "mpinv"),
768 NO_RET, 1, NN_T_GENERIC_OUT(0), NN_T_GENERIC_IN(1), NN_T_GENERIC_IN(2),
769 NN_T_GENERIC_IN(3), WORD_T_GENERIC_IN(4))
770
771
772
773 /*********** Fp layer tests ************************************************/
774 /* Testing addition in F_p */
775 GENERIC_TEST_FP(fp_add, FP_ADD, "+", fp_add, "cfff", "ioii",
776 SET_PARAMETER_PRETTY_NAME(4, "p", "sum", "input1", "input2"),
777 NO_RET, 0, 2,
778 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2), FP_T_GENERIC_IN(3))
779
780 /* Testing subtraction in F_p */
781 GENERIC_TEST_FP(fp_sub, FP_SUB, "-", fp_sub, "cfff", "ioii",
782 SET_PARAMETER_PRETTY_NAME(4, "p", "diff", "input1", "input2"),
783 NO_RET, 0, 2,
784 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2), FP_T_GENERIC_IN(3))
785
786 /* Testing multiplication in F_p */
787 GENERIC_TEST_FP(fp_mul, FP_MUL, "*", fp_mul, "cfff", "ioii",
788 SET_PARAMETER_PRETTY_NAME(4, "p", "prod", "input1", "input2"),
789 NO_RET, 0, 2,
790 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2), FP_T_GENERIC_IN(3))
791 GENERIC_TEST_FP(fp_sqr, FP_SQR, "(^2)", fp_sqr, "cff", "ioi",
792 SET_PARAMETER_PRETTY_NAME(3, "p", "prod", "input1"),
793 NO_RET, 0, 2,
794 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2))
795
796 /* Testing division in F_p */
797 GENERIC_TEST_FP(fp_div, FP_DIV, "/", fp_div, "cfff", "ioii",
798 SET_PARAMETER_PRETTY_NAME(4, "p", "quo", "input1", "input2"),
799 NO_RET, 0, 2,
800 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2), FP_T_GENERIC_IN(3))
801
802 /* Testing Montgomery multiplication in F_p */
803 GENERIC_TEST_FP(fp_mul_monty, FP_MUL_MONTY, "*_monty", fp_mul_monty, "cfff", "ioii",
804 SET_PARAMETER_PRETTY_NAME(4, "p", "prod", "input1", "input2"),
805 NO_RET, 0, 2,
806 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2), FP_T_GENERIC_IN(3))
807 GENERIC_TEST_FP(fp_sqr_monty, FP_SQR_MONTY, "(^2)_monty", fp_sqr_monty, "cff", "ioi",
808 SET_PARAMETER_PRETTY_NAME(3, "p", "prod", "input1"),
809 NO_RET, 0, 2,
810 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2))
811
812 /* Testing exponentiation in F_p */
813 GENERIC_TEST_FP(fp_pow, FP_POW, "exp", fp_pow, "cffn", "ioii",
814 SET_PARAMETER_PRETTY_NAME(4, "p", "pow", "input", "exp"),
815 NO_RET, 0, 2,
816 FP_T_GENERIC_OUT(1), FP_T_GENERIC_IN(2), NN_T_GENERIC_IN(3))
817
818 /* Testing square residue in F_p */
819 GENERIC_TEST_FP(fp_sqrt, FP_SQRT, "sqrt", fp_sqrt, "cfffs", "iooiO",
820 SET_PARAMETER_PRETTY_NAME(4, "sqrt1", "sqrt2", "p", "ret"),
821 RET, 0, 3,
822 FP_T_GENERIC_OUT(1), FP_T_GENERIC_OUT(2), FP_T_GENERIC_IN(3))
823
824 /*****************************************************************/
825
826 /*
827 * Read data on given fd until first newline character and put it in buf
828 * followed by a null character. buffer size is passed via buflen. The
829 * length of read line is returned to the caller in buflen on success
830 * (not including null character terminating read string).
831 *
832 * 0 is returned on success.
833 * -1 is returned on end of file.
834 * -2 is returned on error (buffer not sufficient, etc)
835 */
836 int read_string(int fd, char *buf, unsigned int *buflen);
read_string(int fd,char * buf,unsigned int * buflen)837 int read_string(int fd, char *buf, unsigned int *buflen)
838 {
839 unsigned int pos = 0, len;
840 int ret = -1;
841 char c;
842
843 MUST_HAVE((buf != NULL) && (buflen != NULL), ret, err);
844
845 len = *buflen;
846
847 if (len < 2) {
848 ret = -2;
849 goto err;
850 }
851
852 len -= 1; /* keep some space to terminate the string */
853
854 while ((len > 0) && ((ret = read(fd, &c, 1)) != 0) && (c != '\n')) {
855 buf[pos++] = c;
856 len -= 1;
857 }
858
859 if (len == 0) {
860 ret = -2;
861 goto err;
862 }
863
864 if (!ret) {
865 ret = -1;
866 goto err;
867 }
868
869 /* Terminate the string */
870 buf[pos] = 0;
871 *buflen = pos;
872 ret = 0;
873
874 err:
875 return ret;
876 }
877
878
879 /*
880 * Parse a test file and perform the tests it provides, one
881 * by one, in order.
882 */
main(int argc,char * argv[])883 int main(int argc, char *argv[])
884 {
885 nn fp_ctx_modulus, fp_ctx_r, fp_ctx_r_square, fp_ctx_mpinv;
886 nn fp_ctx_pshift, fp_ctx_pnorm, fp_ctx_prec;
887 fp_ctx fp_ctx_param;
888 int ret, cmp;
889 u64 u_params[MAX_PARAMS];
890 void *params[MAX_PARAMS];
891 unsigned int ibuflen = BIT_LEN_WORDS(NN_MAX_BIT_LEN) * WORD_BYTES * 10;
892 unsigned long int test_num, line = 0, oktests = 0;
893 int test_ret;
894 unsigned int len = ibuflen;
895 int nrecs;
896 int fd = 0, nn_local_cnt = 0, fp_local_cnt = 0, fp_ctx_local_cnt = 0;
897 unsigned int nn_len;
898 char op[1024];
899 char *ibuf = NULL, *rec = NULL;
900 nn *tmp;
901 fp *fp_tmp;
902 int (*curr_test_fun) (const char *, void **, int);
903 unsigned long p_tmp;
904
905 ret = nn_init(&fp_ctx_modulus, 0);
906 ret |= nn_init(&fp_ctx_r, 0);
907 ret |= nn_init(&fp_ctx_r_square, 0);
908 ret |= nn_init(&fp_ctx_mpinv, 0);
909 ret |= nn_init(&fp_ctx_pshift, 0);
910 ret |= nn_init(&fp_ctx_pnorm, 0);
911 ret |= nn_init(&fp_ctx_prec, 0);
912
913 /* First "fake" context initialization with junk value
914 * one as prime number
915 */
916 ret |= nn_one(&fp_ctx_modulus);
917 ret |= fp_ctx_init_from_p(&fp_ctx_param, &fp_ctx_modulus);
918 GENERIC_TEST_FP_DECL_INIT_MAX(fp_params, &fp_ctx_param)
919 GENERIC_TEST_NN_DECL_INIT_MAX(nn_params, 0)
920
921 if(ret){
922 goto err;
923 }
924
925 #ifdef WITH_ASSERT_BACKTRACE
926 memset(backtrace_buffer, 0, sizeof(backtrace_buffer) - 1);
927 if (signal(SIGINT, assert_signal_handler) == SIG_ERR) {
928 printf("Error: can't catch SIGINT signal ...\n");
929 return -1;
930 }
931 #endif
932
933 if (argc > 2) {
934 printf("Usage: %s [test_file]\n", argv[0]);
935 printf(" If no test_file provided, stdin is taken\n");
936 return -1;
937 }
938
939 /* Special case where we want to dump information */
940 if (argc == 2) {
941 if (memcmp(argv[1], "-info", sizeof("-info")) == 0){
942 printf("%d %d\n", WORDSIZE, NN_MAX_BASE);
943 return 0;
944 }
945 }
946
947 ibuf = (char*)malloc(ibuflen);
948 if (!ibuf) {
949 return -1;
950 }
951 memset(ibuf, 0, ibuflen);
952
953 if(argc == 2){
954 fd = open(argv[1], O_RDONLY);
955 }
956 else{
957 fd = STDIN_FILENO;
958 }
959 while (read_string(fd, ibuf, &len) == 0) {
960 char *t, *s = ibuf;
961 int i;
962
963 /* Find end of first record (the test number) */
964 t = strchr(s, ' ');
965 if (t == NULL) {
966 printf("\nLine %lu: unable to find record #1\n", line);
967 return -1;
968 }
969 *t = 0; /* mark end of record */
970 test_num = strtoul(s, NULL, 10);
971 assert(line == test_num);
972 s = t + 1; /* jump to beginning of next record */
973
974 /* Find end of second record (operation type) */
975 t = strchr(s, ' ');
976 if (t == NULL) {
977 printf("\nLine %lu: unable to find record #2\n", line);
978 return -1;
979 }
980 *t = 0; /* mark end of record */
981 strncpy(op, s, sizeof(op) - 1); /* Copy opcode */
982 s = t + 1; /* jump to beginning of next record */
983
984 /* Pretty print the evolution of our tests */
985 if((line % 1000 == 0) && (line != 0)){
986 printf("\r%*s", 40, "");
987 printf("\rTest %lu on the go [%s]", line, op);
988 fflush(stdout);
989 }
990
991 /* Find end of third record (str of types for next records) */
992 t = strchr(s, ' ');
993 if (t == NULL) {
994 printf("\nLine %lu: unable to find record #3\n", line);
995 return -1;
996 }
997 *t = 0; /* mark end of record */
998 nrecs = (int)(t - s);
999
1000 rec = t + 1;
1001 ADD_TO_BACKTRACE("--------------\n");
1002 for (i = 0; i < nrecs; i++) {
1003 /* Find end of record */
1004 t = strchr(rec, ' ');
1005 if (t == NULL) {
1006 t = ibuf + len;
1007 }
1008 *t = 0;
1009 switch (s[i]) {
1010 case 'c': /* fp_ctx */
1011 if (fp_ctx_local_cnt > 0) {
1012 printf("\nLine %lu: Only one fp_ctx allowed\n", line);
1013 ret = -1;
1014 goto err;
1015 }
1016 /*
1017 * We expect a 3 nn of the same size (p, r, r^2)
1018 * followed by a single word providing mpinv
1019 * and an additional nn and two words.
1020 */
1021 assert(((t - rec) % 2) == 0);
1022 nn_len = (unsigned int)(t - rec -
1023 3 * (WORD_BYTES * 2)) /
1024 (2 * 4);
1025 assert((nn_len % WORD_BYTES) == 0);
1026 fp_ctx_local_cnt++;
1027 tmp = &fp_ctx_modulus;
1028 ret = nn_set_wlen(tmp, (u8)(nn_len / WORD_BYTES)); EG(ret, err);
1029 ret = nn_import_from_hexbuf(tmp, rec, 2 * nn_len); EG(ret, err);
1030
1031 /* Initialize fp context from the prime modulus */
1032 ret = fp_ctx_init_from_p(&fp_ctx_param, &fp_ctx_modulus); EG(ret, err);
1033 /* Now get the other Fp context values and check that
1034 * everything is OK
1035 */
1036 tmp = &fp_ctx_r;
1037 ret = nn_set_wlen(tmp, (u8)(nn_len / WORD_BYTES)); EG(ret, err);
1038 ret = nn_import_from_hexbuf(tmp, rec + (2 * nn_len),
1039 2 * nn_len); EG(ret, err);
1040
1041 /* Compare r */
1042 ret = nn_cmp(&fp_ctx_r, &(fp_ctx_param.r), &cmp);
1043 if(ret || cmp){
1044 printf("\nLine %lu: Fp context import failed\n", line);
1045 nn_print("Imported r from file =", &fp_ctx_r);
1046 nn_print("Computed r from modulus=", &(fp_ctx_param.r));
1047 ret = -1;
1048 goto err;
1049 }
1050 tmp = &fp_ctx_r_square;
1051 ret = nn_set_wlen(tmp, (u8)(nn_len / WORD_BYTES)); EG(ret, err);
1052 ret = nn_import_from_hexbuf(tmp, rec + (4 * nn_len),
1053 2 * nn_len); EG(ret, err);
1054
1055 /* Compare r_square */
1056 ret = nn_cmp(&fp_ctx_r_square, &(fp_ctx_param.r_square), &cmp);
1057 if(ret || cmp){
1058 printf("\nLine %lu: Fp context import failed\n", line);
1059 nn_print("Imported r_square from file =", &fp_ctx_r_square);
1060 nn_print("Computed r_square from modulus=", &(fp_ctx_param.r_square));
1061 ret = -1;
1062 goto err;
1063 }
1064 tmp = &fp_ctx_mpinv;
1065 ret = nn_set_wlen(tmp, 1); EG(ret, err);
1066 ret = nn_import_from_hexbuf(tmp, rec + (6 * nn_len),
1067 WORD_BYTES * 2); EG(ret, err);
1068
1069 /* Compare mpinv */
1070 if(fp_ctx_mpinv.val[0] != fp_ctx_param.mpinv){
1071 printf("\nLine %lu: Fp context import failed\n", line);
1072 printf("Imported mpinv from modulus=" PRINTF_WORD_HEX_FMT, fp_ctx_mpinv.val[0]);
1073 printf("Computed mpiv from file =" PRINTF_WORD_HEX_FMT, fp_ctx_param.mpinv);
1074 ret = -1;
1075 goto err;
1076 }
1077 tmp = &fp_ctx_pshift;
1078 ret = nn_set_wlen(tmp, 1); EG(ret, err);
1079 ret = nn_import_from_hexbuf(tmp, rec + (6 * nn_len + 2 * WORD_BYTES),
1080 WORD_BYTES * 2); EG(ret, err);
1081
1082 /* Compare p_shift */
1083 if((bitcnt_t)fp_ctx_pshift.val[0] != fp_ctx_param.p_shift){
1084 printf("\nLine %lu: Fp context import failed\n", line);
1085 printf("Imported mpinv from modulus=%d", (bitcnt_t)fp_ctx_pshift.val[0]);
1086 printf("Computed mpiv from file =%d", fp_ctx_param.p_shift);
1087 ret = -1;
1088 goto err;
1089 }
1090 tmp = &fp_ctx_pnorm;
1091 ret = nn_set_wlen(tmp, (u8)(nn_len / WORD_BYTES)); EG(ret, err);
1092 ret = nn_import_from_hexbuf(tmp, rec + (6 * nn_len + 4 * WORD_BYTES),
1093 nn_len * 2); EG(ret, err);
1094
1095 /* Compare p_normalized */
1096 ret = nn_cmp(&fp_ctx_pnorm, &(fp_ctx_param.p_normalized), &cmp);
1097 if(ret || (cmp != 0)){
1098 printf("\nLine %lu: Fp context import failed\n", line);
1099 nn_print("Imported r_square from file =", &fp_ctx_pnorm);
1100 nn_print("Computed r_square from modulus=", &(fp_ctx_param.p_normalized));
1101 return -1;
1102 }
1103 tmp = &fp_ctx_prec;
1104 ret = nn_set_wlen(tmp, 1); EG(ret, err);
1105 ret = nn_import_from_hexbuf(tmp, rec + (8 * nn_len + 4 * WORD_BYTES),
1106 WORD_BYTES * 2); EG(ret, err);
1107
1108 /* Compare p_reciprocal */
1109 if(fp_ctx_prec.val[0] != fp_ctx_param.p_reciprocal){
1110 printf("\nLine %lu: Fp context import failed\n", line);
1111 printf("Imported mpinv from modulus=" PRINTF_WORD_HEX_FMT, fp_ctx_prec.val[0]);
1112 printf("Computed mpiv from file =" PRINTF_WORD_HEX_FMT, fp_ctx_param.p_reciprocal);
1113 ret = -1;
1114 goto err;
1115 }
1116 params[i] = &fp_ctx_param;
1117 ADD_TO_BACKTRACE("'c' param: %s\n", rec);
1118 break;
1119 case 'f': /* fp */
1120 if (fp_ctx_local_cnt != 1) {
1121 printf("\nLine %lu: No fp_ctx available\n", line);
1122 ret = -1;
1123 goto err;
1124 }
1125 if (fp_local_cnt >= NUM_PRE_ALLOCATED_FP) {
1126 printf("\nLine %lu: Not enough fp\n",
1127 line);
1128 ret = -1;
1129 goto err;
1130 }
1131 assert(((t - rec) % 2) == 0);
1132 nn_len = (unsigned int)(t - rec) / 2;
1133 assert((nn_len / WORD_BYTES) <=
1134 fp_ctx_param.p.wlen);
1135 fp_tmp = fp_params_ptr[fp_local_cnt++];
1136 fp_tmp->ctx = &fp_ctx_param;
1137 tmp = &(fp_tmp->fp_val);
1138 ret = nn_set_wlen(tmp, (u8)(nn_len / WORD_BYTES)); EG(ret, err);
1139 ret = nn_import_from_hexbuf(tmp, rec, 2 * nn_len); EG(ret, err);
1140 ret = nn_set_wlen(tmp, fp_ctx_param.p.wlen); EG(ret, err);
1141 params[i] = fp_tmp;
1142 ADD_TO_BACKTRACE("'f' param: %s\n", rec);
1143 break;
1144 case 'p': /* raw pointer value. Useful for NULL */
1145 p_tmp = strtoull(rec, NULL, 10);
1146 params[i] = (void *)p_tmp;
1147 ADD_TO_BACKTRACE("'p' param: %s\n", rec);
1148 /* If this is not a NULL pointer, this is weird!
1149 * Abort ...
1150 */
1151 if(params[i] != NULL){
1152 printf("\nLine %lu: imported a pointer (type 'p') non NULL\n",
1153 line);
1154 ret = -1;
1155 goto err;
1156 }
1157 break;
1158 case 'n': /* nn */
1159 if (nn_local_cnt >= NUM_PRE_ALLOCATED_NN) {
1160 printf("\nLine %lu: Not enough nn\n",
1161 line);
1162 return -1;
1163 }
1164 assert(((t - rec) % 2) == 0);
1165 nn_len = (unsigned int)(t - rec) / 2;
1166 assert((nn_len % WORD_BYTES) == 0);
1167 tmp = nn_params_ptr[nn_local_cnt++];
1168 ret = nn_set_wlen(tmp, (u8)(nn_len / WORD_BYTES)); EG(ret, err);
1169 ret = nn_import_from_hexbuf(tmp, rec, 2 * nn_len); EG(ret, err);
1170 params[i] = tmp;
1171 ADD_TO_BACKTRACE("'n' param: %s\n", rec);
1172 break;
1173 case 'u': /* unsigned long int (in base 10) */
1174 u_params[i] = (u64)strtoull(rec, NULL, 10);
1175 params[i] = &u_params[i];
1176 ADD_TO_BACKTRACE("'u' param: %s\n", rec);
1177 break;
1178 case 's': /* signed long int (in base 10) */
1179 u_params[i] = (u64)strtoll(rec, NULL, 10);
1180 params[i] = &u_params[i];
1181 ADD_TO_BACKTRACE("'s' param: %s\n", rec);
1182 break;
1183 default:
1184 printf("\nUnknown record type '%c'\n", s[i]);
1185 ret = -1;
1186 goto err;
1187 }
1188 rec = t + 1;
1189 }
1190 /* Save current parameters format in the global variable */
1191 memcpy(global_parameters, s, LOCAL_MIN(nrecs, MAX_PARAMS));
1192 curr_test_fun = NULL;
1193 FIND_FUN_IN_DISPATCH_TABLE(op, curr_test_fun);
1194 if (curr_test_fun == NULL) {
1195 printf("\nLine %lu: unknown opcode %s\n", line, op);
1196 } else {
1197 ADD_TO_BACKTRACE("\nLine %lu: testing opcode %s\n", line, op);
1198 test_ret = curr_test_fun(op, params, (int)test_num);
1199 if (test_ret == 1) {
1200 ADD_TO_BACKTRACE("-- TEST OK ---\n");
1201 oktests += (unsigned long)test_ret;
1202 } else {
1203 ADD_TO_BACKTRACE("-- TEST NOK --\n");
1204 }
1205 }
1206 line += 1;
1207 len = ibuflen;
1208 nn_local_cnt = 0;
1209 fp_local_cnt = 0;
1210 fp_ctx_local_cnt = 0;
1211 }
1212
1213 printf("\n%lu/%lu tests passed successfully (%lu on error)\n",
1214 oktests, line, line - oktests);
1215
1216 if(fd != 0){
1217 close(fd);
1218 }
1219 if(ibuf != NULL){
1220 free(ibuf);
1221 }
1222
1223 return 0;
1224 err:
1225 printf("Error: critical error occured! Leaving ...\n");
1226 if(fd != 0){
1227 close(fd);
1228 }
1229 if(ibuf != NULL){
1230 free(ibuf);
1231 }
1232 return -1;
1233 }
1234