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