Coverage Report

Created: 2026-10-10 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/BearSSL/src/ec/ecdsa_i31_vrfy_raw.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining 
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be 
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 */
24
25
#include "inner.h"
26
27
#define I31_LEN     ((BR_MAX_EC_SIZE + 61) / 31)
28
#define POINT_LEN   (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
29
30
/* see bearssl_ec.h */
31
uint32_t
32
br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
33
  const void *hash, size_t hash_len,
34
  const br_ec_public_key *pk,
35
  const void *sig, size_t sig_len)
36
1.33k
{
37
  /*
38
   * IMPORTANT: this code is fit only for curves with a prime
39
   * order. This is needed so that modular reduction of the X
40
   * coordinate of a point can be done with a simple subtraction.
41
   */
42
1.33k
  const br_ec_curve_def *cd;
43
1.33k
  uint32_t n[I31_LEN], r[I31_LEN], s[I31_LEN], t1[I31_LEN], t2[I31_LEN];
44
1.33k
  unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3];
45
1.33k
  unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3];
46
1.33k
  unsigned char eU[POINT_LEN];
47
1.33k
  size_t nlen, rlen, ulen;
48
1.33k
  uint32_t n0i, res;
49
50
  /*
51
   * If the curve is not supported, then report an error.
52
   */
53
1.33k
  if (((impl->supported_curves >> pk->curve) & 1) == 0) {
54
0
    return 0;
55
0
  }
56
57
  /*
58
   * Get the curve parameters (generator and order).
59
   */
60
1.33k
  switch (pk->curve) {
61
444
  case BR_EC_secp256r1:
62
444
    cd = &br_secp256r1;
63
444
    break;
64
416
  case BR_EC_secp384r1:
65
416
    cd = &br_secp384r1;
66
416
    break;
67
479
  case BR_EC_secp521r1:
68
479
    cd = &br_secp521r1;
69
479
    break;
70
0
  default:
71
0
    return 0;
72
1.33k
  }
73
74
  /*
75
   * Signature length must be even.
76
   */
77
1.33k
  if (sig_len & 1) {
78
0
    return 0;
79
0
  }
80
1.33k
  rlen = sig_len >> 1;
81
82
  /*
83
   * Public key point must have the proper size for this curve.
84
   */
85
1.33k
  if (pk->qlen != cd->generator_len) {
86
0
    return 0;
87
0
  }
88
89
  /*
90
   * Get modulus; then decode the r and s values. They must be
91
   * lower than the modulus, and s must not be null.
92
   */
93
1.33k
  nlen = cd->order_len;
94
1.33k
  br_i31_decode(n, cd->order, nlen);
95
1.33k
  n0i = br_i31_ninv31(n[1]);
96
1.33k
  if (!br_i31_decode_mod(r, sig, rlen, n)) {
97
16
    return 0;
98
16
  }
99
1.32k
  if (!br_i31_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) {
100
17
    return 0;
101
17
  }
102
1.30k
  if (br_i31_iszero(s)) {
103
56
    return 0;
104
56
  }
105
106
  /*
107
   * Invert s. We do that with a modular exponentiation; we use
108
   * the fact that for all the curves we support, the least
109
   * significant byte is not 0 or 1, so we can subtract 2 without
110
   * any carry to process.
111
   * We also want 1/s in Montgomery representation, which can be
112
   * done by converting _from_ Montgomery representation before
113
   * the inversion (because (1/s)*R = 1/(s/R)).
114
   */
115
1.25k
  br_i31_from_monty(s, n, n0i);
116
1.25k
  memcpy(tx, cd->order, nlen);
117
1.25k
  tx[nlen - 1] -= 2;
118
1.25k
  br_i31_modpow(s, tx, nlen, n, n0i, t1, t2);
119
120
  /*
121
   * Truncate the hash to the modulus length (in bits) and reduce
122
   * it modulo the curve order. The modular reduction can be done
123
   * with a subtraction since the truncation already reduced the
124
   * value to the modulus bit length.
125
   */
126
1.25k
  br_ecdsa_i31_bits2int(t1, hash, hash_len, n[0]);
127
1.25k
  br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1);
128
129
  /*
130
   * Multiply the (truncated, reduced) hash value with 1/s, result in
131
   * t2, encoded in ty.
132
   */
133
1.25k
  br_i31_montymul(t2, t1, s, n, n0i);
134
1.25k
  br_i31_encode(ty, nlen, t2);
135
136
  /*
137
   * Multiply r with 1/s, result in t1, encoded in tx.
138
   */
139
1.25k
  br_i31_montymul(t1, r, s, n, n0i);
140
1.25k
  br_i31_encode(tx, nlen, t1);
141
142
  /*
143
   * Compute the point x*Q + y*G.
144
   */
145
1.25k
  ulen = cd->generator_len;
146
1.25k
  memcpy(eU, pk->q, ulen);
147
1.25k
  res = impl->muladd(eU, NULL, ulen,
148
1.25k
    tx, nlen, ty, nlen, cd->curve);
149
150
  /*
151
   * Get the X coordinate, reduce modulo the curve order, and
152
   * compare with the 'r' value.
153
   *
154
   * The modular reduction can be done with subtractions because
155
   * we work with curves of prime order, so the curve order is
156
   * close to the field order (Hasse's theorem).
157
   */
158
1.25k
  br_i31_zero(t1, n[0]);
159
1.25k
  br_i31_decode(t1, &eU[1], ulen >> 1);
160
1.25k
  t1[0] = n[0];
161
1.25k
  br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1);
162
1.25k
  res &= ~br_i31_sub(t1, r, 1);
163
1.25k
  res &= br_i31_iszero(t1);
164
1.25k
  return res;
165
1.30k
}