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 #include <libecc/nn/nn_logical.h> 17*f0865ec9SKyle Evans #include <libecc/nn/nn.h> 18*f0865ec9SKyle Evans 19*f0865ec9SKyle Evans /* 20*f0865ec9SKyle Evans * nn_lshift_fixedlen: left logical shift in N, i.e. compute out = (in << cnt). 21*f0865ec9SKyle Evans * 22*f0865ec9SKyle Evans * Aliasing is possible for 'in' and 'out', i.e. x <<= cnt can be computed 23*f0865ec9SKyle Evans * using nn_lshift_fixedlen(x, x, cnt). 24*f0865ec9SKyle Evans * 25*f0865ec9SKyle Evans * The function supports 'in' and 'out' parameters of differents sizes. 26*f0865ec9SKyle Evans * 27*f0865ec9SKyle Evans * The operation time of the function depends on the size of 'in' and 28*f0865ec9SKyle Evans * 'out' parameters and the value of 'cnt'. It does not depend on the 29*f0865ec9SKyle Evans * value of 'in'. 30*f0865ec9SKyle Evans * 31*f0865ec9SKyle Evans * It is to be noted that the function uses out->wlen as the 32*f0865ec9SKyle Evans * upper limit for its work, i.e. bits shifted above out->wlen 33*f0865ec9SKyle Evans * are lost (the NN size of the output is not modified). 34*f0865ec9SKyle Evans * 35*f0865ec9SKyle Evans * The function returns 0 on sucess, -1 on error. 36*f0865ec9SKyle Evans * 37*f0865ec9SKyle Evans * Aliasing supported. 38*f0865ec9SKyle Evans */ 39*f0865ec9SKyle Evans int nn_lshift_fixedlen(nn_t out, nn_src_t in, bitcnt_t cnt) 40*f0865ec9SKyle Evans { 41*f0865ec9SKyle Evans int ipos, opos, dec, ret; 42*f0865ec9SKyle Evans bitcnt_t lshift, hshift; 43*f0865ec9SKyle Evans u8 owlen, iwlen; 44*f0865ec9SKyle Evans 45*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 46*f0865ec9SKyle Evans ret = nn_check_initialized(out); EG(ret, err); 47*f0865ec9SKyle Evans owlen = out->wlen; 48*f0865ec9SKyle Evans iwlen = in->wlen; 49*f0865ec9SKyle Evans 50*f0865ec9SKyle Evans dec = cnt / WORD_BITS; 51*f0865ec9SKyle Evans hshift = cnt % WORD_BITS; 52*f0865ec9SKyle Evans lshift = (bitcnt_t)(WORD_BITS - hshift); 53*f0865ec9SKyle Evans 54*f0865ec9SKyle Evans for (opos = owlen - 1; opos >= 0; opos--) { 55*f0865ec9SKyle Evans word_t hipart = 0, lopart = 0; 56*f0865ec9SKyle Evans 57*f0865ec9SKyle Evans ipos = opos - dec - 1; 58*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 59*f0865ec9SKyle Evans lopart = WRSHIFT(in->val[ipos], lshift); 60*f0865ec9SKyle Evans } 61*f0865ec9SKyle Evans 62*f0865ec9SKyle Evans ipos = opos - dec; 63*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 64*f0865ec9SKyle Evans hipart = WLSHIFT(in->val[ipos], hshift); 65*f0865ec9SKyle Evans } 66*f0865ec9SKyle Evans 67*f0865ec9SKyle Evans out->val[opos] = hipart | lopart; 68*f0865ec9SKyle Evans } 69*f0865ec9SKyle Evans 70*f0865ec9SKyle Evans err: 71*f0865ec9SKyle Evans return ret; 72*f0865ec9SKyle Evans } 73*f0865ec9SKyle Evans 74*f0865ec9SKyle Evans /* 75*f0865ec9SKyle Evans * nn_lshift: left logical shift in N, i.e. compute out = (in << cnt). 76*f0865ec9SKyle Evans * 77*f0865ec9SKyle Evans * Aliasing is possible for 'in' and 'out', i.e. x <<= cnt can be computed 78*f0865ec9SKyle Evans * using nn_lshift(x, x, cnt). 79*f0865ec9SKyle Evans * 80*f0865ec9SKyle Evans * The function supports 'in' and 'out' parameters of differents sizes. 81*f0865ec9SKyle Evans * 82*f0865ec9SKyle Evans * The operation time of the function depends on the size of 'in' and 83*f0865ec9SKyle Evans * 'out' parameters and the value of 'cnt'. It does not depend on the 84*f0865ec9SKyle Evans * value of 'in'. 85*f0865ec9SKyle Evans * 86*f0865ec9SKyle Evans * It is to be noted that the function computes the output bit length 87*f0865ec9SKyle Evans * depending on the shift count and the input length, i.e. out bit length 88*f0865ec9SKyle Evans * will be roughly in bit length plus cnt, maxed to NN_MAX_BIT_LEN. 89*f0865ec9SKyle Evans * 90*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 91*f0865ec9SKyle Evans * 92*f0865ec9SKyle Evans * Aliasing supported. 93*f0865ec9SKyle Evans */ 94*f0865ec9SKyle Evans int nn_lshift(nn_t out, nn_src_t in, bitcnt_t cnt) 95*f0865ec9SKyle Evans { 96*f0865ec9SKyle Evans bitcnt_t lshift, hshift, blen; 97*f0865ec9SKyle Evans int ipos, opos, dec, ret; 98*f0865ec9SKyle Evans u8 owlen, iwlen; 99*f0865ec9SKyle Evans 100*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 101*f0865ec9SKyle Evans iwlen = in->wlen; 102*f0865ec9SKyle Evans 103*f0865ec9SKyle Evans /* Initialize output if no aliasing is used */ 104*f0865ec9SKyle Evans if (out != in) { 105*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err); 106*f0865ec9SKyle Evans } 107*f0865ec9SKyle Evans 108*f0865ec9SKyle Evans /* Adapt output length accordingly */ 109*f0865ec9SKyle Evans ret = nn_bitlen(in, &blen); EG(ret, err); 110*f0865ec9SKyle Evans owlen = (u8)LOCAL_MIN(BIT_LEN_WORDS(cnt + blen), 111*f0865ec9SKyle Evans BIT_LEN_WORDS(NN_MAX_BIT_LEN)); 112*f0865ec9SKyle Evans out->wlen = owlen; 113*f0865ec9SKyle Evans 114*f0865ec9SKyle Evans dec = cnt / WORD_BITS; 115*f0865ec9SKyle Evans hshift = cnt % WORD_BITS; 116*f0865ec9SKyle Evans lshift = (bitcnt_t)(WORD_BITS - hshift); 117*f0865ec9SKyle Evans 118*f0865ec9SKyle Evans for (opos = owlen - 1; opos >= 0; opos--) { 119*f0865ec9SKyle Evans word_t hipart = 0, lopart = 0; 120*f0865ec9SKyle Evans 121*f0865ec9SKyle Evans ipos = opos - dec - 1; 122*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 123*f0865ec9SKyle Evans lopart = WRSHIFT(in->val[ipos], lshift); 124*f0865ec9SKyle Evans } 125*f0865ec9SKyle Evans 126*f0865ec9SKyle Evans ipos = opos - dec; 127*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 128*f0865ec9SKyle Evans hipart = WLSHIFT(in->val[ipos], hshift); 129*f0865ec9SKyle Evans } 130*f0865ec9SKyle Evans 131*f0865ec9SKyle Evans out->val[opos] = hipart | lopart; 132*f0865ec9SKyle Evans } 133*f0865ec9SKyle Evans 134*f0865ec9SKyle Evans err: 135*f0865ec9SKyle Evans return ret; 136*f0865ec9SKyle Evans } 137*f0865ec9SKyle Evans 138*f0865ec9SKyle Evans /* 139*f0865ec9SKyle Evans * nn_rshift_fixedlen: right logical shift in N, i.e. compute out = (in >> cnt). 140*f0865ec9SKyle Evans * 141*f0865ec9SKyle Evans * Aliasing is possible for 'in' and 'out', i.e. x >>= cnt can be computed 142*f0865ec9SKyle Evans * using nn_rshift_fixedlen(x, x, cnt). 143*f0865ec9SKyle Evans * 144*f0865ec9SKyle Evans * The function supports 'in' and 'out' parameters of differents sizes. 145*f0865ec9SKyle Evans * 146*f0865ec9SKyle Evans * The operation time of the function depends on the size of 'in' and 147*f0865ec9SKyle Evans * 'out' parameters and the value of 'cnt'. It does not depend on the 148*f0865ec9SKyle Evans * value of 'in'. 149*f0865ec9SKyle Evans * It is to be noted that the function uses out->wlen as the 150*f0865ec9SKyle Evans * upper limit for its work, which means zeroes are shifted in while 151*f0865ec9SKyle Evans * keeping the same NN output size. 152*f0865ec9SKyle Evans * 153*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 154*f0865ec9SKyle Evans * 155*f0865ec9SKyle Evans * Aliasing supported. 156*f0865ec9SKyle Evans */ 157*f0865ec9SKyle Evans int nn_rshift_fixedlen(nn_t out, nn_src_t in, bitcnt_t cnt) 158*f0865ec9SKyle Evans { 159*f0865ec9SKyle Evans int ipos, opos, dec, ret; 160*f0865ec9SKyle Evans bitcnt_t lshift, hshift; 161*f0865ec9SKyle Evans u8 owlen, iwlen; 162*f0865ec9SKyle Evans 163*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 164*f0865ec9SKyle Evans ret = nn_check_initialized(out); EG(ret, err); 165*f0865ec9SKyle Evans owlen = out->wlen; 166*f0865ec9SKyle Evans iwlen = in->wlen; 167*f0865ec9SKyle Evans 168*f0865ec9SKyle Evans dec = cnt / WORD_BITS; 169*f0865ec9SKyle Evans lshift = cnt % WORD_BITS; 170*f0865ec9SKyle Evans hshift = (bitcnt_t)(WORD_BITS - lshift); 171*f0865ec9SKyle Evans 172*f0865ec9SKyle Evans for (opos = 0; opos < owlen; opos++) { 173*f0865ec9SKyle Evans word_t hipart = 0, lopart = 0; 174*f0865ec9SKyle Evans 175*f0865ec9SKyle Evans ipos = opos + dec; 176*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 177*f0865ec9SKyle Evans lopart = WRSHIFT(in->val[ipos], lshift); 178*f0865ec9SKyle Evans } 179*f0865ec9SKyle Evans 180*f0865ec9SKyle Evans ipos = opos + dec + 1; 181*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 182*f0865ec9SKyle Evans hipart = WLSHIFT(in->val[ipos], hshift); 183*f0865ec9SKyle Evans } 184*f0865ec9SKyle Evans 185*f0865ec9SKyle Evans out->val[opos] = hipart | lopart; 186*f0865ec9SKyle Evans } 187*f0865ec9SKyle Evans 188*f0865ec9SKyle Evans err: 189*f0865ec9SKyle Evans return ret; 190*f0865ec9SKyle Evans } 191*f0865ec9SKyle Evans 192*f0865ec9SKyle Evans /* 193*f0865ec9SKyle Evans * nn_rshift: right logical shift in N, i.e. compute out = (in >> cnt). 194*f0865ec9SKyle Evans * 195*f0865ec9SKyle Evans * Aliasing is possible for 'in' and 'out', i.e. x >>= cnt can be computed 196*f0865ec9SKyle Evans * using nn_rshift_fixedlen(x, x, cnt). 197*f0865ec9SKyle Evans * 198*f0865ec9SKyle Evans * The function supports 'in' and 'out' parameters of differents sizes. 199*f0865ec9SKyle Evans * 200*f0865ec9SKyle Evans * The operation time of the function depends on the size of 'in' and 201*f0865ec9SKyle Evans * 'out' parameters and the value of 'cnt'. It does not depend on the 202*f0865ec9SKyle Evans * value of 'in'. 203*f0865ec9SKyle Evans * It is to be noted that the function adapts the output size to 204*f0865ec9SKyle Evans * the input size and the shift bit count, i.e. out bit lenth is roughly 205*f0865ec9SKyle Evans * equal to input bit length minus cnt. 206*f0865ec9SKyle Evans * 207*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 208*f0865ec9SKyle Evans * 209*f0865ec9SKyle Evans * Aliasing supported. 210*f0865ec9SKyle Evans */ 211*f0865ec9SKyle Evans int nn_rshift(nn_t out, nn_src_t in, bitcnt_t cnt) 212*f0865ec9SKyle Evans { 213*f0865ec9SKyle Evans int ipos, opos, dec, ret; 214*f0865ec9SKyle Evans bitcnt_t lshift, hshift; 215*f0865ec9SKyle Evans u8 owlen, iwlen; 216*f0865ec9SKyle Evans bitcnt_t blen; 217*f0865ec9SKyle Evans 218*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 219*f0865ec9SKyle Evans iwlen = in->wlen; 220*f0865ec9SKyle Evans /* Initialize output if no aliasing is used */ 221*f0865ec9SKyle Evans if (out != in) { 222*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err); 223*f0865ec9SKyle Evans } 224*f0865ec9SKyle Evans 225*f0865ec9SKyle Evans dec = cnt / WORD_BITS; 226*f0865ec9SKyle Evans lshift = cnt % WORD_BITS; 227*f0865ec9SKyle Evans hshift = (bitcnt_t)(WORD_BITS - lshift); 228*f0865ec9SKyle Evans 229*f0865ec9SKyle Evans /* Adapt output length accordingly */ 230*f0865ec9SKyle Evans ret = nn_bitlen(in, &blen); EG(ret, err); 231*f0865ec9SKyle Evans if (cnt > blen) { 232*f0865ec9SKyle Evans owlen = 0; 233*f0865ec9SKyle Evans } else { 234*f0865ec9SKyle Evans owlen = (u8)BIT_LEN_WORDS(blen - cnt); 235*f0865ec9SKyle Evans } 236*f0865ec9SKyle Evans /* Adapt output length in out */ 237*f0865ec9SKyle Evans out->wlen = owlen; 238*f0865ec9SKyle Evans 239*f0865ec9SKyle Evans for (opos = 0; opos < owlen; opos++) { 240*f0865ec9SKyle Evans word_t hipart = 0, lopart = 0; 241*f0865ec9SKyle Evans 242*f0865ec9SKyle Evans ipos = opos + dec; 243*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 244*f0865ec9SKyle Evans lopart = WRSHIFT(in->val[ipos], lshift); 245*f0865ec9SKyle Evans } 246*f0865ec9SKyle Evans 247*f0865ec9SKyle Evans ipos = opos + dec + 1; 248*f0865ec9SKyle Evans if ((ipos >= 0) && (ipos < iwlen)) { 249*f0865ec9SKyle Evans hipart = WLSHIFT(in->val[ipos], hshift); 250*f0865ec9SKyle Evans } 251*f0865ec9SKyle Evans 252*f0865ec9SKyle Evans out->val[opos] = hipart | lopart; 253*f0865ec9SKyle Evans } 254*f0865ec9SKyle Evans 255*f0865ec9SKyle Evans /* 256*f0865ec9SKyle Evans * Zero the output upper part now that we don't need it anymore 257*f0865ec9SKyle Evans * NB: as we cannot use our normalize helper here (since a consistency 258*f0865ec9SKyle Evans * check is done on wlen and upper part), we have to do this manually 259*f0865ec9SKyle Evans */ 260*f0865ec9SKyle Evans for (opos = owlen; opos < NN_MAX_WORD_LEN; opos++) { 261*f0865ec9SKyle Evans out->val[opos] = 0; 262*f0865ec9SKyle Evans } 263*f0865ec9SKyle Evans 264*f0865ec9SKyle Evans err: 265*f0865ec9SKyle Evans return ret; 266*f0865ec9SKyle Evans } 267*f0865ec9SKyle Evans 268*f0865ec9SKyle Evans /* 269*f0865ec9SKyle Evans * This function right rotates the input NN value by the value 'cnt' on the 270*f0865ec9SKyle Evans * bitlen basis. The function does it in the following way; right rotation 271*f0865ec9SKyle Evans * of x by cnt is "simply": (x >> cnt) ^ (x << (bitlen - cnt)) 272*f0865ec9SKyle Evans * 273*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 274*f0865ec9SKyle Evans * 275*f0865ec9SKyle Evans * Aliasing supported. 276*f0865ec9SKyle Evans */ 277*f0865ec9SKyle Evans int nn_rrot(nn_t out, nn_src_t in, bitcnt_t cnt, bitcnt_t bitlen) 278*f0865ec9SKyle Evans { 279*f0865ec9SKyle Evans u8 owlen = (u8)BIT_LEN_WORDS(bitlen); 280*f0865ec9SKyle Evans int ret; 281*f0865ec9SKyle Evans nn tmp; 282*f0865ec9SKyle Evans tmp.magic = WORD(0); 283*f0865ec9SKyle Evans 284*f0865ec9SKyle Evans MUST_HAVE((bitlen <= NN_MAX_BIT_LEN), ret, err); 285*f0865ec9SKyle Evans MUST_HAVE((cnt < bitlen), ret, err); 286*f0865ec9SKyle Evans 287*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 288*f0865ec9SKyle Evans ret = nn_init(&tmp, 0); EG(ret, err); 289*f0865ec9SKyle Evans ret = nn_lshift(&tmp, in, (bitcnt_t)(bitlen - cnt)); EG(ret, err); 290*f0865ec9SKyle Evans ret = nn_set_wlen(&tmp, owlen); EG(ret, err); 291*f0865ec9SKyle Evans ret = nn_rshift(out, in, cnt); EG(ret, err); 292*f0865ec9SKyle Evans ret = nn_set_wlen(out, owlen); EG(ret, err); 293*f0865ec9SKyle Evans ret = nn_xor(out, out, &tmp); EG(ret, err); 294*f0865ec9SKyle Evans 295*f0865ec9SKyle Evans /* Mask the last word if necessary */ 296*f0865ec9SKyle Evans if (((bitlen % WORD_BITS) != 0) && (out->wlen > 0)) { 297*f0865ec9SKyle Evans /* shift operation below is ok (less than WORD_BITS) */ 298*f0865ec9SKyle Evans word_t mask = (word_t)(((word_t)(WORD(1) << (bitlen % WORD_BITS))) - 1); 299*f0865ec9SKyle Evans out->val[out->wlen - 1] &= mask; 300*f0865ec9SKyle Evans } 301*f0865ec9SKyle Evans 302*f0865ec9SKyle Evans err: 303*f0865ec9SKyle Evans nn_uninit(&tmp); 304*f0865ec9SKyle Evans 305*f0865ec9SKyle Evans return ret; 306*f0865ec9SKyle Evans } 307*f0865ec9SKyle Evans 308*f0865ec9SKyle Evans /* 309*f0865ec9SKyle Evans * This function left rotates the input NN value by the value 'cnt' on the 310*f0865ec9SKyle Evans * bitlen basis. The function does it in the following way; Left rotation 311*f0865ec9SKyle Evans * of x by cnt is "simply": (x << cnt) ^ (x >> (bitlen - cnt)) 312*f0865ec9SKyle Evans * 313*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 314*f0865ec9SKyle Evans * 315*f0865ec9SKyle Evans * Aliasing supported. 316*f0865ec9SKyle Evans */ 317*f0865ec9SKyle Evans int nn_lrot(nn_t out, nn_src_t in, bitcnt_t cnt, bitcnt_t bitlen) 318*f0865ec9SKyle Evans { 319*f0865ec9SKyle Evans u8 owlen = (u8)BIT_LEN_WORDS(bitlen); 320*f0865ec9SKyle Evans int ret; 321*f0865ec9SKyle Evans nn tmp; 322*f0865ec9SKyle Evans tmp.magic = WORD(0); 323*f0865ec9SKyle Evans 324*f0865ec9SKyle Evans MUST_HAVE(!(bitlen > NN_MAX_BIT_LEN), ret, err); 325*f0865ec9SKyle Evans MUST_HAVE(!(cnt >= bitlen), ret, err); 326*f0865ec9SKyle Evans 327*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 328*f0865ec9SKyle Evans ret = nn_init(&tmp, 0); EG(ret, err); 329*f0865ec9SKyle Evans ret = nn_lshift(&tmp, in, cnt); EG(ret, err); 330*f0865ec9SKyle Evans ret = nn_set_wlen(&tmp, owlen); EG(ret, err); 331*f0865ec9SKyle Evans ret = nn_rshift(out, in, (bitcnt_t)(bitlen - cnt)); EG(ret, err); 332*f0865ec9SKyle Evans ret = nn_set_wlen(out, owlen); EG(ret, err); 333*f0865ec9SKyle Evans ret = nn_xor(out, out, &tmp); EG(ret, err); 334*f0865ec9SKyle Evans 335*f0865ec9SKyle Evans /* Mask the last word if necessary */ 336*f0865ec9SKyle Evans if (((bitlen % WORD_BITS) != 0) && (out->wlen > 0)) { 337*f0865ec9SKyle Evans word_t mask = (word_t)(((word_t)(WORD(1) << (bitlen % WORD_BITS))) - 1); 338*f0865ec9SKyle Evans out->val[out->wlen - 1] &= mask; 339*f0865ec9SKyle Evans } 340*f0865ec9SKyle Evans 341*f0865ec9SKyle Evans err: 342*f0865ec9SKyle Evans nn_uninit(&tmp); 343*f0865ec9SKyle Evans 344*f0865ec9SKyle Evans return ret; 345*f0865ec9SKyle Evans } 346*f0865ec9SKyle Evans 347*f0865ec9SKyle Evans /* 348*f0865ec9SKyle Evans * Compute XOR between B and C and put the result in A. B and C must be 349*f0865ec9SKyle Evans * initialized. Aliasing is supported, i.e. A can be one of the parameter B or 350*f0865ec9SKyle Evans * C. If aliasing is not used, A will be initialized by the function. Function 351*f0865ec9SKyle Evans * execution time depends on the word length of larger parameter but not on its 352*f0865ec9SKyle Evans * particular value. 353*f0865ec9SKyle Evans * 354*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 355*f0865ec9SKyle Evans * 356*f0865ec9SKyle Evans * Aliasing supported. 357*f0865ec9SKyle Evans */ 358*f0865ec9SKyle Evans int nn_xor(nn_t A, nn_src_t B, nn_src_t C) 359*f0865ec9SKyle Evans { 360*f0865ec9SKyle Evans int ret; 361*f0865ec9SKyle Evans u8 i; 362*f0865ec9SKyle Evans 363*f0865ec9SKyle Evans ret = nn_check_initialized(B); EG(ret, err); 364*f0865ec9SKyle Evans ret = nn_check_initialized(C); EG(ret, err); 365*f0865ec9SKyle Evans 366*f0865ec9SKyle Evans /* Initialize the output if no aliasing is used */ 367*f0865ec9SKyle Evans if ((A != B) && (A != C)) { 368*f0865ec9SKyle Evans ret = nn_init(A, 0); EG(ret, err); 369*f0865ec9SKyle Evans } 370*f0865ec9SKyle Evans 371*f0865ec9SKyle Evans /* Set output wlen accordingly */ 372*f0865ec9SKyle Evans A->wlen = (C->wlen < B->wlen) ? B->wlen : C->wlen; 373*f0865ec9SKyle Evans 374*f0865ec9SKyle Evans for (i = 0; i < A->wlen; i++) { 375*f0865ec9SKyle Evans A->val[i] = (B->val[i] ^ C->val[i]); 376*f0865ec9SKyle Evans } 377*f0865ec9SKyle Evans 378*f0865ec9SKyle Evans err: 379*f0865ec9SKyle Evans return ret; 380*f0865ec9SKyle Evans } 381*f0865ec9SKyle Evans 382*f0865ec9SKyle Evans /* 383*f0865ec9SKyle Evans * Compute logical OR between B and C and put the result in A. B and C must be 384*f0865ec9SKyle Evans * initialized. Aliasing is supported, i.e. A can be one of the parameter B or 385*f0865ec9SKyle Evans * C. If aliasing is not used, A will be initialized by the function. Function 386*f0865ec9SKyle Evans * execution time depends on the word length of larger parameter but not on its 387*f0865ec9SKyle Evans * particular value. 388*f0865ec9SKyle Evans * 389*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 390*f0865ec9SKyle Evans * 391*f0865ec9SKyle Evans * Aliasing supported. 392*f0865ec9SKyle Evans */ 393*f0865ec9SKyle Evans int nn_or(nn_t A, nn_src_t B, nn_src_t C) 394*f0865ec9SKyle Evans { 395*f0865ec9SKyle Evans int ret; 396*f0865ec9SKyle Evans u8 i; 397*f0865ec9SKyle Evans 398*f0865ec9SKyle Evans ret = nn_check_initialized(B); EG(ret, err); 399*f0865ec9SKyle Evans ret = nn_check_initialized(C); EG(ret, err); 400*f0865ec9SKyle Evans 401*f0865ec9SKyle Evans /* Initialize the output if no aliasing is used */ 402*f0865ec9SKyle Evans if ((A != B) && (A != C)) { 403*f0865ec9SKyle Evans ret = nn_init(A, 0); EG(ret, err); 404*f0865ec9SKyle Evans } 405*f0865ec9SKyle Evans 406*f0865ec9SKyle Evans /* Set output wlen accordingly */ 407*f0865ec9SKyle Evans A->wlen = (C->wlen < B->wlen) ? B->wlen : C->wlen; 408*f0865ec9SKyle Evans 409*f0865ec9SKyle Evans for (i = 0; i < A->wlen; i++) { 410*f0865ec9SKyle Evans A->val[i] = (B->val[i] | C->val[i]); 411*f0865ec9SKyle Evans } 412*f0865ec9SKyle Evans 413*f0865ec9SKyle Evans err: 414*f0865ec9SKyle Evans return ret; 415*f0865ec9SKyle Evans } 416*f0865ec9SKyle Evans 417*f0865ec9SKyle Evans /* 418*f0865ec9SKyle Evans * Compute logical AND between B and C and put the result in A. B and C must be 419*f0865ec9SKyle Evans * initialized. Aliasing is supported, i.e. A can be one of the parameter B or 420*f0865ec9SKyle Evans * C. If aliasing is not used, A will be initialized by the function. Function 421*f0865ec9SKyle Evans * execution time depends on the word length of larger parameter but not on its 422*f0865ec9SKyle Evans * particular value. 423*f0865ec9SKyle Evans * 424*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 425*f0865ec9SKyle Evans * 426*f0865ec9SKyle Evans * Aliasing supported. 427*f0865ec9SKyle Evans */ 428*f0865ec9SKyle Evans int nn_and(nn_t A, nn_src_t B, nn_src_t C) 429*f0865ec9SKyle Evans { 430*f0865ec9SKyle Evans int ret; 431*f0865ec9SKyle Evans u8 i; 432*f0865ec9SKyle Evans 433*f0865ec9SKyle Evans ret = nn_check_initialized(B); EG(ret, err); 434*f0865ec9SKyle Evans ret = nn_check_initialized(C); EG(ret, err); 435*f0865ec9SKyle Evans 436*f0865ec9SKyle Evans /* Initialize the output if no aliasing is used */ 437*f0865ec9SKyle Evans if ((A != B) && (A != C)) { 438*f0865ec9SKyle Evans ret = nn_init(A, 0); EG(ret, err); 439*f0865ec9SKyle Evans } 440*f0865ec9SKyle Evans 441*f0865ec9SKyle Evans /* Set output wlen accordingly */ 442*f0865ec9SKyle Evans A->wlen = (C->wlen < B->wlen) ? B->wlen : C->wlen; 443*f0865ec9SKyle Evans 444*f0865ec9SKyle Evans for (i = 0; i < A->wlen; i++) { 445*f0865ec9SKyle Evans A->val[i] = (B->val[i] & C->val[i]); 446*f0865ec9SKyle Evans } 447*f0865ec9SKyle Evans 448*f0865ec9SKyle Evans err: 449*f0865ec9SKyle Evans return ret; 450*f0865ec9SKyle Evans } 451*f0865ec9SKyle Evans 452*f0865ec9SKyle Evans /* 453*f0865ec9SKyle Evans * Compute logical NOT of B and put the result in A. B must be initialized. 454*f0865ec9SKyle Evans * Aliasing is supported. If aliasing is not used, A will be initialized by 455*f0865ec9SKyle Evans * the function. 456*f0865ec9SKyle Evans * 457*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 458*f0865ec9SKyle Evans * 459*f0865ec9SKyle Evans * Aliasing supported. 460*f0865ec9SKyle Evans */ 461*f0865ec9SKyle Evans int nn_not(nn_t A, nn_src_t B) 462*f0865ec9SKyle Evans { 463*f0865ec9SKyle Evans int ret; 464*f0865ec9SKyle Evans u8 i; 465*f0865ec9SKyle Evans 466*f0865ec9SKyle Evans ret = nn_check_initialized(B); EG(ret, err); 467*f0865ec9SKyle Evans 468*f0865ec9SKyle Evans /* Initialize the output if no aliasing is used */ 469*f0865ec9SKyle Evans if (A != B) { 470*f0865ec9SKyle Evans ret = nn_init(A, 0); EG(ret, err); 471*f0865ec9SKyle Evans } 472*f0865ec9SKyle Evans 473*f0865ec9SKyle Evans /* Set output wlen accordingly */ 474*f0865ec9SKyle Evans A->wlen = B->wlen; 475*f0865ec9SKyle Evans 476*f0865ec9SKyle Evans for (i = 0; i < A->wlen; i++) { 477*f0865ec9SKyle Evans A->val[i] = (word_t)(~(B->val[i])); 478*f0865ec9SKyle Evans } 479*f0865ec9SKyle Evans 480*f0865ec9SKyle Evans err: 481*f0865ec9SKyle Evans return ret; 482*f0865ec9SKyle Evans } 483*f0865ec9SKyle Evans 484*f0865ec9SKyle Evans /* Count leading zeros of a word. This is constant time */ 485*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static u8 wclz(word_t A) 486*f0865ec9SKyle Evans { 487*f0865ec9SKyle Evans u8 cnt = WORD_BITS, over = 0; 488*f0865ec9SKyle Evans int i; 489*f0865ec9SKyle Evans 490*f0865ec9SKyle Evans for (i = (WORD_BITS - 1); i >= 0; i--) { 491*f0865ec9SKyle Evans /* i is less than WORD_BITS so shift operations below are ok */ 492*f0865ec9SKyle Evans u8 mask = (u8)(((A & (WORD(1) << i)) >> i) & 0x1); 493*f0865ec9SKyle Evans over |= mask; 494*f0865ec9SKyle Evans cnt = (u8)(cnt - over); 495*f0865ec9SKyle Evans } 496*f0865ec9SKyle Evans 497*f0865ec9SKyle Evans return cnt; 498*f0865ec9SKyle Evans } 499*f0865ec9SKyle Evans 500*f0865ec9SKyle Evans /* 501*f0865ec9SKyle Evans * Count leading zeros of an initialized nn. This is NOT constant time. The 502*f0865ec9SKyle Evans * function returns 0 on success, -1 on error. On success, the number of 503*f0865ec9SKyle Evans * leading zeroes is available in 'lz'. 'lz' is not meaningful on error. 504*f0865ec9SKyle Evans */ 505*f0865ec9SKyle Evans int nn_clz(nn_src_t in, bitcnt_t *lz) 506*f0865ec9SKyle Evans { 507*f0865ec9SKyle Evans bitcnt_t cnt = 0; 508*f0865ec9SKyle Evans int ret; 509*f0865ec9SKyle Evans u8 i; 510*f0865ec9SKyle Evans 511*f0865ec9SKyle Evans /* Sanity check */ 512*f0865ec9SKyle Evans MUST_HAVE((lz != NULL), ret, err); 513*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 514*f0865ec9SKyle Evans 515*f0865ec9SKyle Evans for (i = in->wlen; i > 0; i--) { 516*f0865ec9SKyle Evans if (in->val[i - 1] == 0) { 517*f0865ec9SKyle Evans cnt = (bitcnt_t)(cnt + WORD_BITS); 518*f0865ec9SKyle Evans } else { 519*f0865ec9SKyle Evans cnt = (bitcnt_t)(cnt + wclz(in->val[i - 1])); 520*f0865ec9SKyle Evans break; 521*f0865ec9SKyle Evans } 522*f0865ec9SKyle Evans } 523*f0865ec9SKyle Evans *lz = cnt; 524*f0865ec9SKyle Evans 525*f0865ec9SKyle Evans err: 526*f0865ec9SKyle Evans return ret; 527*f0865ec9SKyle Evans } 528*f0865ec9SKyle Evans 529*f0865ec9SKyle Evans /* 530*f0865ec9SKyle Evans * Compute bit length of given nn. This is NOT constant-time. The 531*f0865ec9SKyle Evans * function returns 0 on success, -1 on error. On success, the bit length 532*f0865ec9SKyle Evans * of 'in' is available in 'blen'. 'blen' is not meaningful on error. 533*f0865ec9SKyle Evans */ 534*f0865ec9SKyle Evans int nn_bitlen(nn_src_t in, bitcnt_t *blen) 535*f0865ec9SKyle Evans { 536*f0865ec9SKyle Evans bitcnt_t _blen = 0; 537*f0865ec9SKyle Evans int ret; 538*f0865ec9SKyle Evans u8 i; 539*f0865ec9SKyle Evans 540*f0865ec9SKyle Evans /* Sanity check */ 541*f0865ec9SKyle Evans MUST_HAVE((blen != NULL), ret, err); 542*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 543*f0865ec9SKyle Evans 544*f0865ec9SKyle Evans for (i = in->wlen; i > 0; i--) { 545*f0865ec9SKyle Evans if (in->val[i - 1] != 0) { 546*f0865ec9SKyle Evans _blen = (bitcnt_t)((i * WORD_BITS) - wclz(in->val[i - 1])); 547*f0865ec9SKyle Evans break; 548*f0865ec9SKyle Evans } 549*f0865ec9SKyle Evans } 550*f0865ec9SKyle Evans (*blen) = _blen; 551*f0865ec9SKyle Evans 552*f0865ec9SKyle Evans err: 553*f0865ec9SKyle Evans return ret; 554*f0865ec9SKyle Evans } 555*f0865ec9SKyle Evans 556*f0865ec9SKyle Evans /* 557*f0865ec9SKyle Evans * On success (return value is 0), the function provides via 'bitval' the value 558*f0865ec9SKyle Evans * of the bit at position 'bit' in 'in' nn. 'bitval' in not meaningful error 559*f0865ec9SKyle Evans * (when return value is -1). 560*f0865ec9SKyle Evans */ 561*f0865ec9SKyle Evans int nn_getbit(nn_src_t in, bitcnt_t bit, u8 *bitval) 562*f0865ec9SKyle Evans { 563*f0865ec9SKyle Evans bitcnt_t widx = bit / WORD_BITS; 564*f0865ec9SKyle Evans u8 bidx = bit % WORD_BITS; 565*f0865ec9SKyle Evans int ret; 566*f0865ec9SKyle Evans 567*f0865ec9SKyle Evans /* Sanity check */ 568*f0865ec9SKyle Evans MUST_HAVE((bitval != NULL), ret, err); 569*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 570*f0865ec9SKyle Evans MUST_HAVE((bit < NN_MAX_BIT_LEN), ret, err); 571*f0865ec9SKyle Evans 572*f0865ec9SKyle Evans /* bidx is less than WORD_BITS so shift operations below are ok */ 573*f0865ec9SKyle Evans (*bitval) = (u8)((((in->val[widx]) & (WORD(1) << bidx)) >> bidx) & 0x1); 574*f0865ec9SKyle Evans 575*f0865ec9SKyle Evans err: 576*f0865ec9SKyle Evans return ret; 577*f0865ec9SKyle Evans } 578