Coverage Report

Created: 2026-10-27 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/bn/mul.cc.inc
Line
Count
Source
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
using namespace bssl;
29
30
static void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, size_t na,
31
549k
                          const BN_ULONG *b, size_t nb) {
32
549k
  if (na < nb) {
33
7.59k
    size_t itmp = na;
34
7.59k
    na = nb;
35
7.59k
    nb = itmp;
36
7.59k
    const BN_ULONG *ltmp = a;
37
7.59k
    a = b;
38
7.59k
    b = ltmp;
39
7.59k
  }
40
549k
  BN_ULONG *rr = &(r[na]);
41
549k
  if (nb == 0) {
42
0
    OPENSSL_memset(r, 0, na * sizeof(BN_ULONG));
43
0
    return;
44
0
  }
45
549k
  rr[0] = bn_mul_words(r, a, na, b[0]);
46
47
931k
  for (;;) {
48
931k
    if (--nb == 0) {
49
222k
      return;
50
222k
    }
51
708k
    rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
52
708k
    if (--nb == 0) {
53
38.9k
      return;
54
38.9k
    }
55
669k
    rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
56
669k
    if (--nb == 0) {
57
14.1k
      return;
58
14.1k
    }
59
655k
    rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
60
655k
    if (--nb == 0) {
61
273k
      return;
62
273k
    }
63
382k
    rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
64
382k
    rr += 4;
65
382k
    r += 4;
66
382k
    b += 4;
67
382k
  }
68
549k
}
69
70
// bn_sub_part_words sets |r| to |a| - |b|. It returns the borrow bit, which is
71
// one if the operation underflowed and zero otherwise. `cl` is the common
72
// length, that is, the shorter of len(a) or len(b). `dl` is the delta length,
73
// that is, len(a) - len(b). |r|'s length matches the larger of |a| and |b|, or
74
// cl + abs(dl).
75
//
76
// TODO(davidben): Make this take `size_t`. The `cl` + `dl` calling convention
77
// is confusing.
78
static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
79
0
                                  const BN_ULONG *b, int cl, int dl) {
80
0
  assert(cl >= 0);
81
0
  BN_ULONG borrow = bn_sub_words(r, a, b, cl);
82
0
  if (dl == 0) {
83
0
    return borrow;
84
0
  }
85
86
0
  r += cl;
87
0
  a += cl;
88
0
  b += cl;
89
90
0
  if (dl < 0) {
91
    // `a` is shorter than `b`. Complete the subtraction as if the excess words
92
    // in `a` were zeros.
93
0
    dl = -dl;
94
0
    for (int i = 0; i < dl; i++) {
95
0
      r[i] = CRYPTO_subc_w(0, b[i], borrow, &borrow);
96
0
    }
97
0
  } else {
98
    // `b` is shorter than `a`. Complete the subtraction as if the excess words
99
    // in `b` were zeros.
100
0
    for (int i = 0; i < dl; i++) {
101
0
      r[i] = CRYPTO_subc_w(a[i], 0, borrow, &borrow);
102
0
    }
103
0
  }
104
105
0
  return borrow;
106
0
}
107
108
// bn_abs_sub_part_words computes |r| = |a| - |b|, storing the absolute value
109
// and returning a mask of all ones if the result was negative and all zeros if
110
// the result was positive. `cl` and `dl` follow the `bn_sub_part_words` calling
111
// convention.
112
//
113
// TODO(davidben): Make this take `size_t`. The `cl` + `dl` calling convention
114
// is confusing.
115
//
116
// TODO(davidben): This function used to be used as part of a general Karatsuba
117
// multiplication implementation, which had to account for differently-sized
118
// inputs. Now it is only used as part of RSA key generation, which does not
119
// need all this.
120
static BN_ULONG bn_abs_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
121
                                      const BN_ULONG *b, int cl, int dl,
122
0
                                      BN_ULONG *tmp) {
123
0
  BN_ULONG borrow = bn_sub_part_words(tmp, a, b, cl, dl);
124
0
  bn_sub_part_words(r, b, a, cl, -dl);
125
0
  int r_len = cl + (dl < 0 ? -dl : dl);
126
0
  borrow = 0 - borrow;
127
0
  bn_select_words(r, borrow, r /* tmp < 0 */, tmp /* tmp >= 0 */, r_len);
128
0
  return borrow;
129
0
}
130
131
int bssl::bn_abs_sub_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
132
0
                               BN_CTX *ctx) {
133
0
  int cl = a->width < b->width ? a->width : b->width;
134
0
  int dl = a->width - b->width;
135
0
  int r_len = a->width < b->width ? b->width : a->width;
136
0
  BN_CTXScope scope(ctx);
137
0
  BIGNUM *tmp = BN_CTX_get(ctx);
138
0
  if (tmp == nullptr || !bn_wexpand(r, r_len) || !bn_wexpand(tmp, r_len)) {
139
0
    return 0;
140
0
  }
141
0
  bn_abs_sub_part_words(r->d, a->d, b->d, cl, dl, tmp->d);
142
0
  r->width = r_len;
143
0
  r->neg = 0;
144
0
  return 1;
145
0
}
146
147
// bn_mul_impl implements `BN_mul` and `bn_mul_consttime`. Note this function
148
// breaks `BIGNUM` invariants and may return a negative zero. This is handled by
149
// the callers.
150
static int bn_mul_impl(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
151
678k
                       BN_CTX *ctx) {
152
678k
  int al = a->width;
153
678k
  int bl = b->width;
154
678k
  if (al == 0 || bl == 0) {
155
101k
    BN_zero(r);
156
101k
    return 1;
157
101k
  }
158
159
576k
  int i, top;
160
576k
  BIGNUM *rr;
161
576k
  BN_CTXScope scope(ctx);
162
576k
  if (r == a || r == b) {
163
273k
    rr = BN_CTX_get(ctx);
164
273k
    if (rr == nullptr) {
165
0
      return 0;
166
0
    }
167
303k
  } else {
168
303k
    rr = r;
169
303k
  }
170
576k
  rr->neg = a->neg ^ b->neg;
171
172
576k
  i = al - bl;
173
576k
  if (i == 0) {
174
561k
    if (al == 8) {
175
27.6k
      if (!bn_wexpand(rr, 16)) {
176
0
        return 0;
177
0
      }
178
27.6k
      rr->width = 16;
179
27.6k
      bn_mul_comba8(rr->d, a->d, b->d);
180
27.6k
      goto end;
181
27.6k
    }
182
561k
  }
183
184
549k
  top = al + bl;
185
549k
  if (!bn_wexpand(rr, top)) {
186
0
    return 0;
187
0
  }
188
549k
  rr->width = top;
189
549k
  bn_mul_normal(rr->d, a->d, al, b->d, bl);
190
191
576k
end:
192
576k
  if (r != rr && !BN_copy(r, rr)) {
193
0
    return 0;
194
0
  }
195
576k
  return 1;
196
576k
}
197
198
590k
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
199
590k
  if (!bn_mul_impl(r, a, b, ctx)) {
200
0
    return 0;
201
0
  }
202
203
  // This additionally fixes any negative zeros created by `bn_mul_impl`.
204
590k
  bn_set_minimal_width(r);
205
590k
  return 1;
206
590k
}
207
208
int bssl::bn_mul_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
209
87.5k
                           BN_CTX *ctx) {
210
  // Prevent negative zeros.
211
87.5k
  if (a->neg || b->neg) {
212
0
    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
213
0
    return 0;
214
0
  }
215
216
87.5k
  return bn_mul_impl(r, a, b, ctx);
217
87.5k
}
218
219
void bssl::bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
220
0
                        size_t num_a, const BN_ULONG *b, size_t num_b) {
221
0
  if (num_r != num_a + num_b) {
222
0
    abort();
223
0
  }
224
  // TODO(davidben): Should this call `bn_mul_comba4` too? `BN_mul` does not
225
  // hit that code.
226
0
  if (num_a == 8 && num_b == 8) {
227
0
    bn_mul_comba8(r, a, b);
228
0
  } else {
229
0
    bn_mul_normal(r, a, num_a, b, num_b);
230
0
  }
231
0
}
232
233
319k
static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, size_t n) {
234
319k
  if (n == 0) {
235
0
    return;
236
0
  }
237
238
319k
  size_t max = n * 2;
239
319k
  const BN_ULONG *ap = a;
240
319k
  BN_ULONG *rp = r;
241
319k
  rp[0] = rp[max - 1] = 0;
242
319k
  rp++;
243
244
  // Compute the contribution of a[i] * a[j] for all i < j.
245
319k
  if (n > 1) {
246
2.39k
    ap++;
247
2.39k
    rp[n - 1] = bn_mul_words(rp, ap, n - 1, ap[-1]);
248
2.39k
    rp += 2;
249
2.39k
  }
250
319k
  if (n > 2) {
251
12.5k
    for (size_t i = n - 2; i > 0; i--) {
252
10.9k
      ap++;
253
10.9k
      rp[i] = bn_mul_add_words(rp, ap, i, ap[-1]);
254
10.9k
      rp += 2;
255
10.9k
    }
256
1.64k
  }
257
258
  // The final result fits in `max` words, so none of the following operations
259
  // will overflow.
260
261
  // Double `r`, giving the contribution of a[i] * a[j] for all i != j.
262
319k
  bn_add_words(r, r, r, max);
263
264
  // Add in the contribution of a[i] * a[i] for all i.
265
319k
  bn_sqr_add_words(r, a, n);
266
319k
}
267
268
17.3k
int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
269
17.3k
  if (!bn->width) {
270
10.1k
    return 1;
271
10.1k
  }
272
273
7.20k
  if (w == 0) {
274
0
    BN_zero(bn);
275
0
    return 1;
276
0
  }
277
278
7.20k
  BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->width, w);
279
7.20k
  if (ll) {
280
6.26k
    if (!bn_wexpand(bn, bn->width + 1)) {
281
0
      return 0;
282
0
    }
283
6.26k
    bn->d[bn->width++] = ll;
284
6.26k
  }
285
286
7.20k
  return 1;
287
7.20k
}
288
289
5.80M
int bssl::bn_sqr_consttime(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
290
5.80M
  int al = a->width;
291
5.80M
  if (al <= 0) {
292
23.3k
    r->width = 0;
293
23.3k
    r->neg = 0;
294
23.3k
    return 1;
295
23.3k
  }
296
297
5.78M
  BN_CTXScope scope(ctx);
298
5.78M
  BIGNUM *rr = (a != r) ? r : BN_CTX_get(ctx);
299
5.78M
  if (!rr) {
300
0
    return 0;
301
0
  }
302
303
5.78M
  int max = 2 * al;  // Non-zero (from above)
304
5.78M
  if (!bn_wexpand(rr, max)) {
305
0
    return 0;
306
0
  }
307
308
5.78M
  if (al == 4) {
309
5.46M
    bn_sqr_comba4(rr->d, a->d);
310
5.46M
  } else if (al == 8) {
311
324
    bn_sqr_comba8(rr->d, a->d);
312
319k
  } else {
313
319k
    bn_sqr_normal(rr->d, a->d, al);
314
319k
  }
315
316
5.78M
  rr->neg = 0;
317
5.78M
  rr->width = max;
318
319
5.78M
  if (rr != r && !BN_copy(r, rr)) {
320
0
    return 0;
321
0
  }
322
5.78M
  return 1;
323
5.78M
}
324
325
5.51M
int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
326
5.51M
  if (!bn_sqr_consttime(r, a, ctx)) {
327
0
    return 0;
328
0
  }
329
330
5.51M
  bn_set_minimal_width(r);
331
5.51M
  return 1;
332
5.51M
}
333
334
void bssl::bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
335
0
                        size_t num_a) {
336
0
  assert(r != a);
337
0
  if (num_r != 2 * num_a) {
338
0
    abort();
339
0
  }
340
0
  if (num_a == 4) {
341
0
    bn_sqr_comba4(r, a);
342
0
  } else if (num_a == 8) {
343
0
    bn_sqr_comba8(r, a);
344
0
  } else {
345
0
    bn_sqr_normal(r, a, num_a);
346
0
  }
347
0
}