Coverage Report

Created: 2026-04-02 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/ec/scalar.cc.inc
Line
Count
Source
1
// Copyright 2018 The BoringSSL Authors
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/ec.h>
16
#include <openssl/err.h>
17
#include <openssl/mem.h>
18
19
#include "../../internal.h"
20
#include "../bn/internal.h"
21
#include "internal.h"
22
23
24
using namespace bssl;
25
26
int bssl::ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
27
36.0k
                              const BIGNUM *in) {
28
  // Scalars, which are often secret, must be reduced modulo the order. Those
29
  // that are not will be discarded, so leaking the result of the comparison is
30
  // safe.
31
36.0k
  if (!bn_copy_words(out->words, group->order.N.width, in) ||
32
35.2k
      !constant_time_declassify_int(bn_less_than_words(
33
35.2k
          out->words, group->order.N.d, group->order.N.width))) {
34
919
    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
35
919
    return 0;
36
919
  }
37
35.1k
  return 1;
38
36.0k
}
39
40
int bssl::ec_scalar_equal_vartime(const EC_GROUP *group, const EC_SCALAR *a,
41
0
                                  const EC_SCALAR *b) {
42
0
  return OPENSSL_memcmp(a->words, b->words,
43
0
                        group->order.N.width * sizeof(BN_ULONG)) == 0;
44
0
}
45
46
22.1k
int bssl::ec_scalar_is_zero(const EC_GROUP *group, const EC_SCALAR *a) {
47
22.1k
  BN_ULONG mask = 0;
48
124k
  for (int i = 0; i < group->order.N.width; i++) {
49
102k
    mask |= a->words[i];
50
102k
  }
51
22.1k
  return mask == 0;
52
22.1k
}
53
54
int bssl::ec_random_scalar(const EC_GROUP *group, EC_SCALAR *out,
55
0
                           const uint8_t additional_data[32]) {
56
0
  return bn_rand_range_words(out->words, 0, group->order.N.d,
57
0
                             group->order.N.width, additional_data);
58
0
}
59
60
int bssl::ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
61
505
                                   const uint8_t additional_data[32]) {
62
505
  return bn_rand_range_words(out->words, 1, group->order.N.d,
63
505
                             group->order.N.width, additional_data);
64
505
}
65
66
void bssl::ec_scalar_to_bytes(const EC_GROUP *group, uint8_t *out,
67
1.01k
                              size_t *out_len, const EC_SCALAR *in) {
68
1.01k
  size_t len = BN_num_bytes(&group->order.N);
69
1.01k
  bn_words_to_big_endian(out, len, in->words, group->order.N.width);
70
1.01k
  *out_len = len;
71
1.01k
}
72
73
int bssl::ec_scalar_from_bytes(const EC_GROUP *group, EC_SCALAR *out,
74
16.2k
                               const uint8_t *in, size_t len) {
75
16.2k
  if (len != BN_num_bytes(&group->order.N)) {
76
0
    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
77
0
    return 0;
78
0
  }
79
80
16.2k
  bn_big_endian_to_words(out->words, group->order.N.width, in, len);
81
82
16.2k
  if (!bn_less_than_words(out->words, group->order.N.d, group->order.N.width)) {
83
276
    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
84
276
    return 0;
85
276
  }
86
87
15.9k
  return 1;
88
16.2k
}
89
90
void bssl::ec_scalar_reduce(const EC_GROUP *group, EC_SCALAR *out,
91
0
                            const BN_ULONG *words, size_t num) {
92
  // Convert "from" Montgomery form so the value is reduced modulo the order.
93
0
  bn_from_montgomery_small(out->words, group->order.N.width, words, num,
94
0
                           &group->order);
95
  // Convert "to" Montgomery form to remove the R^-1 factor added.
96
0
  ec_scalar_to_montgomery(group, out, out);
97
0
}
98
99
void bssl::ec_scalar_add(const EC_GROUP *group, EC_SCALAR *r,
100
505
                         const EC_SCALAR *a, const EC_SCALAR *b) {
101
505
  const BIGNUM *order = &group->order.N;
102
505
  BN_ULONG tmp[EC_MAX_WORDS];
103
505
  bn_mod_add_words(r->words, a->words, b->words, order->d, tmp, order->width);
104
505
  OPENSSL_cleanse(tmp, sizeof(tmp));
105
505
}
106
107
void bssl::ec_scalar_sub(const EC_GROUP *group, EC_SCALAR *r,
108
0
                         const EC_SCALAR *a, const EC_SCALAR *b) {
109
0
  const BIGNUM *order = &group->order.N;
110
0
  BN_ULONG tmp[EC_MAX_WORDS];
111
0
  bn_mod_sub_words(r->words, a->words, b->words, order->d, tmp, order->width);
112
0
  OPENSSL_cleanse(tmp, sizeof(tmp));
113
0
}
114
115
void bssl::ec_scalar_neg(const EC_GROUP *group, EC_SCALAR *r,
116
0
                         const EC_SCALAR *a) {
117
0
  EC_SCALAR zero;
118
0
  OPENSSL_memset(&zero, 0, sizeof(EC_SCALAR));
119
0
  ec_scalar_sub(group, r, &zero, a);
120
0
}
121
122
void bssl::ec_scalar_select(const EC_GROUP *group, EC_SCALAR *out,
123
                            BN_ULONG mask, const EC_SCALAR *a,
124
0
                            const EC_SCALAR *b) {
125
0
  const BIGNUM *order = &group->order.N;
126
0
  bn_select_words(out->words, mask, a->words, b->words, order->width);
127
0
}
128
129
void bssl::ec_scalar_to_montgomery(const EC_GROUP *group, EC_SCALAR *r,
130
6.62k
                                   const EC_SCALAR *a) {
131
6.62k
  const BIGNUM *order = &group->order.N;
132
6.62k
  bn_to_montgomery_small(r->words, a->words, order->width, &group->order);
133
6.62k
}
134
135
void bssl::ec_scalar_from_montgomery(const EC_GROUP *group, EC_SCALAR *r,
136
2.26k
                                     const EC_SCALAR *a) {
137
2.26k
  const BIGNUM *order = &group->order.N;
138
2.26k
  bn_from_montgomery_small(r->words, order->width, a->words, order->width,
139
2.26k
                           &group->order);
140
2.26k
}
141
142
void bssl::ec_scalar_mul_montgomery(const EC_GROUP *group, EC_SCALAR *r,
143
16.7k
                                    const EC_SCALAR *a, const EC_SCALAR *b) {
144
16.7k
  const BIGNUM *order = &group->order.N;
145
16.7k
  bn_mod_mul_montgomery_small(r->words, a->words, b->words, order->width,
146
16.7k
                              &group->order);
147
16.7k
}
148
149
void bssl::ec_simple_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r,
150
1.75k
                                            const EC_SCALAR *a) {
151
1.75k
  const BIGNUM *order = &group->order.N;
152
1.75k
  bn_mod_inverse0_prime_mont_small(r->words, a->words, order->width,
153
1.75k
                                   &group->order);
154
1.75k
}
155
156
int bssl::ec_simple_scalar_to_montgomery_inv_vartime(const EC_GROUP *group,
157
                                                     EC_SCALAR *r,
158
1.75k
                                                     const EC_SCALAR *a) {
159
1.75k
  if (ec_scalar_is_zero(group, a)) {
160
0
    return 0;
161
0
  }
162
163
  // This implementation (in fact) runs in constant time,
164
  // even though for this interface it is not mandatory.
165
166
  // r = a^-1 in the Montgomery domain. This is
167
  // |ec_scalar_to_montgomery| followed by |ec_scalar_inv0_montgomery|, but
168
  // |ec_scalar_inv0_montgomery| followed by |ec_scalar_from_montgomery| is
169
  // equivalent and slightly more efficient.
170
1.75k
  ec_scalar_inv0_montgomery(group, r, a);
171
1.75k
  ec_scalar_from_montgomery(group, r, r);
172
1.75k
  return 1;
173
1.75k
}
174
175
void bssl::ec_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r,
176
2.26k
                                     const EC_SCALAR *a) {
177
2.26k
  group->meth->scalar_inv0_montgomery(group, r, a);
178
2.26k
}
179
180
int bssl::ec_scalar_to_montgomery_inv_vartime(const EC_GROUP *group,
181
                                              EC_SCALAR *r,
182
7.88k
                                              const EC_SCALAR *a) {
183
7.88k
  return group->meth->scalar_to_montgomery_inv_vartime(group, r, a);
184
7.88k
}