Coverage Report

Created: 2025-06-24 07:00

/src/boringssl/crypto/fipsmodule/bn/mul.cc.inc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/bn.h>
16
17
#include <assert.h>
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include <openssl/err.h>
22
#include <openssl/mem.h>
23
24
#include "../../internal.h"
25
#include "internal.h"
26
27
28
static void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, size_t na,
29
571k
                          const BN_ULONG *b, size_t nb) {
30
571k
  if (na < nb) {
31
7.09k
    size_t itmp = na;
32
7.09k
    na = nb;
33
7.09k
    nb = itmp;
34
7.09k
    const BN_ULONG *ltmp = a;
35
7.09k
    a = b;
36
7.09k
    b = ltmp;
37
7.09k
  }
38
571k
  BN_ULONG *rr = &(r[na]);
39
571k
  if (nb == 0) {
40
0
    OPENSSL_memset(r, 0, na * sizeof(BN_ULONG));
41
0
    return;
42
0
  }
43
571k
  rr[0] = bn_mul_words(r, a, na, b[0]);
44
45
837k
  for (;;) {
46
837k
    if (--nb == 0) {
47
223k
      return;
48
223k
    }
49
614k
    rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
50
614k
    if (--nb == 0) {
51
32.3k
      return;
52
32.3k
    }
53
582k
    rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
54
582k
    if (--nb == 0) {
55
9.27k
      return;
56
9.27k
    }
57
573k
    rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
58
573k
    if (--nb == 0) {
59
306k
      return;
60
306k
    }
61
266k
    rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
62
266k
    rr += 4;
63
266k
    r += 4;
64
266k
    b += 4;
65
266k
  }
66
571k
}
67
68
// bn_sub_part_words sets |r| to |a| - |b|. It returns the borrow bit, which is
69
// one if the operation underflowed and zero otherwise. |cl| is the common
70
// length, that is, the shorter of len(a) or len(b). |dl| is the delta length,
71
// that is, len(a) - len(b). |r|'s length matches the larger of |a| and |b|, or
72
// cl + abs(dl).
73
//
74
// TODO(davidben): Make this take |size_t|. The |cl| + |dl| calling convention
75
// is confusing.
76
static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
77
0
                                  const BN_ULONG *b, int cl, int dl) {
78
0
  assert(cl >= 0);
79
0
  BN_ULONG borrow = bn_sub_words(r, a, b, cl);
80
0
  if (dl == 0) {
81
0
    return borrow;
82
0
  }
83
84
0
  r += cl;
85
0
  a += cl;
86
0
  b += cl;
87
88
0
  if (dl < 0) {
89
    // |a| is shorter than |b|. Complete the subtraction as if the excess words
90
    // in |a| were zeros.
91
0
    dl = -dl;
92
0
    for (int i = 0; i < dl; i++) {
93
0
      r[i] = CRYPTO_subc_w(0, b[i], borrow, &borrow);
94
0
    }
95
0
  } else {
96
    // |b| is shorter than |a|. Complete the subtraction as if the excess words
97
    // in |b| were zeros.
98
0
    for (int i = 0; i < dl; i++) {
99
0
      r[i] = CRYPTO_subc_w(a[i], 0, borrow, &borrow);
100
0
    }
101
0
  }
102
103
0
  return borrow;
104
0
}
105
106
// bn_abs_sub_part_words computes |r| = |a| - |b|, storing the absolute value
107
// and returning a mask of all ones if the result was negative and all zeros if
108
// the result was positive. |cl| and |dl| follow the |bn_sub_part_words| calling
109
// convention.
110
//
111
// TODO(davidben): Make this take |size_t|. The |cl| + |dl| calling convention
112
// is confusing.
113
//
114
// TODO(davidben): This function used to be used as part of a general Karatsuba
115
// multiplication implementation, which had to account for differently-sized
116
// inputs. Now it is only used as part of RSA key generation, which does not
117
// need all this.
118
static BN_ULONG bn_abs_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
119
                                      const BN_ULONG *b, int cl, int dl,
120
0
                                      BN_ULONG *tmp) {
121
0
  BN_ULONG borrow = bn_sub_part_words(tmp, a, b, cl, dl);
122
0
  bn_sub_part_words(r, b, a, cl, -dl);
123
0
  int r_len = cl + (dl < 0 ? -dl : dl);
124
0
  borrow = 0 - borrow;
125
0
  bn_select_words(r, borrow, r /* tmp < 0 */, tmp /* tmp >= 0 */, r_len);
126
0
  return borrow;
127
0
}
128
129
int bn_abs_sub_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
130
0
                         BN_CTX *ctx) {
131
0
  int cl = a->width < b->width ? a->width : b->width;
132
0
  int dl = a->width - b->width;
133
0
  int r_len = a->width < b->width ? b->width : a->width;
134
0
  bssl::BN_CTXScope scope(ctx);
135
0
  BIGNUM *tmp = BN_CTX_get(ctx);
136
0
  if (tmp == nullptr || !bn_wexpand(r, r_len) || !bn_wexpand(tmp, r_len)) {
137
0
    return 0;
138
0
  }
139
0
  bn_abs_sub_part_words(r->d, a->d, b->d, cl, dl, tmp->d);
140
0
  r->width = r_len;
141
0
  return 1;
142
0
}
143
144
// bn_mul_impl implements |BN_mul| and |bn_mul_consttime|. Note this function
145
// breaks |BIGNUM| invariants and may return a negative zero. This is handled by
146
// the callers.
147
static int bn_mul_impl(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
148
641k
                       BN_CTX *ctx) {
149
641k
  int al = a->width;
150
641k
  int bl = b->width;
151
641k
  if (al == 0 || bl == 0) {
152
56.5k
    BN_zero(r);
153
56.5k
    return 1;
154
56.5k
  }
155
156
584k
  int i, top;
157
584k
  BIGNUM *rr;
158
584k
  bssl::BN_CTXScope scope(ctx);
159
584k
  if (r == a || r == b) {
160
252k
    rr = BN_CTX_get(ctx);
161
252k
    if (rr == NULL) {
162
0
      return 0;
163
0
    }
164
332k
  } else {
165
332k
    rr = r;
166
332k
  }
167
584k
  rr->neg = a->neg ^ b->neg;
168
169
584k
  i = al - bl;
170
584k
  if (i == 0) {
171
575k
    if (al == 8) {
172
13.4k
      if (!bn_wexpand(rr, 16)) {
173
0
        return 0;
174
0
      }
175
13.4k
      rr->width = 16;
176
13.4k
      bn_mul_comba8(rr->d, a->d, b->d);
177
13.4k
      goto end;
178
13.4k
    }
179
575k
  }
180
181
571k
  top = al + bl;
182
571k
  if (!bn_wexpand(rr, top)) {
183
0
    return 0;
184
0
  }
185
571k
  rr->width = top;
186
571k
  bn_mul_normal(rr->d, a->d, al, b->d, bl);
187
188
584k
end:
189
584k
  if (r != rr && !BN_copy(r, rr)) {
190
0
    return 0;
191
0
  }
192
584k
  return 1;
193
584k
}
194
195
539k
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
196
539k
  if (!bn_mul_impl(r, a, b, ctx)) {
197
0
    return 0;
198
0
  }
199
200
  // This additionally fixes any negative zeros created by |bn_mul_impl|.
201
539k
  bn_set_minimal_width(r);
202
539k
  return 1;
203
539k
}
204
205
101k
int bn_mul_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
206
  // Prevent negative zeros.
207
101k
  if (a->neg || b->neg) {
208
0
    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
209
0
    return 0;
210
0
  }
211
212
101k
  return bn_mul_impl(r, a, b, ctx);
213
101k
}
214
215
void bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a,
216
0
                  const BN_ULONG *b, size_t num_b) {
217
0
  if (num_r != num_a + num_b) {
218
0
    abort();
219
0
  }
220
  // TODO(davidben): Should this call |bn_mul_comba4| too? |BN_mul| does not
221
  // hit that code.
222
0
  if (num_a == 8 && num_b == 8) {
223
0
    bn_mul_comba8(r, a, b);
224
0
  } else {
225
0
    bn_mul_normal(r, a, num_a, b, num_b);
226
0
  }
227
0
}
228
229
309k
static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, size_t n) {
230
309k
  if (n == 0) {
231
0
    return;
232
0
  }
233
234
309k
  size_t max = n * 2;
235
309k
  const BN_ULONG *ap = a;
236
309k
  BN_ULONG *rp = r;
237
309k
  rp[0] = rp[max - 1] = 0;
238
309k
  rp++;
239
240
  // Compute the contribution of a[i] * a[j] for all i < j.
241
309k
  if (n > 1) {
242
4.36k
    ap++;
243
4.36k
    rp[n - 1] = bn_mul_words(rp, ap, n - 1, ap[-1]);
244
4.36k
    rp += 2;
245
4.36k
  }
246
309k
  if (n > 2) {
247
24.8k
    for (size_t i = n - 2; i > 0; i--) {
248
21.2k
      ap++;
249
21.2k
      rp[i] = bn_mul_add_words(rp, ap, i, ap[-1]);
250
21.2k
      rp += 2;
251
21.2k
    }
252
3.56k
  }
253
254
  // The final result fits in |max| words, so none of the following operations
255
  // will overflow.
256
257
  // Double |r|, giving the contribution of a[i] * a[j] for all i != j.
258
309k
  bn_add_words(r, r, r, max);
259
260
  // Add in the contribution of a[i] * a[i] for all i.
261
309k
  bn_sqr_add_words(r, a, n);
262
309k
}
263
264
18.6k
int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
265
18.6k
  if (!bn->width) {
266
10.6k
    return 1;
267
10.6k
  }
268
269
7.95k
  if (w == 0) {
270
0
    BN_zero(bn);
271
0
    return 1;
272
0
  }
273
274
7.95k
  BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->width, w);
275
7.95k
  if (ll) {
276
7.05k
    if (!bn_wexpand(bn, bn->width + 1)) {
277
0
      return 0;
278
0
    }
279
7.05k
    bn->d[bn->width++] = ll;
280
7.05k
  }
281
282
7.95k
  return 1;
283
7.95k
}
284
285
6.45M
int bn_sqr_consttime(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
286
6.45M
  int al = a->width;
287
6.45M
  if (al <= 0) {
288
10.8k
    r->width = 0;
289
10.8k
    r->neg = 0;
290
10.8k
    return 1;
291
10.8k
  }
292
293
6.44M
  bssl::BN_CTXScope scope(ctx);
294
6.44M
  BIGNUM *rr = (a != r) ? r : BN_CTX_get(ctx);
295
6.44M
  if (!rr) {
296
0
    return 0;
297
0
  }
298
299
6.44M
  int max = 2 * al;  // Non-zero (from above)
300
6.44M
  if (!bn_wexpand(rr, max)) {
301
0
    return 0;
302
0
  }
303
304
6.44M
  if (al == 4) {
305
6.13M
    bn_sqr_comba4(rr->d, a->d);
306
6.13M
  } else if (al == 8) {
307
375
    bn_sqr_comba8(rr->d, a->d);
308
309k
  } else {
309
309k
    bn_sqr_normal(rr->d, a->d, al);
310
309k
  }
311
312
6.44M
  rr->neg = 0;
313
6.44M
  rr->width = max;
314
315
6.44M
  if (rr != r && !BN_copy(r, rr)) {
316
0
    return 0;
317
0
  }
318
6.44M
  return 1;
319
6.44M
}
320
321
6.17M
int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
322
6.17M
  if (!bn_sqr_consttime(r, a, ctx)) {
323
0
    return 0;
324
0
  }
325
326
6.17M
  bn_set_minimal_width(r);
327
6.17M
  return 1;
328
6.17M
}
329
330
0
void bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a) {
331
0
  assert(r != a);
332
0
  if (num_r != 2 * num_a) {
333
0
    abort();
334
0
  }
335
0
  if (num_a == 4) {
336
0
    bn_sqr_comba4(r, a);
337
0
  } else if (num_a == 8) {
338
0
    bn_sqr_comba8(r, a);
339
0
  } else {
340
0
    bn_sqr_normal(r, a, num_a);
341
0
  }
342
0
}