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 */ 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 */ 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); 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 */ 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