• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2024 The BoringSSL Authors
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/base.h>
16 
17 #include <assert.h>
18 #include <string.h>
19 
20 #include <openssl/bn.h>
21 #include <openssl/bytestring.h>
22 #include <openssl/crypto.h>
23 #include <openssl/ec.h>
24 #include <openssl/evp.h>
25 #include <openssl/hkdf.h>
26 #include <openssl/hmac.h>
27 #include <openssl/mem.h>
28 #include <openssl/rand.h>
29 #include <openssl/sha.h>
30 
31 #include "../fipsmodule/bn/internal.h"
32 #include "../fipsmodule/ec/internal.h"
33 #include "../internal.h"
34 #include "./internal.h"
35 #include "openssl/err.h"
36 
37 BSSL_NAMESPACE_BEGIN
38 namespace spake2plus {
39 namespace {
40 
41 const uint8_t kDefaultAdditionalData[32] = {0};
42 
43 // https://www.rfc-editor.org/rfc/rfc9383.html#appendix-B
44 // seed: 1.2.840.10045.3.1.7 point generation seed (M)
45 // M =
46 // 02886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f
47 //
48 // `M` is interpreted as a X9.62-format compressed point. This is then the
49 // uncompressed form:
50 const uint8_t kM_bytes[] = {
51     0x04, 0x88, 0x6e, 0x2f, 0x97, 0xac, 0xe4, 0x6e, 0x55, 0xba, 0x9d,
52     0xd7, 0x24, 0x25, 0x79, 0xf2, 0x99, 0x3b, 0x64, 0xe1, 0x6e, 0xf3,
53     0xdc, 0xab, 0x95, 0xaf, 0xd4, 0x97, 0x33, 0x3d, 0x8f, 0xa1, 0x2f,
54     0x5f, 0xf3, 0x55, 0x16, 0x3e, 0x43, 0xce, 0x22, 0x4e, 0x0b, 0x0e,
55     0x65, 0xff, 0x02, 0xac, 0x8e, 0x5c, 0x7b, 0xe0, 0x94, 0x19, 0xc7,
56     0x85, 0xe0, 0xca, 0x54, 0x7d, 0x55, 0xa1, 0x2e, 0x2d, 0x20};
57 
58 // https://www.rfc-editor.org/rfc/rfc9383.html#appendix-B
59 // seed: 1.2.840.10045.3.1.7 point generation seed (N)
60 // N =
61 // 03d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b49
62 //
63 // `N` is interpreted as a X9.62-format compressed point. This is then the
64 // uncompressed form:
65 const uint8_t kN_bytes[] = {
66     0x04, 0xd8, 0xbb, 0xd6, 0xc6, 0x39, 0xc6, 0x29, 0x37, 0xb0, 0x4d,
67     0x99, 0x7f, 0x38, 0xc3, 0x77, 0x07, 0x19, 0xc6, 0x29, 0xd7, 0x01,
68     0x4d, 0x49, 0xa2, 0x4b, 0x4f, 0x98, 0xba, 0xa1, 0x29, 0x2b, 0x49,
69     0x07, 0xd6, 0x0a, 0xa6, 0xbf, 0xad, 0xe4, 0x50, 0x08, 0xa6, 0x36,
70     0x33, 0x7f, 0x51, 0x68, 0xc6, 0x4d, 0x9b, 0xd3, 0x60, 0x34, 0x80,
71     0x8c, 0xd5, 0x64, 0x49, 0x0b, 0x1e, 0x65, 0x6e, 0xdb, 0xe7};
72 
UpdateWithLengthPrefix(SHA256_CTX * sha,Span<const uint8_t> data)73 void UpdateWithLengthPrefix(SHA256_CTX *sha, Span<const uint8_t> data) {
74   uint8_t len_le[8];
75   CRYPTO_store_u64_le(len_le, data.size());
76   SHA256_Update(sha, len_le, sizeof(len_le));
77   SHA256_Update(sha, data.data(), data.size());
78 }
79 
ConstantToJacobian(const EC_GROUP * group,EC_JACOBIAN * out,bssl::Span<const uint8_t> in)80 void ConstantToJacobian(const EC_GROUP *group, EC_JACOBIAN *out,
81                         bssl::Span<const uint8_t> in) {
82   EC_AFFINE point;
83   BSSL_CHECK(ec_point_from_uncompressed(group, &point, in.data(), in.size()));
84   ec_affine_to_jacobian(group, out, &point);
85 }
86 
ScalarToSizedBuffer(const EC_GROUP * group,const EC_SCALAR * s,Span<uint8_t> out_buf)87 void ScalarToSizedBuffer(const EC_GROUP *group, const EC_SCALAR *s,
88                          Span<uint8_t> out_buf) {
89   size_t out_bytes;
90   ec_scalar_to_bytes(group, out_buf.data(), &out_bytes, s);
91   BSSL_CHECK(out_bytes == out_buf.size());
92 }
93 
AddLengthPrefixed(CBB * cbb,Span<const uint8_t> bytes)94 bool AddLengthPrefixed(CBB *cbb, Span<const uint8_t> bytes) {
95   return CBB_add_u64le(cbb, bytes.size()) &&
96          CBB_add_bytes(cbb, bytes.data(), bytes.size());
97 }
98 
InitTranscriptHash(SHA256_CTX * sha,Span<const uint8_t> context,Span<const uint8_t> id_prover,Span<const uint8_t> id_verifier)99 void InitTranscriptHash(SHA256_CTX *sha, Span<const uint8_t> context,
100                         Span<const uint8_t> id_prover,
101                         Span<const uint8_t> id_verifier) {
102   SHA256_Init(sha);
103   UpdateWithLengthPrefix(sha, context);
104   UpdateWithLengthPrefix(sha, id_prover);
105   UpdateWithLengthPrefix(sha, id_verifier);
106   UpdateWithLengthPrefix(sha, kM_bytes);
107   UpdateWithLengthPrefix(sha, kN_bytes);
108 }
109 
ComputeTranscript(uint8_t out_prover_confirm[kConfirmSize],uint8_t out_verifier_confirm[kConfirmSize],uint8_t out_secret[kSecretSize],const uint8_t prover_share[kShareSize],const uint8_t verifier_share[kShareSize],SHA256_CTX * sha,const EC_AFFINE * Z,const EC_AFFINE * V,const EC_SCALAR * w0)110 bool ComputeTranscript(uint8_t out_prover_confirm[kConfirmSize],
111                        uint8_t out_verifier_confirm[kConfirmSize],
112                        uint8_t out_secret[kSecretSize],
113                        const uint8_t prover_share[kShareSize],
114                        const uint8_t verifier_share[kShareSize],
115                        SHA256_CTX *sha, const EC_AFFINE *Z, const EC_AFFINE *V,
116                        const EC_SCALAR *w0) {
117   const EC_GROUP *group = EC_group_p256();
118 
119   uint8_t Z_enc[kShareSize];
120   size_t Z_enc_len = ec_point_to_bytes(group, Z, POINT_CONVERSION_UNCOMPRESSED,
121                                        Z_enc, sizeof(Z_enc));
122   BSSL_CHECK(Z_enc_len == sizeof(Z_enc));
123 
124   uint8_t V_enc[kShareSize];
125   size_t V_enc_len = ec_point_to_bytes(group, V, POINT_CONVERSION_UNCOMPRESSED,
126                                        V_enc, sizeof(V_enc));
127   BSSL_CHECK(V_enc_len == sizeof(V_enc));
128 
129   uint8_t w0_enc[kVerifierSize];
130   ScalarToSizedBuffer(group, w0, w0_enc);
131 
132   uint8_t K_main[SHA256_DIGEST_LENGTH];
133   UpdateWithLengthPrefix(sha, Span(prover_share, kShareSize));
134   UpdateWithLengthPrefix(sha, Span(verifier_share, kShareSize));
135   UpdateWithLengthPrefix(sha, Z_enc);
136   UpdateWithLengthPrefix(sha, V_enc);
137   UpdateWithLengthPrefix(sha, w0_enc);
138   SHA256_Final(K_main, sha);
139 
140   auto confirmation_str = StringAsBytes("ConfirmationKeys");
141   uint8_t keys[kSecretSize * 2];
142   if (!HKDF(keys, sizeof(keys), EVP_sha256(), K_main, sizeof(K_main), nullptr,
143             0, confirmation_str.data(), confirmation_str.size())) {
144     return false;
145   }
146 
147   auto secret_info_str = StringAsBytes("SharedKey");
148   if (!HKDF(out_secret, kSecretSize, EVP_sha256(), K_main, sizeof(K_main),
149             nullptr, 0, secret_info_str.data(), secret_info_str.size())) {
150     return false;
151   }
152 
153   unsigned prover_confirm_len;
154   if (HMAC(EVP_sha256(), keys, kSecretSize, verifier_share, kShareSize,
155            out_prover_confirm, &prover_confirm_len) == nullptr) {
156     return false;
157   }
158   BSSL_CHECK(prover_confirm_len == kConfirmSize);
159 
160   unsigned verifier_confirm_len;
161   if (HMAC(EVP_sha256(), keys + kSecretSize, kSecretSize, prover_share,
162            kShareSize, out_verifier_confirm,
163            &verifier_confirm_len) == nullptr) {
164     return false;
165   }
166   BSSL_CHECK(verifier_confirm_len == kConfirmSize);
167 
168   return true;
169 }
170 
171 }  // namespace
172 
Register(Span<uint8_t> out_w0,Span<uint8_t> out_w1,Span<uint8_t> out_registration_record,Span<const uint8_t> password,Span<const uint8_t> id_prover,Span<const uint8_t> id_verifier)173 bool Register(Span<uint8_t> out_w0, Span<uint8_t> out_w1,
174               Span<uint8_t> out_registration_record,
175               Span<const uint8_t> password, Span<const uint8_t> id_prover,
176               Span<const uint8_t> id_verifier) {
177   if (out_w0.size() != kVerifierSize || out_w1.size() != kVerifierSize ||
178       out_registration_record.size() != kRegistrationRecordSize) {
179     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
180     return false;
181   }
182 
183   // Offline registration format from:
184   // https://www.rfc-editor.org/rfc/rfc9383.html#section-3.2
185   ScopedCBB mhf_input;
186   if (!CBB_init(mhf_input.get(), password.size() + id_prover.size() +
187                                      id_verifier.size() +
188                                      3 * sizeof(uint64_t)) ||  //
189       !AddLengthPrefixed(mhf_input.get(), password) ||
190       !AddLengthPrefixed(mhf_input.get(), id_prover) ||
191       !AddLengthPrefixed(mhf_input.get(), id_verifier) ||
192       !CBB_flush(mhf_input.get())) {
193     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
194     return false;
195   }
196 
197   // https://neuromancer.sk/std/nist/P-256
198   //   sage: p =
199   //   0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
200   //   ....: K = GF(p)
201   //   ....: a =
202   //   K(0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc)
203   //   ....: b =
204   //   K(0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b)
205   //   ....: E = EllipticCurve(K, (a, b))
206   //   ....: G =
207   //   E(0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
208   //   ....: 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5)
209   //   ....:
210   //   E.set_order(0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63
211   //   ....: 2551 * 0x1)
212   //   sage: k = 64
213   //   sage: L = (2 * (ceil(log(p)/log(2)) + k)) / 8
214 
215   // RFC 9383 Section 3.2
216   constexpr size_t kKDFOutputSize = 80;
217   constexpr size_t kKDFOutputWords = kKDFOutputSize / BN_BYTES;
218 
219   uint8_t key[kKDFOutputSize];
220   if (!EVP_PBE_scrypt((const char *)CBB_data(mhf_input.get()),
221                       CBB_len(mhf_input.get()), nullptr, 0,
222                       /*N=*/32768, /*r=*/8, /*p=*/1,
223                       /*max_mem=*/1024 * 1024 * 33, key, kKDFOutputSize)) {
224     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
225     return false;
226   }
227 
228   const EC_GROUP *group = EC_group_p256();
229   BN_ULONG w0_words[kKDFOutputWords / 2];
230   bn_big_endian_to_words(w0_words, kKDFOutputWords / 2, key,
231                          kKDFOutputSize / 2);
232   EC_SCALAR w0;
233   ec_scalar_reduce(group, &w0, w0_words, kKDFOutputWords / 2);
234   ScalarToSizedBuffer(group, &w0, out_w0);
235 
236   BN_ULONG w1_words[kKDFOutputWords / 2];
237   bn_big_endian_to_words(w1_words, kKDFOutputWords / 2,
238                          key + kKDFOutputSize / 2, kKDFOutputSize / 2);
239   EC_SCALAR w1;
240   ec_scalar_reduce(group, &w1, w1_words, kKDFOutputWords / 2);
241   ScalarToSizedBuffer(group, &w1, out_w1);
242 
243   EC_JACOBIAN L_j;
244   EC_AFFINE L;
245   if (!ec_point_mul_scalar_base(group, &L_j, &w1) ||  //
246       !ec_jacobian_to_affine(group, &L, &L_j) ||      //
247       !ec_point_to_bytes(group, &L, POINT_CONVERSION_UNCOMPRESSED,
248                          out_registration_record.data(),
249                          kRegistrationRecordSize)) {
250     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
251     return false;
252   }
253 
254   return true;
255 }
256 
257 Prover::Prover() = default;
258 Prover::~Prover() = default;
259 
Init(Span<const uint8_t> context,Span<const uint8_t> id_prover,Span<const uint8_t> id_verifier,Span<const uint8_t> w0,Span<const uint8_t> w1,Span<const uint8_t> x)260 bool Prover::Init(Span<const uint8_t> context, Span<const uint8_t> id_prover,
261                   Span<const uint8_t> id_verifier, Span<const uint8_t> w0,
262                   Span<const uint8_t> w1, Span<const uint8_t> x) {
263   const EC_GROUP *group = EC_group_p256();
264 
265   if (!ec_scalar_from_bytes(group, &w0_, w0.data(), w0.size()) ||
266       !ec_scalar_from_bytes(group, &w1_, w1.data(), w1.size()) ||
267       (!x.empty() &&
268        !ec_scalar_from_bytes(group, &x_, x.data(), x.size())) ||  //
269       (x.empty() && !ec_random_scalar(group, &x_, kDefaultAdditionalData))) {
270     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
271     return false;
272   }
273 
274   InitTranscriptHash(&transcript_hash_, context, id_prover, id_verifier);
275 
276   return true;
277 }
278 
GenerateShare(Span<uint8_t> out_share)279 bool Prover::GenerateShare(Span<uint8_t> out_share) {
280   if (state_ != State::kInit || out_share.size() != kShareSize) {
281     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
282     return false;
283   }
284 
285   // Compute X = x×P + w0×M.
286   // TODO(crbug.com/383778231): This could be sped up with a constant-time,
287   // two-point multiplication.
288   const EC_GROUP *group = EC_group_p256();
289   EC_JACOBIAN l;
290   if (!ec_point_mul_scalar_base(group, &l, &x_)) {
291     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
292     return false;
293   }
294 
295   EC_JACOBIAN M_j;
296   ConstantToJacobian(group, &M_j, kM_bytes);
297 
298   EC_JACOBIAN r;
299   if (!ec_point_mul_scalar(group, &r, &M_j, &w0_)) {
300     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
301     return false;
302   }
303 
304   EC_JACOBIAN X_j;
305   group->meth->add(group, &X_j, &l, &r);
306   if (!ec_jacobian_to_affine(group, &X_, &X_j)) {
307     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
308     return false;
309   }
310 
311   size_t written = ec_point_to_bytes(group, &X_, POINT_CONVERSION_UNCOMPRESSED,
312                                      out_share.data(), kShareSize);
313   BSSL_CHECK(written == kShareSize);
314 
315   memcpy(share_, out_share.data(), kShareSize);
316   state_ = State::kShareGenerated;
317   return true;
318 }
319 
ComputeConfirmation(Span<uint8_t> out_confirm,Span<uint8_t> out_secret,Span<const uint8_t> peer_share,Span<const uint8_t> peer_confirm)320 bool Prover::ComputeConfirmation(Span<uint8_t> out_confirm,
321                                  Span<uint8_t> out_secret,
322                                  Span<const uint8_t> peer_share,
323                                  Span<const uint8_t> peer_confirm) {
324   if (state_ != State::kShareGenerated || out_confirm.size() != kConfirmSize ||
325       out_secret.size() != kSecretSize || peer_share.size() != kShareSize ||
326       peer_confirm.size() != kConfirmSize) {
327     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
328     return false;
329   }
330 
331   const EC_GROUP *group = EC_group_p256();
332   EC_AFFINE Y;
333   if (!ec_point_from_uncompressed(group, &Y, peer_share.data(),
334                                   peer_share.size())) {
335     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
336     return false;
337   }
338 
339   EC_JACOBIAN N_j;
340   ConstantToJacobian(group, &N_j, kN_bytes);
341 
342   EC_JACOBIAN r;
343   if (!ec_point_mul_scalar(group, &r, &N_j, &w0_)) {
344     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
345     return false;
346   }
347 
348   ec_felem_neg(group, &r.Y, &r.Y);
349 
350   EC_JACOBIAN Y_j;
351   ec_affine_to_jacobian(group, &Y_j, &Y);
352 
353   EC_JACOBIAN t;
354   group->meth->add(group, &t, &Y_j, &r);
355 
356   EC_JACOBIAN tmp;
357   EC_AFFINE Z, V;
358   // TODO(crbug.com/383778231): The two affine conversions could be batched
359   // together.
360   if (!ec_point_mul_scalar(group, &tmp, &t, &x_) ||   //
361       !ec_jacobian_to_affine(group, &Z, &tmp) ||      //
362       !ec_point_mul_scalar(group, &tmp, &t, &w1_) ||  //
363       !ec_jacobian_to_affine(group, &V, &tmp)) {
364     return 0;
365   }
366 
367   uint8_t verifier_confirm[kConfirmSize];
368   if (!ComputeTranscript(out_confirm.data(), verifier_confirm,
369                          out_secret.data(), share_, peer_share.data(),
370                          &transcript_hash_, &Z, &V, &w0_) ||
371       CRYPTO_memcmp(verifier_confirm, peer_confirm.data(),
372                     sizeof(verifier_confirm)) != 0) {
373     return 0;
374   }
375 
376   state_ = State::kDone;
377   return true;
378 }
379 
380 Verifier::Verifier() = default;
381 Verifier::~Verifier() = default;
382 
Init(Span<const uint8_t> context,Span<const uint8_t> id_prover,Span<const uint8_t> id_verifier,Span<const uint8_t> w0,Span<const uint8_t> registration_record,Span<const uint8_t> y)383 bool Verifier::Init(Span<const uint8_t> context, Span<const uint8_t> id_prover,
384                     Span<const uint8_t> id_verifier, Span<const uint8_t> w0,
385                     Span<const uint8_t> registration_record,
386                     Span<const uint8_t> y) {
387   const EC_GROUP *group = EC_group_p256();
388 
389   if (!ec_scalar_from_bytes(group, &w0_, w0.data(), w0.size()) ||
390       !ec_point_from_uncompressed(group, &L_, registration_record.data(),
391                                   registration_record.size()) ||  //
392       (!y.empty() &&
393        !ec_scalar_from_bytes(group, &y_, y.data(), y.size())) ||  //
394       (y.empty() && !ec_random_scalar(group, &y_, kDefaultAdditionalData))) {
395     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
396     return false;
397   }
398 
399   InitTranscriptHash(&transcript_hash_, context, id_prover, id_verifier);
400 
401   return true;
402 }
403 
404 
ProcessProverShare(Span<uint8_t> out_share,Span<uint8_t> out_confirm,Span<uint8_t> out_secret,Span<const uint8_t> prover_share)405 bool Verifier::ProcessProverShare(Span<uint8_t> out_share,
406                                   Span<uint8_t> out_confirm,
407                                   Span<uint8_t> out_secret,
408                                   Span<const uint8_t> prover_share) {
409   if (state_ != State::kInit ||  //
410       out_share.size() != kShareSize || out_confirm.size() != kConfirmSize ||
411       out_secret.size() != kSecretSize || prover_share.size() != kShareSize) {
412     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
413     return false;
414   }
415 
416   const EC_GROUP *group = EC_group_p256();
417   EC_JACOBIAN l, r, M_j, N_j;
418   ConstantToJacobian(group, &M_j, kM_bytes);
419   ConstantToJacobian(group, &N_j, kN_bytes);
420 
421   // Compute Y = y×P + w0×M.
422   // TODO(crbug.com/383778231): This could be sped up with a constant-time,
423   // two-point multiplication.
424   if (!ec_point_mul_scalar_base(group, &l, &y_) ||
425       !ec_point_mul_scalar(group, &r, &N_j, &w0_)) {
426     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
427     return false;
428   }
429 
430   EC_JACOBIAN Y_j;
431   EC_AFFINE Y;
432   group->meth->add(group, &Y_j, &l, &r);
433   if (!ec_jacobian_to_affine(group, &Y, &Y_j)) {
434     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
435     return false;
436   }
437 
438   const size_t written = ec_point_to_bytes(
439       group, &Y, POINT_CONVERSION_UNCOMPRESSED, out_share.data(), kShareSize);
440   BSSL_CHECK(written == kShareSize);
441 
442   EC_JACOBIAN r2;
443   EC_AFFINE X;
444   if (!ec_point_from_uncompressed(group, &X, prover_share.data(),
445                                   prover_share.size()) ||
446       !ec_point_mul_scalar(group, &r2, &M_j, &w0_)) {
447     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
448     return false;
449   }
450 
451   ec_felem_neg(group, &r2.Y, &r2.Y);
452 
453   EC_JACOBIAN X_j, T;
454   ec_affine_to_jacobian(group, &X_j, &X);
455   group->meth->add(group, &T, &X_j, &r2);
456 
457   // TODO(crbug.com/383778231): The two affine conversions could be batched
458   // together.
459   EC_JACOBIAN tmp;
460   EC_AFFINE Z;
461   if (!ec_point_mul_scalar(group, &tmp, &T, &y_) ||  //
462       !ec_jacobian_to_affine(group, &Z, &tmp)) {
463     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
464     return false;
465   }
466 
467   EC_JACOBIAN L_j;
468   EC_AFFINE V;
469   ec_affine_to_jacobian(group, &L_j, &L_);
470   if (!ec_point_mul_scalar(group, &tmp, &L_j, &y_) ||  //
471       !ec_jacobian_to_affine(group, &V, &tmp)) {
472     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
473     return false;
474   }
475 
476   if (!ComputeTranscript(confirm_, out_confirm.data(), out_secret.data(),
477                          prover_share.data(), out_share.data(),
478                          &transcript_hash_, &Z, &V, &w0_)) {
479     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
480     return false;
481   }
482 
483   state_ = State::kProverShareSeen;
484   return true;
485 }
486 
VerifyProverConfirmation(Span<const uint8_t> peer_confirm)487 bool Verifier::VerifyProverConfirmation(Span<const uint8_t> peer_confirm) {
488   if (state_ != State::kProverShareSeen ||    //
489       peer_confirm.size() != kConfirmSize ||  //
490       CRYPTO_memcmp(confirm_, peer_confirm.data(), sizeof(confirm_)) != 0) {
491     OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
492     return false;
493   }
494 
495   state_ = State::kDone;
496   return true;
497 }
498 
499 }  // namespace spake2plus
500 
501 BSSL_NAMESPACE_END
502