Coverage Report

Created: 2026-06-15 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/ec/simple.cc.inc
Line
Count
Source
1
// Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
2
// Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
//     https://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
16
#include <openssl/ec.h>
17
18
#include <string.h>
19
20
#include <openssl/bn.h>
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
// Most method functions in this file are designed to work with non-trivial
31
// representations of field elements if necessary (see ec_montgomery.cc.inc):
32
// while standard modular addition and subtraction are used, the field_mul and
33
// field_sqr methods will be used for multiplication, and field_encode and
34
// field_decode (if defined) will be used for converting between
35
// representations.
36
//
37
// Functions here specifically assume that if a non-trivial representation is
38
// used, it is a Montgomery representation (i.e. 'encoding' means multiplying
39
// by some factor R).
40
//
41
// TODO(crbug.com/505908440): ec_montgomery.cc.inc is now the only field element
42
// representation. Fold these files together.
43
44
int bssl::ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
45
                                        const BIGNUM *a, const BIGNUM *b,
46
0
                                        BN_CTX *ctx) {
47
  // p must be a prime > 3
48
0
  if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) {
49
0
    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD);
50
0
    return 0;
51
0
  }
52
53
0
  BN_CTXScope scope(ctx);
54
0
  BIGNUM *tmp = BN_CTX_get(ctx);
55
0
  if (tmp == nullptr) {
56
0
    return 0;
57
0
  }
58
59
0
  if (!BN_MONT_CTX_set(&group->field, p, ctx) ||
60
0
      !ec_bignum_to_felem(group, &group->a, a) ||
61
0
      !ec_bignum_to_felem(group, &group->b, b) ||
62
      // Reuse Z from the generator to cache the value one.
63
0
      !ec_bignum_to_felem(group, &group->generator.raw.Z, BN_value_one())) {
64
0
    return 0;
65
0
  }
66
67
  // group->a_is_minus3
68
0
  if (!BN_copy(tmp, a) ||
69
0
      !BN_add_word(tmp, 3)) {
70
0
    return 0;
71
0
  }
72
0
  group->a_is_minus3 = (0 == BN_cmp(tmp, &group->field.N));
73
74
0
  return 1;
75
0
}
76
77
int bssl::ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p,
78
4.31k
                                        BIGNUM *a, BIGNUM *b) {
79
4.31k
  if ((p != nullptr && !BN_copy(p, &group->field.N)) ||
80
4.31k
      (a != nullptr && !ec_felem_to_bignum(group, a, &group->a)) ||
81
4.31k
      (b != nullptr && !ec_felem_to_bignum(group, b, &group->b))) {
82
0
    return 0;
83
0
  }
84
4.31k
  return 1;
85
4.31k
}
86
87
191k
void bssl::ec_GFp_simple_point_init(EC_JACOBIAN *point) {
88
191k
  OPENSSL_memset(&point->X, 0, sizeof(EC_FELEM));
89
191k
  OPENSSL_memset(&point->Y, 0, sizeof(EC_FELEM));
90
191k
  OPENSSL_memset(&point->Z, 0, sizeof(EC_FELEM));
91
191k
}
92
93
356k
void bssl::ec_GFp_simple_point_copy(EC_JACOBIAN *dest, const EC_JACOBIAN *src) {
94
356k
  OPENSSL_memcpy(&dest->X, &src->X, sizeof(EC_FELEM));
95
356k
  OPENSSL_memcpy(&dest->Y, &src->Y, sizeof(EC_FELEM));
96
356k
  OPENSSL_memcpy(&dest->Z, &src->Z, sizeof(EC_FELEM));
97
356k
}
98
99
void bssl::ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
100
28.8k
                                               EC_JACOBIAN *point) {
101
  // Although it is strictly only necessary to zero Z, we zero the entire point
102
  // in case `point` was stack-allocated and yet to be initialized.
103
28.8k
  ec_GFp_simple_point_init(point);
104
28.8k
}
105
106
112k
void bssl::ec_GFp_simple_invert(const EC_GROUP *group, EC_JACOBIAN *point) {
107
112k
  ec_felem_neg(group, &point->Y, &point->Y);
108
112k
}
109
110
int bssl::ec_GFp_simple_is_at_infinity(const EC_GROUP *group,
111
119k
                                       const EC_JACOBIAN *point) {
112
119k
  return ec_felem_non_zero_mask(group, &point->Z) == 0;
113
119k
}
114
115
int bssl::ec_GFp_simple_is_on_curve(const EC_GROUP *group,
116
38.9k
                                    const EC_JACOBIAN *point) {
117
  // We have a curve defined by a Weierstrass equation
118
  //      y^2 = x^3 + a*x + b.
119
  // The point to consider is given in Jacobian projective coordinates
120
  // where  (X, Y, Z)  represents  (x, y) = (X/Z^2, Y/Z^3).
121
  // Substituting this and multiplying by  Z^6  transforms the above equation
122
  // into
123
  //      Y^2 = X^3 + a*X*Z^4 + b*Z^6.
124
  // To test this, we add up the right-hand side in 'rh'.
125
  //
126
  // This function may be used when double-checking the secret result of a point
127
  // multiplication, so we proceed in constant-time.
128
129
  // rh := X^2
130
38.9k
  EC_FELEM rh;
131
38.9k
  ec_felem_sqr(group, &rh, &point->X);
132
133
38.9k
  EC_FELEM tmp, Z4, Z6;
134
38.9k
  ec_felem_sqr(group, &tmp, &point->Z);
135
38.9k
  ec_felem_sqr(group, &Z4, &tmp);
136
38.9k
  ec_felem_mul(group, &Z6, &Z4, &tmp);
137
138
  // rh := rh + a*Z^4
139
38.9k
  if (group->a_is_minus3) {
140
38.9k
    ec_felem_add(group, &tmp, &Z4, &Z4);
141
38.9k
    ec_felem_add(group, &tmp, &tmp, &Z4);
142
38.9k
    ec_felem_sub(group, &rh, &rh, &tmp);
143
38.9k
  } else {
144
0
    ec_felem_mul(group, &tmp, &Z4, &group->a);
145
0
    ec_felem_add(group, &rh, &rh, &tmp);
146
0
  }
147
148
  // rh := (rh + a*Z^4)*X
149
38.9k
  ec_felem_mul(group, &rh, &rh, &point->X);
150
151
  // rh := rh + b*Z^6
152
38.9k
  ec_felem_mul(group, &tmp, &group->b, &Z6);
153
38.9k
  ec_felem_add(group, &rh, &rh, &tmp);
154
155
  // 'lh' := Y^2
156
38.9k
  ec_felem_sqr(group, &tmp, &point->Y);
157
158
38.9k
  ec_felem_sub(group, &tmp, &tmp, &rh);
159
38.9k
  BN_ULONG not_equal = ec_felem_non_zero_mask(group, &tmp);
160
161
  // If Z = 0, the point is infinity, which is always on the curve.
162
38.9k
  BN_ULONG not_infinity = ec_felem_non_zero_mask(group, &point->Z);
163
164
38.9k
  return 1 & ~(not_infinity & not_equal);
165
38.9k
}
166
167
int bssl::ec_GFp_simple_points_equal(const EC_GROUP *group,
168
                                     const EC_JACOBIAN *a,
169
2.14k
                                     const EC_JACOBIAN *b) {
170
  // This function is implemented in constant-time for two reasons. First,
171
  // although EC points are usually public, their Jacobian Z coordinates may be
172
  // secret, or at least are not obviously public. Second, more complex
173
  // protocols will sometimes manipulate secret points.
174
  //
175
  // This does mean that we pay a 6M+2S Jacobian comparison when comparing two
176
  // publicly affine points costs no field operations at all. If needed, we can
177
  // restore this optimization by keeping better track of affine vs. Jacobian
178
  // forms. See https://crbug.com/boringssl/326.
179
180
  // If neither `a` or `b` is infinity, we have to decide whether
181
  //     (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
182
  // or equivalently, whether
183
  //     (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
184
185
2.14k
  EC_FELEM tmp1, tmp2, Za23, Zb23;
186
2.14k
  ec_felem_sqr(group, &Zb23, &b->Z);         // Zb23 = Z_b^2
187
2.14k
  ec_felem_mul(group, &tmp1, &a->X, &Zb23);  // tmp1 = X_a * Z_b^2
188
2.14k
  ec_felem_sqr(group, &Za23, &a->Z);         // Za23 = Z_a^2
189
2.14k
  ec_felem_mul(group, &tmp2, &b->X, &Za23);  // tmp2 = X_b * Z_a^2
190
2.14k
  ec_felem_sub(group, &tmp1, &tmp1, &tmp2);
191
2.14k
  const BN_ULONG x_not_equal = ec_felem_non_zero_mask(group, &tmp1);
192
193
2.14k
  ec_felem_mul(group, &Zb23, &Zb23, &b->Z);  // Zb23 = Z_b^3
194
2.14k
  ec_felem_mul(group, &tmp1, &a->Y, &Zb23);  // tmp1 = Y_a * Z_b^3
195
2.14k
  ec_felem_mul(group, &Za23, &Za23, &a->Z);  // Za23 = Z_a^3
196
2.14k
  ec_felem_mul(group, &tmp2, &b->Y, &Za23);  // tmp2 = Y_b * Z_a^3
197
2.14k
  ec_felem_sub(group, &tmp1, &tmp1, &tmp2);
198
2.14k
  const BN_ULONG y_not_equal = ec_felem_non_zero_mask(group, &tmp1);
199
2.14k
  const BN_ULONG x_and_y_equal = ~(x_not_equal | y_not_equal);
200
201
2.14k
  const BN_ULONG a_not_infinity = ec_felem_non_zero_mask(group, &a->Z);
202
2.14k
  const BN_ULONG b_not_infinity = ec_felem_non_zero_mask(group, &b->Z);
203
2.14k
  const BN_ULONG a_and_b_infinity = ~(a_not_infinity | b_not_infinity);
204
205
2.14k
  const BN_ULONG equal =
206
2.14k
      a_and_b_infinity | (a_not_infinity & b_not_infinity & x_and_y_equal);
207
2.14k
  return equal & 1;
208
2.14k
}
209
210
int bssl::ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
211
0
                                   const EC_JACOBIAN *b) {
212
  // If `b` is not infinity, we have to decide whether
213
  //     (X_a, Y_a) = (X_b/Z_b^2, Y_b/Z_b^3),
214
  // or equivalently, whether
215
  //     (X_a*Z_b^2, Y_a*Z_b^3) = (X_b, Y_b).
216
217
0
  EC_FELEM tmp, Zb2;
218
0
  ec_felem_sqr(group, &Zb2, &b->Z);        // Zb2 = Z_b^2
219
0
  ec_felem_mul(group, &tmp, &a->X, &Zb2);  // tmp = X_a * Z_b^2
220
0
  ec_felem_sub(group, &tmp, &tmp, &b->X);
221
0
  const BN_ULONG x_not_equal = ec_felem_non_zero_mask(group, &tmp);
222
223
0
  ec_felem_mul(group, &tmp, &a->Y, &Zb2);  // tmp = Y_a * Z_b^2
224
0
  ec_felem_mul(group, &tmp, &tmp, &b->Z);  // tmp = Y_a * Z_b^3
225
0
  ec_felem_sub(group, &tmp, &tmp, &b->Y);
226
0
  const BN_ULONG y_not_equal = ec_felem_non_zero_mask(group, &tmp);
227
0
  const BN_ULONG x_and_y_equal = ~(x_not_equal | y_not_equal);
228
229
0
  const BN_ULONG b_not_infinity = ec_felem_non_zero_mask(group, &b->Z);
230
231
0
  const BN_ULONG equal = b_not_infinity & x_and_y_equal;
232
0
  return equal & 1;
233
0
}
234
235
int bssl::ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group,
236
                                         const EC_JACOBIAN *p,
237
0
                                         const EC_SCALAR *r) {
238
0
  if (ec_GFp_simple_is_at_infinity(group, p)) {
239
    // `ec_get_x_coordinate_as_scalar` will check this internally, but this way
240
    // we do not push to the error queue.
241
0
    return 0;
242
0
  }
243
244
0
  EC_SCALAR x;
245
0
  return ec_get_x_coordinate_as_scalar(group, &x, p) &&
246
0
         ec_scalar_equal_vartime(group, &x, r);
247
0
}