1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project 3*f0865ec9SKyle Evans * 4*f0865ec9SKyle Evans * Authors: 5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr> 8*f0865ec9SKyle Evans * 9*f0865ec9SKyle Evans * Contributors: 10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr> 11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr> 12*f0865ec9SKyle Evans * 13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 15*f0865ec9SKyle Evans */ 16*f0865ec9SKyle Evans #define NN_CONSISTENCY_CHECK 17*f0865ec9SKyle Evans #include <libecc/nn/nn.h> 18*f0865ec9SKyle Evans 19*f0865ec9SKyle Evans /* 20*f0865ec9SKyle Evans * Used for the conditional swap algorithm SCA 21*f0865ec9SKyle Evans * resistance, see below in the implementation of 22*f0865ec9SKyle Evans * nn_cnd_swap. 23*f0865ec9SKyle Evans */ 24*f0865ec9SKyle Evans #include <libecc/utils/utils_rand.h> 25*f0865ec9SKyle Evans 26*f0865ec9SKyle Evans /* 27*f0865ec9SKyle Evans * Except otherwise specified, all functions accept *initialized* nn. 28*f0865ec9SKyle Evans * The WORD(NN_MAX_WORD_LEN + WORDSIZE) magic is here to detect modules 29*f0865ec9SKyle Evans * compiled with different WORDSIZE or NN_MAX_WORD_LEN and are binary 30*f0865ec9SKyle Evans * incompatible. 31*f0865ec9SKyle Evans */ 32*f0865ec9SKyle Evans 33*f0865ec9SKyle Evans #define NN_MAGIC ((word_t)((0xb4cf5d56e2023316ULL ^ (WORD(NN_MAX_WORD_LEN + WORDSIZE))))) 34*f0865ec9SKyle Evans 35*f0865ec9SKyle Evans /* 36*f0865ec9SKyle Evans * Local helper internally used to check that the storage space 37*f0865ec9SKyle Evans * above wlen is made of zero words. The function does NOT check 38*f0865ec9SKyle Evans * if given nn has been initialized. This must have been done 39*f0865ec9SKyle Evans * by the caller. 40*f0865ec9SKyle Evans * 41*f0865ec9SKyle Evans * Due to its performance cost, this consistency check is used 42*f0865ec9SKyle Evans * in SHOULD_HAVE macros, meaning that it will only be present 43*f0865ec9SKyle Evans * in DEBUG mode. Hence the ATTRIBUTE_UNUSED so that no warning 44*f0865ec9SKyle Evans * (error in -Werror) is triggered at compilation time. 45*f0865ec9SKyle Evans * 46*f0865ec9SKyle Evans */ 47*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int ATTRIBUTE_UNUSED __nn_is_wlen_consistent(nn_src_t A) 48*f0865ec9SKyle Evans { 49*f0865ec9SKyle Evans word_t val = 0; 50*f0865ec9SKyle Evans u8 i; 51*f0865ec9SKyle Evans 52*f0865ec9SKyle Evans for (i = A->wlen; i < NN_MAX_WORD_LEN; i++) { 53*f0865ec9SKyle Evans val |= (A)->val[i]; 54*f0865ec9SKyle Evans } 55*f0865ec9SKyle Evans 56*f0865ec9SKyle Evans return (val == 0); 57*f0865ec9SKyle Evans } 58*f0865ec9SKyle Evans 59*f0865ec9SKyle Evans /* 60*f0865ec9SKyle Evans * Verify that pointed nn has already been initialized. This function 61*f0865ec9SKyle Evans * should be used as a safety net in all function before using a nn 62*f0865ec9SKyle Evans * received as parameter. Returns 0 on success, -1 on error. 63*f0865ec9SKyle Evans */ 64*f0865ec9SKyle Evans int nn_check_initialized(nn_src_t A) 65*f0865ec9SKyle Evans { 66*f0865ec9SKyle Evans int ret; 67*f0865ec9SKyle Evans 68*f0865ec9SKyle Evans MUST_HAVE((A != NULL), ret, err); 69*f0865ec9SKyle Evans MUST_HAVE((A->magic == NN_MAGIC), ret, err); 70*f0865ec9SKyle Evans MUST_HAVE((A->wlen <= NN_MAX_WORD_LEN), ret, err); 71*f0865ec9SKyle Evans SHOULD_HAVE(__nn_is_wlen_consistent(A), ret, err); 72*f0865ec9SKyle Evans 73*f0865ec9SKyle Evans ret = 0; 74*f0865ec9SKyle Evans 75*f0865ec9SKyle Evans err: 76*f0865ec9SKyle Evans return ret; 77*f0865ec9SKyle Evans } 78*f0865ec9SKyle Evans 79*f0865ec9SKyle Evans /* 80*f0865ec9SKyle Evans * Initialize nn from expected initial byte length 'len', setting its wlen 81*f0865ec9SKyle Evans * to associated (ceil) value and clearing whole storage space. Return 0 82*f0865ec9SKyle Evans * on success, -1 on error. 83*f0865ec9SKyle Evans */ 84*f0865ec9SKyle Evans int nn_init(nn_t A, u16 len) 85*f0865ec9SKyle Evans { 86*f0865ec9SKyle Evans int ret; 87*f0865ec9SKyle Evans u8 i; 88*f0865ec9SKyle Evans 89*f0865ec9SKyle Evans MUST_HAVE(((A != NULL) && (len <= NN_MAX_BYTE_LEN)), ret, err); 90*f0865ec9SKyle Evans 91*f0865ec9SKyle Evans A->wlen = (u8)BYTE_LEN_WORDS(len); 92*f0865ec9SKyle Evans A->magic = NN_MAGIC; 93*f0865ec9SKyle Evans 94*f0865ec9SKyle Evans for (i = 0; i < NN_MAX_WORD_LEN; i++) { 95*f0865ec9SKyle Evans A->val[i] = WORD(0); 96*f0865ec9SKyle Evans } 97*f0865ec9SKyle Evans 98*f0865ec9SKyle Evans ret = 0; 99*f0865ec9SKyle Evans 100*f0865ec9SKyle Evans err: 101*f0865ec9SKyle Evans return ret; 102*f0865ec9SKyle Evans } 103*f0865ec9SKyle Evans 104*f0865ec9SKyle Evans /* 105*f0865ec9SKyle Evans * Uninitialize the pointed nn to prevent further use (magic field in the 106*f0865ec9SKyle Evans * structure is zeroized). The associated storage space is also zeroized. If 107*f0865ec9SKyle Evans * given pointer is NULL or does not point to an initialized nn, the function 108*f0865ec9SKyle Evans * does nothing. 109*f0865ec9SKyle Evans */ 110*f0865ec9SKyle Evans void nn_uninit(nn_t A) 111*f0865ec9SKyle Evans { 112*f0865ec9SKyle Evans if ((A != NULL) && (A->magic == NN_MAGIC)) { 113*f0865ec9SKyle Evans int i; 114*f0865ec9SKyle Evans 115*f0865ec9SKyle Evans for (i = 0; i < NN_MAX_WORD_LEN; i++) { 116*f0865ec9SKyle Evans A->val[i] = WORD(0); 117*f0865ec9SKyle Evans } 118*f0865ec9SKyle Evans 119*f0865ec9SKyle Evans A->wlen = 0; 120*f0865ec9SKyle Evans A->magic = WORD(0); 121*f0865ec9SKyle Evans } 122*f0865ec9SKyle Evans 123*f0865ec9SKyle Evans return; 124*f0865ec9SKyle Evans } 125*f0865ec9SKyle Evans 126*f0865ec9SKyle Evans /* 127*f0865ec9SKyle Evans * Set current value of pointed initialized nn to 0. Returns 0 on success, -1 128*f0865ec9SKyle Evans * on error. 129*f0865ec9SKyle Evans */ 130*f0865ec9SKyle Evans int nn_zero(nn_t A) 131*f0865ec9SKyle Evans { 132*f0865ec9SKyle Evans int ret; 133*f0865ec9SKyle Evans 134*f0865ec9SKyle Evans ret = nn_check_initialized(A); EG(ret, err); 135*f0865ec9SKyle Evans ret = nn_init(A, 0); 136*f0865ec9SKyle Evans 137*f0865ec9SKyle Evans err: 138*f0865ec9SKyle Evans return ret; 139*f0865ec9SKyle Evans } 140*f0865ec9SKyle Evans 141*f0865ec9SKyle Evans /* 142*f0865ec9SKyle Evans * Set current value of pointed initialized nn to given word value. Returns 0 143*f0865ec9SKyle Evans * on success, -1 on error. 144*f0865ec9SKyle Evans */ 145*f0865ec9SKyle Evans int nn_set_word_value(nn_t A, word_t val) 146*f0865ec9SKyle Evans { 147*f0865ec9SKyle Evans int ret; 148*f0865ec9SKyle Evans 149*f0865ec9SKyle Evans ret = nn_zero(A); EG(ret, err); 150*f0865ec9SKyle Evans 151*f0865ec9SKyle Evans A->val[0] = val; 152*f0865ec9SKyle Evans A->wlen = 1; 153*f0865ec9SKyle Evans 154*f0865ec9SKyle Evans err: 155*f0865ec9SKyle Evans return ret; 156*f0865ec9SKyle Evans } 157*f0865ec9SKyle Evans 158*f0865ec9SKyle Evans /* 159*f0865ec9SKyle Evans * Set current value of pointed initialized nn to 1. Returns 0 on success, -1 160*f0865ec9SKyle Evans * on error. 161*f0865ec9SKyle Evans */ 162*f0865ec9SKyle Evans int nn_one(nn_t A) 163*f0865ec9SKyle Evans { 164*f0865ec9SKyle Evans return nn_set_word_value(A, WORD(1)); 165*f0865ec9SKyle Evans } 166*f0865ec9SKyle Evans 167*f0865ec9SKyle Evans /* 168*f0865ec9SKyle Evans * Conditionally swap two nn's content *in constant time*. Swapping is done 169*f0865ec9SKyle Evans * if 'cnd' is not zero. Nothing is done otherwise. Returns 0 on success, -1 170*f0865ec9SKyle Evans * on error. 171*f0865ec9SKyle Evans * 172*f0865ec9SKyle Evans * Aliasing of inputs is supported. 173*f0865ec9SKyle Evans */ 174*f0865ec9SKyle Evans int nn_cnd_swap(int cnd, nn_t in1, nn_t in2) 175*f0865ec9SKyle Evans { 176*f0865ec9SKyle Evans word_t mask = WORD_MASK_IFNOTZERO(cnd); 177*f0865ec9SKyle Evans u8 len, i; 178*f0865ec9SKyle Evans word_t t, r; 179*f0865ec9SKyle Evans volatile word_t r_mask; 180*f0865ec9SKyle Evans int ret; 181*f0865ec9SKyle Evans 182*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 183*f0865ec9SKyle Evans ret = nn_check_initialized(in2); EG(ret, err); 184*f0865ec9SKyle Evans 185*f0865ec9SKyle Evans MUST_HAVE((in1->wlen <= NN_MAX_WORD_LEN), ret, err); 186*f0865ec9SKyle Evans MUST_HAVE((in2->wlen <= NN_MAX_WORD_LEN), ret, err); 187*f0865ec9SKyle Evans 188*f0865ec9SKyle Evans len = (in1->wlen >= in2->wlen) ? in1->wlen : in2->wlen; 189*f0865ec9SKyle Evans 190*f0865ec9SKyle Evans /* Use a random word for randomly masking the delta value hamming 191*f0865ec9SKyle Evans * weight as proposed in Algorithm 4 of "Nonce@once: A Single-Trace 192*f0865ec9SKyle Evans * EM Side Channel Attack on Several Constant-Time Elliptic 193*f0865ec9SKyle Evans * Curve Implementations in Mobile Platforms" by Alam et al. 194*f0865ec9SKyle Evans */ 195*f0865ec9SKyle Evans ret = get_unsafe_random((u8*)&r, sizeof(r)); EG(ret, err); 196*f0865ec9SKyle Evans r_mask = r; 197*f0865ec9SKyle Evans 198*f0865ec9SKyle Evans for (i = 0; i < NN_MAX_WORD_LEN; i++) { 199*f0865ec9SKyle Evans word_t local_mask = WORD_MASK_IFNOTZERO((i < len)); 200*f0865ec9SKyle Evans t = ((in1->val[i] ^ in2->val[i]) & mask) ^ r_mask; 201*f0865ec9SKyle Evans in1->val[i] ^= ((t & local_mask) ^ (r_mask & local_mask)); 202*f0865ec9SKyle Evans in2->val[i] ^= ((t & local_mask) ^ (r_mask & local_mask)); 203*f0865ec9SKyle Evans } 204*f0865ec9SKyle Evans 205*f0865ec9SKyle Evans t = (word_t)(((in1->wlen ^ in2->wlen) & mask) ^ r_mask); 206*f0865ec9SKyle Evans in1->wlen ^= (u8)(t ^ r_mask); 207*f0865ec9SKyle Evans in2->wlen ^= (u8)(t ^ r_mask); 208*f0865ec9SKyle Evans 209*f0865ec9SKyle Evans err: 210*f0865ec9SKyle Evans return ret; 211*f0865ec9SKyle Evans } 212*f0865ec9SKyle Evans 213*f0865ec9SKyle Evans /* 214*f0865ec9SKyle Evans * Adjust internal wlen attribute of given nn to new_wlen. If internal wlen 215*f0865ec9SKyle Evans * attribute value is reduced, words above that limit in A are zeroized. 216*f0865ec9SKyle Evans * new_wlen must be in [0, NN_MAX_WORD_LEN]. 217*f0865ec9SKyle Evans * The trimming is performed in constant time wrt to the length of the 218*f0865ec9SKyle Evans * input to avoid leaking it. 219*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 220*f0865ec9SKyle Evans */ 221*f0865ec9SKyle Evans int nn_set_wlen(nn_t A, u8 new_wlen) 222*f0865ec9SKyle Evans { 223*f0865ec9SKyle Evans int ret; 224*f0865ec9SKyle Evans u8 i; 225*f0865ec9SKyle Evans 226*f0865ec9SKyle Evans ret = nn_check_initialized(A); EG(ret, err); 227*f0865ec9SKyle Evans MUST_HAVE((new_wlen <= NN_MAX_WORD_LEN), ret, err); 228*f0865ec9SKyle Evans MUST_HAVE((A->wlen <= NN_MAX_WORD_LEN), ret, err); 229*f0865ec9SKyle Evans 230*f0865ec9SKyle Evans /* Trimming performed in constant time */ 231*f0865ec9SKyle Evans for (i = 0; i < NN_MAX_WORD_LEN; i++) { 232*f0865ec9SKyle Evans A->val[i] = (word_t)(A->val[i] & WORD_MASK_IFZERO((i >= new_wlen))); 233*f0865ec9SKyle Evans } 234*f0865ec9SKyle Evans 235*f0865ec9SKyle Evans A->wlen = new_wlen; 236*f0865ec9SKyle Evans 237*f0865ec9SKyle Evans err: 238*f0865ec9SKyle Evans return ret; 239*f0865ec9SKyle Evans } 240*f0865ec9SKyle Evans 241*f0865ec9SKyle Evans /* 242*f0865ec9SKyle Evans * The function tests if given nn value is zero. The result of the test is given 243*f0865ec9SKyle Evans * using 'iszero' out parameter (1 if nn is zero, 0 if it is not). The function 244*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 'iszero' is not meaningfull on error. 245*f0865ec9SKyle Evans * When A is valid, check is done *in constant time*. 246*f0865ec9SKyle Evans */ 247*f0865ec9SKyle Evans int nn_iszero(nn_src_t A, int *iszero) 248*f0865ec9SKyle Evans { 249*f0865ec9SKyle Evans int ret, notzero; 250*f0865ec9SKyle Evans u8 i; 251*f0865ec9SKyle Evans 252*f0865ec9SKyle Evans ret = nn_check_initialized(A); EG(ret, err); 253*f0865ec9SKyle Evans MUST_HAVE((A->wlen <= NN_MAX_WORD_LEN), ret, err); 254*f0865ec9SKyle Evans MUST_HAVE((iszero != NULL), ret, err); 255*f0865ec9SKyle Evans 256*f0865ec9SKyle Evans notzero = 0; 257*f0865ec9SKyle Evans for (i = 0; i < NN_MAX_WORD_LEN; i++) { 258*f0865ec9SKyle Evans int mask = ((i < A->wlen) ? 1 : 0); 259*f0865ec9SKyle Evans notzero |= ((A->val[i] != 0) & mask); 260*f0865ec9SKyle Evans } 261*f0865ec9SKyle Evans 262*f0865ec9SKyle Evans *iszero = !notzero; 263*f0865ec9SKyle Evans 264*f0865ec9SKyle Evans err: 265*f0865ec9SKyle Evans return ret; 266*f0865ec9SKyle Evans } 267*f0865ec9SKyle Evans 268*f0865ec9SKyle Evans /* 269*f0865ec9SKyle Evans * The function tests if given nn value is one. The result of the test is given 270*f0865ec9SKyle Evans * using 'isone' out parameter (1 if nn is one, 0 if it is not). The function 271*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 'isone' is not meaningfull on error. 272*f0865ec9SKyle Evans * When A is valid, check is done *in constant time*. 273*f0865ec9SKyle Evans */ 274*f0865ec9SKyle Evans int nn_isone(nn_src_t A, int *isone) 275*f0865ec9SKyle Evans { 276*f0865ec9SKyle Evans int ret, notone; 277*f0865ec9SKyle Evans u8 i; 278*f0865ec9SKyle Evans 279*f0865ec9SKyle Evans ret = nn_check_initialized(A); EG(ret, err); 280*f0865ec9SKyle Evans MUST_HAVE(!(A->wlen > NN_MAX_WORD_LEN), ret, err); 281*f0865ec9SKyle Evans MUST_HAVE((isone != NULL), ret, err); 282*f0865ec9SKyle Evans 283*f0865ec9SKyle Evans /* val[0] access is ok no matter wlen value */ 284*f0865ec9SKyle Evans notone = (A->val[0] != 1); 285*f0865ec9SKyle Evans for (i = 1; i < NN_MAX_WORD_LEN; i++) { 286*f0865ec9SKyle Evans int mask = ((i < A->wlen) ? 1 : 0); 287*f0865ec9SKyle Evans notone |= ((A->val[i] != 0) & mask); 288*f0865ec9SKyle Evans } 289*f0865ec9SKyle Evans 290*f0865ec9SKyle Evans *isone = !notone; 291*f0865ec9SKyle Evans 292*f0865ec9SKyle Evans err: 293*f0865ec9SKyle Evans return ret; 294*f0865ec9SKyle Evans } 295*f0865ec9SKyle Evans 296*f0865ec9SKyle Evans /* 297*f0865ec9SKyle Evans * The function tests if given nn value is odd. The result of the test is given 298*f0865ec9SKyle Evans * using 'isodd' out parameter (1 if nn is odd, 0 if it is not). The function 299*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 'isodd' is not meaningfull on error. 300*f0865ec9SKyle Evans */ 301*f0865ec9SKyle Evans int nn_isodd(nn_src_t A, int *isodd) 302*f0865ec9SKyle Evans { 303*f0865ec9SKyle Evans int ret; 304*f0865ec9SKyle Evans 305*f0865ec9SKyle Evans ret = nn_check_initialized(A); EG(ret, err); 306*f0865ec9SKyle Evans MUST_HAVE((isodd != NULL), ret, err); 307*f0865ec9SKyle Evans 308*f0865ec9SKyle Evans *isodd = (A->wlen != 0) && (A->val[0] & 1); 309*f0865ec9SKyle Evans 310*f0865ec9SKyle Evans err: 311*f0865ec9SKyle Evans return ret; 312*f0865ec9SKyle Evans } 313*f0865ec9SKyle Evans 314*f0865ec9SKyle Evans /* 315*f0865ec9SKyle Evans * Compare given nn against given word value. This is done *in constant time* 316*f0865ec9SKyle Evans * (only depending on the input length, not on its value or on the word value) 317*f0865ec9SKyle Evans * when provided nn is valid. The function returns 0 on success and provides 318*f0865ec9SKyle Evans * the comparison value in 'cmp' parameter. -1 is returned on error, in which 319*f0865ec9SKyle Evans * case 'cmp' is not meaningful. 320*f0865ec9SKyle Evans */ 321*f0865ec9SKyle Evans int nn_cmp_word(nn_src_t in, word_t w, int *cmp) 322*f0865ec9SKyle Evans { 323*f0865ec9SKyle Evans int ret, tmp = 0; 324*f0865ec9SKyle Evans word_t mask; 325*f0865ec9SKyle Evans u8 i; 326*f0865ec9SKyle Evans 327*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 328*f0865ec9SKyle Evans MUST_HAVE((cmp != NULL), ret, err); 329*f0865ec9SKyle Evans 330*f0865ec9SKyle Evans /* No need to read, we can conclude */ 331*f0865ec9SKyle Evans if (in->wlen == 0) { 332*f0865ec9SKyle Evans *cmp = -(w != 0); 333*f0865ec9SKyle Evans ret = 0; 334*f0865ec9SKyle Evans goto err; 335*f0865ec9SKyle Evans } 336*f0865ec9SKyle Evans 337*f0865ec9SKyle Evans /* 338*f0865ec9SKyle Evans * Let's loop on all words above first one to see if one 339*f0865ec9SKyle Evans * of those is non-zero. 340*f0865ec9SKyle Evans */ 341*f0865ec9SKyle Evans for (i = (u8)(in->wlen - 1); i > 0; i--) { 342*f0865ec9SKyle Evans tmp |= (in->val[i] != 0); 343*f0865ec9SKyle Evans } 344*f0865ec9SKyle Evans 345*f0865ec9SKyle Evans /* 346*f0865ec9SKyle Evans * Compare first word of nn w/ w if needed. This 347*f0865ec9SKyle Evans * is done w/ masking to avoid doing or not doing 348*f0865ec9SKyle Evans * it based on 'tmp' (i.e. fact that a high word 349*f0865ec9SKyle Evans * of nn is not zero). 350*f0865ec9SKyle Evans */ 351*f0865ec9SKyle Evans mask = WORD_MASK_IFZERO(tmp); 352*f0865ec9SKyle Evans tmp += (int)(((word_t)(in->val[i] > w)) & (mask)); 353*f0865ec9SKyle Evans tmp -= (int)(((word_t)(in->val[i] < w)) & (mask)); 354*f0865ec9SKyle Evans *cmp = tmp; 355*f0865ec9SKyle Evans 356*f0865ec9SKyle Evans err: 357*f0865ec9SKyle Evans return ret; 358*f0865ec9SKyle Evans } 359*f0865ec9SKyle Evans 360*f0865ec9SKyle Evans /* 361*f0865ec9SKyle Evans * Compare given two nn 'A' and '. This is done *in constant time* (only 362*f0865ec9SKyle Evans * depending on the largest length of the inputs, not on their values). The 363*f0865ec9SKyle Evans * function returns 0 on success and provides the comparison value in 364*f0865ec9SKyle Evans * 'cmp' parameter (0 if A == B, -1 if A < B, +1 if A > B). -1 is returned 365*f0865ec9SKyle Evans * on error, in which case 'cmp' is not meaningful. 366*f0865ec9SKyle Evans * 367*f0865ec9SKyle Evans * Aliasing of inputs is supported. 368*f0865ec9SKyle Evans */ 369*f0865ec9SKyle Evans int nn_cmp(nn_src_t A, nn_src_t B, int *cmp) 370*f0865ec9SKyle Evans { 371*f0865ec9SKyle Evans int tmp, mask, ret, i; 372*f0865ec9SKyle Evans u8 cmp_len; 373*f0865ec9SKyle Evans 374*f0865ec9SKyle Evans ret = nn_check_initialized(A); EG(ret, err); 375*f0865ec9SKyle Evans ret = nn_check_initialized(B); EG(ret, err); 376*f0865ec9SKyle Evans MUST_HAVE((cmp != NULL), ret, err); 377*f0865ec9SKyle Evans 378*f0865ec9SKyle Evans cmp_len = (A->wlen >= B->wlen) ? A->wlen : B->wlen; 379*f0865ec9SKyle Evans 380*f0865ec9SKyle Evans tmp = 0; 381*f0865ec9SKyle Evans for (i = (cmp_len - 1); i >= 0; i--) { /* ok even if cmp_len is 0 */ 382*f0865ec9SKyle Evans mask = !(tmp & 0x1); 383*f0865ec9SKyle Evans tmp += ((A->val[i] > B->val[i]) & mask); 384*f0865ec9SKyle Evans tmp -= ((A->val[i] < B->val[i]) & mask); 385*f0865ec9SKyle Evans } 386*f0865ec9SKyle Evans (*cmp) = tmp; 387*f0865ec9SKyle Evans 388*f0865ec9SKyle Evans err: 389*f0865ec9SKyle Evans return ret; 390*f0865ec9SKyle Evans } 391*f0865ec9SKyle Evans 392*f0865ec9SKyle Evans /* 393*f0865ec9SKyle Evans * Copy given nn 'src_nn' value into 'dst_nn'. This is done *in constant time*. 394*f0865ec9SKyle Evans * 'dst_nn' must point to a declared nn, but *need not be initialized*; it will 395*f0865ec9SKyle Evans * be (manually) initialized by the function. 'src_nn' must have been 396*f0865ec9SKyle Evans * initialized prior to the call. The function returns 0 on success, -1 on error. 397*f0865ec9SKyle Evans * 398*f0865ec9SKyle Evans * Alising of input and output is supported. 399*f0865ec9SKyle Evans */ 400*f0865ec9SKyle Evans int nn_copy(nn_t dst_nn, nn_src_t src_nn) 401*f0865ec9SKyle Evans { 402*f0865ec9SKyle Evans int ret; 403*f0865ec9SKyle Evans u8 i; 404*f0865ec9SKyle Evans 405*f0865ec9SKyle Evans MUST_HAVE((dst_nn != NULL), ret, err); 406*f0865ec9SKyle Evans ret = nn_check_initialized(src_nn); EG(ret, err); 407*f0865ec9SKyle Evans 408*f0865ec9SKyle Evans for (i = 0; i < NN_MAX_WORD_LEN; i++) { 409*f0865ec9SKyle Evans dst_nn->val[i] = src_nn->val[i]; 410*f0865ec9SKyle Evans } 411*f0865ec9SKyle Evans 412*f0865ec9SKyle Evans dst_nn->wlen = src_nn->wlen; 413*f0865ec9SKyle Evans dst_nn->magic = NN_MAGIC; 414*f0865ec9SKyle Evans 415*f0865ec9SKyle Evans err: 416*f0865ec9SKyle Evans return ret; 417*f0865ec9SKyle Evans } 418*f0865ec9SKyle Evans 419*f0865ec9SKyle Evans /* 420*f0865ec9SKyle Evans * Update wlen value of given nn if a set of words below wlen value are zero. 421*f0865ec9SKyle Evans * The function is *not constant time*, i.e. it depends on the input value. 422*f0865ec9SKyle Evans * The function returns 0 on sucess, -1 on error. 423*f0865ec9SKyle Evans */ 424*f0865ec9SKyle Evans int nn_normalize(nn_t in1) 425*f0865ec9SKyle Evans { 426*f0865ec9SKyle Evans int ret; 427*f0865ec9SKyle Evans 428*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 429*f0865ec9SKyle Evans 430*f0865ec9SKyle Evans while ((in1->wlen > 0) && (in1->val[in1->wlen - 1] == 0)) { 431*f0865ec9SKyle Evans in1->wlen--; 432*f0865ec9SKyle Evans } 433*f0865ec9SKyle Evans 434*f0865ec9SKyle Evans err: 435*f0865ec9SKyle Evans return ret; 436*f0865ec9SKyle Evans } 437*f0865ec9SKyle Evans 438*f0865ec9SKyle Evans /* 439*f0865ec9SKyle Evans * Convert given consecutive WORD_BYTES bytes pointed by 'val' from network (big 440*f0865ec9SKyle Evans * endian) order to host order. 'val' needs not point to a word-aligned region. 441*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. On success, the result is 442*f0865ec9SKyle Evans * provided in 'out'. 'out' is not meaningful on error. 443*f0865ec9SKyle Evans */ 444*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _ntohw(const u8 *val, word_t *out) 445*f0865ec9SKyle Evans { 446*f0865ec9SKyle Evans word_t res = 0; 447*f0865ec9SKyle Evans u8 *res_buf = (u8 *)(&res); 448*f0865ec9SKyle Evans int i, ret; 449*f0865ec9SKyle Evans 450*f0865ec9SKyle Evans MUST_HAVE(((val != NULL) && (out != NULL)), ret, err); 451*f0865ec9SKyle Evans 452*f0865ec9SKyle Evans if (arch_is_big_endian()) { 453*f0865ec9SKyle Evans /* copy bytes, one by one to avoid alignement issues */ 454*f0865ec9SKyle Evans for (i = 0; i < WORD_BYTES; i++) { 455*f0865ec9SKyle Evans res_buf[i] = val[i]; 456*f0865ec9SKyle Evans } 457*f0865ec9SKyle Evans } else { 458*f0865ec9SKyle Evans u8 tmp; 459*f0865ec9SKyle Evans 460*f0865ec9SKyle Evans for (i = 0; i < (WORD_BYTES / 2); i++) { 461*f0865ec9SKyle Evans tmp = val[i]; 462*f0865ec9SKyle Evans res_buf[i] = val[WORD_BYTES - i - 1]; 463*f0865ec9SKyle Evans res_buf[WORD_BYTES - i - 1] = tmp; 464*f0865ec9SKyle Evans } 465*f0865ec9SKyle Evans 466*f0865ec9SKyle Evans VAR_ZEROIFY(tmp); 467*f0865ec9SKyle Evans } 468*f0865ec9SKyle Evans 469*f0865ec9SKyle Evans *out = res; 470*f0865ec9SKyle Evans ret = 0; 471*f0865ec9SKyle Evans 472*f0865ec9SKyle Evans err: 473*f0865ec9SKyle Evans return ret; 474*f0865ec9SKyle Evans } 475*f0865ec9SKyle Evans 476*f0865ec9SKyle Evans /* Same as previous function but from host to network byte order. */ 477*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int _htonw(const u8 *val, word_t *out) 478*f0865ec9SKyle Evans { 479*f0865ec9SKyle Evans return _ntohw(val, out); 480*f0865ec9SKyle Evans } 481*f0865ec9SKyle Evans 482*f0865ec9SKyle Evans /* 483*f0865ec9SKyle Evans * 'out_nn' is expected to point to the storage location of a declared nn, 484*f0865ec9SKyle Evans * which will be initialized by the function (i.e. given nn need not be 485*f0865ec9SKyle Evans * initialized). The function then imports value (expected to be in big 486*f0865ec9SKyle Evans * endian) from given buffer 'buf' of length 'buflen' into it. The function 487*f0865ec9SKyle Evans * expects (and enforces) that buflen is less than or equal to NN_MAX_BYTE_LEN. 488*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 489*f0865ec9SKyle Evans */ 490*f0865ec9SKyle Evans int nn_init_from_buf(nn_t out_nn, const u8 *buf, u16 buflen) 491*f0865ec9SKyle Evans { 492*f0865ec9SKyle Evans u8 tmp[NN_MAX_BYTE_LEN]; 493*f0865ec9SKyle Evans u16 wpos; 494*f0865ec9SKyle Evans int ret; 495*f0865ec9SKyle Evans 496*f0865ec9SKyle Evans MUST_HAVE(((out_nn != NULL) && (buf != NULL) && 497*f0865ec9SKyle Evans (buflen <= NN_MAX_BYTE_LEN)), ret, err); 498*f0865ec9SKyle Evans 499*f0865ec9SKyle Evans ret = local_memset(tmp, 0, (u32)(NN_MAX_BYTE_LEN - buflen)); EG(ret, err); 500*f0865ec9SKyle Evans ret = local_memcpy(tmp + NN_MAX_BYTE_LEN - buflen, buf, buflen); EG(ret, err); 501*f0865ec9SKyle Evans 502*f0865ec9SKyle Evans ret = nn_init(out_nn, buflen); EG(ret, err); 503*f0865ec9SKyle Evans 504*f0865ec9SKyle Evans for (wpos = 0; wpos < NN_MAX_WORD_LEN; wpos++) { 505*f0865ec9SKyle Evans u16 buf_pos = (u16)((NN_MAX_WORD_LEN - wpos - 1) * WORD_BYTES); 506*f0865ec9SKyle Evans ret = _ntohw(tmp + buf_pos, &(out_nn->val[wpos])); EG(ret, err); 507*f0865ec9SKyle Evans } 508*f0865ec9SKyle Evans 509*f0865ec9SKyle Evans ret = local_memset(tmp, 0, NN_MAX_BYTE_LEN); 510*f0865ec9SKyle Evans 511*f0865ec9SKyle Evans err: 512*f0865ec9SKyle Evans return ret; 513*f0865ec9SKyle Evans } 514*f0865ec9SKyle Evans 515*f0865ec9SKyle Evans /* 516*f0865ec9SKyle Evans * Export 'buflen' LSB bytes of given nn as a big endian buffer. If buffer 517*f0865ec9SKyle Evans * length is larger than effective size of input nn, padding w/ zero is 518*f0865ec9SKyle Evans * performed. If buffer size is smaller than input nn effective size, 519*f0865ec9SKyle Evans * MSB bytes are simply lost in exported buffer. The function returns 0 520*f0865ec9SKyle Evans * on success, -1 on error. 521*f0865ec9SKyle Evans */ 522*f0865ec9SKyle Evans int nn_export_to_buf(u8 *buf, u16 buflen, nn_src_t in_nn) 523*f0865ec9SKyle Evans { 524*f0865ec9SKyle Evans u8 *src_word_ptr, *dst_word_ptr; 525*f0865ec9SKyle Evans const u8 wb = WORD_BYTES; 526*f0865ec9SKyle Evans u16 remain = buflen; 527*f0865ec9SKyle Evans int ret; 528*f0865ec9SKyle Evans u8 i; 529*f0865ec9SKyle Evans 530*f0865ec9SKyle Evans MUST_HAVE((buf != NULL), ret, err); 531*f0865ec9SKyle Evans ret = nn_check_initialized(in_nn); EG(ret, err); 532*f0865ec9SKyle Evans 533*f0865ec9SKyle Evans ret = local_memset(buf, 0, buflen); EG(ret, err); 534*f0865ec9SKyle Evans 535*f0865ec9SKyle Evans /* 536*f0865ec9SKyle Evans * We consider each word in input nn one at a time and convert 537*f0865ec9SKyle Evans * it to big endian in a temporary word. Based on remaining 538*f0865ec9SKyle Evans * length of output buffer, we copy the LSB bytes of temporary 539*f0865ec9SKyle Evans * word into it at current position. That way, filling of the 540*f0865ec9SKyle Evans * buffer is performed from its end to its beginning, word by 541*f0865ec9SKyle Evans * word, except for the last one, which may be shorten if 542*f0865ec9SKyle Evans * given buffer length is not a multiple of word length. 543*f0865ec9SKyle Evans */ 544*f0865ec9SKyle Evans for (i = 0; remain && (i < in_nn->wlen); i++) { 545*f0865ec9SKyle Evans u16 copylen = (remain > wb) ? wb : remain; 546*f0865ec9SKyle Evans word_t val; 547*f0865ec9SKyle Evans 548*f0865ec9SKyle Evans ret = _htonw((const u8 *)&in_nn->val[i], &val); EG(ret, err); 549*f0865ec9SKyle Evans 550*f0865ec9SKyle Evans dst_word_ptr = (buf + buflen - (i * wb) - copylen); 551*f0865ec9SKyle Evans src_word_ptr = (u8 *)(&val) + wb - copylen; 552*f0865ec9SKyle Evans 553*f0865ec9SKyle Evans ret = local_memcpy(dst_word_ptr, src_word_ptr, copylen); EG(ret, err); 554*f0865ec9SKyle Evans src_word_ptr = NULL; 555*f0865ec9SKyle Evans 556*f0865ec9SKyle Evans remain = (u16)(remain - copylen); 557*f0865ec9SKyle Evans } 558*f0865ec9SKyle Evans 559*f0865ec9SKyle Evans err: 560*f0865ec9SKyle Evans return ret; 561*f0865ec9SKyle Evans } 562*f0865ec9SKyle Evans 563*f0865ec9SKyle Evans /* 564*f0865ec9SKyle Evans * Given a table 'tab' pointing to a set of 'tabsize' NN elements, the 565*f0865ec9SKyle Evans * function copies the value of element at position idx (idx < tabsize) 566*f0865ec9SKyle Evans * in 'out' parameters. Masking is used to avoid leaking which element 567*f0865ec9SKyle Evans * was copied. 568*f0865ec9SKyle Evans * 569*f0865ec9SKyle Evans * Note that the main copying loop is done on the maximum bits for all 570*f0865ec9SKyle Evans * NN elements and not based on the specific effective size of each 571*f0865ec9SKyle Evans * NN elements in 'tab' 572*f0865ec9SKyle Evans * 573*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 574*f0865ec9SKyle Evans * 575*f0865ec9SKyle Evans * Aliasing of out and the selected element inside the tab is NOT supported. 576*f0865ec9SKyle Evans */ 577*f0865ec9SKyle Evans int nn_tabselect(nn_t out, u8 idx, nn_src_t *tab, u8 tabsize) 578*f0865ec9SKyle Evans { 579*f0865ec9SKyle Evans u8 i, k; 580*f0865ec9SKyle Evans word_t mask; 581*f0865ec9SKyle Evans int ret; 582*f0865ec9SKyle Evans 583*f0865ec9SKyle Evans /* Basic sanity checks */ 584*f0865ec9SKyle Evans MUST_HAVE(((tab != NULL) && (idx < tabsize)), ret, err); 585*f0865ec9SKyle Evans 586*f0865ec9SKyle Evans ret = nn_check_initialized(out); EG(ret, err); 587*f0865ec9SKyle Evans 588*f0865ec9SKyle Evans /* Zeroize out and enforce its size. */ 589*f0865ec9SKyle Evans ret = nn_zero(out); EG(ret, err); 590*f0865ec9SKyle Evans 591*f0865ec9SKyle Evans out->wlen = 0; 592*f0865ec9SKyle Evans 593*f0865ec9SKyle Evans for (k = 0; k < tabsize; k++) { 594*f0865ec9SKyle Evans /* Check current element is initialized */ 595*f0865ec9SKyle Evans ret = nn_check_initialized(tab[k]); EG(ret, err); 596*f0865ec9SKyle Evans 597*f0865ec9SKyle Evans mask = WORD_MASK_IFNOTZERO(idx == k); 598*f0865ec9SKyle Evans 599*f0865ec9SKyle Evans out->wlen = (u8)(out->wlen | ((tab[k]->wlen) & mask)); 600*f0865ec9SKyle Evans 601*f0865ec9SKyle Evans for (i = 0; i < NN_MAX_WORD_LEN; i++) { 602*f0865ec9SKyle Evans out->val[i] |= (tab[k]->val[i] & mask); 603*f0865ec9SKyle Evans } 604*f0865ec9SKyle Evans } 605*f0865ec9SKyle Evans 606*f0865ec9SKyle Evans err: 607*f0865ec9SKyle Evans return ret; 608*f0865ec9SKyle Evans } 609