1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1998-2021 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_ciint BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
14e1051a39Sopenharmony_ci{
15e1051a39Sopenharmony_ci    /*
16e1051a39Sopenharmony_ci     * like BN_mod, but returns non-negative remainder (i.e., 0 <= r < |d|
17e1051a39Sopenharmony_ci     * always holds)
18e1051a39Sopenharmony_ci     */
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ci    if (!(BN_mod(r, m, d, ctx)))
21e1051a39Sopenharmony_ci        return 0;
22e1051a39Sopenharmony_ci    if (!r->neg)
23e1051a39Sopenharmony_ci        return 1;
24e1051a39Sopenharmony_ci    /* now   -|d| < r < 0,  so we have to set  r := r + |d| */
25e1051a39Sopenharmony_ci    return (d->neg ? BN_sub : BN_add) (r, r, d);
26e1051a39Sopenharmony_ci}
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_ciint BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
29e1051a39Sopenharmony_ci               BN_CTX *ctx)
30e1051a39Sopenharmony_ci{
31e1051a39Sopenharmony_ci    if (!BN_add(r, a, b))
32e1051a39Sopenharmony_ci        return 0;
33e1051a39Sopenharmony_ci    return BN_nnmod(r, r, m, ctx);
34e1051a39Sopenharmony_ci}
35e1051a39Sopenharmony_ci
36e1051a39Sopenharmony_ci/*
37e1051a39Sopenharmony_ci * BN_mod_add variant that may be used if both a and b are non-negative and
38e1051a39Sopenharmony_ci * less than m. The original algorithm was
39e1051a39Sopenharmony_ci *
40e1051a39Sopenharmony_ci *    if (!BN_uadd(r, a, b))
41e1051a39Sopenharmony_ci *       return 0;
42e1051a39Sopenharmony_ci *    if (BN_ucmp(r, m) >= 0)
43e1051a39Sopenharmony_ci *       return BN_usub(r, r, m);
44e1051a39Sopenharmony_ci *
45e1051a39Sopenharmony_ci * which is replaced with addition, subtracting modulus, and conditional
46e1051a39Sopenharmony_ci * move depending on whether or not subtraction borrowed.
47e1051a39Sopenharmony_ci */
48e1051a39Sopenharmony_ciint bn_mod_add_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
49e1051a39Sopenharmony_ci                         const BIGNUM *m)
50e1051a39Sopenharmony_ci{
51e1051a39Sopenharmony_ci    size_t i, ai, bi, mtop = m->top;
52e1051a39Sopenharmony_ci    BN_ULONG storage[1024 / BN_BITS2];
53e1051a39Sopenharmony_ci    BN_ULONG carry, temp, mask, *rp, *tp = storage;
54e1051a39Sopenharmony_ci    const BN_ULONG *ap, *bp;
55e1051a39Sopenharmony_ci
56e1051a39Sopenharmony_ci    if (bn_wexpand(r, mtop) == NULL)
57e1051a39Sopenharmony_ci        return 0;
58e1051a39Sopenharmony_ci
59e1051a39Sopenharmony_ci    if (mtop > sizeof(storage) / sizeof(storage[0])) {
60e1051a39Sopenharmony_ci        tp = OPENSSL_malloc(mtop * sizeof(BN_ULONG));
61e1051a39Sopenharmony_ci        if (tp == NULL) {
62e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BN, ERR_R_MALLOC_FAILURE);
63e1051a39Sopenharmony_ci            return 0;
64e1051a39Sopenharmony_ci        }
65e1051a39Sopenharmony_ci    }
66e1051a39Sopenharmony_ci
67e1051a39Sopenharmony_ci    ap = a->d != NULL ? a->d : tp;
68e1051a39Sopenharmony_ci    bp = b->d != NULL ? b->d : tp;
69e1051a39Sopenharmony_ci
70e1051a39Sopenharmony_ci    for (i = 0, ai = 0, bi = 0, carry = 0; i < mtop;) {
71e1051a39Sopenharmony_ci        mask = (BN_ULONG)0 - ((i - a->top) >> (8 * sizeof(i) - 1));
72e1051a39Sopenharmony_ci        temp = ((ap[ai] & mask) + carry) & BN_MASK2;
73e1051a39Sopenharmony_ci        carry = (temp < carry);
74e1051a39Sopenharmony_ci
75e1051a39Sopenharmony_ci        mask = (BN_ULONG)0 - ((i - b->top) >> (8 * sizeof(i) - 1));
76e1051a39Sopenharmony_ci        tp[i] = ((bp[bi] & mask) + temp) & BN_MASK2;
77e1051a39Sopenharmony_ci        carry += (tp[i] < temp);
78e1051a39Sopenharmony_ci
79e1051a39Sopenharmony_ci        i++;
80e1051a39Sopenharmony_ci        ai += (i - a->dmax) >> (8 * sizeof(i) - 1);
81e1051a39Sopenharmony_ci        bi += (i - b->dmax) >> (8 * sizeof(i) - 1);
82e1051a39Sopenharmony_ci    }
83e1051a39Sopenharmony_ci    rp = r->d;
84e1051a39Sopenharmony_ci    carry -= bn_sub_words(rp, tp, m->d, mtop);
85e1051a39Sopenharmony_ci    for (i = 0; i < mtop; i++) {
86e1051a39Sopenharmony_ci        rp[i] = (carry & tp[i]) | (~carry & rp[i]);
87e1051a39Sopenharmony_ci        ((volatile BN_ULONG *)tp)[i] = 0;
88e1051a39Sopenharmony_ci    }
89e1051a39Sopenharmony_ci    r->top = mtop;
90e1051a39Sopenharmony_ci    r->flags |= BN_FLG_FIXED_TOP;
91e1051a39Sopenharmony_ci    r->neg = 0;
92e1051a39Sopenharmony_ci
93e1051a39Sopenharmony_ci    if (tp != storage)
94e1051a39Sopenharmony_ci        OPENSSL_free(tp);
95e1051a39Sopenharmony_ci
96e1051a39Sopenharmony_ci    return 1;
97e1051a39Sopenharmony_ci}
98e1051a39Sopenharmony_ci
99e1051a39Sopenharmony_ciint BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
100e1051a39Sopenharmony_ci                     const BIGNUM *m)
101e1051a39Sopenharmony_ci{
102e1051a39Sopenharmony_ci    int ret = bn_mod_add_fixed_top(r, a, b, m);
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_ci    if (ret)
105e1051a39Sopenharmony_ci        bn_correct_top(r);
106e1051a39Sopenharmony_ci
107e1051a39Sopenharmony_ci    return ret;
108e1051a39Sopenharmony_ci}
109e1051a39Sopenharmony_ci
110e1051a39Sopenharmony_ciint BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
111e1051a39Sopenharmony_ci               BN_CTX *ctx)
112e1051a39Sopenharmony_ci{
113e1051a39Sopenharmony_ci    if (!BN_sub(r, a, b))
114e1051a39Sopenharmony_ci        return 0;
115e1051a39Sopenharmony_ci    return BN_nnmod(r, r, m, ctx);
116e1051a39Sopenharmony_ci}
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ci/*
119e1051a39Sopenharmony_ci * BN_mod_sub variant that may be used if both a and b are non-negative,
120e1051a39Sopenharmony_ci * a is less than m, while b is of same bit width as m. It's implemented
121e1051a39Sopenharmony_ci * as subtraction followed by two conditional additions.
122e1051a39Sopenharmony_ci *
123e1051a39Sopenharmony_ci * 0 <= a < m
124e1051a39Sopenharmony_ci * 0 <= b < 2^w < 2*m
125e1051a39Sopenharmony_ci *
126e1051a39Sopenharmony_ci * after subtraction
127e1051a39Sopenharmony_ci *
128e1051a39Sopenharmony_ci * -2*m < r = a - b < m
129e1051a39Sopenharmony_ci *
130e1051a39Sopenharmony_ci * Thus it takes up to two conditional additions to make |r| positive.
131e1051a39Sopenharmony_ci */
132e1051a39Sopenharmony_ciint bn_mod_sub_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
133e1051a39Sopenharmony_ci                         const BIGNUM *m)
134e1051a39Sopenharmony_ci{
135e1051a39Sopenharmony_ci    size_t i, ai, bi, mtop = m->top;
136e1051a39Sopenharmony_ci    BN_ULONG borrow, carry, ta, tb, mask, *rp;
137e1051a39Sopenharmony_ci    const BN_ULONG *ap, *bp;
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_ci    if (bn_wexpand(r, mtop) == NULL)
140e1051a39Sopenharmony_ci        return 0;
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_ci    rp = r->d;
143e1051a39Sopenharmony_ci    ap = a->d != NULL ? a->d : rp;
144e1051a39Sopenharmony_ci    bp = b->d != NULL ? b->d : rp;
145e1051a39Sopenharmony_ci
146e1051a39Sopenharmony_ci    for (i = 0, ai = 0, bi = 0, borrow = 0; i < mtop;) {
147e1051a39Sopenharmony_ci        mask = (BN_ULONG)0 - ((i - a->top) >> (8 * sizeof(i) - 1));
148e1051a39Sopenharmony_ci        ta = ap[ai] & mask;
149e1051a39Sopenharmony_ci
150e1051a39Sopenharmony_ci        mask = (BN_ULONG)0 - ((i - b->top) >> (8 * sizeof(i) - 1));
151e1051a39Sopenharmony_ci        tb = bp[bi] & mask;
152e1051a39Sopenharmony_ci        rp[i] = ta - tb - borrow;
153e1051a39Sopenharmony_ci        if (ta != tb)
154e1051a39Sopenharmony_ci            borrow = (ta < tb);
155e1051a39Sopenharmony_ci
156e1051a39Sopenharmony_ci        i++;
157e1051a39Sopenharmony_ci        ai += (i - a->dmax) >> (8 * sizeof(i) - 1);
158e1051a39Sopenharmony_ci        bi += (i - b->dmax) >> (8 * sizeof(i) - 1);
159e1051a39Sopenharmony_ci    }
160e1051a39Sopenharmony_ci    ap = m->d;
161e1051a39Sopenharmony_ci    for (i = 0, mask = 0 - borrow, carry = 0; i < mtop; i++) {
162e1051a39Sopenharmony_ci        ta = ((ap[i] & mask) + carry) & BN_MASK2;
163e1051a39Sopenharmony_ci        carry = (ta < carry);
164e1051a39Sopenharmony_ci        rp[i] = (rp[i] + ta) & BN_MASK2;
165e1051a39Sopenharmony_ci        carry += (rp[i] < ta);
166e1051a39Sopenharmony_ci    }
167e1051a39Sopenharmony_ci    borrow -= carry;
168e1051a39Sopenharmony_ci    for (i = 0, mask = 0 - borrow, carry = 0; i < mtop; i++) {
169e1051a39Sopenharmony_ci        ta = ((ap[i] & mask) + carry) & BN_MASK2;
170e1051a39Sopenharmony_ci        carry = (ta < carry);
171e1051a39Sopenharmony_ci        rp[i] = (rp[i] + ta) & BN_MASK2;
172e1051a39Sopenharmony_ci        carry += (rp[i] < ta);
173e1051a39Sopenharmony_ci    }
174e1051a39Sopenharmony_ci
175e1051a39Sopenharmony_ci    r->top = mtop;
176e1051a39Sopenharmony_ci    r->flags |= BN_FLG_FIXED_TOP;
177e1051a39Sopenharmony_ci    r->neg = 0;
178e1051a39Sopenharmony_ci
179e1051a39Sopenharmony_ci    return 1;
180e1051a39Sopenharmony_ci}
181e1051a39Sopenharmony_ci
182e1051a39Sopenharmony_ci/*
183e1051a39Sopenharmony_ci * BN_mod_sub variant that may be used if both a and b are non-negative and
184e1051a39Sopenharmony_ci * less than m
185e1051a39Sopenharmony_ci */
186e1051a39Sopenharmony_ciint BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
187e1051a39Sopenharmony_ci                     const BIGNUM *m)
188e1051a39Sopenharmony_ci{
189e1051a39Sopenharmony_ci    if (!BN_sub(r, a, b))
190e1051a39Sopenharmony_ci        return 0;
191e1051a39Sopenharmony_ci    if (r->neg)
192e1051a39Sopenharmony_ci        return BN_add(r, r, m);
193e1051a39Sopenharmony_ci    return 1;
194e1051a39Sopenharmony_ci}
195e1051a39Sopenharmony_ci
196e1051a39Sopenharmony_ci/* slow but works */
197e1051a39Sopenharmony_ciint BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
198e1051a39Sopenharmony_ci               BN_CTX *ctx)
199e1051a39Sopenharmony_ci{
200e1051a39Sopenharmony_ci    BIGNUM *t;
201e1051a39Sopenharmony_ci    int ret = 0;
202e1051a39Sopenharmony_ci
203e1051a39Sopenharmony_ci    bn_check_top(a);
204e1051a39Sopenharmony_ci    bn_check_top(b);
205e1051a39Sopenharmony_ci    bn_check_top(m);
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
208e1051a39Sopenharmony_ci    if ((t = BN_CTX_get(ctx)) == NULL)
209e1051a39Sopenharmony_ci        goto err;
210e1051a39Sopenharmony_ci    if (a == b) {
211e1051a39Sopenharmony_ci        if (!BN_sqr(t, a, ctx))
212e1051a39Sopenharmony_ci            goto err;
213e1051a39Sopenharmony_ci    } else {
214e1051a39Sopenharmony_ci        if (!BN_mul(t, a, b, ctx))
215e1051a39Sopenharmony_ci            goto err;
216e1051a39Sopenharmony_ci    }
217e1051a39Sopenharmony_ci    if (!BN_nnmod(r, t, m, ctx))
218e1051a39Sopenharmony_ci        goto err;
219e1051a39Sopenharmony_ci    bn_check_top(r);
220e1051a39Sopenharmony_ci    ret = 1;
221e1051a39Sopenharmony_ci err:
222e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
223e1051a39Sopenharmony_ci    return ret;
224e1051a39Sopenharmony_ci}
225e1051a39Sopenharmony_ci
226e1051a39Sopenharmony_ciint BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
227e1051a39Sopenharmony_ci{
228e1051a39Sopenharmony_ci    if (!BN_sqr(r, a, ctx))
229e1051a39Sopenharmony_ci        return 0;
230e1051a39Sopenharmony_ci    /* r->neg == 0,  thus we don't need BN_nnmod */
231e1051a39Sopenharmony_ci    return BN_mod(r, r, m, ctx);
232e1051a39Sopenharmony_ci}
233e1051a39Sopenharmony_ci
234e1051a39Sopenharmony_ciint BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
235e1051a39Sopenharmony_ci{
236e1051a39Sopenharmony_ci    if (!BN_lshift1(r, a))
237e1051a39Sopenharmony_ci        return 0;
238e1051a39Sopenharmony_ci    bn_check_top(r);
239e1051a39Sopenharmony_ci    return BN_nnmod(r, r, m, ctx);
240e1051a39Sopenharmony_ci}
241e1051a39Sopenharmony_ci
242e1051a39Sopenharmony_ci/*
243e1051a39Sopenharmony_ci * BN_mod_lshift1 variant that may be used if a is non-negative and less than
244e1051a39Sopenharmony_ci * m
245e1051a39Sopenharmony_ci */
246e1051a39Sopenharmony_ciint BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m)
247e1051a39Sopenharmony_ci{
248e1051a39Sopenharmony_ci    if (!BN_lshift1(r, a))
249e1051a39Sopenharmony_ci        return 0;
250e1051a39Sopenharmony_ci    bn_check_top(r);
251e1051a39Sopenharmony_ci    if (BN_cmp(r, m) >= 0)
252e1051a39Sopenharmony_ci        return BN_sub(r, r, m);
253e1051a39Sopenharmony_ci    return 1;
254e1051a39Sopenharmony_ci}
255e1051a39Sopenharmony_ci
256e1051a39Sopenharmony_ciint BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
257e1051a39Sopenharmony_ci                  BN_CTX *ctx)
258e1051a39Sopenharmony_ci{
259e1051a39Sopenharmony_ci    BIGNUM *abs_m = NULL;
260e1051a39Sopenharmony_ci    int ret;
261e1051a39Sopenharmony_ci
262e1051a39Sopenharmony_ci    if (!BN_nnmod(r, a, m, ctx))
263e1051a39Sopenharmony_ci        return 0;
264e1051a39Sopenharmony_ci
265e1051a39Sopenharmony_ci    if (m->neg) {
266e1051a39Sopenharmony_ci        abs_m = BN_dup(m);
267e1051a39Sopenharmony_ci        if (abs_m == NULL)
268e1051a39Sopenharmony_ci            return 0;
269e1051a39Sopenharmony_ci        abs_m->neg = 0;
270e1051a39Sopenharmony_ci    }
271e1051a39Sopenharmony_ci
272e1051a39Sopenharmony_ci    ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m));
273e1051a39Sopenharmony_ci    bn_check_top(r);
274e1051a39Sopenharmony_ci
275e1051a39Sopenharmony_ci    BN_free(abs_m);
276e1051a39Sopenharmony_ci    return ret;
277e1051a39Sopenharmony_ci}
278e1051a39Sopenharmony_ci
279e1051a39Sopenharmony_ci/*
280e1051a39Sopenharmony_ci * BN_mod_lshift variant that may be used if a is non-negative and less than
281e1051a39Sopenharmony_ci * m
282e1051a39Sopenharmony_ci */
283e1051a39Sopenharmony_ciint BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m)
284e1051a39Sopenharmony_ci{
285e1051a39Sopenharmony_ci    if (r != a) {
286e1051a39Sopenharmony_ci        if (BN_copy(r, a) == NULL)
287e1051a39Sopenharmony_ci            return 0;
288e1051a39Sopenharmony_ci    }
289e1051a39Sopenharmony_ci
290e1051a39Sopenharmony_ci    while (n > 0) {
291e1051a39Sopenharmony_ci        int max_shift;
292e1051a39Sopenharmony_ci
293e1051a39Sopenharmony_ci        /* 0 < r < m */
294e1051a39Sopenharmony_ci        max_shift = BN_num_bits(m) - BN_num_bits(r);
295e1051a39Sopenharmony_ci        /* max_shift >= 0 */
296e1051a39Sopenharmony_ci
297e1051a39Sopenharmony_ci        if (max_shift < 0) {
298e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BN, BN_R_INPUT_NOT_REDUCED);
299e1051a39Sopenharmony_ci            return 0;
300e1051a39Sopenharmony_ci        }
301e1051a39Sopenharmony_ci
302e1051a39Sopenharmony_ci        if (max_shift > n)
303e1051a39Sopenharmony_ci            max_shift = n;
304e1051a39Sopenharmony_ci
305e1051a39Sopenharmony_ci        if (max_shift) {
306e1051a39Sopenharmony_ci            if (!BN_lshift(r, r, max_shift))
307e1051a39Sopenharmony_ci                return 0;
308e1051a39Sopenharmony_ci            n -= max_shift;
309e1051a39Sopenharmony_ci        } else {
310e1051a39Sopenharmony_ci            if (!BN_lshift1(r, r))
311e1051a39Sopenharmony_ci                return 0;
312e1051a39Sopenharmony_ci            --n;
313e1051a39Sopenharmony_ci        }
314e1051a39Sopenharmony_ci
315e1051a39Sopenharmony_ci        /* BN_num_bits(r) <= BN_num_bits(m) */
316e1051a39Sopenharmony_ci
317e1051a39Sopenharmony_ci        if (BN_cmp(r, m) >= 0) {
318e1051a39Sopenharmony_ci            if (!BN_sub(r, r, m))
319e1051a39Sopenharmony_ci                return 0;
320e1051a39Sopenharmony_ci        }
321e1051a39Sopenharmony_ci    }
322e1051a39Sopenharmony_ci    bn_check_top(r);
323e1051a39Sopenharmony_ci
324e1051a39Sopenharmony_ci    return 1;
325e1051a39Sopenharmony_ci}
326