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_add.h> 17*f0865ec9SKyle Evans #include <libecc/nn/nn.h> 18*f0865ec9SKyle Evans 19*f0865ec9SKyle Evans /* 20*f0865ec9SKyle Evans * This module provides conditional addition and subtraction functions between 21*f0865ec9SKyle Evans * two nn: 22*f0865ec9SKyle Evans * 23*f0865ec9SKyle Evans * o out = in1 +/- in2 if cnd is not zero. 24*f0865ec9SKyle Evans * o out = in1 if cnd is zero. 25*f0865ec9SKyle Evans * 26*f0865ec9SKyle Evans * The time taken by the operation does not depend on cnd value, i.e. it is 27*f0865ec9SKyle Evans * constant time for that specific factor, nor on the values of in1 and in2. 28*f0865ec9SKyle Evans * It still depends on the maximal length of in1 and in2. 29*f0865ec9SKyle Evans * 30*f0865ec9SKyle Evans * Common addition and subtraction functions are derived from those conditional 31*f0865ec9SKyle Evans * versions. 32*f0865ec9SKyle Evans */ 33*f0865ec9SKyle Evans 34*f0865ec9SKyle Evans /* 35*f0865ec9SKyle Evans * Conditionally adds 'in2' to 'in1' according to "cnd", storing the result 36*f0865ec9SKyle Evans * in "out" and returning the carry in 'carry' parameter on success. This 37*f0865ec9SKyle Evans * is the lowest level function for conditional addition. The function 38*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 39*f0865ec9SKyle Evans * 40*f0865ec9SKyle Evans * Note that unlike "usual" addition, the function is *in general* not 41*f0865ec9SKyle Evans * commutative, i.e. "_nn_cnd_add(cnd, out, in1, in2)" is not equivalent 42*f0865ec9SKyle Evans * to "_nn_cnd_add(cnd, out, in2, in1)". It is commutative though if "cnd" 43*f0865ec9SKyle Evans * is not zero or 'in1' == 'in2'. 44*f0865ec9SKyle Evans * 45*f0865ec9SKyle Evans * Aliasing of inputs and output is possible. "out" is initialized if needed, 46*f0865ec9SKyle Evans * that is if not aliased to 'in1' or 'in2'. The length of "out" is set to 47*f0865ec9SKyle Evans * the maximal length of 'in1' and 'in2'. Note that both 'in1' and 'in2' will 48*f0865ec9SKyle Evans * be read to this maximal length. As our memory managment model assumes that 49*f0865ec9SKyle Evans * storage arrays only contains zeros past the "wlen" index, correct results 50*f0865ec9SKyle Evans * will be produced. The length of 'out' is not normalized on return. 51*f0865ec9SKyle Evans * 52*f0865ec9SKyle Evans * The runtime of this function should not depend on: 53*f0865ec9SKyle Evans * o the value of "cnd", 54*f0865ec9SKyle Evans * o the data stored in 'in1' and 'in2'. 55*f0865ec9SKyle Evans * It depends on: 56*f0865ec9SKyle Evans * o the maximal length of 'in1' and 'in2'. 57*f0865ec9SKyle Evans * 58*f0865ec9SKyle Evans * This function is for internal use only. 59*f0865ec9SKyle Evans */ 60*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _nn_cnd_add(int cnd, nn_t out, nn_src_t in1, nn_src_t in2, 61*f0865ec9SKyle Evans word_t *carry) 62*f0865ec9SKyle Evans { 63*f0865ec9SKyle Evans word_t tmp, carry1, carry2, _carry = WORD(0); 64*f0865ec9SKyle Evans word_t mask = WORD_MASK_IFNOTZERO(cnd); 65*f0865ec9SKyle Evans u8 i, loop_wlen; 66*f0865ec9SKyle Evans int ret; 67*f0865ec9SKyle Evans 68*f0865ec9SKyle Evans MUST_HAVE((carry != NULL), ret, err); 69*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 70*f0865ec9SKyle Evans ret = nn_check_initialized(in2); EG(ret, err); 71*f0865ec9SKyle Evans 72*f0865ec9SKyle Evans /* Handle aliasing */ 73*f0865ec9SKyle Evans loop_wlen = LOCAL_MAX(in1->wlen, in2->wlen); 74*f0865ec9SKyle Evans if ((out != in1) && (out != in2)) { 75*f0865ec9SKyle Evans ret = nn_init(out, (u16)(loop_wlen * WORD_BYTES)); EG(ret, err); 76*f0865ec9SKyle Evans } else { 77*f0865ec9SKyle Evans ret = nn_set_wlen(out, loop_wlen); EG(ret, err); 78*f0865ec9SKyle Evans } 79*f0865ec9SKyle Evans 80*f0865ec9SKyle Evans /* Perform addition one word at a time, propagating the carry. */ 81*f0865ec9SKyle Evans for (i = 0; i < loop_wlen; i++) { 82*f0865ec9SKyle Evans tmp = (word_t)(in1->val[i] + (in2->val[i] & mask)); 83*f0865ec9SKyle Evans carry1 = (word_t)(tmp < in1->val[i]); 84*f0865ec9SKyle Evans out->val[i] = (word_t)(tmp + _carry); 85*f0865ec9SKyle Evans carry2 = (word_t)(out->val[i] < tmp); 86*f0865ec9SKyle Evans /* There is at most one carry going out. */ 87*f0865ec9SKyle Evans _carry = (word_t)(carry1 | carry2); 88*f0865ec9SKyle Evans } 89*f0865ec9SKyle Evans 90*f0865ec9SKyle Evans (*carry) = _carry; 91*f0865ec9SKyle Evans 92*f0865ec9SKyle Evans err: 93*f0865ec9SKyle Evans return ret; 94*f0865ec9SKyle Evans } 95*f0865ec9SKyle Evans 96*f0865ec9SKyle Evans /* 97*f0865ec9SKyle Evans * Conditionally adds 'in2' to 'in1' according to "cnd", storing the result 98*f0865ec9SKyle Evans * in "out", including the potential carry overflowing past the maximal 99*f0865ec9SKyle Evans * length of 'in1' and 'in2'. It is user responsibility to ensure that the 100*f0865ec9SKyle Evans * resulting nn will not be higher than what can be supported. This is 101*f0865ec9SKyle Evans * for instance guaranteed if both in1->wlen and in2->wlen are less than 102*f0865ec9SKyle Evans * NN_MAX_WORD_LEN. Otherwise the function will error out which could leak 103*f0865ec9SKyle Evans * information. 104*f0865ec9SKyle Evans * 105*f0865ec9SKyle Evans * Note that the length of the output depends the lengths of the inputs, 106*f0865ec9SKyle Evans * but also on their values. 107*f0865ec9SKyle Evans * It is the user responsibility to use this function carefully when 108*f0865ec9SKyle Evans * constant time of an algorithm using this function is seeked. 109*f0865ec9SKyle Evans * This choice was preferred above unconditionally increasing 110*f0865ec9SKyle Evans * the length of the output by one, to ease the management of length 111*f0865ec9SKyle Evans * explosion when multiple additions are performed. 112*f0865ec9SKyle Evans * For finer carry propagation and length control the internal "_nn_cnd_add" 113*f0865ec9SKyle Evans * function can be used. 114*f0865ec9SKyle Evans * 115*f0865ec9SKyle Evans * See "_nn_cnd_add" documentation above for further details. 116*f0865ec9SKyle Evans * 117*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 118*f0865ec9SKyle Evans */ 119*f0865ec9SKyle Evans int nn_cnd_add(int cnd, nn_t out, nn_src_t in1, nn_src_t in2) 120*f0865ec9SKyle Evans { 121*f0865ec9SKyle Evans word_t carry; 122*f0865ec9SKyle Evans int ret; 123*f0865ec9SKyle Evans 124*f0865ec9SKyle Evans ret = _nn_cnd_add(cnd, out, in1, in2, &carry); EG(ret, err); 125*f0865ec9SKyle Evans 126*f0865ec9SKyle Evans /* We cannot allow a non-zero carry if out->wlen is at its limit */ 127*f0865ec9SKyle Evans MUST_HAVE(((out->wlen != NN_MAX_WORD_LEN) || (!carry)), ret, err); 128*f0865ec9SKyle Evans 129*f0865ec9SKyle Evans if (out->wlen != NN_MAX_WORD_LEN) { 130*f0865ec9SKyle Evans /* 131*f0865ec9SKyle Evans * To maintain constant time, we perform carry addition in all 132*f0865ec9SKyle Evans * cases. If carry is 0, no change is performed in practice, 133*f0865ec9SKyle Evans * neither to 'out' value, nor to its length. 134*f0865ec9SKyle Evans * Note that the length of the output can vary and make 135*f0865ec9SKyle Evans * the time taken by further operations on it also vary. 136*f0865ec9SKyle Evans */ 137*f0865ec9SKyle Evans out->val[out->wlen] = carry; 138*f0865ec9SKyle Evans out->wlen = (u8)(out->wlen + carry); 139*f0865ec9SKyle Evans } 140*f0865ec9SKyle Evans 141*f0865ec9SKyle Evans err: 142*f0865ec9SKyle Evans return ret; 143*f0865ec9SKyle Evans } 144*f0865ec9SKyle Evans 145*f0865ec9SKyle Evans /* 146*f0865ec9SKyle Evans * Unconditionally adds 'in2' to 'in1', storing the result in "out", 147*f0865ec9SKyle Evans * including the potential carry overflowing past the maximal length of 148*f0865ec9SKyle Evans * 'in1' and 'in2'. The function returns 0 on success, -1 on error. 149*f0865ec9SKyle Evans * 150*f0865ec9SKyle Evans * Note that the length of the output depends the lengths of the inputs, 151*f0865ec9SKyle Evans * but also on their values. 152*f0865ec9SKyle Evans * It is the user responsibility to use this function carefully when 153*f0865ec9SKyle Evans * constant time of an algorithm using this function is seeked. 154*f0865ec9SKyle Evans * 155*f0865ec9SKyle Evans * See "_nn_cnd_add" documentation for further details. 156*f0865ec9SKyle Evans * 157*f0865ec9SKyle Evans */ 158*f0865ec9SKyle Evans int nn_add(nn_t out, nn_src_t in1, nn_src_t in2) 159*f0865ec9SKyle Evans { 160*f0865ec9SKyle Evans return nn_cnd_add(1, out, in1, in2); 161*f0865ec9SKyle Evans } 162*f0865ec9SKyle Evans 163*f0865ec9SKyle Evans /* 164*f0865ec9SKyle Evans * Compute out = in1 + w where 'in1' is an initialized nn and 'w' a word. It is 165*f0865ec9SKyle Evans * caller responsibility to ensure that the result will fit in a nn (This is 166*f0865ec9SKyle Evans * for instance guaranteed if 'in1' wlen is less than NN_MAX_WORD_LEN). The 167*f0865ec9SKyle Evans * function returns 0 on succes, -1 on error. 168*f0865ec9SKyle Evans * 169*f0865ec9SKyle Evans * The result is stored in 'out' parameter. 'out' is initialized if needed (i.e. 170*f0865ec9SKyle Evans * in case aliasing is not used) and is not normalized on return. 171*f0865ec9SKyle Evans * 172*f0865ec9SKyle Evans * Note that the length of the output depends the lengths of the inputs, 173*f0865ec9SKyle Evans * but also on their values. 174*f0865ec9SKyle Evans * It is the user responsibility to use this function carefully when 175*f0865ec9SKyle Evans * constant time of an algorithm using this function is seeked. 176*f0865ec9SKyle Evans * 177*f0865ec9SKyle Evans * This function is for internal use only. 178*f0865ec9SKyle Evans */ 179*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int nn_add_word(nn_t out, nn_src_t in1, word_t w) 180*f0865ec9SKyle Evans { 181*f0865ec9SKyle Evans word_t carry, tmp; 182*f0865ec9SKyle Evans u8 i, n_wlen; 183*f0865ec9SKyle Evans int ret; 184*f0865ec9SKyle Evans 185*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 186*f0865ec9SKyle Evans 187*f0865ec9SKyle Evans /* Handle aliasing */ 188*f0865ec9SKyle Evans n_wlen = in1->wlen; 189*f0865ec9SKyle Evans if (out != in1) { 190*f0865ec9SKyle Evans ret = nn_init(out, (u16)(n_wlen * WORD_BYTES)); EG(ret, err); 191*f0865ec9SKyle Evans } else { 192*f0865ec9SKyle Evans ret = nn_set_wlen(out, n_wlen); EG(ret, err); 193*f0865ec9SKyle Evans } 194*f0865ec9SKyle Evans 195*f0865ec9SKyle Evans /* No matter its value, propagate the carry. */ 196*f0865ec9SKyle Evans carry = w; 197*f0865ec9SKyle Evans for (i = 0; i < n_wlen; i++) { 198*f0865ec9SKyle Evans tmp = (word_t)(in1->val[i] + carry); 199*f0865ec9SKyle Evans carry = (word_t)(tmp < in1->val[i]); 200*f0865ec9SKyle Evans out->val[i] = tmp; 201*f0865ec9SKyle Evans } 202*f0865ec9SKyle Evans 203*f0865ec9SKyle Evans MUST_HAVE(((out->wlen != NN_MAX_WORD_LEN) || (!carry)), ret, err); 204*f0865ec9SKyle Evans if (out->wlen != NN_MAX_WORD_LEN) { 205*f0865ec9SKyle Evans /* 206*f0865ec9SKyle Evans * To maintain constant time, we perform carry addition in all 207*f0865ec9SKyle Evans * cases. If carry is 0, no change is performed in practice, 208*f0865ec9SKyle Evans * neither to 'out' value, nor to its length. 209*f0865ec9SKyle Evans * Note that the length of the output can vary and make 210*f0865ec9SKyle Evans * the time taken by further operations on it will vary. 211*f0865ec9SKyle Evans */ 212*f0865ec9SKyle Evans out->val[out->wlen] = carry; 213*f0865ec9SKyle Evans out->wlen = (u8)(out->wlen + carry); 214*f0865ec9SKyle Evans } 215*f0865ec9SKyle Evans 216*f0865ec9SKyle Evans err: 217*f0865ec9SKyle Evans return ret; 218*f0865ec9SKyle Evans } 219*f0865ec9SKyle Evans 220*f0865ec9SKyle Evans /* 221*f0865ec9SKyle Evans * Compute out = in1 + 1. Aliasing is supported i.e. nn_inc(in1, in1) works as 222*f0865ec9SKyle Evans * expected and provides in1++. It is caller responsibility to ensure that the 223*f0865ec9SKyle Evans * result will fit in a nn (This is for instance guaranteed if 'in1' wlen is 224*f0865ec9SKyle Evans * less than NN_MAX_WORD_LEN). The function returns 0 on success, -1 on error. 225*f0865ec9SKyle Evans * 226*f0865ec9SKyle Evans * Note that the length of the output depends the lengths of the inputs, 227*f0865ec9SKyle Evans * but also on their values. 228*f0865ec9SKyle Evans * It is the user responsibility to use this function carefully when 229*f0865ec9SKyle Evans * constant time of an algorithm using this function is seeked. 230*f0865ec9SKyle Evans */ 231*f0865ec9SKyle Evans int nn_inc(nn_t out, nn_src_t in1) 232*f0865ec9SKyle Evans { 233*f0865ec9SKyle Evans return nn_add_word(out, in1, WORD(1)); 234*f0865ec9SKyle Evans } 235*f0865ec9SKyle Evans 236*f0865ec9SKyle Evans /* 237*f0865ec9SKyle Evans * Conditionally subtracts 'in2' from 'in1' according to "cnd", 238*f0865ec9SKyle Evans * storing the result in "out": 239*f0865ec9SKyle Evans * o out = in1 - in2 if cnd is not zero. 240*f0865ec9SKyle Evans * o out = in1 if cnd is zero. 241*f0865ec9SKyle Evans * 242*f0865ec9SKyle Evans * 'in1' and 'in2' must point to initialized nn, such that the value of 'in1' 243*f0865ec9SKyle Evans * is larger than 'in2'. Aliasing is supported, i.e. 'out' can point to the 244*f0865ec9SKyle Evans * same nn as 'in1' or 'in2'. If aliasing is not used, 'out' is initialized by 245*f0865ec9SKyle Evans * the function. The length of 'out' is set to the length of 'in1' 246*f0865ec9SKyle Evans * and is not normalized on return. 247*f0865ec9SKyle Evans * 248*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 249*f0865ec9SKyle Evans */ 250*f0865ec9SKyle Evans int nn_cnd_sub(int cnd, nn_t out, nn_src_t in1, nn_src_t in2) 251*f0865ec9SKyle Evans { 252*f0865ec9SKyle Evans word_t tmp, borrow1, borrow2, borrow = WORD(0); 253*f0865ec9SKyle Evans word_t mask = WORD_MASK_IFNOTZERO(cnd); 254*f0865ec9SKyle Evans u8 loop_wlen, i; 255*f0865ec9SKyle Evans int ret; 256*f0865ec9SKyle Evans 257*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 258*f0865ec9SKyle Evans ret = nn_check_initialized(in2); EG(ret, err); 259*f0865ec9SKyle Evans 260*f0865ec9SKyle Evans /* Handle aliasing */ 261*f0865ec9SKyle Evans loop_wlen = LOCAL_MAX(in1->wlen, in2->wlen); 262*f0865ec9SKyle Evans if ((out != in1) && (out != in2)) { 263*f0865ec9SKyle Evans ret = nn_init(out, (u16)(loop_wlen * WORD_BYTES)); EG(ret, err); 264*f0865ec9SKyle Evans } else { 265*f0865ec9SKyle Evans ret = nn_set_wlen(out, in1->wlen); EG(ret, err); 266*f0865ec9SKyle Evans } 267*f0865ec9SKyle Evans 268*f0865ec9SKyle Evans /* Perform subtraction one word at a time, propagating the borrow. */ 269*f0865ec9SKyle Evans for (i = 0; i < loop_wlen; i++) { 270*f0865ec9SKyle Evans tmp = (word_t)(in1->val[i] - (in2->val[i] & mask)); 271*f0865ec9SKyle Evans borrow1 = (word_t)(tmp > in1->val[i]); 272*f0865ec9SKyle Evans out->val[i] = (word_t)(tmp - borrow); 273*f0865ec9SKyle Evans borrow2 = (word_t)(out->val[i] > tmp); 274*f0865ec9SKyle Evans /* There is at most one borrow going out. */ 275*f0865ec9SKyle Evans borrow = (word_t)(borrow1 | borrow2); 276*f0865ec9SKyle Evans } 277*f0865ec9SKyle Evans 278*f0865ec9SKyle Evans /* We only support the in1 >= in2 case */ 279*f0865ec9SKyle Evans ret = (borrow != WORD(0)) ? -1 : 0; 280*f0865ec9SKyle Evans 281*f0865ec9SKyle Evans err: 282*f0865ec9SKyle Evans return ret; 283*f0865ec9SKyle Evans } 284*f0865ec9SKyle Evans 285*f0865ec9SKyle Evans /* Same as the one above, but the subtraction is performed unconditionally. */ 286*f0865ec9SKyle Evans int nn_sub(nn_t out, nn_src_t in1, nn_src_t in2) 287*f0865ec9SKyle Evans { 288*f0865ec9SKyle Evans return nn_cnd_sub(1, out, in1, in2); 289*f0865ec9SKyle Evans } 290*f0865ec9SKyle Evans 291*f0865ec9SKyle Evans /* 292*f0865ec9SKyle Evans * Compute out = in1 - 1 where in1 is a *positive* integer. Aliasing is 293*f0865ec9SKyle Evans * supported i.e. nn_dec(A, A) works as expected and provides A -= 1. 294*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 295*f0865ec9SKyle Evans */ 296*f0865ec9SKyle Evans int nn_dec(nn_t out, nn_src_t in1) 297*f0865ec9SKyle Evans { 298*f0865ec9SKyle Evans const word_t w = WORD(1); 299*f0865ec9SKyle Evans word_t tmp, borrow; 300*f0865ec9SKyle Evans u8 n_wlen, i; 301*f0865ec9SKyle Evans int ret; 302*f0865ec9SKyle Evans 303*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 304*f0865ec9SKyle Evans n_wlen = in1->wlen; 305*f0865ec9SKyle Evans ret = nn_set_wlen(out, n_wlen); EG(ret, err); 306*f0865ec9SKyle Evans 307*f0865ec9SKyle Evans /* Perform subtraction w/ provided word and propagate the borrow */ 308*f0865ec9SKyle Evans borrow = w; 309*f0865ec9SKyle Evans for (i = 0; i < n_wlen; i++) { 310*f0865ec9SKyle Evans tmp = (word_t)(in1->val[i] - borrow); 311*f0865ec9SKyle Evans borrow = (word_t)(tmp > in1->val[i]); 312*f0865ec9SKyle Evans out->val[i] = tmp; 313*f0865ec9SKyle Evans } 314*f0865ec9SKyle Evans 315*f0865ec9SKyle Evans ret = (borrow != WORD(0)) ? -1 : 0; 316*f0865ec9SKyle Evans 317*f0865ec9SKyle Evans err: 318*f0865ec9SKyle Evans return ret; 319*f0865ec9SKyle Evans } 320*f0865ec9SKyle Evans 321*f0865ec9SKyle Evans /* 322*f0865ec9SKyle Evans * The following functions handle modular arithmetic. Our outputs sizes do not 323*f0865ec9SKyle Evans * need a "normalization" since everything will be bounded by the modular number 324*f0865ec9SKyle Evans * size. 325*f0865ec9SKyle Evans * 326*f0865ec9SKyle Evans * Warning: the following functions are only useful when the inputs are < p, 327*f0865ec9SKyle Evans * i.e. we suppose that the input are already reduced modulo p. These primitives 328*f0865ec9SKyle Evans * are mostly useful for the Fp layer. Even though they give results when 329*f0865ec9SKyle Evans * applied to inputs >= p, there is no guarantee that the result is indeed < p 330*f0865ec9SKyle Evans * or correct whatsoever. 331*f0865ec9SKyle Evans */ 332*f0865ec9SKyle Evans 333*f0865ec9SKyle Evans /* 334*f0865ec9SKyle Evans * Compute out = in1 + in2 mod p. The function returns 0 on success, -1 on 335*f0865ec9SKyle Evans * error. 336*f0865ec9SKyle Evans * 337*f0865ec9SKyle Evans * Aliasing not fully supported, for internal use only. 338*f0865ec9SKyle Evans */ 339*f0865ec9SKyle Evans static int _nn_mod_add(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p) 340*f0865ec9SKyle Evans { 341*f0865ec9SKyle Evans int ret, larger, cmp; 342*f0865ec9SKyle Evans 343*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 344*f0865ec9SKyle Evans ret = nn_check_initialized(in2); EG(ret, err); 345*f0865ec9SKyle Evans ret = nn_check_initialized(p); EG(ret, err); 346*f0865ec9SKyle Evans MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */ 347*f0865ec9SKyle Evans SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */ 348*f0865ec9SKyle Evans SHOULD_HAVE((!nn_cmp(in2, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */ 349*f0865ec9SKyle Evans 350*f0865ec9SKyle Evans ret = nn_add(out, in1, in2); EG(ret, err); 351*f0865ec9SKyle Evans /* 352*f0865ec9SKyle Evans * If previous addition extends out->wlen, this may have an effect on 353*f0865ec9SKyle Evans * computation time of functions below. For that reason, we always 354*f0865ec9SKyle Evans * normalize out->wlen to p->wlen + 1. Its length is set to that of 355*f0865ec9SKyle Evans * p after the computations. 356*f0865ec9SKyle Evans * 357*f0865ec9SKyle Evans * We could also use _nn_cnd_add to catch the carry and deal 358*f0865ec9SKyle Evans * with p's of size NN_MAX_WORD_LEN. 359*f0865ec9SKyle Evans * It is still painful because we have no constraint on the lengths 360*f0865ec9SKyle Evans * of in1 and in2 so getting a carry out does not necessarily mean 361*f0865ec9SKyle Evans * that the sum is larger than p... 362*f0865ec9SKyle Evans */ 363*f0865ec9SKyle Evans ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err); 364*f0865ec9SKyle Evans ret = nn_cmp(out, p, &cmp); EG(ret, err); 365*f0865ec9SKyle Evans larger = (cmp >= 0); 366*f0865ec9SKyle Evans ret = nn_cnd_sub(larger, out, out, p); EG(ret, err); 367*f0865ec9SKyle Evans ret = nn_set_wlen(out, p->wlen); 368*f0865ec9SKyle Evans 369*f0865ec9SKyle Evans err: 370*f0865ec9SKyle Evans return ret; 371*f0865ec9SKyle Evans } 372*f0865ec9SKyle Evans 373*f0865ec9SKyle Evans /* 374*f0865ec9SKyle Evans * Compute out = in1 + in2 mod p. The function returns 0 on success, -1 on 375*f0865ec9SKyle Evans * error. 376*f0865ec9SKyle Evans * 377*f0865ec9SKyle Evans * Aliasing is supported. 378*f0865ec9SKyle Evans */ 379*f0865ec9SKyle Evans int nn_mod_add(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p) 380*f0865ec9SKyle Evans { 381*f0865ec9SKyle Evans int ret; 382*f0865ec9SKyle Evans 383*f0865ec9SKyle Evans if(out == p){ 384*f0865ec9SKyle Evans nn p_cpy; 385*f0865ec9SKyle Evans p_cpy.magic = WORD(0); 386*f0865ec9SKyle Evans 387*f0865ec9SKyle Evans ret = nn_copy(&p_cpy, p); EG(ret, err1); 388*f0865ec9SKyle Evans ret = _nn_mod_add(out, in1, in2, &p_cpy); 389*f0865ec9SKyle Evans 390*f0865ec9SKyle Evans err1: 391*f0865ec9SKyle Evans nn_uninit(&p_cpy); 392*f0865ec9SKyle Evans EG(ret, err); 393*f0865ec9SKyle Evans } 394*f0865ec9SKyle Evans else{ 395*f0865ec9SKyle Evans ret = _nn_mod_add(out, in1, in2, p); 396*f0865ec9SKyle Evans } 397*f0865ec9SKyle Evans 398*f0865ec9SKyle Evans err: 399*f0865ec9SKyle Evans return ret; 400*f0865ec9SKyle Evans } 401*f0865ec9SKyle Evans 402*f0865ec9SKyle Evans /* 403*f0865ec9SKyle Evans * Compute out = in1 + 1 mod p. The function returns 0 on success, -1 on error. 404*f0865ec9SKyle Evans * 405*f0865ec9SKyle Evans * Aliasing not fully supported, for internal use only. 406*f0865ec9SKyle Evans */ 407*f0865ec9SKyle Evans static int _nn_mod_inc(nn_t out, nn_src_t in1, nn_src_t p) 408*f0865ec9SKyle Evans { 409*f0865ec9SKyle Evans int larger, ret, cmp; 410*f0865ec9SKyle Evans 411*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 412*f0865ec9SKyle Evans ret = nn_check_initialized(p); EG(ret, err); 413*f0865ec9SKyle Evans MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */ 414*f0865ec9SKyle Evans SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */ 415*f0865ec9SKyle Evans 416*f0865ec9SKyle Evans ret = nn_inc(out, in1); EG(ret, err); 417*f0865ec9SKyle Evans ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err); /* see comment in nn_mod_add() */ 418*f0865ec9SKyle Evans ret = nn_cmp(out, p, &cmp); EG(ret, err); 419*f0865ec9SKyle Evans larger = (cmp >= 0); 420*f0865ec9SKyle Evans ret = nn_cnd_sub(larger, out, out, p); EG(ret, err); 421*f0865ec9SKyle Evans ret = nn_set_wlen(out, p->wlen); 422*f0865ec9SKyle Evans 423*f0865ec9SKyle Evans err: 424*f0865ec9SKyle Evans return ret; 425*f0865ec9SKyle Evans } 426*f0865ec9SKyle Evans 427*f0865ec9SKyle Evans /* 428*f0865ec9SKyle Evans * Compute out = in1 + 1 mod p. The function returns 0 on success, -1 on error. 429*f0865ec9SKyle Evans * 430*f0865ec9SKyle Evans * Aliasing supported. 431*f0865ec9SKyle Evans */ 432*f0865ec9SKyle Evans int nn_mod_inc(nn_t out, nn_src_t in1, nn_src_t p) 433*f0865ec9SKyle Evans { 434*f0865ec9SKyle Evans int ret; 435*f0865ec9SKyle Evans 436*f0865ec9SKyle Evans if(out == p){ 437*f0865ec9SKyle Evans nn p_cpy; 438*f0865ec9SKyle Evans p_cpy.magic = WORD(0); 439*f0865ec9SKyle Evans 440*f0865ec9SKyle Evans ret = nn_copy(&p_cpy, p); EG(ret, err1); 441*f0865ec9SKyle Evans ret = _nn_mod_inc(out, in1, &p_cpy); 442*f0865ec9SKyle Evans 443*f0865ec9SKyle Evans err1: 444*f0865ec9SKyle Evans nn_uninit(&p_cpy); 445*f0865ec9SKyle Evans EG(ret, err); 446*f0865ec9SKyle Evans } 447*f0865ec9SKyle Evans else{ 448*f0865ec9SKyle Evans ret = _nn_mod_inc(out, in1, p); 449*f0865ec9SKyle Evans } 450*f0865ec9SKyle Evans 451*f0865ec9SKyle Evans err: 452*f0865ec9SKyle Evans return ret; 453*f0865ec9SKyle Evans 454*f0865ec9SKyle Evans } 455*f0865ec9SKyle Evans 456*f0865ec9SKyle Evans /* 457*f0865ec9SKyle Evans * Compute out = in1 - in2 mod p. The function returns 0 on success, -1 on 458*f0865ec9SKyle Evans * error. 459*f0865ec9SKyle Evans * 460*f0865ec9SKyle Evans * Aliasing not supported, for internal use only. 461*f0865ec9SKyle Evans */ 462*f0865ec9SKyle Evans static int _nn_mod_sub(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p) 463*f0865ec9SKyle Evans { 464*f0865ec9SKyle Evans int smaller, ret, cmp; 465*f0865ec9SKyle Evans nn_src_t in2_; 466*f0865ec9SKyle Evans nn in2_cpy; 467*f0865ec9SKyle Evans in2_cpy.magic = WORD(0); 468*f0865ec9SKyle Evans 469*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 470*f0865ec9SKyle Evans ret = nn_check_initialized(in2); EG(ret, err); 471*f0865ec9SKyle Evans ret = nn_check_initialized(p); EG(ret, err); 472*f0865ec9SKyle Evans MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */ 473*f0865ec9SKyle Evans SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */ 474*f0865ec9SKyle Evans SHOULD_HAVE((!nn_cmp(in2, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */ 475*f0865ec9SKyle Evans 476*f0865ec9SKyle Evans /* Handle the case where in2 and out are aliased */ 477*f0865ec9SKyle Evans if (in2 == out) { 478*f0865ec9SKyle Evans ret = nn_copy(&in2_cpy, in2); EG(ret, err); 479*f0865ec9SKyle Evans in2_ = &in2_cpy; 480*f0865ec9SKyle Evans } else { 481*f0865ec9SKyle Evans ret = nn_init(&in2_cpy, 0); EG(ret, err); 482*f0865ec9SKyle Evans in2_ = in2; 483*f0865ec9SKyle Evans } 484*f0865ec9SKyle Evans 485*f0865ec9SKyle Evans /* The below trick is used to avoid handling of "negative" numbers. */ 486*f0865ec9SKyle Evans ret = nn_cmp(in1, in2_, &cmp); EG(ret, err); 487*f0865ec9SKyle Evans smaller = (cmp < 0); 488*f0865ec9SKyle Evans ret = nn_cnd_add(smaller, out, in1, p); EG(ret, err); 489*f0865ec9SKyle Evans ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err);/* See Comment in nn_mod_add() */ 490*f0865ec9SKyle Evans ret = nn_sub(out, out, in2_); EG(ret, err); 491*f0865ec9SKyle Evans ret = nn_set_wlen(out, p->wlen); 492*f0865ec9SKyle Evans 493*f0865ec9SKyle Evans err: 494*f0865ec9SKyle Evans nn_uninit(&in2_cpy); 495*f0865ec9SKyle Evans 496*f0865ec9SKyle Evans return ret; 497*f0865ec9SKyle Evans } 498*f0865ec9SKyle Evans 499*f0865ec9SKyle Evans /* 500*f0865ec9SKyle Evans * Compute out = in1 - in2 mod p. The function returns 0 on success, -1 on 501*f0865ec9SKyle Evans * error. 502*f0865ec9SKyle Evans * 503*f0865ec9SKyle Evans * Aliasing supported. 504*f0865ec9SKyle Evans */ 505*f0865ec9SKyle Evans int nn_mod_sub(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p) 506*f0865ec9SKyle Evans { 507*f0865ec9SKyle Evans int ret; 508*f0865ec9SKyle Evans 509*f0865ec9SKyle Evans if(out == p){ 510*f0865ec9SKyle Evans nn p_cpy; 511*f0865ec9SKyle Evans p_cpy.magic = WORD(0); 512*f0865ec9SKyle Evans 513*f0865ec9SKyle Evans ret = nn_copy(&p_cpy, p); EG(ret, err1); 514*f0865ec9SKyle Evans ret = _nn_mod_sub(out, in1, in2, &p_cpy); 515*f0865ec9SKyle Evans 516*f0865ec9SKyle Evans err1: 517*f0865ec9SKyle Evans nn_uninit(&p_cpy); 518*f0865ec9SKyle Evans EG(ret, err); 519*f0865ec9SKyle Evans } 520*f0865ec9SKyle Evans else{ 521*f0865ec9SKyle Evans ret = _nn_mod_sub(out, in1, in2, p); 522*f0865ec9SKyle Evans } 523*f0865ec9SKyle Evans 524*f0865ec9SKyle Evans err: 525*f0865ec9SKyle Evans return ret; 526*f0865ec9SKyle Evans } 527*f0865ec9SKyle Evans 528*f0865ec9SKyle Evans /* 529*f0865ec9SKyle Evans * Compute out = in1 - 1 mod p. The function returns 0 on success, -1 on error 530*f0865ec9SKyle Evans * 531*f0865ec9SKyle Evans * Aliasing not supported, for internal use only. 532*f0865ec9SKyle Evans */ 533*f0865ec9SKyle Evans static int _nn_mod_dec(nn_t out, nn_src_t in1, nn_src_t p) 534*f0865ec9SKyle Evans { 535*f0865ec9SKyle Evans int ret, iszero, cmp; 536*f0865ec9SKyle Evans 537*f0865ec9SKyle Evans ret = nn_check_initialized(in1); EG(ret, err); 538*f0865ec9SKyle Evans ret = nn_check_initialized(p); EG(ret, err); 539*f0865ec9SKyle Evans MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */ 540*f0865ec9SKyle Evans FORCE_USED_VAR(cmp); /* nop to silence possible warning with macro below */ 541*f0865ec9SKyle Evans SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE; Documented above */ 542*f0865ec9SKyle Evans 543*f0865ec9SKyle Evans /* The below trick is used to avoid handling of "negative" numbers. */ 544*f0865ec9SKyle Evans ret = nn_iszero(in1, &iszero); EG(ret, err); 545*f0865ec9SKyle Evans ret = nn_cnd_add(iszero, out, in1, p); EG(ret, err); 546*f0865ec9SKyle Evans ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err); /* See Comment in nn_mod_add() */ 547*f0865ec9SKyle Evans ret = nn_dec(out, out); EG(ret, err); 548*f0865ec9SKyle Evans ret = nn_set_wlen(out, p->wlen); 549*f0865ec9SKyle Evans 550*f0865ec9SKyle Evans err: 551*f0865ec9SKyle Evans return ret; 552*f0865ec9SKyle Evans } 553*f0865ec9SKyle Evans 554*f0865ec9SKyle Evans /* 555*f0865ec9SKyle Evans * Compute out = in1 - 1 mod p. The function returns 0 on success, -1 on error 556*f0865ec9SKyle Evans * 557*f0865ec9SKyle Evans * Aliasing supported. 558*f0865ec9SKyle Evans */ 559*f0865ec9SKyle Evans int nn_mod_dec(nn_t out, nn_src_t in1, nn_src_t p) 560*f0865ec9SKyle Evans { 561*f0865ec9SKyle Evans int ret; 562*f0865ec9SKyle Evans 563*f0865ec9SKyle Evans if(out == p){ 564*f0865ec9SKyle Evans nn p_cpy; 565*f0865ec9SKyle Evans p_cpy.magic = WORD(0); 566*f0865ec9SKyle Evans 567*f0865ec9SKyle Evans ret = nn_copy(&p_cpy, p); EG(ret, err1); 568*f0865ec9SKyle Evans ret = _nn_mod_dec(out, in1, &p_cpy); 569*f0865ec9SKyle Evans 570*f0865ec9SKyle Evans err1: 571*f0865ec9SKyle Evans nn_uninit(&p_cpy); 572*f0865ec9SKyle Evans EG(ret, err); 573*f0865ec9SKyle Evans } 574*f0865ec9SKyle Evans else{ 575*f0865ec9SKyle Evans ret = _nn_mod_dec(out, in1, p); 576*f0865ec9SKyle Evans } 577*f0865ec9SKyle Evans 578*f0865ec9SKyle Evans err: 579*f0865ec9SKyle Evans return ret; 580*f0865ec9SKyle Evans } 581*f0865ec9SKyle Evans 582*f0865ec9SKyle Evans /* 583*f0865ec9SKyle Evans * Compute out = -in mod p. The function returns 0 on success, -1 on error. 584*f0865ec9SKyle Evans * Because we only support positive integers, we compute 585*f0865ec9SKyle Evans * out = p - in (except when value is 0). 586*f0865ec9SKyle Evans * 587*f0865ec9SKyle Evans * We suppose that in is already reduced modulo p. 588*f0865ec9SKyle Evans * 589*f0865ec9SKyle Evans * Aliasing is supported. 590*f0865ec9SKyle Evans * 591*f0865ec9SKyle Evans */ 592*f0865ec9SKyle Evans int nn_mod_neg(nn_t out, nn_src_t in, nn_src_t p) 593*f0865ec9SKyle Evans { 594*f0865ec9SKyle Evans int ret, cmp, iszero; 595*f0865ec9SKyle Evans 596*f0865ec9SKyle Evans FORCE_USED_VAR(cmp); 597*f0865ec9SKyle Evans 598*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err); 599*f0865ec9SKyle Evans ret = nn_check_initialized(p); EG(ret, err); 600*f0865ec9SKyle Evans 601*f0865ec9SKyle Evans SHOULD_HAVE((!nn_cmp(in, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE; Documented above */ 602*f0865ec9SKyle Evans 603*f0865ec9SKyle Evans ret = nn_iszero(in, &iszero); EG(ret, err); 604*f0865ec9SKyle Evans if (iszero) { 605*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err); 606*f0865ec9SKyle Evans ret = nn_zero(out); EG(ret, err); 607*f0865ec9SKyle Evans } else { 608*f0865ec9SKyle Evans ret = nn_sub(out, p, in); EG(ret, err); 609*f0865ec9SKyle Evans } 610*f0865ec9SKyle Evans 611*f0865ec9SKyle Evans err: 612*f0865ec9SKyle Evans return ret; 613*f0865ec9SKyle Evans } 614