1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2016 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_ciBN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w)
14e1051a39Sopenharmony_ci{
15e1051a39Sopenharmony_ci#ifndef BN_LLONG
16e1051a39Sopenharmony_ci    BN_ULONG ret = 0;
17e1051a39Sopenharmony_ci#else
18e1051a39Sopenharmony_ci    BN_ULLONG ret = 0;
19e1051a39Sopenharmony_ci#endif
20e1051a39Sopenharmony_ci    int i;
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ci    if (w == 0)
23e1051a39Sopenharmony_ci        return (BN_ULONG)-1;
24e1051a39Sopenharmony_ci
25e1051a39Sopenharmony_ci#ifndef BN_LLONG
26e1051a39Sopenharmony_ci    /*
27e1051a39Sopenharmony_ci     * If |w| is too long and we don't have BN_ULLONG then we need to fall
28e1051a39Sopenharmony_ci     * back to using BN_div_word
29e1051a39Sopenharmony_ci     */
30e1051a39Sopenharmony_ci    if (w > ((BN_ULONG)1 << BN_BITS4)) {
31e1051a39Sopenharmony_ci        BIGNUM *tmp = BN_dup(a);
32e1051a39Sopenharmony_ci        if (tmp == NULL)
33e1051a39Sopenharmony_ci            return (BN_ULONG)-1;
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_ci        ret = BN_div_word(tmp, w);
36e1051a39Sopenharmony_ci        BN_free(tmp);
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ci        return ret;
39e1051a39Sopenharmony_ci    }
40e1051a39Sopenharmony_ci#endif
41e1051a39Sopenharmony_ci
42e1051a39Sopenharmony_ci    bn_check_top(a);
43e1051a39Sopenharmony_ci    w &= BN_MASK2;
44e1051a39Sopenharmony_ci    for (i = a->top - 1; i >= 0; i--) {
45e1051a39Sopenharmony_ci#ifndef BN_LLONG
46e1051a39Sopenharmony_ci        /*
47e1051a39Sopenharmony_ci         * We can assume here that | w <= ((BN_ULONG)1 << BN_BITS4) | and so
48e1051a39Sopenharmony_ci         * | ret < ((BN_ULONG)1 << BN_BITS4) | and therefore the shifts here are
49e1051a39Sopenharmony_ci         * safe and will not overflow
50e1051a39Sopenharmony_ci         */
51e1051a39Sopenharmony_ci        ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
52e1051a39Sopenharmony_ci        ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w;
53e1051a39Sopenharmony_ci#else
54e1051a39Sopenharmony_ci        ret = (BN_ULLONG) (((ret << (BN_ULLONG) BN_BITS2) | a->d[i]) %
55e1051a39Sopenharmony_ci                           (BN_ULLONG) w);
56e1051a39Sopenharmony_ci#endif
57e1051a39Sopenharmony_ci    }
58e1051a39Sopenharmony_ci    return (BN_ULONG)ret;
59e1051a39Sopenharmony_ci}
60e1051a39Sopenharmony_ci
61e1051a39Sopenharmony_ciBN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w)
62e1051a39Sopenharmony_ci{
63e1051a39Sopenharmony_ci    BN_ULONG ret = 0;
64e1051a39Sopenharmony_ci    int i, j;
65e1051a39Sopenharmony_ci
66e1051a39Sopenharmony_ci    bn_check_top(a);
67e1051a39Sopenharmony_ci    w &= BN_MASK2;
68e1051a39Sopenharmony_ci
69e1051a39Sopenharmony_ci    if (!w)
70e1051a39Sopenharmony_ci        /* actually this an error (division by zero) */
71e1051a39Sopenharmony_ci        return (BN_ULONG)-1;
72e1051a39Sopenharmony_ci    if (a->top == 0)
73e1051a39Sopenharmony_ci        return 0;
74e1051a39Sopenharmony_ci
75e1051a39Sopenharmony_ci    /* normalize input (so bn_div_words doesn't complain) */
76e1051a39Sopenharmony_ci    j = BN_BITS2 - BN_num_bits_word(w);
77e1051a39Sopenharmony_ci    w <<= j;
78e1051a39Sopenharmony_ci    if (!BN_lshift(a, a, j))
79e1051a39Sopenharmony_ci        return (BN_ULONG)-1;
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_ci    for (i = a->top - 1; i >= 0; i--) {
82e1051a39Sopenharmony_ci        BN_ULONG l, d;
83e1051a39Sopenharmony_ci
84e1051a39Sopenharmony_ci        l = a->d[i];
85e1051a39Sopenharmony_ci        d = bn_div_words(ret, l, w);
86e1051a39Sopenharmony_ci        ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2;
87e1051a39Sopenharmony_ci        a->d[i] = d;
88e1051a39Sopenharmony_ci    }
89e1051a39Sopenharmony_ci    if ((a->top > 0) && (a->d[a->top - 1] == 0))
90e1051a39Sopenharmony_ci        a->top--;
91e1051a39Sopenharmony_ci    ret >>= j;
92e1051a39Sopenharmony_ci    if (!a->top)
93e1051a39Sopenharmony_ci        a->neg = 0; /* don't allow negative zero */
94e1051a39Sopenharmony_ci    bn_check_top(a);
95e1051a39Sopenharmony_ci    return ret;
96e1051a39Sopenharmony_ci}
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ciint BN_add_word(BIGNUM *a, BN_ULONG w)
99e1051a39Sopenharmony_ci{
100e1051a39Sopenharmony_ci    BN_ULONG l;
101e1051a39Sopenharmony_ci    int i;
102e1051a39Sopenharmony_ci
103e1051a39Sopenharmony_ci    bn_check_top(a);
104e1051a39Sopenharmony_ci    w &= BN_MASK2;
105e1051a39Sopenharmony_ci
106e1051a39Sopenharmony_ci    /* degenerate case: w is zero */
107e1051a39Sopenharmony_ci    if (!w)
108e1051a39Sopenharmony_ci        return 1;
109e1051a39Sopenharmony_ci    /* degenerate case: a is zero */
110e1051a39Sopenharmony_ci    if (BN_is_zero(a))
111e1051a39Sopenharmony_ci        return BN_set_word(a, w);
112e1051a39Sopenharmony_ci    /* handle 'a' when negative */
113e1051a39Sopenharmony_ci    if (a->neg) {
114e1051a39Sopenharmony_ci        a->neg = 0;
115e1051a39Sopenharmony_ci        i = BN_sub_word(a, w);
116e1051a39Sopenharmony_ci        if (!BN_is_zero(a))
117e1051a39Sopenharmony_ci            a->neg = !(a->neg);
118e1051a39Sopenharmony_ci        return i;
119e1051a39Sopenharmony_ci    }
120e1051a39Sopenharmony_ci    for (i = 0; w != 0 && i < a->top; i++) {
121e1051a39Sopenharmony_ci        a->d[i] = l = (a->d[i] + w) & BN_MASK2;
122e1051a39Sopenharmony_ci        w = (w > l) ? 1 : 0;
123e1051a39Sopenharmony_ci    }
124e1051a39Sopenharmony_ci    if (w && i == a->top) {
125e1051a39Sopenharmony_ci        if (bn_wexpand(a, a->top + 1) == NULL)
126e1051a39Sopenharmony_ci            return 0;
127e1051a39Sopenharmony_ci        a->top++;
128e1051a39Sopenharmony_ci        a->d[i] = w;
129e1051a39Sopenharmony_ci    }
130e1051a39Sopenharmony_ci    bn_check_top(a);
131e1051a39Sopenharmony_ci    return 1;
132e1051a39Sopenharmony_ci}
133e1051a39Sopenharmony_ci
134e1051a39Sopenharmony_ciint BN_sub_word(BIGNUM *a, BN_ULONG w)
135e1051a39Sopenharmony_ci{
136e1051a39Sopenharmony_ci    int i;
137e1051a39Sopenharmony_ci
138e1051a39Sopenharmony_ci    bn_check_top(a);
139e1051a39Sopenharmony_ci    w &= BN_MASK2;
140e1051a39Sopenharmony_ci
141e1051a39Sopenharmony_ci    /* degenerate case: w is zero */
142e1051a39Sopenharmony_ci    if (!w)
143e1051a39Sopenharmony_ci        return 1;
144e1051a39Sopenharmony_ci    /* degenerate case: a is zero */
145e1051a39Sopenharmony_ci    if (BN_is_zero(a)) {
146e1051a39Sopenharmony_ci        i = BN_set_word(a, w);
147e1051a39Sopenharmony_ci        if (i != 0)
148e1051a39Sopenharmony_ci            BN_set_negative(a, 1);
149e1051a39Sopenharmony_ci        return i;
150e1051a39Sopenharmony_ci    }
151e1051a39Sopenharmony_ci    /* handle 'a' when negative */
152e1051a39Sopenharmony_ci    if (a->neg) {
153e1051a39Sopenharmony_ci        a->neg = 0;
154e1051a39Sopenharmony_ci        i = BN_add_word(a, w);
155e1051a39Sopenharmony_ci        a->neg = 1;
156e1051a39Sopenharmony_ci        return i;
157e1051a39Sopenharmony_ci    }
158e1051a39Sopenharmony_ci
159e1051a39Sopenharmony_ci    if ((a->top == 1) && (a->d[0] < w)) {
160e1051a39Sopenharmony_ci        a->d[0] = w - a->d[0];
161e1051a39Sopenharmony_ci        a->neg = 1;
162e1051a39Sopenharmony_ci        return 1;
163e1051a39Sopenharmony_ci    }
164e1051a39Sopenharmony_ci    i = 0;
165e1051a39Sopenharmony_ci    for (;;) {
166e1051a39Sopenharmony_ci        if (a->d[i] >= w) {
167e1051a39Sopenharmony_ci            a->d[i] -= w;
168e1051a39Sopenharmony_ci            break;
169e1051a39Sopenharmony_ci        } else {
170e1051a39Sopenharmony_ci            a->d[i] = (a->d[i] - w) & BN_MASK2;
171e1051a39Sopenharmony_ci            i++;
172e1051a39Sopenharmony_ci            w = 1;
173e1051a39Sopenharmony_ci        }
174e1051a39Sopenharmony_ci    }
175e1051a39Sopenharmony_ci    if ((a->d[i] == 0) && (i == (a->top - 1)))
176e1051a39Sopenharmony_ci        a->top--;
177e1051a39Sopenharmony_ci    bn_check_top(a);
178e1051a39Sopenharmony_ci    return 1;
179e1051a39Sopenharmony_ci}
180e1051a39Sopenharmony_ci
181e1051a39Sopenharmony_ciint BN_mul_word(BIGNUM *a, BN_ULONG w)
182e1051a39Sopenharmony_ci{
183e1051a39Sopenharmony_ci    BN_ULONG ll;
184e1051a39Sopenharmony_ci
185e1051a39Sopenharmony_ci    bn_check_top(a);
186e1051a39Sopenharmony_ci    w &= BN_MASK2;
187e1051a39Sopenharmony_ci    if (a->top) {
188e1051a39Sopenharmony_ci        if (w == 0)
189e1051a39Sopenharmony_ci            BN_zero(a);
190e1051a39Sopenharmony_ci        else {
191e1051a39Sopenharmony_ci            ll = bn_mul_words(a->d, a->d, a->top, w);
192e1051a39Sopenharmony_ci            if (ll) {
193e1051a39Sopenharmony_ci                if (bn_wexpand(a, a->top + 1) == NULL)
194e1051a39Sopenharmony_ci                    return 0;
195e1051a39Sopenharmony_ci                a->d[a->top++] = ll;
196e1051a39Sopenharmony_ci            }
197e1051a39Sopenharmony_ci        }
198e1051a39Sopenharmony_ci    }
199e1051a39Sopenharmony_ci    bn_check_top(a);
200e1051a39Sopenharmony_ci    return 1;
201e1051a39Sopenharmony_ci}
202