Coverage Report

Created: 2026-04-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/evp/p_mldsa.cc
Line
Count
Source
1
// Copyright 2025 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/evp.h>
16
17
#include <assert.h>
18
19
#include <type_traits>
20
21
#include <openssl/bytestring.h>
22
#include <openssl/err.h>
23
#include <openssl/mldsa.h>
24
#include <openssl/nid.h>
25
#include <openssl/span.h>
26
27
#include "../fipsmodule/bcm_interface.h"
28
#include "../mem_internal.h"
29
#include "internal.h"
30
31
using namespace bssl;
32
33
namespace {
34
35
constexpr CBS_ASN1_TAG kSeedTag = CBS_ASN1_CONTEXT_SPECIFIC | 0;
36
37
constexpr uint8_t kMLDSA44OID[] = {OBJ_ENC_ML_DSA_44};
38
constexpr uint8_t kMLDSA65OID[] = {OBJ_ENC_ML_DSA_65};
39
constexpr uint8_t kMLDSA87OID[] = {OBJ_ENC_ML_DSA_87};
40
41
constexpr int kMaxContextLength = 255;
42
43
// We must generate EVP bindings for three ML-DSA algorithms. Define a traits
44
// type that captures the functions and other parameters of an ML-DSA algorithm.
45
#define MAKE_MLDSA_TRAITS(kl)                                                 \
46
  struct MLDSA##kl##Traits {                                                  \
47
    using PublicKey = MLDSA##kl##_public_key;                                 \
48
    using PrivateKey = MLDSA##kl##_private_key;                               \
49
    static constexpr size_t kPublicKeyBytes = MLDSA##kl##_PUBLIC_KEY_BYTES;   \
50
    static constexpr size_t kSignatureBytes = MLDSA##kl##_SIGNATURE_BYTES;    \
51
    static constexpr int kType = EVP_PKEY_ML_DSA_##kl;                        \
52
    static constexpr Span<const uint8_t> kOID = kMLDSA##kl##OID;              \
53
    static constexpr auto PrivateKeyFromSeed =                                \
54
        &MLDSA##kl##_private_key_from_seed;                                   \
55
    static constexpr auto GenerateKey = &MLDSA##kl##_generate_key;            \
56
    static constexpr auto Sign = &MLDSA##kl##_sign;                           \
57
    static constexpr auto ParsePublicKey = &MLDSA##kl##_parse_public_key;     \
58
    static constexpr auto PublicOfPrivate =                                   \
59
        &BCM_mldsa##kl##_public_of_private;                                   \
60
    static constexpr auto MarshalPublicKey = &MLDSA##kl##_marshal_public_key; \
61
    static constexpr auto PublicKeysEqual =                                   \
62
        &BCM_mldsa##kl##_public_keys_equal;                                   \
63
    static constexpr auto Verify = &MLDSA##kl##_verify;                       \
64
    static_assert(std::is_trivially_copyable_v<PublicKey>,                    \
65
                  "PublicKey type must be trivially copyable.");              \
66
  };
67
68
MAKE_MLDSA_TRAITS(44)
69
MAKE_MLDSA_TRAITS(65)
70
MAKE_MLDSA_TRAITS(87)
71
72
// For each ML-DSA variant, the |EvpPkey| must hold a public or private key.
73
// EVP uses the same type for public and private keys, so the representation
74
// must support both. The private key type contains the public key struct in it,
75
// so we use a pointer to either a PrivateKeyData<Traits> or
76
// PublicKeyData<Traits>, with a common base class to dispatch between them.
77
//
78
// TODO(crbug.com/404286922): In C++20, we need fewer |typename|s in front of
79
// dependent type names.
80
81
template <typename Traits>
82
class PrivateKeyData;
83
84
template <typename Traits>
85
class KeyData {
86
 public:
87
  // Returns the underlying public key for the key.
88
  const typename Traits::PublicKey *GetPublicKey() const;
89
90
  // Returns the PrivateKeyData struct for the key, or nullptr if this is a
91
  // public key.
92
  PrivateKeyData<Traits> *AsPrivateKeyData();
93
528
  const PrivateKeyData<Traits> *AsPrivateKeyData() const {
94
528
    return const_cast<KeyData *>(this)->AsPrivateKeyData();
95
528
  }
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA44Traits>::AsPrivateKeyData() const
Line
Count
Source
93
175
  const PrivateKeyData<Traits> *AsPrivateKeyData() const {
94
175
    return const_cast<KeyData *>(this)->AsPrivateKeyData();
95
175
  }
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA65Traits>::AsPrivateKeyData() const
Line
Count
Source
93
163
  const PrivateKeyData<Traits> *AsPrivateKeyData() const {
94
163
    return const_cast<KeyData *>(this)->AsPrivateKeyData();
95
163
  }
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA87Traits>::AsPrivateKeyData() const
Line
Count
Source
93
190
  const PrivateKeyData<Traits> *AsPrivateKeyData() const {
94
190
    return const_cast<KeyData *>(this)->AsPrivateKeyData();
95
190
  }
96
97
  // A KeyData cannot be freed directly. Rather, it must use this wrapper which
98
  // calls the correct subclass's destructor.
99
  static void Free(KeyData *data);
100
101
 protected:
102
485
  explicit KeyData(bool is_private) : is_private_(is_private) {}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA44Traits>::KeyData(bool)
Line
Count
Source
102
162
  explicit KeyData(bool is_private) : is_private_(is_private) {}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA65Traits>::KeyData(bool)
Line
Count
Source
102
156
  explicit KeyData(bool is_private) : is_private_(is_private) {}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA87Traits>::KeyData(bool)
Line
Count
Source
102
167
  explicit KeyData(bool is_private) : is_private_(is_private) {}
103
  ~KeyData() = default;
104
  bool is_private_;
105
};
106
107
template <typename Traits>
108
class PublicKeyData : public KeyData<Traits> {
109
 public:
110
  enum { kAllowUniquePtr = true };
111
71
  PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {}
p_mldsa.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLDSA44Traits>::PublicKeyData()
Line
Count
Source
111
24
  PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {}
p_mldsa.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLDSA65Traits>::PublicKeyData()
Line
Count
Source
111
20
  PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {}
p_mldsa.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLDSA87Traits>::PublicKeyData()
Line
Count
Source
111
27
  PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {}
112
113
  // Allows copying the PublicKey.
114
  explicit PublicKeyData(const typename Traits::PublicKey &key)
115
0
      : KeyData<Traits>(/*is_private=*/false), pub(key) {}
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLDSA44Traits>::PublicKeyData(MLDSA44_public_key const&)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLDSA65Traits>::PublicKeyData(MLDSA65_public_key const&)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLDSA87Traits>::PublicKeyData(MLDSA87_public_key const&)
116
117
  typename Traits::PublicKey pub;
118
};
119
120
template <typename Traits>
121
class PrivateKeyData : public KeyData<Traits> {
122
 public:
123
  enum { kAllowUniquePtr = true };
124
414
  PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {}
p_mldsa.cc:(anonymous namespace)::PrivateKeyData<(anonymous namespace)::MLDSA44Traits>::PrivateKeyData()
Line
Count
Source
124
138
  PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {}
p_mldsa.cc:(anonymous namespace)::PrivateKeyData<(anonymous namespace)::MLDSA65Traits>::PrivateKeyData()
Line
Count
Source
124
136
  PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {}
p_mldsa.cc:(anonymous namespace)::PrivateKeyData<(anonymous namespace)::MLDSA87Traits>::PrivateKeyData()
Line
Count
Source
124
140
  PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {}
125
  typename Traits::PrivateKey priv;
126
  uint8_t seed[MLDSA_SEED_BYTES];
127
};
128
129
template <typename Traits>
130
185
const typename Traits::PublicKey *KeyData<Traits>::GetPublicKey() const {
131
185
  auto *priv_data = AsPrivateKeyData();
132
185
  if (priv_data != nullptr) {
133
178
    return Traits::PublicOfPrivate(&priv_data->priv);
134
178
  }
135
7
  return &static_cast<const PublicKeyData<Traits> *>(this)->pub;
136
185
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA44Traits>::GetPublicKey() const
Line
Count
Source
130
70
const typename Traits::PublicKey *KeyData<Traits>::GetPublicKey() const {
131
70
  auto *priv_data = AsPrivateKeyData();
132
70
  if (priv_data != nullptr) {
133
63
    return Traits::PublicOfPrivate(&priv_data->priv);
134
63
  }
135
7
  return &static_cast<const PublicKeyData<Traits> *>(this)->pub;
136
70
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA65Traits>::GetPublicKey() const
Line
Count
Source
130
54
const typename Traits::PublicKey *KeyData<Traits>::GetPublicKey() const {
131
54
  auto *priv_data = AsPrivateKeyData();
132
54
  if (priv_data != nullptr) {
133
54
    return Traits::PublicOfPrivate(&priv_data->priv);
134
54
  }
135
0
  return &static_cast<const PublicKeyData<Traits> *>(this)->pub;
136
54
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA87Traits>::GetPublicKey() const
Line
Count
Source
130
61
const typename Traits::PublicKey *KeyData<Traits>::GetPublicKey() const {
131
61
  auto *priv_data = AsPrivateKeyData();
132
61
  if (priv_data != nullptr) {
133
61
    return Traits::PublicOfPrivate(&priv_data->priv);
134
61
  }
135
0
  return &static_cast<const PublicKeyData<Traits> *>(this)->pub;
136
61
}
137
138
template <typename Traits>
139
881
PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() {
140
881
  if (is_private_) {
141
864
    return static_cast<PrivateKeyData<Traits> *>(this);
142
864
  }
143
17
  return nullptr;
144
881
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA44Traits>::AsPrivateKeyData()
Line
Count
Source
139
288
PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() {
140
288
  if (is_private_) {
141
273
    return static_cast<PrivateKeyData<Traits> *>(this);
142
273
  }
143
15
  return nullptr;
144
288
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA65Traits>::AsPrivateKeyData()
Line
Count
Source
139
273
PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() {
140
273
  if (is_private_) {
141
272
    return static_cast<PrivateKeyData<Traits> *>(this);
142
272
  }
143
1
  return nullptr;
144
273
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA87Traits>::AsPrivateKeyData()
Line
Count
Source
139
320
PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() {
140
320
  if (is_private_) {
141
319
    return static_cast<PrivateKeyData<Traits> *>(this);
142
319
  }
143
1
  return nullptr;
144
320
}
145
146
template <typename Traits>
147
353
void KeyData<Traits>::Free(KeyData<Traits> *data) {
148
353
  if (data == nullptr) {
149
0
    return;
150
0
  }
151
  // Delete the more specific subclass. This is moot for now, because neither
152
  // type has a non-trivial destructor.
153
353
  auto *priv_data = data->AsPrivateKeyData();
154
353
  if (priv_data) {
155
343
    Delete(priv_data);
156
343
  } else {
157
10
    Delete(static_cast<PublicKeyData<Traits> *>(data));
158
10
  }
159
353
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA44Traits>::Free((anonymous namespace)::KeyData<(anonymous namespace)::MLDSA44Traits>*)
Line
Count
Source
147
113
void KeyData<Traits>::Free(KeyData<Traits> *data) {
148
113
  if (data == nullptr) {
149
0
    return;
150
0
  }
151
  // Delete the more specific subclass. This is moot for now, because neither
152
  // type has a non-trivial destructor.
153
113
  auto *priv_data = data->AsPrivateKeyData();
154
113
  if (priv_data) {
155
105
    Delete(priv_data);
156
105
  } else {
157
8
    Delete(static_cast<PublicKeyData<Traits> *>(data));
158
8
  }
159
113
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA65Traits>::Free((anonymous namespace)::KeyData<(anonymous namespace)::MLDSA65Traits>*)
Line
Count
Source
147
110
void KeyData<Traits>::Free(KeyData<Traits> *data) {
148
110
  if (data == nullptr) {
149
0
    return;
150
0
  }
151
  // Delete the more specific subclass. This is moot for now, because neither
152
  // type has a non-trivial destructor.
153
110
  auto *priv_data = data->AsPrivateKeyData();
154
110
  if (priv_data) {
155
109
    Delete(priv_data);
156
109
  } else {
157
1
    Delete(static_cast<PublicKeyData<Traits> *>(data));
158
1
  }
159
110
}
p_mldsa.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLDSA87Traits>::Free((anonymous namespace)::KeyData<(anonymous namespace)::MLDSA87Traits>*)
Line
Count
Source
147
130
void KeyData<Traits>::Free(KeyData<Traits> *data) {
148
130
  if (data == nullptr) {
149
0
    return;
150
0
  }
151
  // Delete the more specific subclass. This is moot for now, because neither
152
  // type has a non-trivial destructor.
153
130
  auto *priv_data = data->AsPrivateKeyData();
154
130
  if (priv_data) {
155
129
    Delete(priv_data);
156
129
  } else {
157
1
    Delete(static_cast<PublicKeyData<Traits> *>(data));
158
1
  }
159
130
}
160
161
struct MldsaPkeyCtx {
162
  bssl::Array<uint8_t> context;
163
};
164
165
166
// Finally, MLDSAImplementation instantiates the methods themselves.
167
168
template <typename Traits>
169
struct MLDSAImplementation {
170
881
  static KeyData<Traits> *GetKeyData(EvpPkey *pkey) {
171
881
    assert(pkey->ameth == &asn1_method);
172
881
    return static_cast<KeyData<Traits> *>(pkey->pkey);
173
881
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::GetKeyData(bssl::EvpPkey*)
Line
Count
Source
170
288
  static KeyData<Traits> *GetKeyData(EvpPkey *pkey) {
171
288
    assert(pkey->ameth == &asn1_method);
172
288
    return static_cast<KeyData<Traits> *>(pkey->pkey);
173
288
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::GetKeyData(bssl::EvpPkey*)
Line
Count
Source
170
273
  static KeyData<Traits> *GetKeyData(EvpPkey *pkey) {
171
273
    assert(pkey->ameth == &asn1_method);
172
273
    return static_cast<KeyData<Traits> *>(pkey->pkey);
173
273
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::GetKeyData(bssl::EvpPkey*)
Line
Count
Source
170
320
  static KeyData<Traits> *GetKeyData(EvpPkey *pkey) {
171
320
    assert(pkey->ameth == &asn1_method);
172
320
    return static_cast<KeyData<Traits> *>(pkey->pkey);
173
320
  }
174
175
528
  static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) {
176
528
    return GetKeyData(const_cast<EvpPkey *>(pkey));
177
528
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::GetKeyData(bssl::EvpPkey const*)
Line
Count
Source
175
175
  static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) {
176
175
    return GetKeyData(const_cast<EvpPkey *>(pkey));
177
175
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::GetKeyData(bssl::EvpPkey const*)
Line
Count
Source
175
163
  static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) {
176
163
    return GetKeyData(const_cast<EvpPkey *>(pkey));
177
163
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::GetKeyData(bssl::EvpPkey const*)
Line
Count
Source
175
190
  static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) {
176
190
    return GetKeyData(const_cast<EvpPkey *>(pkey));
177
190
  }
178
179
353
  static void PkeyFree(EvpPkey *pkey) {
180
353
    KeyData<Traits>::Free(GetKeyData(pkey));
181
353
    pkey->pkey = nullptr;
182
353
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::PkeyFree(bssl::EvpPkey*)
Line
Count
Source
179
113
  static void PkeyFree(EvpPkey *pkey) {
180
113
    KeyData<Traits>::Free(GetKeyData(pkey));
181
113
    pkey->pkey = nullptr;
182
113
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::PkeyFree(bssl::EvpPkey*)
Line
Count
Source
179
110
  static void PkeyFree(EvpPkey *pkey) {
180
110
    KeyData<Traits>::Free(GetKeyData(pkey));
181
110
    pkey->pkey = nullptr;
182
110
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::PkeyFree(bssl::EvpPkey*)
Line
Count
Source
179
130
  static void PkeyFree(EvpPkey *pkey) {
180
130
    KeyData<Traits>::Free(GetKeyData(pkey));
181
130
    pkey->pkey = nullptr;
182
130
  }
183
184
414
  static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) {
185
414
    auto priv = MakeUnique<PrivateKeyData<Traits>>();
186
414
    if (priv == nullptr) {
187
0
      return 0;
188
0
    }
189
190
414
    if (len != MLDSA_SEED_BYTES ||
191
343
        !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) {
192
71
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
193
71
      return 0;
194
71
    }
195
343
    OPENSSL_memcpy(priv->seed, in, len);
196
343
    evp_pkey_set0(pkey, &asn1_method, priv.release());
197
343
    return 1;
198
414
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::SetPrivateSeed(bssl::EvpPkey*, unsigned char const*, unsigned long)
Line
Count
Source
184
138
  static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) {
185
138
    auto priv = MakeUnique<PrivateKeyData<Traits>>();
186
138
    if (priv == nullptr) {
187
0
      return 0;
188
0
    }
189
190
138
    if (len != MLDSA_SEED_BYTES ||
191
105
        !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) {
192
33
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
193
33
      return 0;
194
33
    }
195
105
    OPENSSL_memcpy(priv->seed, in, len);
196
105
    evp_pkey_set0(pkey, &asn1_method, priv.release());
197
105
    return 1;
198
138
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::SetPrivateSeed(bssl::EvpPkey*, unsigned char const*, unsigned long)
Line
Count
Source
184
136
  static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) {
185
136
    auto priv = MakeUnique<PrivateKeyData<Traits>>();
186
136
    if (priv == nullptr) {
187
0
      return 0;
188
0
    }
189
190
136
    if (len != MLDSA_SEED_BYTES ||
191
109
        !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) {
192
27
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
193
27
      return 0;
194
27
    }
195
109
    OPENSSL_memcpy(priv->seed, in, len);
196
109
    evp_pkey_set0(pkey, &asn1_method, priv.release());
197
109
    return 1;
198
136
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::SetPrivateSeed(bssl::EvpPkey*, unsigned char const*, unsigned long)
Line
Count
Source
184
140
  static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) {
185
140
    auto priv = MakeUnique<PrivateKeyData<Traits>>();
186
140
    if (priv == nullptr) {
187
0
      return 0;
188
0
    }
189
190
140
    if (len != MLDSA_SEED_BYTES ||
191
129
        !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) {
192
11
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
193
11
      return 0;
194
11
    }
195
129
    OPENSSL_memcpy(priv->seed, in, len);
196
129
    evp_pkey_set0(pkey, &asn1_method, priv.release());
197
129
    return 1;
198
140
  }
199
200
71
  static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) {
201
71
    auto pub = MakeUnique<PublicKeyData<Traits>>();
202
71
    if (pub == nullptr) {
203
0
      return 0;
204
0
    }
205
71
    CBS cbs;
206
71
    CBS_init(&cbs, in, len);
207
71
    if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) {
208
61
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
209
61
      return 0;
210
61
    }
211
10
    evp_pkey_set0(pkey, &asn1_method, pub.release());
212
10
    return 1;
213
71
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::SetRawPublic(bssl::EvpPkey*, unsigned char const*, unsigned long)
Line
Count
Source
200
24
  static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) {
201
24
    auto pub = MakeUnique<PublicKeyData<Traits>>();
202
24
    if (pub == nullptr) {
203
0
      return 0;
204
0
    }
205
24
    CBS cbs;
206
24
    CBS_init(&cbs, in, len);
207
24
    if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) {
208
16
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
209
16
      return 0;
210
16
    }
211
8
    evp_pkey_set0(pkey, &asn1_method, pub.release());
212
8
    return 1;
213
24
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::SetRawPublic(bssl::EvpPkey*, unsigned char const*, unsigned long)
Line
Count
Source
200
20
  static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) {
201
20
    auto pub = MakeUnique<PublicKeyData<Traits>>();
202
20
    if (pub == nullptr) {
203
0
      return 0;
204
0
    }
205
20
    CBS cbs;
206
20
    CBS_init(&cbs, in, len);
207
20
    if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) {
208
19
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
209
19
      return 0;
210
19
    }
211
1
    evp_pkey_set0(pkey, &asn1_method, pub.release());
212
1
    return 1;
213
20
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::SetRawPublic(bssl::EvpPkey*, unsigned char const*, unsigned long)
Line
Count
Source
200
27
  static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) {
201
27
    auto pub = MakeUnique<PublicKeyData<Traits>>();
202
27
    if (pub == nullptr) {
203
0
      return 0;
204
0
    }
205
27
    CBS cbs;
206
27
    CBS_init(&cbs, in, len);
207
27
    if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) {
208
26
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
209
26
      return 0;
210
26
    }
211
1
    evp_pkey_set0(pkey, &asn1_method, pub.release());
212
1
    return 1;
213
27
  }
214
215
  static int GetPrivateSeed(const EvpPkey *pkey, uint8_t *out,
216
0
                            size_t *out_len) {
217
0
    const auto *priv = GetKeyData(pkey)->AsPrivateKeyData();
218
0
    if (priv == nullptr) {
219
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
220
0
      return 0;
221
0
    }
222
0
    if (out == nullptr) {
223
0
      *out_len = MLDSA_SEED_BYTES;
224
0
      return 1;
225
0
    }
226
0
    if (*out_len < MLDSA_SEED_BYTES) {
227
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
228
0
      return 0;
229
0
    }
230
0
    OPENSSL_memcpy(out, priv->seed, MLDSA_SEED_BYTES);
231
0
    *out_len = MLDSA_SEED_BYTES;
232
0
    return 1;
233
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::GetPrivateSeed(bssl::EvpPkey const*, unsigned char*, unsigned long*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::GetPrivateSeed(bssl::EvpPkey const*, unsigned char*, unsigned long*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::GetPrivateSeed(bssl::EvpPkey const*, unsigned char*, unsigned long*)
234
235
0
  static int GetRawPublic(const EvpPkey *pkey, uint8_t *out, size_t *out_len) {
236
0
    const auto *pub = GetKeyData(pkey)->GetPublicKey();
237
0
    if (out == nullptr) {
238
0
      *out_len = Traits::kPublicKeyBytes;
239
0
      return 1;
240
0
    }
241
0
    if (*out_len < Traits::kPublicKeyBytes) {
242
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
243
0
      return 0;
244
0
    }
245
0
    CBB cbb;
246
0
    CBB_init_fixed(&cbb, out, Traits::kPublicKeyBytes);
247
0
    BSSL_CHECK(Traits::MarshalPublicKey(&cbb, pub));
248
0
    BSSL_CHECK(CBB_len(&cbb) == Traits::kPublicKeyBytes);
249
0
    *out_len = Traits::kPublicKeyBytes;
250
0
    return 1;
251
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::GetRawPublic(bssl::EvpPkey const*, unsigned char*, unsigned long*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::GetRawPublic(bssl::EvpPkey const*, unsigned char*, unsigned long*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::GetRawPublic(bssl::EvpPkey const*, unsigned char*, unsigned long*)
252
253
  static evp_decode_result_t DecodePublic(const EVP_PKEY_ALG *alg, EvpPkey *out,
254
261
                                          CBS *params, CBS *key) {
255
    // The parameters must be omitted. See
256
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
257
261
    if (CBS_len(params) != 0) {
258
190
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
259
190
      return evp_decode_error;
260
190
    }
261
71
    return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok
262
71
                                                          : evp_decode_error;
263
261
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::DecodePublic(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*)
Line
Count
Source
254
52
                                          CBS *params, CBS *key) {
255
    // The parameters must be omitted. See
256
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
257
52
    if (CBS_len(params) != 0) {
258
28
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
259
28
      return evp_decode_error;
260
28
    }
261
24
    return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok
262
24
                                                          : evp_decode_error;
263
52
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::DecodePublic(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*)
Line
Count
Source
254
85
                                          CBS *params, CBS *key) {
255
    // The parameters must be omitted. See
256
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
257
85
    if (CBS_len(params) != 0) {
258
65
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
259
65
      return evp_decode_error;
260
65
    }
261
20
    return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok
262
20
                                                          : evp_decode_error;
263
85
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::DecodePublic(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*)
Line
Count
Source
254
124
                                          CBS *params, CBS *key) {
255
    // The parameters must be omitted. See
256
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
257
124
    if (CBS_len(params) != 0) {
258
97
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
259
97
      return evp_decode_error;
260
97
    }
261
27
    return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok
262
27
                                                          : evp_decode_error;
263
124
  }
264
265
185
  static int EncodePublic(CBB *out, const EvpPkey *pkey) {
266
185
    const auto *pub = GetKeyData(pkey)->GetPublicKey();
267
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 4.
268
185
    CBB spki, algorithm, key_bitstring;
269
185
    if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
270
185
        !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
271
185
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
272
185
                              Traits::kOID.size()) ||
273
185
        !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
274
185
        !CBB_add_u8(&key_bitstring, 0 /* no unused bits */) ||
275
185
        !Traits::MarshalPublicKey(&key_bitstring, pub) ||
276
185
        !CBB_flush(out)) {
277
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
278
0
      return 0;
279
0
    }
280
185
    return 1;
281
185
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::EncodePublic(cbb_st*, bssl::EvpPkey const*)
Line
Count
Source
265
70
  static int EncodePublic(CBB *out, const EvpPkey *pkey) {
266
70
    const auto *pub = GetKeyData(pkey)->GetPublicKey();
267
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 4.
268
70
    CBB spki, algorithm, key_bitstring;
269
70
    if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
270
70
        !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
271
70
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
272
70
                              Traits::kOID.size()) ||
273
70
        !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
274
70
        !CBB_add_u8(&key_bitstring, 0 /* no unused bits */) ||
275
70
        !Traits::MarshalPublicKey(&key_bitstring, pub) ||
276
70
        !CBB_flush(out)) {
277
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
278
0
      return 0;
279
0
    }
280
70
    return 1;
281
70
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::EncodePublic(cbb_st*, bssl::EvpPkey const*)
Line
Count
Source
265
54
  static int EncodePublic(CBB *out, const EvpPkey *pkey) {
266
54
    const auto *pub = GetKeyData(pkey)->GetPublicKey();
267
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 4.
268
54
    CBB spki, algorithm, key_bitstring;
269
54
    if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
270
54
        !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
271
54
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
272
54
                              Traits::kOID.size()) ||
273
54
        !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
274
54
        !CBB_add_u8(&key_bitstring, 0 /* no unused bits */) ||
275
54
        !Traits::MarshalPublicKey(&key_bitstring, pub) ||
276
54
        !CBB_flush(out)) {
277
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
278
0
      return 0;
279
0
    }
280
54
    return 1;
281
54
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::EncodePublic(cbb_st*, bssl::EvpPkey const*)
Line
Count
Source
265
61
  static int EncodePublic(CBB *out, const EvpPkey *pkey) {
266
61
    const auto *pub = GetKeyData(pkey)->GetPublicKey();
267
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 4.
268
61
    CBB spki, algorithm, key_bitstring;
269
61
    if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
270
61
        !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
271
61
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
272
61
                              Traits::kOID.size()) ||
273
61
        !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
274
61
        !CBB_add_u8(&key_bitstring, 0 /* no unused bits */) ||
275
61
        !Traits::MarshalPublicKey(&key_bitstring, pub) ||
276
61
        !CBB_flush(out)) {
277
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
278
0
      return 0;
279
0
    }
280
61
    return 1;
281
61
  }
282
283
0
  static bool EqualPublic(const EvpPkey *a, const EvpPkey *b) {
284
0
    const auto *a_pub = GetKeyData(a)->GetPublicKey();
285
0
    const auto *b_pub = GetKeyData(b)->GetPublicKey();
286
0
    return Traits::PublicKeysEqual(a_pub, b_pub);
287
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::EqualPublic(bssl::EvpPkey const*, bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::EqualPublic(bssl::EvpPkey const*, bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::EqualPublic(bssl::EvpPkey const*, bssl::EvpPkey const*)
288
289
0
  static bool HasPublic(const EvpPkey *pk) { return true; }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::HasPublic(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::HasPublic(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::HasPublic(bssl::EvpPkey const*)
290
291
0
  static bool CopyPublic(EvpPkey *out, const EvpPkey *pk) {
292
0
    auto *public_copy =
293
0
        New<PublicKeyData<Traits>>(*GetKeyData(pk)->GetPublicKey());
294
0
    if (public_copy == nullptr) {
295
0
      OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
296
0
      return false;
297
0
    }
298
0
    evp_pkey_set0(out, pk->ameth, public_copy);
299
0
    return true;
300
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::CopyPublic(bssl::EvpPkey*, bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::CopyPublic(bssl::EvpPkey*, bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::CopyPublic(bssl::EvpPkey*, bssl::EvpPkey const*)
301
302
  static evp_decode_result_t DecodePrivate(const EVP_PKEY_ALG *alg,
303
                                           EvpPkey *out, CBS *params,
304
523
                                           CBS *key) {
305
    // The parameters must be omitted. See
306
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
307
523
    if (CBS_len(params) != 0) {
308
41
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
309
41
      return evp_decode_error;
310
41
    }
311
312
    // See draft-ietf-lamps-dilithium-certificates-13, Section 6. Three
313
    // different encodings were specified, adding complexity to the question of
314
    // whether a private key is valid. We only implement the "seed"
315
    // representation. Give this case a different error for easier diagnostics.
316
    //
317
    // The "expandedKey" representation was a last-minute accommodation for
318
    // legacy hardware, which should be updated to use seeds. Supporting it
319
    // complicates the notion of a private key with both seedful and seedless
320
    // variants.
321
    //
322
    // The "both" representation is technically unsound and
323
    // dangerous, so we do not implement it. Systems composed of components,
324
    // some of which look at one half of the "both" representation, and half of
325
    // the other, will appear to interop, but break when an input is
326
    // inconsistent. The expanded key can be computed from the seed, so there is
327
    // no purpose in this form.
328
482
    CBS seed;
329
482
    if (!CBS_get_asn1(key, &seed, kSeedTag)) {
330
14
      OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED);
331
14
      return evp_decode_error;
332
14
    }
333
468
    if (CBS_len(key) != 0) {
334
54
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
335
54
      return evp_decode_error;
336
54
    }
337
414
    return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed))
338
414
               ? evp_decode_ok
339
414
               : evp_decode_error;
340
468
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::DecodePrivate(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*)
Line
Count
Source
304
165
                                           CBS *key) {
305
    // The parameters must be omitted. See
306
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
307
165
    if (CBS_len(params) != 0) {
308
7
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
309
7
      return evp_decode_error;
310
7
    }
311
312
    // See draft-ietf-lamps-dilithium-certificates-13, Section 6. Three
313
    // different encodings were specified, adding complexity to the question of
314
    // whether a private key is valid. We only implement the "seed"
315
    // representation. Give this case a different error for easier diagnostics.
316
    //
317
    // The "expandedKey" representation was a last-minute accommodation for
318
    // legacy hardware, which should be updated to use seeds. Supporting it
319
    // complicates the notion of a private key with both seedful and seedless
320
    // variants.
321
    //
322
    // The "both" representation is technically unsound and
323
    // dangerous, so we do not implement it. Systems composed of components,
324
    // some of which look at one half of the "both" representation, and half of
325
    // the other, will appear to interop, but break when an input is
326
    // inconsistent. The expanded key can be computed from the seed, so there is
327
    // no purpose in this form.
328
158
    CBS seed;
329
158
    if (!CBS_get_asn1(key, &seed, kSeedTag)) {
330
4
      OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED);
331
4
      return evp_decode_error;
332
4
    }
333
154
    if (CBS_len(key) != 0) {
334
16
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
335
16
      return evp_decode_error;
336
16
    }
337
138
    return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed))
338
138
               ? evp_decode_ok
339
138
               : evp_decode_error;
340
154
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::DecodePrivate(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*)
Line
Count
Source
304
177
                                           CBS *key) {
305
    // The parameters must be omitted. See
306
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
307
177
    if (CBS_len(params) != 0) {
308
12
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
309
12
      return evp_decode_error;
310
12
    }
311
312
    // See draft-ietf-lamps-dilithium-certificates-13, Section 6. Three
313
    // different encodings were specified, adding complexity to the question of
314
    // whether a private key is valid. We only implement the "seed"
315
    // representation. Give this case a different error for easier diagnostics.
316
    //
317
    // The "expandedKey" representation was a last-minute accommodation for
318
    // legacy hardware, which should be updated to use seeds. Supporting it
319
    // complicates the notion of a private key with both seedful and seedless
320
    // variants.
321
    //
322
    // The "both" representation is technically unsound and
323
    // dangerous, so we do not implement it. Systems composed of components,
324
    // some of which look at one half of the "both" representation, and half of
325
    // the other, will appear to interop, but break when an input is
326
    // inconsistent. The expanded key can be computed from the seed, so there is
327
    // no purpose in this form.
328
165
    CBS seed;
329
165
    if (!CBS_get_asn1(key, &seed, kSeedTag)) {
330
4
      OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED);
331
4
      return evp_decode_error;
332
4
    }
333
161
    if (CBS_len(key) != 0) {
334
25
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
335
25
      return evp_decode_error;
336
25
    }
337
136
    return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed))
338
136
               ? evp_decode_ok
339
136
               : evp_decode_error;
340
161
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::DecodePrivate(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*)
Line
Count
Source
304
181
                                           CBS *key) {
305
    // The parameters must be omitted. See
306
    // draft-ietf-lamps-dilithium-certificates-13, Section 2.
307
181
    if (CBS_len(params) != 0) {
308
22
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
309
22
      return evp_decode_error;
310
22
    }
311
312
    // See draft-ietf-lamps-dilithium-certificates-13, Section 6. Three
313
    // different encodings were specified, adding complexity to the question of
314
    // whether a private key is valid. We only implement the "seed"
315
    // representation. Give this case a different error for easier diagnostics.
316
    //
317
    // The "expandedKey" representation was a last-minute accommodation for
318
    // legacy hardware, which should be updated to use seeds. Supporting it
319
    // complicates the notion of a private key with both seedful and seedless
320
    // variants.
321
    //
322
    // The "both" representation is technically unsound and
323
    // dangerous, so we do not implement it. Systems composed of components,
324
    // some of which look at one half of the "both" representation, and half of
325
    // the other, will appear to interop, but break when an input is
326
    // inconsistent. The expanded key can be computed from the seed, so there is
327
    // no purpose in this form.
328
159
    CBS seed;
329
159
    if (!CBS_get_asn1(key, &seed, kSeedTag)) {
330
6
      OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED);
331
6
      return evp_decode_error;
332
6
    }
333
153
    if (CBS_len(key) != 0) {
334
13
      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
335
13
      return evp_decode_error;
336
13
    }
337
140
    return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed))
338
140
               ? evp_decode_ok
339
140
               : evp_decode_error;
340
153
  }
341
342
343
  static int EncodePrivate(CBB *out, const EvpPkey *pkey) {
343
343
    const auto *priv = GetKeyData(pkey)->AsPrivateKeyData();
344
343
    if (priv == nullptr) {
345
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
346
0
      return 0;
347
0
    }
348
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 6. We
349
    // encode only the seed representation.
350
343
    CBB pkcs8, algorithm, private_key;
351
343
    if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
352
343
        !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
353
343
        !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
354
343
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
355
343
                              Traits::kOID.size()) ||
356
343
        !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
357
343
        !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed,
358
343
                              sizeof(priv->seed)) ||
359
343
        !CBB_flush(out)) {
360
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
361
0
      return 0;
362
0
    }
363
343
    return 1;
364
343
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::EncodePrivate(cbb_st*, bssl::EvpPkey const*)
Line
Count
Source
342
105
  static int EncodePrivate(CBB *out, const EvpPkey *pkey) {
343
105
    const auto *priv = GetKeyData(pkey)->AsPrivateKeyData();
344
105
    if (priv == nullptr) {
345
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
346
0
      return 0;
347
0
    }
348
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 6. We
349
    // encode only the seed representation.
350
105
    CBB pkcs8, algorithm, private_key;
351
105
    if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
352
105
        !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
353
105
        !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
354
105
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
355
105
                              Traits::kOID.size()) ||
356
105
        !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
357
105
        !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed,
358
105
                              sizeof(priv->seed)) ||
359
105
        !CBB_flush(out)) {
360
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
361
0
      return 0;
362
0
    }
363
105
    return 1;
364
105
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::EncodePrivate(cbb_st*, bssl::EvpPkey const*)
Line
Count
Source
342
109
  static int EncodePrivate(CBB *out, const EvpPkey *pkey) {
343
109
    const auto *priv = GetKeyData(pkey)->AsPrivateKeyData();
344
109
    if (priv == nullptr) {
345
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
346
0
      return 0;
347
0
    }
348
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 6. We
349
    // encode only the seed representation.
350
109
    CBB pkcs8, algorithm, private_key;
351
109
    if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
352
109
        !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
353
109
        !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
354
109
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
355
109
                              Traits::kOID.size()) ||
356
109
        !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
357
109
        !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed,
358
109
                              sizeof(priv->seed)) ||
359
109
        !CBB_flush(out)) {
360
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
361
0
      return 0;
362
0
    }
363
109
    return 1;
364
109
  }
p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::EncodePrivate(cbb_st*, bssl::EvpPkey const*)
Line
Count
Source
342
129
  static int EncodePrivate(CBB *out, const EvpPkey *pkey) {
343
129
    const auto *priv = GetKeyData(pkey)->AsPrivateKeyData();
344
129
    if (priv == nullptr) {
345
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
346
0
      return 0;
347
0
    }
348
    // See draft-ietf-lamps-dilithium-certificates-13, Sections 2 and 6. We
349
    // encode only the seed representation.
350
129
    CBB pkcs8, algorithm, private_key;
351
129
    if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
352
129
        !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
353
129
        !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
354
129
        !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(),
355
129
                              Traits::kOID.size()) ||
356
129
        !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
357
129
        !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed,
358
129
                              sizeof(priv->seed)) ||
359
129
        !CBB_flush(out)) {
360
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
361
0
      return 0;
362
0
    }
363
129
    return 1;
364
129
  }
365
366
0
  static bool HasPrivate(const EvpPkey *pk) {
367
0
    return GetKeyData(pk)->AsPrivateKeyData() != nullptr;
368
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::HasPrivate(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::HasPrivate(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::HasPrivate(bssl::EvpPkey const*)
369
370
0
  static int PkeySize(const EvpPkey *pkey) { return Traits::kSignatureBytes; }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::PkeySize(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::PkeySize(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::PkeySize(bssl::EvpPkey const*)
371
0
  static int PkeyBits(const EvpPkey *pkey) {
372
    // OpenSSL counts the bits in the public key serialization.
373
0
    return Traits::kPublicKeyBytes * 8;
374
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::PkeyBits(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::PkeyBits(bssl::EvpPkey const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::PkeyBits(bssl::EvpPkey const*)
375
376
0
  static int Init(EvpPkeyCtx *ctx, const EVP_PKEY_ALG *) {
377
0
    MldsaPkeyCtx *mctx = New<MldsaPkeyCtx>();
378
0
    if (mctx == nullptr) {
379
0
      return 0;
380
0
    }
381
0
    ctx->data = mctx;
382
0
    return 1;
383
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::Init(bssl::EvpPkeyCtx*, evp_pkey_alg_st const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::Init(bssl::EvpPkeyCtx*, evp_pkey_alg_st const*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::Init(bssl::EvpPkeyCtx*, evp_pkey_alg_st const*)
384
385
0
  static void Cleanup(EvpPkeyCtx *ctx) {
386
0
    Delete(static_cast<MldsaPkeyCtx *>(ctx->data));
387
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::Cleanup(bssl::EvpPkeyCtx*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::Cleanup(bssl::EvpPkeyCtx*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::Cleanup(bssl::EvpPkeyCtx*)
388
389
0
  static int CopyContext(EvpPkeyCtx *dst, EvpPkeyCtx *src) {
390
0
    if (!Init(dst, nullptr)) {
391
0
      return 0;
392
0
    }
393
0
    MldsaPkeyCtx *sctx = static_cast<MldsaPkeyCtx *>(src->data);
394
0
    MldsaPkeyCtx *dctx = static_cast<MldsaPkeyCtx *>(dst->data);
395
0
    if (!dctx->context.CopyFrom(sctx->context)) {
396
0
      return 0;
397
0
    }
398
0
    return 1;
399
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::CopyContext(bssl::EvpPkeyCtx*, bssl::EvpPkeyCtx*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::CopyContext(bssl::EvpPkeyCtx*, bssl::EvpPkeyCtx*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::CopyContext(bssl::EvpPkeyCtx*, bssl::EvpPkeyCtx*)
400
401
0
  static int KeyGen(EvpPkeyCtx *ctx, EvpPkey *pkey) {
402
0
    auto priv = MakeUnique<PrivateKeyData<Traits>>();
403
0
    if (priv == nullptr) {
404
0
      return 0;
405
0
    }
406
0
    uint8_t unused_public[Traits::kPublicKeyBytes];
407
0
    if (!Traits::GenerateKey(unused_public, priv->seed, &priv->priv)) {
408
0
      return 0;
409
0
    }
410
0
    evp_pkey_set0(pkey, &asn1_method, priv.release());
411
0
    return 1;
412
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::KeyGen(bssl::EvpPkeyCtx*, bssl::EvpPkey*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::KeyGen(bssl::EvpPkeyCtx*, bssl::EvpPkey*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::KeyGen(bssl::EvpPkeyCtx*, bssl::EvpPkey*)
413
414
  static int SignMessage(EvpPkeyCtx *ctx, uint8_t *sig, size_t *siglen,
415
0
                         const uint8_t *tbs, size_t tbslen) {
416
0
    const auto *priv_data = GetKeyData(ctx->pkey.get())->AsPrivateKeyData();
417
0
    if (priv_data == nullptr) {
418
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
419
0
      return 0;
420
0
    }
421
0
    if (sig == nullptr) {
422
0
      *siglen = Traits::kSignatureBytes;
423
0
      return 1;
424
0
    }
425
0
    if (*siglen < Traits::kSignatureBytes) {
426
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
427
0
      return 0;
428
0
    }
429
0
    MldsaPkeyCtx *mctx = static_cast<MldsaPkeyCtx *>(ctx->data);
430
0
    if (!Traits::Sign(sig, &priv_data->priv, tbs, tbslen, mctx->context.data(),
431
0
                      mctx->context.size())) {
432
0
      return 0;
433
0
    }
434
0
    *siglen = Traits::kSignatureBytes;
435
0
    return 1;
436
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::SignMessage(bssl::EvpPkeyCtx*, unsigned char*, unsigned long*, unsigned char const*, unsigned long)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::SignMessage(bssl::EvpPkeyCtx*, unsigned char*, unsigned long*, unsigned char const*, unsigned long)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::SignMessage(bssl::EvpPkeyCtx*, unsigned char*, unsigned long*, unsigned char const*, unsigned long)
437
438
  static int VerifyMessage(EvpPkeyCtx *ctx, const uint8_t *sig, size_t siglen,
439
0
                           const uint8_t *tbs, size_t tbslen) {
440
0
    const auto *pub = GetKeyData(ctx->pkey.get())->GetPublicKey();
441
0
    MldsaPkeyCtx *mctx = static_cast<MldsaPkeyCtx *>(ctx->data);
442
0
    if (!Traits::Verify(pub, sig, siglen, tbs, tbslen, mctx->context.data(),
443
0
                        mctx->context.size())) {
444
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
445
0
      return 0;
446
0
    }
447
0
    return 1;
448
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::VerifyMessage(bssl::EvpPkeyCtx*, unsigned char const*, unsigned long, unsigned char const*, unsigned long)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::VerifyMessage(bssl::EvpPkeyCtx*, unsigned char const*, unsigned long, unsigned char const*, unsigned long)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::VerifyMessage(bssl::EvpPkeyCtx*, unsigned char const*, unsigned long, unsigned char const*, unsigned long)
449
450
0
  static int Ctrl(EvpPkeyCtx *ctx, int type, int p1, void *p2) {
451
0
    MldsaPkeyCtx *mctx = static_cast<MldsaPkeyCtx *>(ctx->data);
452
0
    switch (type) {
453
0
      case EVP_PKEY_CTRL_SIGNATURE_CONTEXT_STRING: {
454
0
        const auto *context_string =
455
0
            reinterpret_cast<const Span<const uint8_t> *>(p2);
456
0
        if (context_string == nullptr ||
457
0
            context_string->size() > kMaxContextLength) {
458
0
          OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
459
0
          return 0;
460
0
        }
461
0
        return mctx->context.CopyFrom(*context_string);
462
0
      }
463
464
0
      default:
465
0
        OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
466
0
        return 0;
467
0
    }
468
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::Ctrl(bssl::EvpPkeyCtx*, int, int, void*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::Ctrl(bssl::EvpPkeyCtx*, int, int, void*)
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::Ctrl(bssl::EvpPkeyCtx*, int, int, void*)
469
470
  static constexpr EVP_PKEY_CTX_METHOD pkey_method = {
471
      Traits::kType,
472
      &Init,
473
      &CopyContext,
474
      &Cleanup,
475
      &KeyGen,
476
      /*sign=*/nullptr,
477
      &SignMessage,
478
      /*verify=*/nullptr,
479
      &VerifyMessage,
480
      /*verify_recover=*/nullptr,
481
      /*encrypt=*/nullptr,
482
      /*decrypt=*/nullptr,
483
      /*derive=*/nullptr,
484
      /*paramgen=*/nullptr,
485
      /*encap=*/nullptr,
486
      /*decap=*/nullptr,
487
      &Ctrl,
488
  };
489
490
0
  static constexpr EVP_PKEY_ASN1_METHOD BuildASN1Method() {
491
0
    EVP_PKEY_ASN1_METHOD ret = {
492
0
        Traits::kType,
493
0
        // The OID is filled in below.
494
0
        /*oid=*/{},
495
0
        /*oid_len=*/0,
496
0
        &pkey_method,
497
0
        &DecodePublic,
498
0
        &EncodePublic,
499
0
        &EqualPublic,
500
0
        &HasPublic,
501
0
        &CopyPublic,
502
0
        &DecodePrivate,
503
0
        &EncodePrivate,
504
0
        &HasPrivate,
505
0
        // While exporting the seed as the "raw" private key would be natural,
506
0
        // OpenSSL connected these APIs to the "raw private key", so we export
507
0
        // the seed separately.
508
0
        /*set_priv_raw=*/nullptr,
509
0
        &SetPrivateSeed,
510
0
        &SetRawPublic,
511
0
        /*get_priv_raw=*/nullptr,
512
0
        &GetPrivateSeed,
513
0
        &GetRawPublic,
514
0
        /*set1_tls_encodedpoint=*/nullptr,
515
0
        /*get1_tls_encodedpoint=*/nullptr,
516
0
        /*pkey_opaque=*/nullptr,
517
0
        &PkeySize,
518
0
        &PkeyBits,
519
0
        /*param_missing=*/nullptr,
520
0
        /*param_copy=*/nullptr,
521
0
        /*param_equal=*/nullptr,
522
0
        &PkeyFree,
523
0
    };
524
0
    // TODO(crbug.com/404286922): Use std::copy in C++20, when it's constexpr.
525
0
    // TODO(crbug.com/450823446): Better yet, make this field an InplaceVector
526
0
    // and give it a suitable constructor.
527
0
    constexpr auto oid = Traits::kOID;
528
0
    static_assert(oid.size() <= sizeof(ret.oid));
529
0
    for (size_t i = 0; i < oid.size(); i++) {
530
0
      ret.oid[i] = oid[i];
531
0
    }
532
0
    ret.oid_len = oid.size();
533
0
    return ret;
534
0
  }
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA44Traits>::BuildASN1Method()
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA65Traits>::BuildASN1Method()
Unexecuted instantiation: p_mldsa.cc:(anonymous namespace)::MLDSAImplementation<(anonymous namespace)::MLDSA87Traits>::BuildASN1Method()
535
536
  static constexpr EVP_PKEY_ASN1_METHOD asn1_method = BuildASN1Method();
537
  static constexpr EVP_PKEY_ALG pkey_alg = {&asn1_method, &pkey_method};
538
};
539
540
}  // namespace
541
542
256k
const EVP_PKEY_ALG *EVP_pkey_ml_dsa_44() {
543
256k
  return &MLDSAImplementation<MLDSA44Traits>::pkey_alg;
544
256k
}
545
546
256k
const EVP_PKEY_ALG *EVP_pkey_ml_dsa_65() {
547
256k
  return &MLDSAImplementation<MLDSA65Traits>::pkey_alg;
548
256k
}
549
550
256k
const EVP_PKEY_ALG *EVP_pkey_ml_dsa_87() {
551
256k
  return &MLDSAImplementation<MLDSA87Traits>::pkey_alg;
552
256k
}