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