xref: /freebsd/crypto/openssl/crypto/bn/bn_add.c (revision b077aed3)
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