/src/openssl30/crypto/bn/bn_mod.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  * Copyright 1998-2021 The OpenSSL Project Authors. All Rights Reserved. | 
| 3 |  |  * | 
| 4 |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
| 5 |  |  * this file except in compliance with the License.  You can obtain a copy | 
| 6 |  |  * in the file LICENSE in the source distribution or at | 
| 7 |  |  * https://www.openssl.org/source/license.html | 
| 8 |  |  */ | 
| 9 |  |  | 
| 10 |  | #include "internal/cryptlib.h" | 
| 11 |  | #include "bn_local.h" | 
| 12 |  |  | 
| 13 |  | int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) | 
| 14 | 51.8M | { | 
| 15 |  |     /* | 
| 16 |  |      * like BN_mod, but returns non-negative remainder (i.e., 0 <= r < |d| | 
| 17 |  |      * always holds) | 
| 18 |  |      */ | 
| 19 |  |  | 
| 20 | 51.8M |     if (!(BN_mod(r, m, d, ctx))) | 
| 21 | 7 |         return 0; | 
| 22 | 51.8M |     if (!r->neg) | 
| 23 | 51.4M |         return 1; | 
| 24 |  |     /* now   -|d| < r < 0,  so we have to set  r := r + |d| */ | 
| 25 | 336k |     return (d->neg ? BN_sub : BN_add) (r, r, d); | 
| 26 | 51.8M | } | 
| 27 |  |  | 
| 28 |  | int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, | 
| 29 |  |                BN_CTX *ctx) | 
| 30 | 435 | { | 
| 31 | 435 |     if (!BN_add(r, a, b)) | 
| 32 | 0 |         return 0; | 
| 33 | 435 |     return BN_nnmod(r, r, m, ctx); | 
| 34 | 435 | } | 
| 35 |  |  | 
| 36 |  | /* | 
| 37 |  |  * BN_mod_add variant that may be used if both a and b are non-negative and | 
| 38 |  |  * less than m. The original algorithm was | 
| 39 |  |  * | 
| 40 |  |  *    if (!BN_uadd(r, a, b)) | 
| 41 |  |  *       return 0; | 
| 42 |  |  *    if (BN_ucmp(r, m) >= 0) | 
| 43 |  |  *       return BN_usub(r, r, m); | 
| 44 |  |  * | 
| 45 |  |  * which is replaced with addition, subtracting modulus, and conditional | 
| 46 |  |  * move depending on whether or not subtraction borrowed. | 
| 47 |  |  */ | 
| 48 |  | int bn_mod_add_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, | 
| 49 |  |                          const BIGNUM *m) | 
| 50 | 4.54M | { | 
| 51 | 4.54M |     size_t i, ai, bi, mtop = m->top; | 
| 52 | 4.54M |     BN_ULONG storage[1024 / BN_BITS2]; | 
| 53 | 4.54M |     BN_ULONG carry, temp, mask, *rp, *tp = storage; | 
| 54 | 4.54M |     const BN_ULONG *ap, *bp; | 
| 55 |  |  | 
| 56 | 4.54M |     if (bn_wexpand(r, mtop) == NULL) | 
| 57 | 0 |         return 0; | 
| 58 |  |  | 
| 59 | 4.54M |     if (mtop > sizeof(storage) / sizeof(storage[0])) { | 
| 60 | 3.04k |         tp = OPENSSL_malloc(mtop * sizeof(BN_ULONG)); | 
| 61 | 3.04k |         if (tp == NULL) { | 
| 62 | 0 |             ERR_raise(ERR_LIB_BN, ERR_R_MALLOC_FAILURE); | 
| 63 | 0 |             return 0; | 
| 64 | 0 |         } | 
| 65 | 3.04k |     } | 
| 66 |  |  | 
| 67 | 4.54M |     ap = a->d != NULL ? a->d : tp; | 
| 68 | 4.54M |     bp = b->d != NULL ? b->d : tp; | 
| 69 |  |  | 
| 70 | 23.1M |     for (i = 0, ai = 0, bi = 0, carry = 0; i < mtop;) { | 
| 71 | 18.5M |         mask = (BN_ULONG)0 - ((i - a->top) >> (8 * sizeof(i) - 1)); | 
| 72 | 18.5M |         temp = ((ap[ai] & mask) + carry) & BN_MASK2; | 
| 73 | 18.5M |         carry = (temp < carry); | 
| 74 |  |  | 
| 75 | 18.5M |         mask = (BN_ULONG)0 - ((i - b->top) >> (8 * sizeof(i) - 1)); | 
| 76 | 18.5M |         tp[i] = ((bp[bi] & mask) + temp) & BN_MASK2; | 
| 77 | 18.5M |         carry += (tp[i] < temp); | 
| 78 |  |  | 
| 79 | 18.5M |         i++; | 
| 80 | 18.5M |         ai += (i - a->dmax) >> (8 * sizeof(i) - 1); | 
| 81 | 18.5M |         bi += (i - b->dmax) >> (8 * sizeof(i) - 1); | 
| 82 | 18.5M |     } | 
| 83 | 4.54M |     rp = r->d; | 
| 84 | 4.54M |     carry -= bn_sub_words(rp, tp, m->d, mtop); | 
| 85 | 23.1M |     for (i = 0; i < mtop; i++) { | 
| 86 | 18.5M |         rp[i] = (carry & tp[i]) | (~carry & rp[i]); | 
| 87 | 18.5M |         ((volatile BN_ULONG *)tp)[i] = 0; | 
| 88 | 18.5M |     } | 
| 89 | 4.54M |     r->top = mtop; | 
| 90 | 4.54M |     r->flags |= BN_FLG_FIXED_TOP; | 
| 91 | 4.54M |     r->neg = 0; | 
| 92 |  |  | 
| 93 | 4.54M |     if (tp != storage) | 
| 94 | 3.04k |         OPENSSL_free(tp); | 
| 95 |  |  | 
| 96 | 4.54M |     return 1; | 
| 97 | 4.54M | } | 
| 98 |  |  | 
| 99 |  | int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, | 
| 100 |  |                      const BIGNUM *m) | 
| 101 | 5.88M | { | 
| 102 | 5.88M |     int ret = bn_mod_add_fixed_top(r, a, b, m); | 
| 103 |  |  | 
| 104 | 5.88M |     if (ret) | 
| 105 | 5.88M |         bn_correct_top(r); | 
| 106 |  |  | 
| 107 | 5.88M |     return ret; | 
| 108 | 5.88M | } | 
| 109 |  |  | 
| 110 |  | int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, | 
| 111 |  |                BN_CTX *ctx) | 
| 112 | 0 | { | 
| 113 | 0 |     if (!BN_sub(r, a, b)) | 
| 114 | 0 |         return 0; | 
| 115 | 0 |     return BN_nnmod(r, r, m, ctx); | 
| 116 | 0 | } | 
| 117 |  |  | 
| 118 |  | /* | 
| 119 |  |  * BN_mod_sub variant that may be used if both a and b are non-negative, | 
| 120 |  |  * a is less than m, while b is of same bit width as m. It's implemented | 
| 121 |  |  * as subtraction followed by two conditional additions. | 
| 122 |  |  * | 
| 123 |  |  * 0 <= a < m | 
| 124 |  |  * 0 <= b < 2^w < 2*m | 
| 125 |  |  * | 
| 126 |  |  * after subtraction | 
| 127 |  |  * | 
| 128 |  |  * -2*m < r = a - b < m | 
| 129 |  |  * | 
| 130 |  |  * Thus it takes up to two conditional additions to make |r| positive. | 
| 131 |  |  */ | 
| 132 |  | int bn_mod_sub_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, | 
| 133 |  |                          const BIGNUM *m) | 
| 134 | 5.12k | { | 
| 135 | 5.12k |     size_t i, ai, bi, mtop = m->top; | 
| 136 | 5.12k |     BN_ULONG borrow, carry, ta, tb, mask, *rp; | 
| 137 | 5.12k |     const BN_ULONG *ap, *bp; | 
| 138 |  |  | 
| 139 | 5.12k |     if (bn_wexpand(r, mtop) == NULL) | 
| 140 | 0 |         return 0; | 
| 141 |  |  | 
| 142 | 5.12k |     rp = r->d; | 
| 143 | 5.12k |     ap = a->d != NULL ? a->d : rp; | 
| 144 | 5.12k |     bp = b->d != NULL ? b->d : rp; | 
| 145 |  |  | 
| 146 | 87.0k |     for (i = 0, ai = 0, bi = 0, borrow = 0; i < mtop;) { | 
| 147 | 81.9k |         mask = (BN_ULONG)0 - ((i - a->top) >> (8 * sizeof(i) - 1)); | 
| 148 | 81.9k |         ta = ap[ai] & mask; | 
| 149 |  |  | 
| 150 | 81.9k |         mask = (BN_ULONG)0 - ((i - b->top) >> (8 * sizeof(i) - 1)); | 
| 151 | 81.9k |         tb = bp[bi] & mask; | 
| 152 | 81.9k |         rp[i] = ta - tb - borrow; | 
| 153 | 81.9k |         if (ta != tb) | 
| 154 | 62.3k |             borrow = (ta < tb); | 
| 155 |  |  | 
| 156 | 81.9k |         i++; | 
| 157 | 81.9k |         ai += (i - a->dmax) >> (8 * sizeof(i) - 1); | 
| 158 | 81.9k |         bi += (i - b->dmax) >> (8 * sizeof(i) - 1); | 
| 159 | 81.9k |     } | 
| 160 | 5.12k |     ap = m->d; | 
| 161 | 87.0k |     for (i = 0, mask = 0 - borrow, carry = 0; i < mtop; i++) { | 
| 162 | 81.9k |         ta = ((ap[i] & mask) + carry) & BN_MASK2; | 
| 163 | 81.9k |         carry = (ta < carry); | 
| 164 | 81.9k |         rp[i] = (rp[i] + ta) & BN_MASK2; | 
| 165 | 81.9k |         carry += (rp[i] < ta); | 
| 166 | 81.9k |     } | 
| 167 | 5.12k |     borrow -= carry; | 
| 168 | 87.0k |     for (i = 0, mask = 0 - borrow, carry = 0; i < mtop; i++) { | 
| 169 | 81.9k |         ta = ((ap[i] & mask) + carry) & BN_MASK2; | 
| 170 | 81.9k |         carry = (ta < carry); | 
| 171 | 81.9k |         rp[i] = (rp[i] + ta) & BN_MASK2; | 
| 172 | 81.9k |         carry += (rp[i] < ta); | 
| 173 | 81.9k |     } | 
| 174 |  |  | 
| 175 | 5.12k |     r->top = mtop; | 
| 176 | 5.12k |     r->flags |= BN_FLG_FIXED_TOP; | 
| 177 | 5.12k |     r->neg = 0; | 
| 178 |  |  | 
| 179 | 5.12k |     return 1; | 
| 180 | 5.12k | } | 
| 181 |  |  | 
| 182 |  | /* | 
| 183 |  |  * BN_mod_sub variant that may be used if both a and b are non-negative and | 
| 184 |  |  * less than m | 
| 185 |  |  */ | 
| 186 |  | int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, | 
| 187 |  |                      const BIGNUM *m) | 
| 188 | 5.77M | { | 
| 189 | 5.77M |     if (!BN_sub(r, a, b)) | 
| 190 | 0 |         return 0; | 
| 191 | 5.77M |     if (r->neg) | 
| 192 | 2.75M |         return BN_add(r, r, m); | 
| 193 | 3.01M |     return 1; | 
| 194 | 5.77M | } | 
| 195 |  |  | 
| 196 |  | /* slow but works */ | 
| 197 |  | int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, | 
| 198 |  |                BN_CTX *ctx) | 
| 199 | 48.6M | { | 
| 200 | 48.6M |     BIGNUM *t; | 
| 201 | 48.6M |     int ret = 0; | 
| 202 |  |  | 
| 203 | 48.6M |     bn_check_top(a); | 
| 204 | 48.6M |     bn_check_top(b); | 
| 205 | 48.6M |     bn_check_top(m); | 
| 206 |  |  | 
| 207 | 48.6M |     BN_CTX_start(ctx); | 
| 208 | 48.6M |     if ((t = BN_CTX_get(ctx)) == NULL) | 
| 209 | 0 |         goto err; | 
| 210 | 48.6M |     if (a == b) { | 
| 211 | 46.4M |         if (!BN_sqr(t, a, ctx)) | 
| 212 | 0 |             goto err; | 
| 213 | 46.4M |     } else { | 
| 214 | 2.15M |         if (!BN_mul(t, a, b, ctx)) | 
| 215 | 0 |             goto err; | 
| 216 | 2.15M |     } | 
| 217 | 48.6M |     if (!BN_nnmod(r, t, m, ctx)) | 
| 218 | 7 |         goto err; | 
| 219 | 48.6M |     bn_check_top(r); | 
| 220 | 48.6M |     ret = 1; | 
| 221 | 48.6M |  err: | 
| 222 | 48.6M |     BN_CTX_end(ctx); | 
| 223 | 48.6M |     return ret; | 
| 224 | 48.6M | } | 
| 225 |  |  | 
| 226 |  | int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) | 
| 227 | 2.05M | { | 
| 228 | 2.05M |     if (!BN_sqr(r, a, ctx)) | 
| 229 | 0 |         return 0; | 
| 230 |  |     /* r->neg == 0,  thus we don't need BN_nnmod */ | 
| 231 | 2.05M |     return BN_mod(r, r, m, ctx); | 
| 232 | 2.05M | } | 
| 233 |  |  | 
| 234 |  | int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) | 
| 235 | 0 | { | 
| 236 | 0 |     if (!BN_lshift1(r, a)) | 
| 237 | 0 |         return 0; | 
| 238 | 0 |     bn_check_top(r); | 
| 239 | 0 |     return BN_nnmod(r, r, m, ctx); | 
| 240 | 0 | } | 
| 241 |  |  | 
| 242 |  | /* | 
| 243 |  |  * BN_mod_lshift1 variant that may be used if a is non-negative and less than | 
| 244 |  |  * m | 
| 245 |  |  */ | 
| 246 |  | int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m) | 
| 247 | 2.45M | { | 
| 248 | 2.45M |     if (!BN_lshift1(r, a)) | 
| 249 | 0 |         return 0; | 
| 250 | 2.45M |     bn_check_top(r); | 
| 251 | 2.45M |     if (BN_cmp(r, m) >= 0) | 
| 252 | 1.20M |         return BN_sub(r, r, m); | 
| 253 | 1.25M |     return 1; | 
| 254 | 2.45M | } | 
| 255 |  |  | 
| 256 |  | int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, | 
| 257 |  |                   BN_CTX *ctx) | 
| 258 | 0 | { | 
| 259 | 0 |     BIGNUM *abs_m = NULL; | 
| 260 | 0 |     int ret; | 
| 261 |  | 
 | 
| 262 | 0 |     if (!BN_nnmod(r, a, m, ctx)) | 
| 263 | 0 |         return 0; | 
| 264 |  |  | 
| 265 | 0 |     if (m->neg) { | 
| 266 | 0 |         abs_m = BN_dup(m); | 
| 267 | 0 |         if (abs_m == NULL) | 
| 268 | 0 |             return 0; | 
| 269 | 0 |         abs_m->neg = 0; | 
| 270 | 0 |     } | 
| 271 |  |  | 
| 272 | 0 |     ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m)); | 
| 273 | 0 |     bn_check_top(r); | 
| 274 |  | 
 | 
| 275 | 0 |     BN_free(abs_m); | 
| 276 | 0 |     return ret; | 
| 277 | 0 | } | 
| 278 |  |  | 
| 279 |  | /* | 
| 280 |  |  * BN_mod_lshift variant that may be used if a is non-negative and less than | 
| 281 |  |  * m | 
| 282 |  |  */ | 
| 283 |  | int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) | 
| 284 | 1.31M | { | 
| 285 | 1.31M |     if (r != a) { | 
| 286 | 1.02M |         if (BN_copy(r, a) == NULL) | 
| 287 | 0 |             return 0; | 
| 288 | 1.02M |     } | 
| 289 |  |  | 
| 290 | 3.63M |     while (n > 0) { | 
| 291 | 2.31M |         int max_shift; | 
| 292 |  |  | 
| 293 |  |         /* 0 < r < m */ | 
| 294 | 2.31M |         max_shift = BN_num_bits(m) - BN_num_bits(r); | 
| 295 |  |         /* max_shift >= 0 */ | 
| 296 |  |  | 
| 297 | 2.31M |         if (max_shift < 0) { | 
| 298 | 0 |             ERR_raise(ERR_LIB_BN, BN_R_INPUT_NOT_REDUCED); | 
| 299 | 0 |             return 0; | 
| 300 | 0 |         } | 
| 301 |  |  | 
| 302 | 2.31M |         if (max_shift > n) | 
| 303 | 463k |             max_shift = n; | 
| 304 |  |  | 
| 305 | 2.31M |         if (max_shift) { | 
| 306 | 1.08M |             if (!BN_lshift(r, r, max_shift)) | 
| 307 | 0 |                 return 0; | 
| 308 | 1.08M |             n -= max_shift; | 
| 309 | 1.23M |         } else { | 
| 310 | 1.23M |             if (!BN_lshift1(r, r)) | 
| 311 | 0 |                 return 0; | 
| 312 | 1.23M |             --n; | 
| 313 | 1.23M |         } | 
| 314 |  |  | 
| 315 |  |         /* BN_num_bits(r) <= BN_num_bits(m) */ | 
| 316 |  |  | 
| 317 | 2.31M |         if (BN_cmp(r, m) >= 0) { | 
| 318 | 1.38M |             if (!BN_sub(r, r, m)) | 
| 319 | 0 |                 return 0; | 
| 320 | 1.38M |         } | 
| 321 | 2.31M |     } | 
| 322 | 1.31M |     bn_check_top(r); | 
| 323 |  |  | 
| 324 | 1.31M |     return 1; | 
| 325 | 1.31M | } |