Coverage Report

Created: 2026-06-28 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/bn/exponentiation.cc
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
19
#include <openssl/err.h>
20
21
#include "../fipsmodule/bn/internal.h"
22
23
24
using namespace bssl;
25
26
0
int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
27
0
  BN_CTXScope scope(ctx);
28
0
  BIGNUM *rr;
29
0
  if (r == a || r == p) {
30
0
    rr = BN_CTX_get(ctx);
31
0
  } else {
32
0
    rr = r;
33
0
  }
34
35
0
  BIGNUM *v = BN_CTX_get(ctx);
36
0
  if (rr == nullptr || v == nullptr) {
37
0
    return 0;
38
0
  }
39
40
0
  if (BN_copy(v, a) == nullptr) {
41
0
    return 0;
42
0
  }
43
0
  int bits = BN_num_bits(p);
44
45
0
  if (BN_is_odd(p)) {
46
0
    if (BN_copy(rr, a) == nullptr) {
47
0
      return 0;
48
0
    }
49
0
  } else {
50
0
    if (!BN_one(rr)) {
51
0
      return 0;
52
0
    }
53
0
  }
54
55
0
  for (int i = 1; i < bits; i++) {
56
0
    if (!BN_sqr(v, v, ctx)) {
57
0
      return 0;
58
0
    }
59
0
    if (BN_is_bit_set(p, i)) {
60
0
      if (!BN_mul(rr, rr, v, ctx)) {
61
0
        return 0;
62
0
      }
63
0
    }
64
0
  }
65
66
0
  if (r != rr && !BN_copy(r, rr)) {
67
0
    return 0;
68
0
  }
69
0
  return 1;
70
0
}
71
72
static int mod_exp_even(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
73
903
                        const BIGNUM *m, BN_CTX *ctx) {
74
  // No cryptographic operations require modular exponentiation with an even
75
  // modulus. We support it for backwards compatibility with any applications
76
  // that may have relied on the operation, but optimize for simplicity over
77
  // performance with straightforward square-and-multiply routine.
78
903
  int bits = BN_num_bits(p);
79
903
  if (bits == 0) {
80
40
    return BN_one(r);
81
40
  }
82
83
  // Make a copy of `a`, in case it aliases `r`.
84
863
  BN_CTXScope scope(ctx);
85
863
  BIGNUM *tmp = BN_CTX_get(ctx);
86
863
  if (tmp == nullptr || !BN_copy(tmp, a)) {
87
0
    return 0;
88
0
  }
89
90
863
  assert(BN_is_bit_set(p, bits - 1));
91
863
  if (!BN_copy(r, tmp)) {
92
0
    return 0;
93
0
  }
94
95
55.4k
  for (int i = bits - 2; i >= 0; i--) {
96
54.5k
    if (!BN_mod_sqr(r, r, m, ctx) ||
97
54.5k
        (BN_is_bit_set(p, i) && !BN_mod_mul(r, r, tmp, m, ctx))) {
98
0
      return 0;
99
0
    }
100
54.5k
  }
101
102
863
  return 1;
103
863
}
104
105
int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
106
2.27k
               BN_CTX *ctx) {
107
2.27k
  if (m->neg) {
108
0
    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
109
0
    return 0;
110
0
  }
111
2.27k
  if (a->neg || BN_ucmp(a, m) >= 0) {
112
1.65k
    if (!BN_nnmod(r, a, m, ctx)) {
113
0
      return 0;
114
0
    }
115
1.65k
    a = r;
116
1.65k
  }
117
118
2.27k
  if (BN_is_odd(m)) {
119
1.37k
    return BN_mod_exp_mont(r, a, p, m, ctx, nullptr);
120
1.37k
  }
121
122
903
  return mod_exp_even(r, a, p, m, ctx);
123
2.27k
}
124
125
int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
126
                         const BIGNUM *m, BN_CTX *ctx,
127
0
                         const BN_MONT_CTX *mont) {
128
  // BN_mod_exp_mont requires reduced inputs.
129
0
  if (bn_minimal_width(m) == 1) {
130
0
    a %= m->d[0];
131
0
  }
132
133
0
  UniquePtr<BIGNUM> a_bignum(BN_new());
134
0
  if (a_bignum == nullptr || !BN_set_word(a_bignum.get(), a)) {
135
0
    OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
136
0
    return 0;
137
0
  }
138
139
0
  return BN_mod_exp_mont(rr, a_bignum.get(), p, m, ctx, mont);
140
0
}
141
142
int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
143
                     const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
144
0
                     BN_CTX *ctx, const BN_MONT_CTX *mont) {
145
  // Allocate a montgomery context if it was not supplied by the caller.
146
0
  UniquePtr<BN_MONT_CTX> new_mont;
147
0
  if (mont == nullptr) {
148
0
    new_mont.reset(BN_MONT_CTX_new_for_modulus(m, ctx));
149
0
    if (new_mont == nullptr) {
150
0
      return 0;
151
0
    }
152
0
    mont = new_mont.get();
153
0
  }
154
155
  // BN_mod_mul_montgomery removes one Montgomery factor, so passing one
156
  // Montgomery-encoded and one non-Montgomery-encoded value gives a
157
  // non-Montgomery-encoded result.
158
0
  UniquePtr<BIGNUM> tmp(BN_new());
159
0
  if (tmp == nullptr ||  //
160
0
      !BN_mod_exp_mont(rr, a1, p1, m, ctx, mont) ||
161
0
      !BN_mod_exp_mont(tmp.get(), a2, p2, m, ctx, mont) ||
162
0
      !BN_to_montgomery(rr, rr, mont, ctx) ||
163
0
      !BN_mod_mul_montgomery(rr, rr, tmp.get(), mont, ctx)) {
164
0
    return 0;
165
0
  }
166
167
0
  return 1;
168
0
}