1e71b7053SJung-uk Kim /*
2b077aed3SPierre Pronchery * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
374664626SKris Kennaway *
4b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy
6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html
874664626SKris Kennaway */
974664626SKris Kennaway
10e71b7053SJung-uk Kim #include "internal/cryptlib.h"
1117f01e99SJung-uk Kim #include "bn_local.h"
1274664626SKris Kennaway
13e71b7053SJung-uk Kim /* signed add of b to a. */
BN_add(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)14f579bf8eSKris Kennaway int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
1574664626SKris Kennaway {
16e71b7053SJung-uk Kim int ret, r_neg, cmp_res;
1774664626SKris Kennaway
1874664626SKris Kennaway bn_check_top(a);
1974664626SKris Kennaway bn_check_top(b);
2074664626SKris Kennaway
21e71b7053SJung-uk Kim if (a->neg == b->neg) {
22e71b7053SJung-uk Kim r_neg = a->neg;
233b4e3dcbSSimon L. B. Nielsen ret = BN_uadd(r, a, b);
24e71b7053SJung-uk Kim } else {
25e71b7053SJung-uk Kim cmp_res = BN_ucmp(a, b);
26e71b7053SJung-uk Kim if (cmp_res > 0) {
27e71b7053SJung-uk Kim r_neg = a->neg;
28e71b7053SJung-uk Kim ret = BN_usub(r, a, b);
29e71b7053SJung-uk Kim } else if (cmp_res < 0) {
30e71b7053SJung-uk Kim r_neg = b->neg;
31e71b7053SJung-uk Kim ret = BN_usub(r, b, a);
32e71b7053SJung-uk Kim } else {
33e71b7053SJung-uk Kim r_neg = 0;
34e71b7053SJung-uk Kim BN_zero(r);
35e71b7053SJung-uk Kim ret = 1;
36e71b7053SJung-uk Kim }
37e71b7053SJung-uk Kim }
38e71b7053SJung-uk Kim
39e71b7053SJung-uk Kim r->neg = r_neg;
403b4e3dcbSSimon L. B. Nielsen bn_check_top(r);
413b4e3dcbSSimon L. B. Nielsen return ret;
4274664626SKris Kennaway }
4374664626SKris Kennaway
44e71b7053SJung-uk Kim /* signed sub of b from a. */
BN_sub(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)45e71b7053SJung-uk Kim int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
46e71b7053SJung-uk Kim {
47e71b7053SJung-uk Kim int ret, r_neg, cmp_res;
48e71b7053SJung-uk Kim
49e71b7053SJung-uk Kim bn_check_top(a);
50e71b7053SJung-uk Kim bn_check_top(b);
51e71b7053SJung-uk Kim
52e71b7053SJung-uk Kim if (a->neg != b->neg) {
53e71b7053SJung-uk Kim r_neg = a->neg;
54e71b7053SJung-uk Kim ret = BN_uadd(r, a, b);
55e71b7053SJung-uk Kim } else {
56e71b7053SJung-uk Kim cmp_res = BN_ucmp(a, b);
57e71b7053SJung-uk Kim if (cmp_res > 0) {
58e71b7053SJung-uk Kim r_neg = a->neg;
59e71b7053SJung-uk Kim ret = BN_usub(r, a, b);
60e71b7053SJung-uk Kim } else if (cmp_res < 0) {
61e71b7053SJung-uk Kim r_neg = !b->neg;
62e71b7053SJung-uk Kim ret = BN_usub(r, b, a);
63e71b7053SJung-uk Kim } else {
64e71b7053SJung-uk Kim r_neg = 0;
65e71b7053SJung-uk Kim BN_zero(r);
66e71b7053SJung-uk Kim ret = 1;
67e71b7053SJung-uk Kim }
68e71b7053SJung-uk Kim }
69e71b7053SJung-uk Kim
70e71b7053SJung-uk Kim r->neg = r_neg;
71e71b7053SJung-uk Kim bn_check_top(r);
72e71b7053SJung-uk Kim return ret;
73e71b7053SJung-uk Kim }
74e71b7053SJung-uk Kim
75e71b7053SJung-uk Kim /* unsigned add of b to a, r can be equal to a or b. */
BN_uadd(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)7674664626SKris Kennaway int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
7774664626SKris Kennaway {
783b4e3dcbSSimon L. B. Nielsen int max, min, dif;
79e71b7053SJung-uk Kim const BN_ULONG *ap, *bp;
80e71b7053SJung-uk Kim BN_ULONG *rp, carry, t1, t2;
8174664626SKris Kennaway
8274664626SKris Kennaway bn_check_top(a);
8374664626SKris Kennaway bn_check_top(b);
8474664626SKris Kennaway
856f9291ceSJung-uk Kim if (a->top < b->top) {
86e71b7053SJung-uk Kim const BIGNUM *tmp;
87e71b7053SJung-uk Kim
886f9291ceSJung-uk Kim tmp = a;
896f9291ceSJung-uk Kim a = b;
906f9291ceSJung-uk Kim b = tmp;
916f9291ceSJung-uk Kim }
9274664626SKris Kennaway max = a->top;
9374664626SKris Kennaway min = b->top;
943b4e3dcbSSimon L. B. Nielsen dif = max - min;
9574664626SKris Kennaway
9674664626SKris Kennaway if (bn_wexpand(r, max + 1) == NULL)
973b4e3dcbSSimon L. B. Nielsen return 0;
9874664626SKris Kennaway
9974664626SKris Kennaway r->top = max;
10074664626SKris Kennaway
10174664626SKris Kennaway ap = a->d;
10274664626SKris Kennaway bp = b->d;
10374664626SKris Kennaway rp = r->d;
10474664626SKris Kennaway
10574664626SKris Kennaway carry = bn_add_words(rp, ap, bp, min);
10674664626SKris Kennaway rp += min;
10774664626SKris Kennaway ap += min;
10874664626SKris Kennaway
1096f9291ceSJung-uk Kim while (dif) {
1103b4e3dcbSSimon L. B. Nielsen dif--;
11174664626SKris Kennaway t1 = *(ap++);
112e71b7053SJung-uk Kim t2 = (t1 + carry) & BN_MASK2;
1133b4e3dcbSSimon L. B. Nielsen *(rp++) = t2;
114e71b7053SJung-uk Kim carry &= (t2 == 0);
11574664626SKris Kennaway }
116e71b7053SJung-uk Kim *rp = carry;
117e71b7053SJung-uk Kim r->top += carry;
118e71b7053SJung-uk Kim
1195c87c606SMark Murray r->neg = 0;
1203b4e3dcbSSimon L. B. Nielsen bn_check_top(r);
1213b4e3dcbSSimon L. B. Nielsen return 1;
12274664626SKris Kennaway }
12374664626SKris Kennaway
12474664626SKris Kennaway /* unsigned subtraction of b from a, a must be larger than b. */
BN_usub(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)12574664626SKris Kennaway int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
12674664626SKris Kennaway {
1273b4e3dcbSSimon L. B. Nielsen int max, min, dif;
128e71b7053SJung-uk Kim BN_ULONG t1, t2, borrow, *rp;
129e71b7053SJung-uk Kim const BN_ULONG *ap, *bp;
13074664626SKris Kennaway
13174664626SKris Kennaway bn_check_top(a);
13274664626SKris Kennaway bn_check_top(b);
13374664626SKris Kennaway
1343b4e3dcbSSimon L. B. Nielsen max = a->top;
1353b4e3dcbSSimon L. B. Nielsen min = b->top;
1363b4e3dcbSSimon L. B. Nielsen dif = max - min;
1373b4e3dcbSSimon L. B. Nielsen
1386f9291ceSJung-uk Kim if (dif < 0) { /* hmm... should not be happening */
139b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BN, BN_R_ARG2_LT_ARG3);
140e71b7053SJung-uk Kim return 0;
14174664626SKris Kennaway }
14274664626SKris Kennaway
1436f9291ceSJung-uk Kim if (bn_wexpand(r, max) == NULL)
144e71b7053SJung-uk Kim return 0;
14574664626SKris Kennaway
14674664626SKris Kennaway ap = a->d;
14774664626SKris Kennaway bp = b->d;
14874664626SKris Kennaway rp = r->d;
14974664626SKris Kennaway
150e71b7053SJung-uk Kim borrow = bn_sub_words(rp, ap, bp, min);
15174664626SKris Kennaway ap += min;
15274664626SKris Kennaway rp += min;
153e71b7053SJung-uk Kim
1546f9291ceSJung-uk Kim while (dif) {
1553b4e3dcbSSimon L. B. Nielsen dif--;
15674664626SKris Kennaway t1 = *(ap++);
157e71b7053SJung-uk Kim t2 = (t1 - borrow) & BN_MASK2;
15874664626SKris Kennaway *(rp++) = t2;
159e71b7053SJung-uk Kim borrow &= (t1 == 0);
16074664626SKris Kennaway }
161e71b7053SJung-uk Kim
162e71b7053SJung-uk Kim while (max && *--rp == 0)
163e71b7053SJung-uk Kim max--;
16474664626SKris Kennaway
16574664626SKris Kennaway r->top = max;
1665c87c606SMark Murray r->neg = 0;
167e71b7053SJung-uk Kim bn_pollute(r);
168e71b7053SJung-uk Kim
169e71b7053SJung-uk Kim return 1;
17074664626SKris Kennaway }
17174664626SKris Kennaway
172