xref: /freebsd/crypto/libecc/src/arithmetic_tests/arithmetic_tests.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
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