1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2020 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_ci/* signed add of b to a. */ 14e1051a39Sopenharmony_ciint BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) 15e1051a39Sopenharmony_ci{ 16e1051a39Sopenharmony_ci int ret, r_neg, cmp_res; 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci bn_check_top(a); 19e1051a39Sopenharmony_ci bn_check_top(b); 20e1051a39Sopenharmony_ci 21e1051a39Sopenharmony_ci if (a->neg == b->neg) { 22e1051a39Sopenharmony_ci r_neg = a->neg; 23e1051a39Sopenharmony_ci ret = BN_uadd(r, a, b); 24e1051a39Sopenharmony_ci } else { 25e1051a39Sopenharmony_ci cmp_res = BN_ucmp(a, b); 26e1051a39Sopenharmony_ci if (cmp_res > 0) { 27e1051a39Sopenharmony_ci r_neg = a->neg; 28e1051a39Sopenharmony_ci ret = BN_usub(r, a, b); 29e1051a39Sopenharmony_ci } else if (cmp_res < 0) { 30e1051a39Sopenharmony_ci r_neg = b->neg; 31e1051a39Sopenharmony_ci ret = BN_usub(r, b, a); 32e1051a39Sopenharmony_ci } else { 33e1051a39Sopenharmony_ci r_neg = 0; 34e1051a39Sopenharmony_ci BN_zero(r); 35e1051a39Sopenharmony_ci ret = 1; 36e1051a39Sopenharmony_ci } 37e1051a39Sopenharmony_ci } 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_ci r->neg = r_neg; 40e1051a39Sopenharmony_ci bn_check_top(r); 41e1051a39Sopenharmony_ci return ret; 42e1051a39Sopenharmony_ci} 43e1051a39Sopenharmony_ci 44e1051a39Sopenharmony_ci/* signed sub of b from a. */ 45e1051a39Sopenharmony_ciint BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) 46e1051a39Sopenharmony_ci{ 47e1051a39Sopenharmony_ci int ret, r_neg, cmp_res; 48e1051a39Sopenharmony_ci 49e1051a39Sopenharmony_ci bn_check_top(a); 50e1051a39Sopenharmony_ci bn_check_top(b); 51e1051a39Sopenharmony_ci 52e1051a39Sopenharmony_ci if (a->neg != b->neg) { 53e1051a39Sopenharmony_ci r_neg = a->neg; 54e1051a39Sopenharmony_ci ret = BN_uadd(r, a, b); 55e1051a39Sopenharmony_ci } else { 56e1051a39Sopenharmony_ci cmp_res = BN_ucmp(a, b); 57e1051a39Sopenharmony_ci if (cmp_res > 0) { 58e1051a39Sopenharmony_ci r_neg = a->neg; 59e1051a39Sopenharmony_ci ret = BN_usub(r, a, b); 60e1051a39Sopenharmony_ci } else if (cmp_res < 0) { 61e1051a39Sopenharmony_ci r_neg = !b->neg; 62e1051a39Sopenharmony_ci ret = BN_usub(r, b, a); 63e1051a39Sopenharmony_ci } else { 64e1051a39Sopenharmony_ci r_neg = 0; 65e1051a39Sopenharmony_ci BN_zero(r); 66e1051a39Sopenharmony_ci ret = 1; 67e1051a39Sopenharmony_ci } 68e1051a39Sopenharmony_ci } 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ci r->neg = r_neg; 71e1051a39Sopenharmony_ci bn_check_top(r); 72e1051a39Sopenharmony_ci return ret; 73e1051a39Sopenharmony_ci} 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci/* unsigned add of b to a, r can be equal to a or b. */ 76e1051a39Sopenharmony_ciint BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) 77e1051a39Sopenharmony_ci{ 78e1051a39Sopenharmony_ci int max, min, dif; 79e1051a39Sopenharmony_ci const BN_ULONG *ap, *bp; 80e1051a39Sopenharmony_ci BN_ULONG *rp, carry, t1, t2; 81e1051a39Sopenharmony_ci 82e1051a39Sopenharmony_ci bn_check_top(a); 83e1051a39Sopenharmony_ci bn_check_top(b); 84e1051a39Sopenharmony_ci 85e1051a39Sopenharmony_ci if (a->top < b->top) { 86e1051a39Sopenharmony_ci const BIGNUM *tmp; 87e1051a39Sopenharmony_ci 88e1051a39Sopenharmony_ci tmp = a; 89e1051a39Sopenharmony_ci a = b; 90e1051a39Sopenharmony_ci b = tmp; 91e1051a39Sopenharmony_ci } 92e1051a39Sopenharmony_ci max = a->top; 93e1051a39Sopenharmony_ci min = b->top; 94e1051a39Sopenharmony_ci dif = max - min; 95e1051a39Sopenharmony_ci 96e1051a39Sopenharmony_ci if (bn_wexpand(r, max + 1) == NULL) 97e1051a39Sopenharmony_ci return 0; 98e1051a39Sopenharmony_ci 99e1051a39Sopenharmony_ci r->top = max; 100e1051a39Sopenharmony_ci 101e1051a39Sopenharmony_ci ap = a->d; 102e1051a39Sopenharmony_ci bp = b->d; 103e1051a39Sopenharmony_ci rp = r->d; 104e1051a39Sopenharmony_ci 105e1051a39Sopenharmony_ci carry = bn_add_words(rp, ap, bp, min); 106e1051a39Sopenharmony_ci rp += min; 107e1051a39Sopenharmony_ci ap += min; 108e1051a39Sopenharmony_ci 109e1051a39Sopenharmony_ci while (dif) { 110e1051a39Sopenharmony_ci dif--; 111e1051a39Sopenharmony_ci t1 = *(ap++); 112e1051a39Sopenharmony_ci t2 = (t1 + carry) & BN_MASK2; 113e1051a39Sopenharmony_ci *(rp++) = t2; 114e1051a39Sopenharmony_ci carry &= (t2 == 0); 115e1051a39Sopenharmony_ci } 116e1051a39Sopenharmony_ci *rp = carry; 117e1051a39Sopenharmony_ci r->top += carry; 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_ci r->neg = 0; 120e1051a39Sopenharmony_ci bn_check_top(r); 121e1051a39Sopenharmony_ci return 1; 122e1051a39Sopenharmony_ci} 123e1051a39Sopenharmony_ci 124e1051a39Sopenharmony_ci/* unsigned subtraction of b from a, a must be larger than b. */ 125e1051a39Sopenharmony_ciint BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) 126e1051a39Sopenharmony_ci{ 127e1051a39Sopenharmony_ci int max, min, dif; 128e1051a39Sopenharmony_ci BN_ULONG t1, t2, borrow, *rp; 129e1051a39Sopenharmony_ci const BN_ULONG *ap, *bp; 130e1051a39Sopenharmony_ci 131e1051a39Sopenharmony_ci bn_check_top(a); 132e1051a39Sopenharmony_ci bn_check_top(b); 133e1051a39Sopenharmony_ci 134e1051a39Sopenharmony_ci max = a->top; 135e1051a39Sopenharmony_ci min = b->top; 136e1051a39Sopenharmony_ci dif = max - min; 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci if (dif < 0) { /* hmm... should not be happening */ 139e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BN, BN_R_ARG2_LT_ARG3); 140e1051a39Sopenharmony_ci return 0; 141e1051a39Sopenharmony_ci } 142e1051a39Sopenharmony_ci 143e1051a39Sopenharmony_ci if (bn_wexpand(r, max) == NULL) 144e1051a39Sopenharmony_ci return 0; 145e1051a39Sopenharmony_ci 146e1051a39Sopenharmony_ci ap = a->d; 147e1051a39Sopenharmony_ci bp = b->d; 148e1051a39Sopenharmony_ci rp = r->d; 149e1051a39Sopenharmony_ci 150e1051a39Sopenharmony_ci borrow = bn_sub_words(rp, ap, bp, min); 151e1051a39Sopenharmony_ci ap += min; 152e1051a39Sopenharmony_ci rp += min; 153e1051a39Sopenharmony_ci 154e1051a39Sopenharmony_ci while (dif) { 155e1051a39Sopenharmony_ci dif--; 156e1051a39Sopenharmony_ci t1 = *(ap++); 157e1051a39Sopenharmony_ci t2 = (t1 - borrow) & BN_MASK2; 158e1051a39Sopenharmony_ci *(rp++) = t2; 159e1051a39Sopenharmony_ci borrow &= (t1 == 0); 160e1051a39Sopenharmony_ci } 161e1051a39Sopenharmony_ci 162e1051a39Sopenharmony_ci while (max && *--rp == 0) 163e1051a39Sopenharmony_ci max--; 164e1051a39Sopenharmony_ci 165e1051a39Sopenharmony_ci r->top = max; 166e1051a39Sopenharmony_ci r->neg = 0; 167e1051a39Sopenharmony_ci bn_pollute(r); 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_ci return 1; 170e1051a39Sopenharmony_ci} 171e1051a39Sopenharmony_ci 172