From 404fe0f8a79ca0f28118990a06e921b63035991c Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Mon, 18 Nov 2024 10:16:01 -0800 Subject: [PATCH] Addition of generic NIST-DSA PKEY and ASN1 to support ML-DSA (#1963) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### 1. PKEY structure changes This PR adds the support to include additional signature algorithms (in this case ML-DSA-44 and ML-DSA-87) to AWS-LC. Before this PR AWS-LC only supported ML-DSA-65, as such, we were utilizing the `void *ptr` of `evp_pkey_st`, rather than a distinct structure for ML-DSA. This PR introduces the new structure `PQDSA_KEY * pqdsa_key;` inside `evp_pkey_st` to support ML-DSA and any additional FIPS digital signature algorithms provided by NIST, should AWS-LC wish to include them in the library. ``` union { void *ptr; RSA *rsa; DSA *dsa; DH *dh; EC_KEY *ec; KEM_KEY *kem_key; PQDSA_KEY * pqdsa_key; } pkey; ``` While the structure `DSA` [already exists](https://github.com/jakemas/aws-lc/blob/5d49dfe3c651925da7fd97ec6413f9e3bbd28508/crypto/dsa/internal.h) it does not provide support for FIPS-like signature APIs (see more at [NIST api conventions](https://csrc.nist.gov/CSRC/media/Projects/Post-Quantum-Cryptography/documents/example-files/api-notes.pdf). Rather than create a PKEY struct of the form `MLDSA_KEY` that can only support ML-DSA, this is an opportunity to build support for future signature algorithms that have similar. calling structures, de-randomized testing modes, API converntions, etc. by making a more generic structure type -- much like we did for `KEM_KEY`. Under the design in this PR, adding SLH-DSA to the PKEY struct would be very simple, as it conforms to a `PQDSA_KEY` in design. So too will be true of any additional signature algorithms produced by NISTs call for [additional signature algorithms](https://csrc.nist.gov/projects/pqc-dig-sig). As, such, `PQDSA_KEY` utilizes a new structure to hold public/secret keys, as well as a `PQDSA` struct which defines signature algorithm specific information: ``` struct pqdsa_key_st { const PQDSA *pqdsa; uint8_t *public_key; uint8_t *secret_key; }; ``` ``` typedef struct { int nid; const uint8_t *oid; uint8_t oid_len; const char *comment; size_t public_key_len; size_t secret_key_len; size_t signature_len; size_t keygen_seed_len; size_t sign_seed_len; const PQDSA_METHOD *method; } PQDSA; ``` This allows us to use a single PKEY structure for all NIST FIPS signature algorithms, much like the existing PKEY struct `KEM_KEY *kem_key` for KEMS. As a consequence, we are now able to define signature methods such as: ``` DEFINE_LOCAL_DATA(PQDSA_METHOD, sig_ml_dsa_65_method) { out->keygen = ml_dsa_65_keypair; out->sign = ml_dsa_65_sign; out->verify = ml_dsa_65_verify; } DEFINE_LOCAL_DATA(PQDSA, sig_ml_dsa_65) { out->nid = NID_MLDSA65; out->oid = kOIDMLDSA65; out->oid_len = sizeof(kOIDMLDSA65); out->comment = "MLDSA65 "; out->public_key_len = MLDSA65_PUBLIC_KEY_BYTES; out->secret_key_len = MLDSA65_PRIVATE_KEY_BYTES; out->signature_len = MLDSA65_SIGNATURE_BYTES; out->keygen_seed_len = MLDSA65_KEYGEN_SEED_BYTES; out->sign_seed_len = MLDSA65_SIGNATURE_SEED_BYTES; out->method = sig_ml_dsa_65_method(); } ``` much like the existing [kem.c](https://github.com/jakemas/aws-lc/blob/e4092fb224a2336b8e0d908f311924794d739042/crypto/fipsmodule/kem/kem.c) file. These structures will be incredibly useful for subsequent PRs, in which we will be adding de-randomized APIs to support FIPS validation and KATs from seeds. In effect, we will be extending the method to include: ``` DEFINE_LOCAL_DATA(PQDSA_METHOD, sig_ml_dsa_65_method) { out->keygen = ml_dsa_65_keypair; out->keygen_internal = ml_dsa_65_keypair_internal; out->sign = ml_dsa_65_sign; out->sign_internal = ml_dsa_65_sign_internal; out->verify = ml_dsa_65_verify; } ``` The directory `dilithium/p_dilithium3.c` is used to house generic `PKEY` operations, as well as PQDSA specific EVP functions such as `EVP_PKEY_pqdsa_set_params`, `EVP_PKEY_pqdsa_set_params`, which work in a similar way to [p_kem.c](https://github.com/jakemas/aws-lc/blob/3f03f7d7b2eccca69f278feaeb073ab9a5540c61/crypto/fipsmodule/evp/p_kem.c) functions `EVP_PKEY_CTX_kem_set_params` and `EVP_PKEY_kem_set_params`. The directory `dilithium/p_dilithium3_asn1.c` is used to house generic `asn.1` operations for NIST FIPS DSA algorithms. Rather than rename/relocate these files in this PR (which will convolute the CR), I will move these files in a subsequent PR. #### 2. Internal Design ![pqdsa1](https://github.com/user-attachments/assets/1c771c69-f96a-49fb-98d1-e8d51d5eff36) We introduce new structures: `PQDSA_METHOD`, `PQDSA`, `PQDSA_KEY` which are very similar to how both EC Crypto, and the KEM API is implemented. The figure above shows the newly proposed structures and their integration into the existing EVP structures. - `PQDSA_METHOD` is a table of function pointers with 5 functions defined for a `PQDSA`: key generation, key generation internal (for testing/FIPS), sign, sign internal (for testing/FIPS), and verify. Every `PQDSA` implementation has to implement this API, for example `sig_ml_dsa_44_method` implements the three functions for ML-DSA-44 (analogous to `EC_METHOD` and for example, `EC_GFp_nistz256_method`). - `PQDSA` is a structure that holds basic information about the DSA: the id, size of parameters, and the pointer to the implementation of the corresponding `PQDSA_METHOD`. - `PQDSA_KEY` structure is a helper structure that holds pointers to public and secret key and the pointer to the corresponding `PQDSA`. - `PQDSA_PKEY_CTX` is a helper structure used to store DSA parameters in an `EVP_PKEY_CTX` object (the same as `EC_PKEY_CTX`). Since `PQDSA` has everything we need, that’s what we store in `PQDSA_PKEY_CTX`. #### 3. OID changes We now have real OIDs available from https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration. These have been added to the `obj` files and automatically populated by `go run objects.go`. We include the following NIDs for ML-DSA: ``` //2.16.840.1.101.3.4.3.17 static const uint8_t kOIDMLDSA44[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11}; //2.16.840.1.101.3.4.3.18 static const uint8_t kOIDMLDSA65[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12}; //2.16.840.1.101.3.4.3.19 static const uint8_t kOIDMLDSA87[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13}; ``` and a "top-level" NID `EVP_PKEY_NISTDSA` (similar to [EVP_PKEY_KEM](https://github.com/jakemas/aws-lc/blob/c82a6f9b1bdc7ec0abf7571c92c64db91959428d/include/openssl/evp.h#L210) to subset all NIST FIPS DSA algorithms. Much like for the KEM API, we include functions `SIG_find_dsa_by_nid(int nid)` to return actual algorithm specific methods. #### 4. Testing structure changes Prior to this PR all testing for ML-DSA-65 was done as a series of g-tests. As we now have the ability to get algorithm/security level specific parameters from the `NISTDSA` struct, I have overhauled the testing suite to be parameterized over the currently supported signature algorithms: ``` static const struct ML_DSA parameterSet[] = { {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt", mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1973}, }; ``` For each of the above parameter sets we run: ``` TEST_P(MLDSAParameterTest, KAT) TEST_P(MLDSAParameterTest, KeyGen) TEST_P(MLDSAParameterTest, KeyCmp) TEST_P(MLDSAParameterTest, KeySize) TEST_P(MLDSAParameterTest, NewKeyFromBytes) TEST_P(MLDSAParameterTest, RawFunctions) TEST_P(MLDSAParameterTest, SIGOperations) TEST_P(MLDSAParameterTest, MarshalParse) ``` #### 5. X.509 changes Changes to X.509 code have been minimized to only the required changes to support this PR. This is already a big PR and I want to avoid expansion wherever possible. For X.509 the changes predominantly are regarding the change of NIDs from the old Dilithium NIDs to the new NIST DSA NIDs/OIDs. As the OIDs changed, so too much the test certificates `kDilithium3Cert`, `kDilithium3CertNull`, and `kDilithium3CertParam`. These have been regenerated using the following: ``` Tool used https://github.com/google/der-ascii 1. First generate a valid test certificate in PEM encoding, say cert.pem 2. Convert PEM to DER: openssl x509 -in cert.pem -out cert.der -outform DER 3. Convert DER to ASCII: der2ascii -i cert.der >> cert.txt 4. Make edits to cert.txt as desired, say; certnew.txt 5. Convert ASCII to DER: ascii2der -i certnew.txt >> certnew.der 6. Convert DER to PEM: openssl x509 -in certnew.der -inform DER -out certnew.pem -outform PEM ``` For step (1) "generate a valid test certificate" you can use the X.509 test `Dilithium3SignVerifyCert` with added code to print the certificate (or store to file): ``` TEST(X509Test, Dilithium3SignVerifyCert) { // Generate mldsa key bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx); ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(), NID_MLDSA65)); ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); EVP_PKEY *raw = nullptr; ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); bssl::UniquePtr pkey(raw); ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr)); bssl::UniquePtr leaf = MakeTestCert("Intermediate", "Leaf", pkey.get(), false); ASSERT_TRUE(leaf); bssl::ScopedEVP_MD_CTX md_ctx; EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey.get()); ASSERT_TRUE(X509_sign_ctx(leaf.get(), md_ctx.get())); // print certificate and PEM encoding: bssl::UniquePtr bio(BIO_new(BIO_s_mem())); X509_print(bio.get(), leaf.get()); PEM_write_bio_X509(bio.get(),leaf.get()); const uint8_t *out; size_t outlen; ASSERT_TRUE(BIO_mem_contents(bio.get(), &out, &outlen)); printf("%s",out); } ``` #### 6. Speed Tool `ML-DSA-65` has been added to the speed tool. To facilitate the new APIs used in this PR, the API version has been incremented by 1. The speed tool now produces benchmarks for all three parameter levels, example output: ``` Did 2871 MLDSA65 keygen operations in 1051869us (2729.4 ops/sec) Did 774 MLDSA65 signing operations in 1039468us (744.6 ops/sec) Did 2893 MLDSA65 verify operations in 1089059us (2656.4 ops/sec) ``` ### Call-outs: - `algorithm.c` : modified OIDs from DILITHIUM to PQDSA - `base.h` : added PQDSA_KEY struct - `evp.h` : added EVP_PKEY_pqdsa_set_params and EVP_PKEY_CTX_pqdsa_set_params functions to setting the specific OID (NID_MLDSAXX) for a PKEY of type EVP_PKEY_NISTDSA - `evp_extra_test.cc` : updated example MLDSA65 private key with new OID and encoding - `dilithium/internal.h` : new file to hold ML-DSA structure - `evp_extra/internal.h` : modified ML-DSA-65 specific ASN.1 and PKEY method to a generic one for all NIST PQC signature algorithms - `fipsmodule/evp/internal.h` : added PQDSA_KEY to PKEY structures to hold PKEY types for NIST PQC signature algorithms - `nid.h`, `obj_dat.h`, `obj_mac.num`, `obj_xref.c`, `objects.txt`: all modified to include designated OIDs for ML-DSA. - `p_dilithium3.c`: temporarily holds PQDSA new/clear/init functions. All existing PKEY functions (keygen/sign/verify) have been modified to use generic PQDSA and extract algorithm specific parameters/function methods. - `p_dilithium3_asn1.c`: All existing ASN1 functions (get/set/encode/decode/size/bits/free) have been modified to use generic PQDSA and extract algorithm specific parameters/function methods. - `p_dilithium_test.cc` : has been modified to parameterize all tests into a single test suite that use algorithm specific parameterization - `evp_extra/p_methods`: dilithium specific methods renamed - `print.c`, `speed.cc`, `x509_test.cc` : updated to retain functionality ### Testing: See above for description of changes to testing framework. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- crypto/CMakeLists.txt | 9 +- crypto/dilithium/internal.h | 71 ++ .../dilithium/{sig_dilithium3.c => ml_dsa.c} | 43 +- crypto/dilithium/ml_dsa.h | 36 + crypto/dilithium/p_dilithium3.c | 125 --- crypto/dilithium/p_dilithium3_asn1.c | 248 ------ crypto/dilithium/p_dilithium_test.cc | 780 ------------------ crypto/dilithium/p_pqdsa.c | 287 +++++++ crypto/dilithium/p_pqdsa_asn1.c | 223 +++++ crypto/dilithium/p_pqdsa_test.cc | 746 +++++++++++++++++ crypto/dilithium/pqdsa.c | 119 +++ crypto/dilithium/sig_dilithium.h | 47 -- crypto/evp_extra/evp_asn1.c | 29 +- crypto/evp_extra/evp_extra_test.cc | 634 +++++++------- crypto/evp_extra/internal.h | 17 +- crypto/evp_extra/p_methods.c | 4 +- crypto/evp_extra/print.c | 31 +- crypto/fipsmodule/evp/internal.h | 1 + crypto/obj/obj_dat.h | 59 +- crypto/obj/obj_mac.num | 4 + crypto/obj/obj_xref.c | 2 +- crypto/obj/objects.txt | 14 +- crypto/x509/algorithm.c | 15 +- crypto/x509/x509_test.cc | 753 ++++++++--------- include/openssl/base.h | 3 +- include/openssl/evp.h | 22 +- include/openssl/nid.h | 16 + tool/speed.cc | 13 +- 28 files changed, 2389 insertions(+), 1962 deletions(-) create mode 100644 crypto/dilithium/internal.h rename crypto/dilithium/{sig_dilithium3.c => ml_dsa.c} (54%) create mode 100644 crypto/dilithium/ml_dsa.h delete mode 100644 crypto/dilithium/p_dilithium3.c delete mode 100644 crypto/dilithium/p_dilithium3_asn1.c delete mode 100644 crypto/dilithium/p_dilithium_test.cc create mode 100644 crypto/dilithium/p_pqdsa.c create mode 100644 crypto/dilithium/p_pqdsa_asn1.c create mode 100644 crypto/dilithium/p_pqdsa_test.cc create mode 100644 crypto/dilithium/pqdsa.c delete mode 100644 crypto/dilithium/sig_dilithium.h diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index db3a743f02..4874b448ea 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -323,9 +323,10 @@ if(ENABLE_DILITHIUM) set( DILITHIUM_SOURCES - dilithium/p_dilithium3.c - dilithium/p_dilithium3_asn1.c - dilithium/sig_dilithium3.c + dilithium/pqdsa.c + dilithium/p_pqdsa.c + dilithium/p_pqdsa_asn1.c + dilithium/ml_dsa.c ) endif() @@ -775,7 +776,7 @@ if(BUILD_TESTING) ecdh_extra/ecdh_test.cc dh_extra/dh_test.cc digest_extra/digest_test.cc - dilithium/p_dilithium_test.cc + dilithium/p_pqdsa_test.cc dsa/dsa_test.cc des/des_test.cc endian_test.cc diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h new file mode 100644 index 0000000000..be19b0d561 --- /dev/null +++ b/crypto/dilithium/internal.h @@ -0,0 +1,71 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef AWSLC_HEADER_PQDSA_INTERNAL_H +#define AWSLC_HEADER_PQDSA_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +// PQDSA_METHOD structure and helper functions. +typedef struct { + int (*keygen)(uint8_t *public_key, + uint8_t *private_key); + + int (*sign)(const uint8_t *private_key, + uint8_t *sig, + size_t *sig_len, + const uint8_t *message, + size_t message_len, + const uint8_t *ctx_string, + size_t ctx_string_len); + + int (*verify)(const uint8_t *public_key, + const uint8_t *sig, + size_t sig_len, + const uint8_t *message, + size_t message_len, + const uint8_t *ctx_string, + size_t ctx_string_len); + +} PQDSA_METHOD; + +// PQDSA structure and helper functions. +typedef struct { + int nid; + const uint8_t *oid; + uint8_t oid_len; + const char *comment; + size_t public_key_len; + size_t private_key_len; + size_t signature_len; + size_t keygen_seed_len; + size_t sign_seed_len; + const PQDSA_METHOD *method; +} PQDSA; + +// PQDSA_KEY structure and helper functions. +struct pqdsa_key_st { + const PQDSA *pqdsa; + uint8_t *public_key; + uint8_t *private_key; +}; + +int PQDSA_KEY_init(PQDSA_KEY *key, const PQDSA *pqdsa); +const PQDSA * PQDSA_find_dsa_by_nid(int nid); +const EVP_PKEY_ASN1_METHOD *PQDSA_find_asn1_by_nid(int nid); +const PQDSA *PQDSA_KEY_get0_dsa(PQDSA_KEY* key); +PQDSA_KEY *PQDSA_KEY_new(void); +void PQDSA_KEY_free(PQDSA_KEY *key); +int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid); + +int PQDSA_KEY_set_raw_public_key(PQDSA_KEY *key, const uint8_t *in); +int PQDSA_KEY_set_raw_private_key(PQDSA_KEY *key, const uint8_t *in); +#if defined(__cplusplus) +} // extern C +#endif + +#endif // AWSLC_HEADER_DSA_TEST_INTERNAL_H diff --git a/crypto/dilithium/sig_dilithium3.c b/crypto/dilithium/ml_dsa.c similarity index 54% rename from crypto/dilithium/sig_dilithium3.c rename to crypto/dilithium/ml_dsa.c index 2be7dd4dc5..267ef0381f 100644 --- a/crypto/dilithium/sig_dilithium3.c +++ b/crypto/dilithium/ml_dsa.c @@ -1,8 +1,9 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR ISC + #include "../evp_extra/internal.h" #include "../fipsmodule/evp/internal.h" -#include "sig_dilithium.h" +#include "ml_dsa.h" #include "pqcrystals_dilithium_ref_common/sign.h" #include "pqcrystals_dilithium_ref_common/params.h" @@ -20,39 +21,39 @@ #include "./pqcrystals_dilithium_ref_common/symmetric-shake.c" // Note: These methods currently default to using the reference code for -// Dilithium. In a future where AWS-LC has optimized options available, +// ML-DSA. In a future where AWS-LC has optimized options available, // those can be conditionally (or based on compile-time flags) called here, // depending on platform support. -int ml_dsa_65_keypair(uint8_t *public_key /* OUT */, - uint8_t *secret_key /* OUT */) { +int ml_dsa_65_keypair(uint8_t *public_key /* OUT */, + uint8_t *private_key /* OUT */) { ml_dsa_params params; ml_dsa_65_params_init(¶ms); - return crypto_sign_keypair(¶ms, public_key, secret_key); + return (crypto_sign_keypair(¶ms, public_key, private_key) == 0); } -int ml_dsa_65_sign(uint8_t *sig /* OUT */, - size_t *sig_len /* OUT */, - const uint8_t *message /* IN */, - size_t message_len /* IN */, - const uint8_t *ctx /* IN */, - size_t ctx_len /* IN */, - const uint8_t *secret_key /* IN */) { +int ml_dsa_65_sign(const uint8_t *private_key /* IN */, + uint8_t *sig /* OUT */, + size_t *sig_len /* OUT */, + const uint8_t *message /* IN */, + size_t message_len /* IN */, + const uint8_t *ctx_string /* IN */, + size_t ctx_string_len /* IN */) { ml_dsa_params params; ml_dsa_65_params_init(¶ms); return crypto_sign_signature(¶ms, sig, sig_len, message, message_len, - ctx, ctx_len, secret_key); + ctx_string, ctx_string_len, private_key) == 0; } -int ml_dsa_65_verify(const uint8_t *message /* IN */, - size_t message_len /* IN */, - const uint8_t *sig /* IN */, - size_t sig_len /* IN */, - const uint8_t *ctx /* IN */, - size_t ctx_len /* IN */, - const uint8_t *public_key /* IN */) { +int ml_dsa_65_verify(const uint8_t *public_key /* IN */, + const uint8_t *sig /* IN */, + size_t sig_len /* IN */, + const uint8_t *message /* IN */, + size_t message_len /* IN */, + const uint8_t *ctx_string /* IN */, + size_t ctx_string_len /* IN */) { ml_dsa_params params; ml_dsa_65_params_init(¶ms); return crypto_sign_verify(¶ms, sig, sig_len, message, message_len, - ctx, ctx_len, public_key); + ctx_string, ctx_string_len, public_key) == 0; } diff --git a/crypto/dilithium/ml_dsa.h b/crypto/dilithium/ml_dsa.h new file mode 100644 index 0000000000..9716d260a6 --- /dev/null +++ b/crypto/dilithium/ml_dsa.h @@ -0,0 +1,36 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef ML_DSA_H +#define ML_DSA_H + +#include +#include +#include +#include + +#define MLDSA65_PUBLIC_KEY_BYTES 1952 +#define MLDSA65_PRIVATE_KEY_BYTES 4032 +#define MLDSA65_SIGNATURE_BYTES 3309 +#define MLDSA65_KEYGEN_SEED_BYTES 32 +#define MLDSA65_SIGNATURE_SEED_BYTES 32 + +int ml_dsa_65_keypair(uint8_t *public_key, + uint8_t *private_key); + +int ml_dsa_65_sign(const uint8_t *private_key, + uint8_t *sig, + size_t *sig_len, + const uint8_t *message, + size_t message_len, + const uint8_t *ctx_string, + size_t ctx_string_len); + +int ml_dsa_65_verify(const uint8_t *public_key, + const uint8_t *sig, + size_t sig_len, + const uint8_t *message, + size_t message_len, + const uint8_t *ctx_string, + size_t ctx_string_len); +#endif diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c deleted file mode 100644 index 23b565cbf3..0000000000 --- a/crypto/dilithium/p_dilithium3.c +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 OR ISC - -#include -#include -#include - -#include "../crypto/internal.h" -#include "../fipsmodule/evp/internal.h" -#include "../evp_extra/internal.h" -#include "sig_dilithium.h" - -static int pkey_dilithium3_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { - DILITHIUM3_KEY *key = OPENSSL_malloc(sizeof(DILITHIUM3_KEY)); - if (key == NULL) { - goto err; - } - key->pub = OPENSSL_malloc(DILITHIUM3_PUBLIC_KEY_BYTES); - if (key->pub == NULL) { - goto err; - } - key->priv = OPENSSL_malloc(DILITHIUM3_PRIVATE_KEY_BYTES); - if (key->priv == NULL) { - goto err; - } - - if (pkey == NULL || ctx == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); - goto err; - } - - evp_pkey_set_method(pkey, &dilithium3_asn1_meth); - - if (ml_dsa_65_keypair(key->pub, key->priv) != 0) { - goto err; - } - - OPENSSL_free(pkey->pkey.ptr); - pkey->pkey.ptr = key; - return 1; - -err: - if (key != NULL) { - OPENSSL_free(key->pub); - OPENSSL_free(key->priv); - } - OPENSSL_free(key); - return 0; - -} - -static int pkey_dilithium3_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, - size_t *siglen, const uint8_t *tbs, - size_t tbslen) { - if (ctx == NULL || ctx->pkey->pkey.ptr == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); - return 0; - } - - DILITHIUM3_KEY *key = ctx->pkey->pkey.ptr; - - if (!key->priv) { - OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); - return 0; - } - // Caller is getting parameter values. - if (sig == NULL) { - *siglen = DILITHIUM3_SIGNATURE_BYTES; - return 1; - } - - if (*siglen < DILITHIUM3_SIGNATURE_BYTES) { - OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); - return 0; - } - - if (ml_dsa_65_sign(sig, siglen, tbs, tbslen, NULL, 0, key->priv) != 0) { - OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); - return 0; - } - return 1; -} - -static int pkey_dilithium3_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, - size_t siglen, const uint8_t *tbs, - size_t tbslen) { - if (ctx == NULL || ctx->pkey->pkey.ptr == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); - return 0; - } - - DILITHIUM3_KEY *key = ctx->pkey->pkey.ptr; - - if (siglen != DILITHIUM3_SIGNATURE_BYTES || - ml_dsa_65_verify(tbs, tbslen, sig, siglen, NULL, 0, key->pub) != 0) { - OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); - return 0; - } - return 1; -} - -const EVP_PKEY_METHOD dilithium3_pkey_meth = { - EVP_PKEY_DILITHIUM3, - NULL /* init */, - NULL /* copy */, - NULL /* cleanup */, - pkey_dilithium3_keygen, - NULL /* sign_init */, - NULL /* sign */, - pkey_dilithium3_sign_message, - NULL /* verify_init */, - NULL /* verify */, - pkey_dilithium3_verify_message, - NULL /* verify_recover */, - NULL /* encrypt */, - NULL /* decrypt */, - NULL /* derive */, - NULL /* paramgen */, - NULL /* ctrl */, - NULL /* ctrl_str */, - NULL /* keygen deterministic */, - NULL /* encapsulate deterministic */, - NULL /* encapsulate */, - NULL /* decapsulate */, -}; diff --git a/crypto/dilithium/p_dilithium3_asn1.c b/crypto/dilithium/p_dilithium3_asn1.c deleted file mode 100644 index ecd3faf818..0000000000 --- a/crypto/dilithium/p_dilithium3_asn1.c +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 OR ISC - -#include - -#include -#include -#include - -#include "../evp_extra/internal.h" -#include "../fipsmodule/evp/internal.h" -#include "../internal.h" -#include "sig_dilithium.h" - - -static void dilithium3_free(EVP_PKEY *pkey) { - DILITHIUM3_KEY *key = pkey->pkey.ptr; - if (key == NULL) { - return; - } - OPENSSL_free(key->pub); - key->pub = NULL; - OPENSSL_free(key->priv); - key->priv = NULL; - OPENSSL_free(pkey->pkey.ptr); - pkey->pkey.ptr = NULL; -} - -static int dilithium3_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, - size_t privkey_len, const uint8_t *pubkey, size_t pubkey_len) { - if (privkey_len != DILITHIUM3_PRIVATE_KEY_BYTES) { - OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); - return 0; - } - - // At time of writing, all |set_priv_raw| and |dilithium3_set_priv_raw| - // invocations specify NULL public key. If that changes, we should modify - // the conditional below to set the public key on |key|. - if (pubkey != NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return 0; - } - - DILITHIUM3_KEY *key = OPENSSL_malloc(sizeof(DILITHIUM3_KEY)); - if (key == NULL) { - return 0; - } - key->priv = OPENSSL_malloc(DILITHIUM3_PRIVATE_KEY_BYTES); - if (key->priv == NULL) { - OPENSSL_free(key); - return 0; - } - - key->pub = NULL; - OPENSSL_memcpy(key->priv, privkey, privkey_len); - - dilithium3_free(pkey); - pkey->pkey.ptr = key; - return 1; -} - -static int dilithium3_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { - if (len != DILITHIUM3_PUBLIC_KEY_BYTES) { - OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_KEYBITS); - return 0; - } - - DILITHIUM3_KEY *key = OPENSSL_malloc(sizeof(DILITHIUM3_KEY)); - if (key == NULL) { - return 0; - } - key->pub = OPENSSL_malloc(DILITHIUM3_PUBLIC_KEY_BYTES); - if (key->pub == NULL) { - OPENSSL_free(key); - return 0; - } - - OPENSSL_memcpy(key->pub, in, len); - key->priv = NULL; - - dilithium3_free(pkey); - pkey->pkey.ptr = key; - return 1; -} - -static int dilithium3_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, - size_t *out_len) { - const DILITHIUM3_KEY *key = pkey->pkey.ptr; - if (key->priv == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); - return 0; - } - - if (out == NULL) { - *out_len = DILITHIUM3_PRIVATE_KEY_BYTES; - return 1; - } - - if (*out_len < DILITHIUM3_PRIVATE_KEY_BYTES) { - OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); - return 0; - } - - OPENSSL_memcpy(out, key->priv, DILITHIUM3_PRIVATE_KEY_BYTES); - *out_len = DILITHIUM3_PRIVATE_KEY_BYTES; - return 1; -} - -static int dilithium3_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, - size_t *out_len) { - const DILITHIUM3_KEY *key = pkey->pkey.ptr; - if (key->pub == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return 0; - } - - if (out == NULL) { - *out_len = DILITHIUM3_PUBLIC_KEY_BYTES; - return 1; - } - - if (*out_len < DILITHIUM3_PUBLIC_KEY_BYTES) { - OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); - return 0; - } - - OPENSSL_memcpy(out, key->pub, DILITHIUM3_PUBLIC_KEY_BYTES); - *out_len = DILITHIUM3_PUBLIC_KEY_BYTES; - return 1; -} - -static int dilithium3_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { - // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 4. - // The parameters must be omitted. - if (CBS_len(params) != 0) { - OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); - return 0; - } - - return dilithium3_set_pub_raw(out, CBS_data(key), CBS_len(key)); -} - -static int dilithium3_pub_encode(CBB *out, const EVP_PKEY *pkey) { - const DILITHIUM3_KEY *key = pkey->pkey.ptr; - if (key->pub == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return 0; - } - - // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 4. - // TODO: finalize this definition - OCTETSTRING to BITSTRING conversion. - CBB spki, algorithm, oid, key_bitstring; - if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || - !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || - !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || - !CBB_add_bytes(&oid, dilithium3_asn1_meth.oid, dilithium3_asn1_meth.oid_len) || - !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || - !CBB_add_u8(&key_bitstring, 0 /* padding */) || - !CBB_add_bytes(&key_bitstring, key->pub, DILITHIUM3_PUBLIC_KEY_BYTES) || - !CBB_flush(out)) { - OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); - return 0; - } - - return 1; -} - -static int dilithium3_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { - const DILITHIUM3_KEY *a_key = a->pkey.ptr; - const DILITHIUM3_KEY *b_key = b->pkey.ptr; - return OPENSSL_memcmp(a_key->pub, b_key->pub, DILITHIUM3_PUBLIC_KEY_BYTES) == 0; -} - -static int dilithium3_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey) { - // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 6. - - // The parameters must be omitted. - if (CBS_len(params) != 0 ) { - OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); - return 0; - } - - return dilithium3_set_priv_raw(out, CBS_data(key), CBS_len(key), NULL, 0); -} - -static int dilithium3_priv_encode(CBB *out, const EVP_PKEY *pkey) { - DILITHIUM3_KEY *key = pkey->pkey.ptr; - if (key->priv == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); - return 0; - } - // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 6. - CBB pkcs8, algorithm, oid, private_key; - if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || - !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || - !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || - !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || - !CBB_add_bytes(&oid, dilithium3_asn1_meth.oid, dilithium3_asn1_meth.oid_len) || - !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || - !CBB_add_bytes(&private_key, key->priv, DILITHIUM3_PRIVATE_KEY_BYTES) || - !CBB_flush(out)) { - OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); - return 0; - } - - return 1; -} - -static int dilithium3_size(const EVP_PKEY *pkey) { - return DILITHIUM3_SIGNATURE_BYTES; -} - -static int dilithium3_bits(const EVP_PKEY *pkey) { - return 8 * (DILITHIUM3_PUBLIC_KEY_BYTES); -} - -const EVP_PKEY_ASN1_METHOD dilithium3_asn1_meth = { - EVP_PKEY_DILITHIUM3, - // 1.3.6.1.4.1.2.267.7.6.5 = Dilithium SIG Round-3. These are temp values from - // https://github.com/IETF-Hackathon/pqc-certificates/blob/master/docs/oid_mapping.md - // as we await NIST to release OIDs. - {0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x06, 0x05}, - 11, - - "DILITHIUM3", - "AWS-LC DILITHIUM3 method", - - dilithium3_pub_decode, - dilithium3_pub_encode, - dilithium3_pub_cmp, - dilithium3_priv_decode, - dilithium3_priv_encode, - NULL /*priv_encode_v2*/, - dilithium3_set_priv_raw, - dilithium3_set_pub_raw, - dilithium3_get_priv_raw, - dilithium3_get_pub_raw, - NULL /* pkey_opaque */, - dilithium3_size, - dilithium3_bits, - NULL /* param_missing */, - NULL /* param_copy */, - NULL /* param_cmp */, - dilithium3_free, -}; - - - diff --git a/crypto/dilithium/p_dilithium_test.cc b/crypto/dilithium/p_dilithium_test.cc deleted file mode 100644 index b1aef073ad..0000000000 --- a/crypto/dilithium/p_dilithium_test.cc +++ /dev/null @@ -1,780 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 OR ISC - -#include -#include -#include -#include -#include -#include -#include "../test/test_util.h" - -#include -#include "../crypto/evp_extra/internal.h" -#include "../fipsmodule/evp/internal.h" -#include "../internal.h" - -#ifdef ENABLE_DILITHIUM - -#include "../test/file_test.h" -#include "../test/test_util.h" -#include "../rand_extra/pq_custom_randombytes.h" -#include "sig_dilithium.h" - -static const uint8_t kPublicKey[] = { 0xBB, 0x0A, 0x41, 0x1A, 0x53, 0x91, 0x4E, - 0x67, 0x77, 0x78, 0xD0, 0xBC, 0xF0, 0xFD, 0x8A, 0x39, 0x65, 0x96, 0x48, - 0x54, 0xF5, 0x91, 0xCE, 0xDB, 0x3B, 0x92, 0xBF, 0x2A, 0xC4, 0x01, 0xCD, - 0xBE, 0x9E, 0x60, 0x05, 0x45, 0x68, 0x3E, 0xC0, 0xC6, 0xDC, 0xBB, 0x76, - 0x42, 0x2D, 0x91, 0x47, 0xC2, 0x7C, 0x96, 0xAA, 0x5B, 0x28, 0x0D, 0x3B, - 0x24, 0x50, 0x12, 0x4E, 0x05, 0x0F, 0xBD, 0x09, 0xB5, 0x51, 0xF5, 0xD6, - 0x12, 0x93, 0xF8, 0x62, 0x69, 0x92, 0x25, 0x3B, 0x2E, 0x1B, 0xC8, 0x47, - 0xFA, 0x06, 0x2C, 0x21, 0x8A, 0x62, 0xA2, 0x0A, 0x3F, 0x1B, 0xD3, 0x6D, - 0x2D, 0x82, 0x4D, 0x7D, 0xDE, 0x80, 0xBB, 0x08, 0x79, 0x53, 0xD8, 0xDB, - 0xCD, 0x73, 0xF8, 0x8F, 0x85, 0xA8, 0xB4, 0xB5, 0x63, 0xF5, 0x6A, 0x9C, - 0xD5, 0x58, 0xAC, 0xD7, 0x9C, 0x96, 0x3C, 0xEA, 0x5A, 0x66, 0x69, 0xD6, - 0x5E, 0xC3, 0xD5, 0x81, 0xFE, 0x6B, 0x42, 0xA0, 0xB6, 0x58, 0x54, 0xFA, - 0x2F, 0xBE, 0x92, 0x9A, 0x41, 0xF8, 0x32, 0x10, 0x10, 0x86, 0x77, 0x01, - 0xD6, 0xEF, 0x81, 0x14, 0x1B, 0xA3, 0x8B, 0xF4, 0x33, 0x94, 0x4E, 0x85, - 0xDC, 0x94, 0x7C, 0x01, 0x9E, 0x6D, 0x9E, 0x7A, 0x26, 0x0F, 0xCF, 0xA0, - 0x7D, 0x92, 0xB0, 0x84, 0x95, 0x76, 0xDF, 0x40, 0x85, 0x87, 0xEF, 0xF5, - 0x33, 0x52, 0x2E, 0xF6, 0x73, 0x9E, 0xDA, 0x27, 0x6C, 0xEE, 0x08, 0xFE, - 0x7A, 0x67, 0x43, 0x88, 0xC6, 0xF0, 0xF1, 0x0C, 0x08, 0xA5, 0x67, 0xC4, - 0xB0, 0x01, 0xFB, 0x5B, 0x59, 0xFC, 0xAE, 0xCF, 0x07, 0x14, 0x52, 0x45, - 0xD0, 0xEB, 0x97, 0xAB, 0x0E, 0x52, 0x65, 0x12, 0x41, 0xA2, 0x03, 0xB1, - 0xE5, 0x1E, 0xA6, 0x33, 0xCE, 0x9A, 0x5C, 0x8F, 0xDF, 0x1A, 0x42, 0x6C, - 0xB6, 0xCB, 0x78, 0xDD, 0x02, 0x78, 0xD9, 0xD8, 0xAE, 0x31, 0x5F, 0x13, - 0xEB, 0x71, 0xD3, 0xAD, 0x6B, 0xD0, 0x98, 0x18, 0x7A, 0x5B, 0x0D, 0xA9, - 0x5D, 0x35, 0xB4, 0x26, 0x5E, 0xCA, 0xF6, 0x7D, 0xC3, 0x9F, 0xE1, 0xBD, - 0xFB, 0x73, 0xA6, 0xF1, 0xE0, 0x26, 0x0F, 0xCA, 0x1B, 0xC3, 0xA9, 0xD0, - 0x27, 0x46, 0x82, 0x49, 0x73, 0xED, 0x3A, 0x6B, 0x61, 0x05, 0xD8, 0xA7, - 0x7F, 0x2B, 0x36, 0x1C, 0x69, 0x31, 0x73, 0x29, 0xDE, 0x6D, 0x28, 0xB6, - 0xEA, 0xFE, 0x37, 0xC2, 0xC0, 0x94, 0x4B, 0x3E, 0xD4, 0x21, 0x3F, 0xE0, - 0x02, 0xFA, 0x5F, 0x16, 0xCE, 0x16, 0x66, 0xB5, 0xC9, 0xF6, 0x3F, 0x2A, - 0x5C, 0x83, 0x00, 0x5F, 0xDA, 0x0B, 0x6E, 0xE7, 0xB6, 0x55, 0x55, 0xBF, - 0x50, 0x29, 0x8E, 0x39, 0xA2, 0xB7, 0x85, 0x79, 0xC3, 0xCE, 0x93, 0x63, - 0x57, 0xD1, 0xF2, 0x03, 0x6E, 0x42, 0x78, 0xB3, 0x5F, 0x72, 0x5C, 0x7D, - 0xB0, 0xE0, 0x55, 0x96, 0xE1, 0x34, 0x0B, 0x5C, 0x75, 0xA9, 0xEF, 0x17, - 0x47, 0x5B, 0xDC, 0x4F, 0x01, 0x5D, 0x80, 0x60, 0x14, 0xA7, 0x9A, 0xD3, - 0x38, 0x07, 0xDA, 0x61, 0x0D, 0x7F, 0x37, 0xEC, 0x0A, 0xD3, 0x54, 0x91, - 0x53, 0x16, 0x3D, 0xAD, 0xC8, 0x2C, 0xAC, 0xBB, 0x1B, 0x03, 0xD7, 0x96, - 0x8D, 0x6D, 0x2D, 0x81, 0xBB, 0x57, 0xDB, 0x10, 0x3E, 0xFD, 0xCF, 0xA9, - 0xA3, 0xA4, 0xAF, 0xF7, 0xA1, 0x9F, 0x4B, 0xB0, 0x3E, 0x3D, 0x51, 0x15, - 0xEA, 0x63, 0x8C, 0x75, 0x59, 0x78, 0xBB, 0xEC, 0x94, 0x47, 0xA8, 0x81, - 0x7B, 0x98, 0xF1, 0x6E, 0x0A, 0xAD, 0xE6, 0x42, 0x58, 0x37, 0x76, 0x8E, - 0x06, 0xA5, 0x43, 0xBF, 0xE9, 0xFA, 0x53, 0x2E, 0xAC, 0x2E, 0xBC, 0x6A, - 0x99, 0x08, 0x51, 0x98, 0xAC, 0x3A, 0x23, 0x52, 0x19, 0x07, 0x81, 0x14, - 0x4C, 0x62, 0x3F, 0x38, 0x2C, 0xB6, 0x70, 0x33, 0xD8, 0xB3, 0x97, 0x5B, - 0x9C, 0x54, 0x62, 0x63, 0x03, 0xA8, 0xAD, 0xC1, 0xB3, 0xC6, 0x3A, 0x74, - 0x5D, 0x6E, 0x9C, 0x3F, 0xCE, 0xE8, 0x79, 0xF4, 0x02, 0x90, 0x3A, 0x2B, - 0x51, 0x50, 0x9F, 0x88, 0xF5, 0x98, 0xA7, 0xC4, 0xD2, 0xE9, 0x4F, 0xCA, - 0x52, 0xE9, 0xE1, 0xB2, 0xB3, 0x78, 0xB0, 0xA2, 0x33, 0x9F, 0xA8, 0xC3, - 0xD9, 0xB6, 0xDD, 0x6A, 0x05, 0x5B, 0xC7, 0x52, 0xC3, 0x68, 0xC2, 0x30, - 0x7F, 0x74, 0x1E, 0x07, 0x66, 0xC3, 0xA4, 0x2D, 0x84, 0xAA, 0x17, 0xD6, - 0x49, 0x89, 0x60, 0x31, 0x0E, 0x4E, 0xAE, 0xCF, 0x56, 0x93, 0x40, 0x3C, - 0x9B, 0xC9, 0x13, 0x5C, 0x5D, 0x38, 0x94, 0xAE, 0x6F, 0xE9, 0x04, 0xB7, - 0xA6, 0x1E, 0xAB, 0xB9, 0xD4, 0x04, 0xFF, 0x3C, 0x99, 0x2F, 0xE4, 0x80, - 0x69, 0xDB, 0x50, 0x5B, 0xAC, 0x34, 0x48, 0x77, 0xF6, 0xB2, 0x00, 0x02, - 0x8D, 0x75, 0xA0, 0x2E, 0x93, 0x0A, 0x20, 0x22, 0x2F, 0x73, 0x15, 0xEA, - 0xEA, 0xBD, 0x8B, 0xE6, 0x85, 0xFD, 0x30, 0x97, 0xF7, 0x24, 0xB9, 0xD5, - 0x30, 0xA0, 0x7A, 0x36, 0x0E, 0xA4, 0xE1, 0xEA, 0xFD, 0xE6, 0xDD, 0xB6, - 0xFF, 0xC6, 0xFC, 0x20, 0xD6, 0x71, 0x36, 0x1B, 0x5D, 0xF2, 0x63, 0xCA, - 0xC6, 0xDE, 0x55, 0xF2, 0x39, 0x05, 0x9A, 0x88, 0x0C, 0x7C, 0xAC, 0x5C, - 0xC0, 0x50, 0x05, 0x1F, 0xDE, 0xBB, 0x6E, 0xF2, 0x06, 0x77, 0x9A, 0xC7, - 0x03, 0x14, 0x26, 0xD4, 0x5D, 0xE0, 0xA9, 0x02, 0xC6, 0xA1, 0xCA, 0x4B, - 0x8D, 0xAC, 0x0B, 0x54, 0xC1, 0xF7, 0x91, 0xBF, 0xD0, 0xE6, 0xEE, 0x4B, - 0x21, 0x82, 0xE2, 0x33, 0xD2, 0xB4, 0xC0, 0x14, 0x64, 0xC8, 0x6B, 0xD0, - 0x50, 0xE5, 0x4A, 0x84, 0xF2, 0x25, 0x23, 0x2E, 0xD2, 0x65, 0x3B, 0x4A, - 0x72, 0x03, 0xAA, 0x0C, 0x82, 0x98, 0x14, 0x11, 0x8E, 0x4A, 0x1F, 0x77, - 0xE1, 0x82, 0xBE, 0xB4, 0x5C, 0xE4, 0x7A, 0x74, 0xFE, 0x29, 0x42, 0xCD, - 0x9D, 0xED, 0x40, 0xC8, 0x88, 0x85, 0xFA, 0x98, 0xBA, 0xBC, 0x45, 0xC7, - 0xCE, 0x5B, 0xB8, 0x36, 0x1B, 0x2A, 0x69, 0x55, 0xF5, 0x98, 0xCF, 0xD7, - 0x4E, 0x7F, 0x2F, 0x59, 0x4D, 0x26, 0x33, 0x54, 0xD2, 0x5F, 0x51, 0xFD, - 0xD2, 0xB9, 0xBB, 0xE0, 0x99, 0x5A, 0xDD, 0xD0, 0x11, 0xEA, 0xFC, 0x84, - 0xD2, 0x21, 0x06, 0x26, 0xEA, 0x2E, 0xBA, 0x52, 0xEB, 0x39, 0xF0, 0x97, - 0x5B, 0xCC, 0x76, 0xAF, 0x87, 0x94, 0x9F, 0xB0, 0xA0, 0xD1, 0x59, 0x9F, - 0x73, 0x83, 0x69, 0x50, 0x76, 0x03, 0x0D, 0x44, 0x13, 0xE1, 0x2B, 0x31, - 0xF9, 0xF4, 0xE2, 0x6D, 0xCD, 0x31, 0xBF, 0x39, 0xFC, 0x61, 0xA1, 0x40, - 0x52, 0x56, 0xF5, 0xD7, 0x12, 0x12, 0xAB, 0x5E, 0x81, 0x48, 0x8A, 0x2E, - 0xE8, 0x85, 0xDC, 0xE7, 0x65, 0x16, 0x6B, 0xBE, 0x28, 0x93, 0x95, 0x0B, - 0x0E, 0x20, 0xFE, 0x4F, 0xF7, 0xEB, 0x0E, 0xEF, 0x2D, 0x41, 0x0C, 0x24, - 0x0C, 0x3F, 0xA6, 0x62, 0x61, 0xB3, 0x7A, 0x5E, 0x9A, 0xEF, 0xF6, 0xAE, - 0x93, 0x51, 0xD5, 0xD7, 0x94, 0xBB, 0xA0, 0x9E, 0xDF, 0x90, 0x87, 0xBD, - 0xD3, 0xF8, 0x4B, 0x86, 0x9E, 0xFF, 0xC5, 0xD7, 0xAF, 0x32, 0x72, 0xC4, - 0xB8, 0x4D, 0x4C, 0x3E, 0xCD, 0xB1, 0xEE, 0xAE, 0xDD, 0x31, 0x12, 0xC6, - 0xD8, 0xC8, 0xFA, 0x20, 0x90, 0xB1, 0x83, 0xAA, 0x33, 0x1F, 0x07, 0xA6, - 0xC1, 0xA1, 0x31, 0x05, 0x3F, 0xE3, 0xA5, 0x4D, 0x41, 0x8B, 0x1C, 0x5B, - 0x51, 0x10, 0x03, 0x0B, 0x0B, 0x2C, 0x3F, 0x97, 0xC5, 0xA2, 0x38, 0x0D, - 0xCB, 0xEF, 0x53, 0x45, 0xBE, 0x28, 0x35, 0x6E, 0x02, 0x10, 0xE8, 0x29, - 0x23, 0xE7, 0xE4, 0xC8, 0x90, 0x99, 0x72, 0xDB, 0xB9, 0x32, 0xB7, 0x87, - 0x52, 0x85, 0x7C, 0x92, 0x47, 0xAF, 0x71, 0x0B, 0x51, 0xC7, 0x8F, 0x24, - 0xE4, 0x7C, 0xE2, 0xF3, 0x33, 0x05, 0xFF, 0x92, 0x0C, 0xC0, 0x01, 0xF0, - 0xF5, 0xEF, 0x52, 0xA1, 0x69, 0xA3, 0x58, 0xFC, 0x48, 0x58, 0x28, 0xBA, - 0x53, 0xA2, 0x3D, 0x03, 0x89, 0x34, 0x12, 0x78, 0xBC, 0x31, 0x5A, 0x93, - 0x62, 0x32, 0xE5, 0xE2, 0x10, 0x56, 0xC0, 0xCA, 0xED, 0x1E, 0x2E, 0x6E, - 0x23, 0x6B, 0xA1, 0x46, 0x6D, 0x7D, 0x58, 0x0B, 0xCC, 0xB0, 0x5B, 0x7B, - 0xA1, 0x48, 0x89, 0xF6, 0x10, 0xBE, 0x8C, 0x30, 0x10, 0xE6, 0xE1, 0x87, - 0x3C, 0xD0, 0x27, 0x47, 0x06, 0xAA, 0xB9, 0x73, 0x26, 0xED, 0x7F, 0x38, - 0xCA, 0xC5, 0xD0, 0x3F, 0x27, 0xEE, 0xA9, 0x5F, 0xF0, 0x31, 0xA9, 0x88, - 0x26, 0x7D, 0x32, 0x34, 0x13, 0xD1, 0xDC, 0x39, 0x7F, 0xAC, 0x3B, 0xB6, - 0xC6, 0x97, 0x5E, 0x44, 0xCA, 0x68, 0xA4, 0x84, 0x90, 0xD0, 0x90, 0x6F, - 0x93, 0xB4, 0xDA, 0x61, 0x43, 0x23, 0xE8, 0x31, 0x34, 0xCD, 0x2F, 0xCA, - 0xB8, 0x63, 0x5F, 0x59, 0x71, 0xE2, 0x2A, 0x11, 0x4F, 0xD0, 0x12, 0xF6, - 0x70, 0x5F, 0xEE, 0xA8, 0xB2, 0x98, 0x89, 0x6C, 0xED, 0x76, 0xCD, 0xE3, - 0x81, 0x1E, 0x5C, 0xEC, 0x7D, 0xB6, 0x21, 0xCE, 0x49, 0x25, 0x7F, 0x97, - 0x8F, 0x1F, 0xBA, 0x81, 0x0B, 0x9F, 0x58, 0xA9, 0x16, 0x19, 0xA2, 0x56, - 0x2F, 0x89, 0x59, 0xA6, 0x8D, 0x97, 0x7C, 0xF7, 0x02, 0xB3, 0x39, 0x37, - 0x4B, 0x79, 0xCF, 0x84, 0x6B, 0xDE, 0x40, 0x6D, 0x1D, 0x17, 0x5E, 0x48, - 0x62, 0x6C, 0x07, 0xE8, 0xBC, 0x0E, 0xD6, 0xD4, 0xEC, 0xA7, 0x55, 0x16, - 0x57, 0x05, 0xC2, 0x5B, 0xA8, 0xBB, 0xA1, 0x8B, 0x63, 0x04, 0x63, 0x99, - 0xC2, 0x11, 0x29, 0xCC, 0x37, 0xC7, 0xB1, 0x70, 0x34, 0x27, 0x1F, 0xD7, - 0xB4, 0x4D, 0xD6, 0xF3, 0x4A, 0x92, 0xF6, 0xA6, 0xAA, 0x8F, 0xC6, 0xC8, - 0x6B, 0xE1, 0xFC, 0x97, 0xAF, 0xC9, 0x6F, 0x68, 0xF1, 0x41, 0xA1, 0xB2, - 0x8C, 0x9E, 0xE2, 0xD7, 0x64, 0xA3, 0xD9, 0x47, 0xBD, 0xBA, 0xFC, 0x84, - 0x14, 0x6C, 0x4B, 0xCC, 0xE6, 0xB4, 0x93, 0x54, 0x03, 0xA6, 0x14, 0xD5, - 0xB1, 0xFB, 0xBC, 0x8E, 0x96, 0x88, 0xB4, 0xD6, 0x86, 0xE5, 0xEE, 0x5B, - 0x1A, 0xA1, 0x7C, 0x43, 0x46, 0x6B, 0x80, 0x2C, 0xAD, 0xDE, 0x4B, 0xA9, - 0x75, 0xA1, 0x42, 0xC7, 0x0B, 0x72, 0xCF, 0x10, 0xA7, 0x5A, 0xD8, 0x96, - 0x0D, 0xC1, 0xB2, 0xAB, 0x5D, 0xD2, 0xA5, 0x5E, 0xE6, 0x72, 0xE6, 0x46, - 0x72, 0x85, 0xAF, 0xC3, 0xD0, 0x09, 0x81, 0xF8, 0x9F, 0xA2, 0xD6, 0x40, - 0xB4, 0x50, 0x0D, 0x35, 0x6A, 0xEB, 0x9F, 0xC2, 0xF1, 0x41, 0x5A, 0x2B, - 0x87, 0xE5, 0x1D, 0xA3, 0x36, 0x6F, 0x5A, 0x95, 0x49, 0xD5, 0x67, 0x1E, - 0xD5, 0x6D, 0xCF, 0x8A, 0xF7, 0xF9, 0x53, 0x9C, 0xCC, 0x7E, 0xD1, 0x3A, - 0xBD, 0xB9, 0x36, 0xEB, 0x82, 0xC5, 0xB5, 0xAC, 0xE7, 0x60, 0x4B, 0x1F, - 0x96, 0xF8, 0xF5, 0x6F, 0x4D, 0x11, 0x76, 0xAF, 0xD0, 0x79, 0x86, 0xD7, - 0xCF, 0x49, 0x61, 0x93, 0x2E, 0xDA, 0xFD, 0x64, 0x4E, 0xB3, 0x27, 0xFA, - 0x38, 0x91, 0x27, 0xA0, 0x94, 0x35, 0xD6, 0x8E, 0x03, 0x6E, 0xB8, 0x67, - 0x2B, 0x35, 0x8E, 0x56, 0x49, 0x52, 0xF1, 0x82, 0x9A, 0x6A, 0x9C, 0xE4, - 0x4E, 0x56, 0xD1, 0x2E, 0xCB, 0xD4, 0x1E, 0x27, 0x69, 0xA9, 0xA4, 0xFE, - 0xB4, 0x33, 0x0C, 0xCD, 0x7A, 0xA9, 0xC2, 0x60, 0x64, 0xB2, 0x4A, 0x34, - 0xBF, 0x8F, 0x67, 0x9A, 0x82, 0x1E, 0x03, 0x0B, 0x85, 0x6F, 0xA6, 0xA0, - 0x2A, 0x7B, 0x27, 0xC6, 0xEA, 0x67, 0x8C, 0xD9, 0xB4, 0x57, 0xAB, 0xBA, - 0x97, 0x6E, 0x51, 0x94, 0x20, 0x00, 0x8B, 0x0C, 0x2B, 0xF9, 0x9D, 0xEA, - 0xB6, 0xAC, 0x56, 0x6F, 0xEF, 0x29, 0x6D, 0x15, 0xC5, 0x30, 0xAB, 0x10, - 0xA7, 0x2F, 0x82, 0x95, 0xAC, 0x78, 0xE1, 0x91, 0x61, 0xE4, 0xA0, 0x40, - 0x98, 0x84, 0x91, 0xDF, 0xD9, 0x6C, 0x78, 0x2F, 0xC3, 0x37, 0x81, 0xC7, - 0x4E, 0xE0, 0x74, 0x0A, 0xD9, 0xBB, 0xBE, 0x30, 0x2C, 0x18, 0x14, 0x88, - 0xAF, 0xDB, 0xD1, 0x56, 0x3C, 0x3D, 0x8E, 0xA7, 0xD8, 0x4E, 0x4C, 0xFE, - 0x29, 0x59, 0x44, 0x0B, 0x39, 0x90, 0x3C, 0x7A, 0xE2, 0xDE, 0x74, 0xB3, - 0xAD, 0xFC, 0xBD, 0x69, 0xAD, 0x23, 0x85, 0x61, 0x49, 0x36, 0x88, 0x26, - 0xED, 0x3A, 0x5A, 0xB0, 0x68, 0x11, 0x34, 0x5A, 0x91, 0xD1, 0x6F, 0x88, - 0xDE, 0x9A, 0x11, 0x43, 0xCD, 0x26, 0xDB, 0x14, 0x80, 0x17, 0xF7, 0xFD, - 0x78, 0x87, 0xA5, 0x14, 0x5A, 0x59, 0x2C, 0x45, 0x54, 0xE7, 0x6D, 0x30, - 0x77, 0x06, 0x2F, 0xF9, 0xD4, 0xDB, 0xCC, 0xDE, 0x60, 0x82, 0x45, 0x14, - 0x19, 0xB7, 0x38, 0x22, 0xDA, 0xC1, 0x6E, 0x51, 0xA4, 0xD6, 0xD1, 0xBF, - 0x6F, 0xA0, 0x47, 0x95, 0x0C, 0x76, 0x50, 0xBA, 0x07, 0xF4, 0xC4, 0x4A, - 0xD0, 0x43, 0x86, 0x3E, 0x40, 0x1B, 0xFB, 0xCB, 0xB4, 0x56, 0x83, 0xD5, - 0xD1, 0xEE, 0x24, 0xB7, 0xB5, 0x40, 0x78, 0x0B, 0xA0, 0x9E, 0x4B, 0x83, - 0xBE, 0x0C, 0x26, 0x76, 0xBF, 0x5E, 0xF2, 0xE9, 0x1B, 0x1D, 0x29, 0x70, - 0x62, 0x38, 0x97, 0xD2, 0xC5, 0x37, 0xFA, 0xE8, 0xF1, 0xE6, 0x79, 0xC2, - 0x20, 0x1C, 0xC7, 0x27, 0x65, 0xA6, 0xD1, 0x7F, 0xE7, 0x7B, 0x28, 0x84, - 0x0A, 0x29, 0x28, 0x6B, 0xD2, 0xDD, 0x1B, 0xF9, 0x12, 0xDE, 0xFC, 0xA9, - 0x09, 0x61, 0xD9, 0xF6, 0x63, 0x7C, 0x8A, 0x00, 0xD8, 0x73, 0xA7, 0x98, - 0xD8, 0xB2, 0xB4, 0x80, 0x98, 0xCA, 0x7D, 0x40, 0xC6, 0x4E, 0x51, 0x41, - 0x84, 0x25, 0x57, 0xD6, 0xED, 0x67, 0x4A, 0x76, 0xC3, 0xFA, 0x4D, 0x37, - 0xA5, 0x4E, 0xCF, 0x19, 0x38, 0xDA, 0x34, 0x02, 0x5D, 0xD9, 0x66, 0xA9, - 0xDF, 0x78, 0xE1, 0x4F, 0xD7, 0xB1, 0x37, 0xC6, 0x60, 0x94, 0x09, 0xD3, - 0xE6, 0xC4, 0xDA, 0x03, 0x84, 0xE6, 0x6F, 0xAB, 0x26, 0xBA, 0xDF, 0xF4, - 0x23, 0xD2, 0x00, 0xCE, 0x85, 0x6E, 0x8C, 0xE9, 0x17, 0xB2, 0x8D, 0x81, - 0x32, 0x01, 0xCC, 0x21, 0xE9, 0x47, 0x43, 0x6F, 0x47, 0xF4, 0x5B, 0x6F, - 0x2B, 0x31, 0xE5, 0x4A, 0x0B, 0xF2, 0x77, 0x28, 0x0A, 0xAC, 0xAF, 0x7A, - 0xF0, 0xF0, 0x33, 0x59, 0xBB, 0xCC, 0xB9, 0xF8, 0x08, 0x94, 0x3D, 0x25, - 0x4E, 0x0C, 0x92, 0x68, 0xDE, 0x7F, 0x82, 0x15, 0xBB, 0x42, 0xF2, 0x94, - 0x8C, 0xE0, 0x72, 0x90, 0x9E, 0x58, 0xF0, 0x6E, 0x29, 0x1E, 0xAD, 0xFC, - 0x35, 0x87, 0xD9, 0x88, 0xDD, 0xA6, 0xFE, 0xAF, 0x3B, 0x2E, 0xD9, 0x0C, - 0x9B, 0x0A, 0x91, 0xE6, 0x0E, 0xD4, 0xD0, 0xFF, 0xD9, 0x64, 0x7E, 0xCF, - 0xF9, 0x7D, 0x10, 0x10, 0x16, 0x5D, 0xE2, 0x9F, 0xD4, 0x54, 0x47, 0xC1, - 0xCF, 0xF1, 0x6D, 0xED, 0x42, 0xCB, 0x1B, 0xA1, 0x87, 0xED, 0xB1, 0x15, - 0xD2, -}; - -static const uint8_t kPublicKeySPKI[] = { - 0x30, 0x82, 0x07, 0xb4, 0x30, 0x0d, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, - 0x01, 0x02, 0x82, 0x0b, 0x07, 0x06, 0x05, 0x03, 0x82, 0x07, 0xa1, 0x00, - 0xbb, 0x0a, 0x41, 0x1a, 0x53, 0x91, 0x4e, 0x67, 0x77, 0x78, 0xd0, 0xbc, - 0xf0, 0xfd, 0x8a, 0x39, 0x65, 0x96, 0x48, 0x54, 0xf5, 0x91, 0xce, 0xdb, - 0x3b, 0x92, 0xbf, 0x2a, 0xc4, 0x01, 0xcd, 0xbe, 0x9e, 0x60, 0x05, 0x45, - 0x68, 0x3e, 0xc0, 0xc6, 0xdc, 0xbb, 0x76, 0x42, 0x2d, 0x91, 0x47, 0xc2, - 0x7c, 0x96, 0xaa, 0x5b, 0x28, 0x0d, 0x3b, 0x24, 0x50, 0x12, 0x4e, 0x05, - 0x0f, 0xbd, 0x09, 0xb5, 0x51, 0xf5, 0xd6, 0x12, 0x93, 0xf8, 0x62, 0x69, - 0x92, 0x25, 0x3b, 0x2e, 0x1b, 0xc8, 0x47, 0xfa, 0x06, 0x2c, 0x21, 0x8a, - 0x62, 0xa2, 0x0a, 0x3f, 0x1b, 0xd3, 0x6d, 0x2d, 0x82, 0x4d, 0x7d, 0xde, - 0x80, 0xbb, 0x08, 0x79, 0x53, 0xd8, 0xdb, 0xcd, 0x73, 0xf8, 0x8f, 0x85, - 0xa8, 0xb4, 0xb5, 0x63, 0xf5, 0x6a, 0x9c, 0xd5, 0x58, 0xac, 0xd7, 0x9c, - 0x96, 0x3c, 0xea, 0x5a, 0x66, 0x69, 0xd6, 0x5e, 0xc3, 0xd5, 0x81, 0xfe, - 0x6b, 0x42, 0xa0, 0xb6, 0x58, 0x54, 0xfa, 0x2f, 0xbe, 0x92, 0x9a, 0x41, - 0xf8, 0x32, 0x10, 0x10, 0x86, 0x77, 0x01, 0xd6, 0xef, 0x81, 0x14, 0x1b, - 0xa3, 0x8b, 0xf4, 0x33, 0x94, 0x4e, 0x85, 0xdc, 0x94, 0x7c, 0x01, 0x9e, - 0x6d, 0x9e, 0x7a, 0x26, 0x0f, 0xcf, 0xa0, 0x7d, 0x92, 0xb0, 0x84, 0x95, - 0x76, 0xdf, 0x40, 0x85, 0x87, 0xef, 0xf5, 0x33, 0x52, 0x2e, 0xf6, 0x73, - 0x9e, 0xda, 0x27, 0x6c, 0xee, 0x08, 0xfe, 0x7a, 0x67, 0x43, 0x88, 0xc6, - 0xf0, 0xf1, 0x0c, 0x08, 0xa5, 0x67, 0xc4, 0xb0, 0x01, 0xfb, 0x5b, 0x59, - 0xfc, 0xae, 0xcf, 0x07, 0x14, 0x52, 0x45, 0xd0, 0xeb, 0x97, 0xab, 0x0e, - 0x52, 0x65, 0x12, 0x41, 0xa2, 0x03, 0xb1, 0xe5, 0x1e, 0xa6, 0x33, 0xce, - 0x9a, 0x5c, 0x8f, 0xdf, 0x1a, 0x42, 0x6c, 0xb6, 0xcb, 0x78, 0xdd, 0x02, - 0x78, 0xd9, 0xd8, 0xae, 0x31, 0x5f, 0x13, 0xeb, 0x71, 0xd3, 0xad, 0x6b, - 0xd0, 0x98, 0x18, 0x7a, 0x5b, 0x0d, 0xa9, 0x5d, 0x35, 0xb4, 0x26, 0x5e, - 0xca, 0xf6, 0x7d, 0xc3, 0x9f, 0xe1, 0xbd, 0xfb, 0x73, 0xa6, 0xf1, 0xe0, - 0x26, 0x0f, 0xca, 0x1b, 0xc3, 0xa9, 0xd0, 0x27, 0x46, 0x82, 0x49, 0x73, - 0xed, 0x3a, 0x6b, 0x61, 0x05, 0xd8, 0xa7, 0x7f, 0x2b, 0x36, 0x1c, 0x69, - 0x31, 0x73, 0x29, 0xde, 0x6d, 0x28, 0xb6, 0xea, 0xfe, 0x37, 0xc2, 0xc0, - 0x94, 0x4b, 0x3e, 0xd4, 0x21, 0x3f, 0xe0, 0x02, 0xfa, 0x5f, 0x16, 0xce, - 0x16, 0x66, 0xb5, 0xc9, 0xf6, 0x3f, 0x2a, 0x5c, 0x83, 0x00, 0x5f, 0xda, - 0x0b, 0x6e, 0xe7, 0xb6, 0x55, 0x55, 0xbf, 0x50, 0x29, 0x8e, 0x39, 0xa2, - 0xb7, 0x85, 0x79, 0xc3, 0xce, 0x93, 0x63, 0x57, 0xd1, 0xf2, 0x03, 0x6e, - 0x42, 0x78, 0xb3, 0x5f, 0x72, 0x5c, 0x7d, 0xb0, 0xe0, 0x55, 0x96, 0xe1, - 0x34, 0x0b, 0x5c, 0x75, 0xa9, 0xef, 0x17, 0x47, 0x5b, 0xdc, 0x4f, 0x01, - 0x5d, 0x80, 0x60, 0x14, 0xa7, 0x9a, 0xd3, 0x38, 0x07, 0xda, 0x61, 0x0d, - 0x7f, 0x37, 0xec, 0x0a, 0xd3, 0x54, 0x91, 0x53, 0x16, 0x3d, 0xad, 0xc8, - 0x2c, 0xac, 0xbb, 0x1b, 0x03, 0xd7, 0x96, 0x8d, 0x6d, 0x2d, 0x81, 0xbb, - 0x57, 0xdb, 0x10, 0x3e, 0xfd, 0xcf, 0xa9, 0xa3, 0xa4, 0xaf, 0xf7, 0xa1, - 0x9f, 0x4b, 0xb0, 0x3e, 0x3d, 0x51, 0x15, 0xea, 0x63, 0x8c, 0x75, 0x59, - 0x78, 0xbb, 0xec, 0x94, 0x47, 0xa8, 0x81, 0x7b, 0x98, 0xf1, 0x6e, 0x0a, - 0xad, 0xe6, 0x42, 0x58, 0x37, 0x76, 0x8e, 0x06, 0xa5, 0x43, 0xbf, 0xe9, - 0xfa, 0x53, 0x2e, 0xac, 0x2e, 0xbc, 0x6a, 0x99, 0x08, 0x51, 0x98, 0xac, - 0x3a, 0x23, 0x52, 0x19, 0x07, 0x81, 0x14, 0x4c, 0x62, 0x3f, 0x38, 0x2c, - 0xb6, 0x70, 0x33, 0xd8, 0xb3, 0x97, 0x5b, 0x9c, 0x54, 0x62, 0x63, 0x03, - 0xa8, 0xad, 0xc1, 0xb3, 0xc6, 0x3a, 0x74, 0x5d, 0x6e, 0x9c, 0x3f, 0xce, - 0xe8, 0x79, 0xf4, 0x02, 0x90, 0x3a, 0x2b, 0x51, 0x50, 0x9f, 0x88, 0xf5, - 0x98, 0xa7, 0xc4, 0xd2, 0xe9, 0x4f, 0xca, 0x52, 0xe9, 0xe1, 0xb2, 0xb3, - 0x78, 0xb0, 0xa2, 0x33, 0x9f, 0xa8, 0xc3, 0xd9, 0xb6, 0xdd, 0x6a, 0x05, - 0x5b, 0xc7, 0x52, 0xc3, 0x68, 0xc2, 0x30, 0x7f, 0x74, 0x1e, 0x07, 0x66, - 0xc3, 0xa4, 0x2d, 0x84, 0xaa, 0x17, 0xd6, 0x49, 0x89, 0x60, 0x31, 0x0e, - 0x4e, 0xae, 0xcf, 0x56, 0x93, 0x40, 0x3c, 0x9b, 0xc9, 0x13, 0x5c, 0x5d, - 0x38, 0x94, 0xae, 0x6f, 0xe9, 0x04, 0xb7, 0xa6, 0x1e, 0xab, 0xb9, 0xd4, - 0x04, 0xff, 0x3c, 0x99, 0x2f, 0xe4, 0x80, 0x69, 0xdb, 0x50, 0x5b, 0xac, - 0x34, 0x48, 0x77, 0xf6, 0xb2, 0x00, 0x02, 0x8d, 0x75, 0xa0, 0x2e, 0x93, - 0x0a, 0x20, 0x22, 0x2f, 0x73, 0x15, 0xea, 0xea, 0xbd, 0x8b, 0xe6, 0x85, - 0xfd, 0x30, 0x97, 0xf7, 0x24, 0xb9, 0xd5, 0x30, 0xa0, 0x7a, 0x36, 0x0e, - 0xa4, 0xe1, 0xea, 0xfd, 0xe6, 0xdd, 0xb6, 0xff, 0xc6, 0xfc, 0x20, 0xd6, - 0x71, 0x36, 0x1b, 0x5d, 0xf2, 0x63, 0xca, 0xc6, 0xde, 0x55, 0xf2, 0x39, - 0x05, 0x9a, 0x88, 0x0c, 0x7c, 0xac, 0x5c, 0xc0, 0x50, 0x05, 0x1f, 0xde, - 0xbb, 0x6e, 0xf2, 0x06, 0x77, 0x9a, 0xc7, 0x03, 0x14, 0x26, 0xd4, 0x5d, - 0xe0, 0xa9, 0x02, 0xc6, 0xa1, 0xca, 0x4b, 0x8d, 0xac, 0x0b, 0x54, 0xc1, - 0xf7, 0x91, 0xbf, 0xd0, 0xe6, 0xee, 0x4b, 0x21, 0x82, 0xe2, 0x33, 0xd2, - 0xb4, 0xc0, 0x14, 0x64, 0xc8, 0x6b, 0xd0, 0x50, 0xe5, 0x4a, 0x84, 0xf2, - 0x25, 0x23, 0x2e, 0xd2, 0x65, 0x3b, 0x4a, 0x72, 0x03, 0xaa, 0x0c, 0x82, - 0x98, 0x14, 0x11, 0x8e, 0x4a, 0x1f, 0x77, 0xe1, 0x82, 0xbe, 0xb4, 0x5c, - 0xe4, 0x7a, 0x74, 0xfe, 0x29, 0x42, 0xcd, 0x9d, 0xed, 0x40, 0xc8, 0x88, - 0x85, 0xfa, 0x98, 0xba, 0xbc, 0x45, 0xc7, 0xce, 0x5b, 0xb8, 0x36, 0x1b, - 0x2a, 0x69, 0x55, 0xf5, 0x98, 0xcf, 0xd7, 0x4e, 0x7f, 0x2f, 0x59, 0x4d, - 0x26, 0x33, 0x54, 0xd2, 0x5f, 0x51, 0xfd, 0xd2, 0xb9, 0xbb, 0xe0, 0x99, - 0x5a, 0xdd, 0xd0, 0x11, 0xea, 0xfc, 0x84, 0xd2, 0x21, 0x06, 0x26, 0xea, - 0x2e, 0xba, 0x52, 0xeb, 0x39, 0xf0, 0x97, 0x5b, 0xcc, 0x76, 0xaf, 0x87, - 0x94, 0x9f, 0xb0, 0xa0, 0xd1, 0x59, 0x9f, 0x73, 0x83, 0x69, 0x50, 0x76, - 0x03, 0x0d, 0x44, 0x13, 0xe1, 0x2b, 0x31, 0xf9, 0xf4, 0xe2, 0x6d, 0xcd, - 0x31, 0xbf, 0x39, 0xfc, 0x61, 0xa1, 0x40, 0x52, 0x56, 0xf5, 0xd7, 0x12, - 0x12, 0xab, 0x5e, 0x81, 0x48, 0x8a, 0x2e, 0xe8, 0x85, 0xdc, 0xe7, 0x65, - 0x16, 0x6b, 0xbe, 0x28, 0x93, 0x95, 0x0b, 0x0e, 0x20, 0xfe, 0x4f, 0xf7, - 0xeb, 0x0e, 0xef, 0x2d, 0x41, 0x0c, 0x24, 0x0c, 0x3f, 0xa6, 0x62, 0x61, - 0xb3, 0x7a, 0x5e, 0x9a, 0xef, 0xf6, 0xae, 0x93, 0x51, 0xd5, 0xd7, 0x94, - 0xbb, 0xa0, 0x9e, 0xdf, 0x90, 0x87, 0xbd, 0xd3, 0xf8, 0x4b, 0x86, 0x9e, - 0xff, 0xc5, 0xd7, 0xaf, 0x32, 0x72, 0xc4, 0xb8, 0x4d, 0x4c, 0x3e, 0xcd, - 0xb1, 0xee, 0xae, 0xdd, 0x31, 0x12, 0xc6, 0xd8, 0xc8, 0xfa, 0x20, 0x90, - 0xb1, 0x83, 0xaa, 0x33, 0x1f, 0x07, 0xa6, 0xc1, 0xa1, 0x31, 0x05, 0x3f, - 0xe3, 0xa5, 0x4d, 0x41, 0x8b, 0x1c, 0x5b, 0x51, 0x10, 0x03, 0x0b, 0x0b, - 0x2c, 0x3f, 0x97, 0xc5, 0xa2, 0x38, 0x0d, 0xcb, 0xef, 0x53, 0x45, 0xbe, - 0x28, 0x35, 0x6e, 0x02, 0x10, 0xe8, 0x29, 0x23, 0xe7, 0xe4, 0xc8, 0x90, - 0x99, 0x72, 0xdb, 0xb9, 0x32, 0xb7, 0x87, 0x52, 0x85, 0x7c, 0x92, 0x47, - 0xaf, 0x71, 0x0b, 0x51, 0xc7, 0x8f, 0x24, 0xe4, 0x7c, 0xe2, 0xf3, 0x33, - 0x05, 0xff, 0x92, 0x0c, 0xc0, 0x01, 0xf0, 0xf5, 0xef, 0x52, 0xa1, 0x69, - 0xa3, 0x58, 0xfc, 0x48, 0x58, 0x28, 0xba, 0x53, 0xa2, 0x3d, 0x03, 0x89, - 0x34, 0x12, 0x78, 0xbc, 0x31, 0x5a, 0x93, 0x62, 0x32, 0xe5, 0xe2, 0x10, - 0x56, 0xc0, 0xca, 0xed, 0x1e, 0x2e, 0x6e, 0x23, 0x6b, 0xa1, 0x46, 0x6d, - 0x7d, 0x58, 0x0b, 0xcc, 0xb0, 0x5b, 0x7b, 0xa1, 0x48, 0x89, 0xf6, 0x10, - 0xbe, 0x8c, 0x30, 0x10, 0xe6, 0xe1, 0x87, 0x3c, 0xd0, 0x27, 0x47, 0x06, - 0xaa, 0xb9, 0x73, 0x26, 0xed, 0x7f, 0x38, 0xca, 0xc5, 0xd0, 0x3f, 0x27, - 0xee, 0xa9, 0x5f, 0xf0, 0x31, 0xa9, 0x88, 0x26, 0x7d, 0x32, 0x34, 0x13, - 0xd1, 0xdc, 0x39, 0x7f, 0xac, 0x3b, 0xb6, 0xc6, 0x97, 0x5e, 0x44, 0xca, - 0x68, 0xa4, 0x84, 0x90, 0xd0, 0x90, 0x6f, 0x93, 0xb4, 0xda, 0x61, 0x43, - 0x23, 0xe8, 0x31, 0x34, 0xcd, 0x2f, 0xca, 0xb8, 0x63, 0x5f, 0x59, 0x71, - 0xe2, 0x2a, 0x11, 0x4f, 0xd0, 0x12, 0xf6, 0x70, 0x5f, 0xee, 0xa8, 0xb2, - 0x98, 0x89, 0x6c, 0xed, 0x76, 0xcd, 0xe3, 0x81, 0x1e, 0x5c, 0xec, 0x7d, - 0xb6, 0x21, 0xce, 0x49, 0x25, 0x7f, 0x97, 0x8f, 0x1f, 0xba, 0x81, 0x0b, - 0x9f, 0x58, 0xa9, 0x16, 0x19, 0xa2, 0x56, 0x2f, 0x89, 0x59, 0xa6, 0x8d, - 0x97, 0x7c, 0xf7, 0x02, 0xb3, 0x39, 0x37, 0x4b, 0x79, 0xcf, 0x84, 0x6b, - 0xde, 0x40, 0x6d, 0x1d, 0x17, 0x5e, 0x48, 0x62, 0x6c, 0x07, 0xe8, 0xbc, - 0x0e, 0xd6, 0xd4, 0xec, 0xa7, 0x55, 0x16, 0x57, 0x05, 0xc2, 0x5b, 0xa8, - 0xbb, 0xa1, 0x8b, 0x63, 0x04, 0x63, 0x99, 0xc2, 0x11, 0x29, 0xcc, 0x37, - 0xc7, 0xb1, 0x70, 0x34, 0x27, 0x1f, 0xd7, 0xb4, 0x4d, 0xd6, 0xf3, 0x4a, - 0x92, 0xf6, 0xa6, 0xaa, 0x8f, 0xc6, 0xc8, 0x6b, 0xe1, 0xfc, 0x97, 0xaf, - 0xc9, 0x6f, 0x68, 0xf1, 0x41, 0xa1, 0xb2, 0x8c, 0x9e, 0xe2, 0xd7, 0x64, - 0xa3, 0xd9, 0x47, 0xbd, 0xba, 0xfc, 0x84, 0x14, 0x6c, 0x4b, 0xcc, 0xe6, - 0xb4, 0x93, 0x54, 0x03, 0xa6, 0x14, 0xd5, 0xb1, 0xfb, 0xbc, 0x8e, 0x96, - 0x88, 0xb4, 0xd6, 0x86, 0xe5, 0xee, 0x5b, 0x1a, 0xa1, 0x7c, 0x43, 0x46, - 0x6b, 0x80, 0x2c, 0xad, 0xde, 0x4b, 0xa9, 0x75, 0xa1, 0x42, 0xc7, 0x0b, - 0x72, 0xcf, 0x10, 0xa7, 0x5a, 0xd8, 0x96, 0x0d, 0xc1, 0xb2, 0xab, 0x5d, - 0xd2, 0xa5, 0x5e, 0xe6, 0x72, 0xe6, 0x46, 0x72, 0x85, 0xaf, 0xc3, 0xd0, - 0x09, 0x81, 0xf8, 0x9f, 0xa2, 0xd6, 0x40, 0xb4, 0x50, 0x0d, 0x35, 0x6a, - 0xeb, 0x9f, 0xc2, 0xf1, 0x41, 0x5a, 0x2b, 0x87, 0xe5, 0x1d, 0xa3, 0x36, - 0x6f, 0x5a, 0x95, 0x49, 0xd5, 0x67, 0x1e, 0xd5, 0x6d, 0xcf, 0x8a, 0xf7, - 0xf9, 0x53, 0x9c, 0xcc, 0x7e, 0xd1, 0x3a, 0xbd, 0xb9, 0x36, 0xeb, 0x82, - 0xc5, 0xb5, 0xac, 0xe7, 0x60, 0x4b, 0x1f, 0x96, 0xf8, 0xf5, 0x6f, 0x4d, - 0x11, 0x76, 0xaf, 0xd0, 0x79, 0x86, 0xd7, 0xcf, 0x49, 0x61, 0x93, 0x2e, - 0xda, 0xfd, 0x64, 0x4e, 0xb3, 0x27, 0xfa, 0x38, 0x91, 0x27, 0xa0, 0x94, - 0x35, 0xd6, 0x8e, 0x03, 0x6e, 0xb8, 0x67, 0x2b, 0x35, 0x8e, 0x56, 0x49, - 0x52, 0xf1, 0x82, 0x9a, 0x6a, 0x9c, 0xe4, 0x4e, 0x56, 0xd1, 0x2e, 0xcb, - 0xd4, 0x1e, 0x27, 0x69, 0xa9, 0xa4, 0xfe, 0xb4, 0x33, 0x0c, 0xcd, 0x7a, - 0xa9, 0xc2, 0x60, 0x64, 0xb2, 0x4a, 0x34, 0xbf, 0x8f, 0x67, 0x9a, 0x82, - 0x1e, 0x03, 0x0b, 0x85, 0x6f, 0xa6, 0xa0, 0x2a, 0x7b, 0x27, 0xc6, 0xea, - 0x67, 0x8c, 0xd9, 0xb4, 0x57, 0xab, 0xba, 0x97, 0x6e, 0x51, 0x94, 0x20, - 0x00, 0x8b, 0x0c, 0x2b, 0xf9, 0x9d, 0xea, 0xb6, 0xac, 0x56, 0x6f, 0xef, - 0x29, 0x6d, 0x15, 0xc5, 0x30, 0xab, 0x10, 0xa7, 0x2f, 0x82, 0x95, 0xac, - 0x78, 0xe1, 0x91, 0x61, 0xe4, 0xa0, 0x40, 0x98, 0x84, 0x91, 0xdf, 0xd9, - 0x6c, 0x78, 0x2f, 0xc3, 0x37, 0x81, 0xc7, 0x4e, 0xe0, 0x74, 0x0a, 0xd9, - 0xbb, 0xbe, 0x30, 0x2c, 0x18, 0x14, 0x88, 0xaf, 0xdb, 0xd1, 0x56, 0x3c, - 0x3d, 0x8e, 0xa7, 0xd8, 0x4e, 0x4c, 0xfe, 0x29, 0x59, 0x44, 0x0b, 0x39, - 0x90, 0x3c, 0x7a, 0xe2, 0xde, 0x74, 0xb3, 0xad, 0xfc, 0xbd, 0x69, 0xad, - 0x23, 0x85, 0x61, 0x49, 0x36, 0x88, 0x26, 0xed, 0x3a, 0x5a, 0xb0, 0x68, - 0x11, 0x34, 0x5a, 0x91, 0xd1, 0x6f, 0x88, 0xde, 0x9a, 0x11, 0x43, 0xcd, - 0x26, 0xdb, 0x14, 0x80, 0x17, 0xf7, 0xfd, 0x78, 0x87, 0xa5, 0x14, 0x5a, - 0x59, 0x2c, 0x45, 0x54, 0xe7, 0x6d, 0x30, 0x77, 0x06, 0x2f, 0xf9, 0xd4, - 0xdb, 0xcc, 0xde, 0x60, 0x82, 0x45, 0x14, 0x19, 0xb7, 0x38, 0x22, 0xda, - 0xc1, 0x6e, 0x51, 0xa4, 0xd6, 0xd1, 0xbf, 0x6f, 0xa0, 0x47, 0x95, 0x0c, - 0x76, 0x50, 0xba, 0x07, 0xf4, 0xc4, 0x4a, 0xd0, 0x43, 0x86, 0x3e, 0x40, - 0x1b, 0xfb, 0xcb, 0xb4, 0x56, 0x83, 0xd5, 0xd1, 0xee, 0x24, 0xb7, 0xb5, - 0x40, 0x78, 0x0b, 0xa0, 0x9e, 0x4b, 0x83, 0xbe, 0x0c, 0x26, 0x76, 0xbf, - 0x5e, 0xf2, 0xe9, 0x1b, 0x1d, 0x29, 0x70, 0x62, 0x38, 0x97, 0xd2, 0xc5, - 0x37, 0xfa, 0xe8, 0xf1, 0xe6, 0x79, 0xc2, 0x20, 0x1c, 0xc7, 0x27, 0x65, - 0xa6, 0xd1, 0x7f, 0xe7, 0x7b, 0x28, 0x84, 0x0a, 0x29, 0x28, 0x6b, 0xd2, - 0xdd, 0x1b, 0xf9, 0x12, 0xde, 0xfc, 0xa9, 0x09, 0x61, 0xd9, 0xf6, 0x63, - 0x7c, 0x8a, 0x00, 0xd8, 0x73, 0xa7, 0x98, 0xd8, 0xb2, 0xb4, 0x80, 0x98, - 0xca, 0x7d, 0x40, 0xc6, 0x4e, 0x51, 0x41, 0x84, 0x25, 0x57, 0xd6, 0xed, - 0x67, 0x4a, 0x76, 0xc3, 0xfa, 0x4d, 0x37, 0xa5, 0x4e, 0xcf, 0x19, 0x38, - 0xda, 0x34, 0x02, 0x5d, 0xd9, 0x66, 0xa9, 0xdf, 0x78, 0xe1, 0x4f, 0xd7, - 0xb1, 0x37, 0xc6, 0x60, 0x94, 0x09, 0xd3, 0xe6, 0xc4, 0xda, 0x03, 0x84, - 0xe6, 0x6f, 0xab, 0x26, 0xba, 0xdf, 0xf4, 0x23, 0xd2, 0x00, 0xce, 0x85, - 0x6e, 0x8c, 0xe9, 0x17, 0xb2, 0x8d, 0x81, 0x32, 0x01, 0xcc, 0x21, 0xe9, - 0x47, 0x43, 0x6f, 0x47, 0xf4, 0x5b, 0x6f, 0x2b, 0x31, 0xe5, 0x4a, 0x0b, - 0xf2, 0x77, 0x28, 0x0a, 0xac, 0xaf, 0x7a, 0xf0, 0xf0, 0x33, 0x59, 0xbb, - 0xcc, 0xb9, 0xf8, 0x08, 0x94, 0x3d, 0x25, 0x4e, 0x0c, 0x92, 0x68, 0xde, - 0x7f, 0x82, 0x15, 0xbb, 0x42, 0xf2, 0x94, 0x8c, 0xe0, 0x72, 0x90, 0x9e, - 0x58, 0xf0, 0x6e, 0x29, 0x1e, 0xad, 0xfc, 0x35, 0x87, 0xd9, 0x88, 0xdd, - 0xa6, 0xfe, 0xaf, 0x3b, 0x2e, 0xd9, 0x0c, 0x9b, 0x0a, 0x91, 0xe6, 0x0e, - 0xd4, 0xd0, 0xff, 0xd9, 0x64, 0x7e, 0xcf, 0xf9, 0x7d, 0x10, 0x10, 0x16, - 0x5d, 0xe2, 0x9f, 0xd4, 0x54, 0x47, 0xc1, 0xcf, 0xf1, 0x6d, 0xed, 0x42, - 0xcb, 0x1b, 0xa1, 0x87, 0xed, 0xb1, 0x15, 0xd2, -}; - -TEST(Dilithium3Test, KeyGeneration) { - // Basic key generation tests for Dilithium3 - // Generate a Dilithium3 key - EVP_PKEY_CTX *dilithium_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - ASSERT_NE(dilithium_pkey_ctx, nullptr); - - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey, nullptr); - - EXPECT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx)); - EXPECT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx, &dilithium_pkey)); - ASSERT_NE(dilithium_pkey->pkey.ptr, nullptr); - - const DILITHIUM3_KEY *dilithium3Key = (DILITHIUM3_KEY *)(dilithium_pkey->pkey.ptr); - EXPECT_NE(dilithium3Key->priv, nullptr); - - // Extract public key and check it is of the correct size - uint8_t *buf = nullptr; - size_t buf_size; - EXPECT_TRUE(EVP_PKEY_get_raw_public_key(dilithium_pkey, buf, &buf_size)); - EXPECT_EQ((size_t)DILITHIUM3_PUBLIC_KEY_BYTES, buf_size); - - buf = (uint8_t *)OPENSSL_malloc(buf_size); - ASSERT_NE(buf, nullptr); - EXPECT_TRUE(EVP_PKEY_get_raw_public_key(dilithium_pkey, buf, &buf_size)); - - buf_size = 0; - EXPECT_FALSE(EVP_PKEY_get_raw_public_key(dilithium_pkey, buf, &buf_size)); - - uint32_t err = ERR_get_error(); - EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); - EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err)); - OPENSSL_free(buf); - buf = nullptr; - - // Extract private key and check it is of the correct size - EXPECT_TRUE(EVP_PKEY_get_raw_private_key(dilithium_pkey, buf, &buf_size)); - EXPECT_EQ((size_t)DILITHIUM3_PRIVATE_KEY_BYTES, buf_size); - - buf = (uint8_t *)OPENSSL_malloc(buf_size); - ASSERT_NE(buf, nullptr); - EXPECT_TRUE(EVP_PKEY_get_raw_private_key(dilithium_pkey, buf, &buf_size)); - - buf_size = 0; - EXPECT_FALSE(EVP_PKEY_get_raw_private_key(dilithium_pkey, buf, &buf_size)); - err = ERR_get_error(); - EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); - EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err)); - OPENSSL_free(buf); - - EVP_PKEY_CTX_free(dilithium_pkey_ctx); - EVP_PKEY_free(dilithium_pkey); -} - -TEST(Dilithium3Test, KeyComparison) { - // Generate two Dilithium3 keys are check that they are not equal. - EVP_PKEY_CTX *dilithium_pkey_ctx1 = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - ASSERT_NE(dilithium_pkey_ctx1, nullptr); - - EVP_PKEY *dilithium_pkey1 = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey1, nullptr); - - EXPECT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx1)); - EXPECT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx1, &dilithium_pkey1)); - ASSERT_NE(dilithium_pkey1->pkey.ptr, nullptr); - - EVP_PKEY_CTX *dilithium_pkey_ctx2 = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - ASSERT_NE(dilithium_pkey_ctx2, nullptr); - - EVP_PKEY *dilithium_pkey2 = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey2, nullptr); - - EXPECT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx2)); - EXPECT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx2, &dilithium_pkey2)); - ASSERT_NE(dilithium_pkey2->pkey.ptr, nullptr); - - EXPECT_EQ(0, EVP_PKEY_cmp(dilithium_pkey1, dilithium_pkey2)); - - EVP_PKEY_free(dilithium_pkey1); - EVP_PKEY_free(dilithium_pkey2); - EVP_PKEY_CTX_free(dilithium_pkey_ctx1); - EVP_PKEY_CTX_free(dilithium_pkey_ctx2); -} - -TEST(Dilithium3Test, NewKeyFromBytes) { - // Test the generation of a Dilithium3 key from bytes - // Source key - EVP_PKEY_CTX *dilithium_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - ASSERT_NE(dilithium_pkey_ctx, nullptr); - - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey, nullptr); - - EXPECT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx)); - EXPECT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx, &dilithium_pkey)); - ASSERT_NE(dilithium_pkey->pkey.ptr, nullptr); - const DILITHIUM3_KEY *dilithium3Key = (DILITHIUM3_KEY *)(dilithium_pkey->pkey.ptr); - EXPECT_NE(dilithium3Key->pub, nullptr); - EXPECT_NE(dilithium3Key->priv, nullptr); - - // New raw public key - EVP_PKEY *new_public = EVP_PKEY_new_raw_public_key(EVP_PKEY_DILITHIUM3, - NULL, - dilithium3Key->pub, - DILITHIUM3_PUBLIC_KEY_BYTES); - ASSERT_NE(new_public, nullptr); - const DILITHIUM3_KEY *newDilithium3Key = (DILITHIUM3_KEY *)(new_public->pkey.ptr); - EXPECT_NE(newDilithium3Key->pub, nullptr); - EXPECT_EQ(newDilithium3Key->priv, nullptr); - - uint8_t *buf = nullptr; - size_t buf_size; - EXPECT_FALSE(EVP_PKEY_get_raw_private_key(new_public, buf, &buf_size)); - uint32_t err = ERR_get_error(); - EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); - EXPECT_EQ(EVP_R_NOT_A_PRIVATE_KEY, ERR_GET_REASON(err)); - - // EVP_PKEY_cmp just compares the public keys so this should return 1 - EXPECT_EQ(1, EVP_PKEY_cmp(dilithium_pkey, new_public)); - - // New raw private key - EVP_PKEY *new_private = EVP_PKEY_new_raw_private_key(EVP_PKEY_DILITHIUM3, - NULL, - dilithium3Key->priv, - DILITHIUM3_PRIVATE_KEY_BYTES); - ASSERT_NE(new_private, nullptr); - newDilithium3Key = (DILITHIUM3_KEY *)(new_private->pkey.ptr); - EXPECT_EQ(0, OPENSSL_memcmp(dilithium3Key->priv, newDilithium3Key->priv, - DILITHIUM3_PRIVATE_KEY_BYTES)); - EXPECT_EQ(newDilithium3Key->pub, nullptr); - EXPECT_NE(newDilithium3Key->priv, nullptr); - - EVP_PKEY_CTX_free(dilithium_pkey_ctx); - EVP_PKEY_free(new_public); - EVP_PKEY_free(new_private); - EVP_PKEY_free(dilithium_pkey); -} - -TEST(Dilithium3Test, KeySize) { - // Test the key size of Dilithium3 key is as expected - EVP_PKEY_CTX *dilithium_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - ASSERT_NE(dilithium_pkey_ctx, nullptr); - - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey, nullptr); - - EXPECT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx)); - EXPECT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx, &dilithium_pkey)); - - EXPECT_EQ(DILITHIUM3_SIGNATURE_BYTES, EVP_PKEY_size(dilithium_pkey)); - EXPECT_EQ(8*(DILITHIUM3_PUBLIC_KEY_BYTES), EVP_PKEY_bits(dilithium_pkey)); - - EVP_PKEY_CTX_free(dilithium_pkey_ctx); - EVP_PKEY_free(dilithium_pkey); -} - -TEST(Dilithium3Test, Encoding) { - // Test Dilithium keypairs are extractable, and encode/parse correctly. - // generate dilithium key - EVP_PKEY_CTX *dilithium_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - EVP_PKEY_keygen_init(dilithium_pkey_ctx); - EVP_PKEY_keygen(dilithium_pkey_ctx, &dilithium_pkey); - const DILITHIUM3_KEY *dilithium3Key = (DILITHIUM3_KEY *)(dilithium_pkey->pkey.ptr); - - // Create a public key. - bssl::UniquePtr pubkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_DILITHIUM3, - NULL, - dilithium3Key->pub, - DILITHIUM3_PUBLIC_KEY_BYTES)); - ASSERT_TRUE(pubkey); - EXPECT_EQ(EVP_PKEY_DILITHIUM3, EVP_PKEY_id(pubkey.get())); - - // The public key must be extractable. - uint8_t pub_buf[1952]; - size_t pub_len; - ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pubkey.get(), nullptr, &pub_len)); - EXPECT_EQ(pub_len, 1952u); - ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pubkey.get(), pub_buf, &pub_len)); - - // The public key must encode properly. - bssl::ScopedCBB cbb; - uint8_t *der; - size_t der_len; - ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pubkey.get())); - ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); - bssl::UniquePtr free_der(der); - - // The public key must parse properly. - CBS cbs; - CBS_init(&cbs, der, der_len); - EVP_PKEY *dilithium_pkey_from_der = EVP_parse_public_key(&cbs); - ASSERT_TRUE(dilithium_pkey_from_der); - EXPECT_EQ(1, EVP_PKEY_cmp(dilithium_pkey, dilithium_pkey_from_der)); - - // Create a private key. - bssl::UniquePtr privkey(EVP_PKEY_new_raw_private_key(EVP_PKEY_DILITHIUM3, - NULL, - dilithium3Key->priv, - DILITHIUM3_PRIVATE_KEY_BYTES)); - ASSERT_TRUE(privkey); - EXPECT_EQ(EVP_PKEY_DILITHIUM3, EVP_PKEY_id(privkey.get())); - - // The private key must be extractable. - uint8_t priv_buf[4032]; - size_t priv_len; - ASSERT_TRUE(EVP_PKEY_get_raw_private_key(privkey.get(), nullptr, &priv_len)); - EXPECT_EQ(priv_len, 4032u); - ASSERT_TRUE(EVP_PKEY_get_raw_private_key(privkey.get(), priv_buf, &priv_len)); - - // The private key must encode properly. - ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(EVP_marshal_private_key(cbb.get(), privkey.get())); - ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); - free_der.reset(der); - - // The private key must parse properly. - CBS_init(&cbs, der, der_len); - EVP_PKEY *dilithium_priv_from_der = EVP_parse_private_key(&cbs); - ASSERT_TRUE(dilithium_priv_from_der); - const DILITHIUM3_KEY *dilithium3Key_from_der = (DILITHIUM3_KEY *)(dilithium_priv_from_der->pkey.ptr); - // The private key dilithium3Key_from_der must be equal to the original key - EXPECT_EQ(Bytes(dilithium3Key->priv, DILITHIUM3_PRIVATE_KEY_BYTES), - Bytes(dilithium3Key_from_der->priv, DILITHIUM3_PRIVATE_KEY_BYTES)); - - // Marshalling incorrect type should fail - ASSERT_FALSE(EVP_marshal_public_key(cbb.get(), privkey.get())); - ASSERT_FALSE(EVP_marshal_private_key(cbb.get(), pubkey.get())); - - EVP_PKEY_CTX_free(dilithium_pkey_ctx); - EVP_PKEY_free(dilithium_pkey); - EVP_PKEY_free(dilithium_pkey_from_der); - EVP_PKEY_free(dilithium_priv_from_der); -} - -TEST(Dilithium3Test, Decoding) { - // Generate a Dilithium3 public key based on the public key bytes - bssl::UniquePtr pubkey(EVP_PKEY_new_raw_public_key( - EVP_PKEY_DILITHIUM3, nullptr, kPublicKey, sizeof(kPublicKey))); - ASSERT_TRUE(pubkey); - EXPECT_EQ(EVP_PKEY_DILITHIUM3, EVP_PKEY_id(pubkey.get())); - - // Encode the public key as DER - bssl::ScopedCBB cbb; - uint8_t *der; - size_t der_len; - ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pubkey.get())); - ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); - bssl::UniquePtr free_der(der); - - // Test that the encoded public key encodes as expected - EXPECT_EQ(Bytes(kPublicKeySPKI), Bytes(der, der_len)); - - // We now decode the DER structure, then parse as a PKEY. - CBS cbs; - CBS_init(&cbs, der, der_len); - EVP_PKEY *dilithium_pkey_from_der = EVP_parse_public_key(&cbs); - ASSERT_TRUE(dilithium_pkey_from_der); - - // Extract the public key and check it is equivalent to original key - uint8_t pub_buf[1952]; - size_t pub_len; - ASSERT_TRUE(EVP_PKEY_get_raw_public_key(dilithium_pkey_from_der, nullptr, &pub_len)); - EXPECT_EQ(pub_len, 1952u); - ASSERT_TRUE(EVP_PKEY_get_raw_public_key(dilithium_pkey_from_der, pub_buf, &pub_len)); - EXPECT_EQ(Bytes(kPublicKey), Bytes(pub_buf, pub_len)); - - EVP_PKEY_free(dilithium_pkey_from_der); -} - -TEST(Dilithium3Test, SIGOperations) { - // Test basic functionality for Dilithium3 - // Generate a Dilithium3 key - EVP_PKEY_CTX *dilithium_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - ASSERT_NE(dilithium_pkey_ctx, nullptr); - - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey, nullptr); - - EXPECT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx)); - EXPECT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx, &dilithium_pkey)); - - // Sign a message - bssl::ScopedEVP_MD_CTX md_ctx; - uint8_t signature[DILITHIUM3_SIGNATURE_BYTES]; - size_t signature_len = DILITHIUM3_SIGNATURE_BYTES; - std::vector msg = { - 0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49, - 0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x32, 0x2e}; - std::vector badmsg = { - 0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49, - 0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x31, 0x2e}; - - ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), NULL, NULL, NULL, dilithium_pkey)); - ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature, &signature_len, - msg.data(), msg.size())); - - // Verify the correct signed message - ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), signature, signature_len, - msg.data(), msg.size())); - - // Verify the signed message fails upon a bad message - ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature, signature_len, - badmsg.data(), badmsg.size())); - - // Sign the bad message - uint8_t signature1[DILITHIUM3_SIGNATURE_BYTES]; - ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature1, &signature_len, - badmsg.data(), badmsg.size())); - - // Check that the two signatures are not equal - EXPECT_NE(0, OPENSSL_memcmp(signature, signature1, signature_len)); - - // Verify the signed message fails upon a bad signature - ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature1, signature_len, - msg.data(), msg.size())); - - EVP_PKEY_free(dilithium_pkey); - EVP_PKEY_CTX_free(dilithium_pkey_ctx); - md_ctx.Reset(); -} - -struct ML_DSA { - const char name[20]; - const int nid; - const size_t public_key_len; - const size_t secret_key_len; - const size_t signature_len; - const char *kat_filename; -}; - -static const struct ML_DSA parameterSet[] = { - {"MLDSA65", NID_DILITHIUM3_R3, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt"}, -}; - -class MLDSAParameterTest : public testing::TestWithParam {}; - -INSTANTIATE_TEST_SUITE_P(All, MLDSAParameterTest, testing::ValuesIn(parameterSet), - [](const testing::TestParamInfo ¶ms) - -> std::string { return params.param.name; }); - - -TEST_P(MLDSAParameterTest, KAT) { - std::string kat_filepath = "crypto/"; - kat_filepath += GetParam().kat_filename; - - FileTestGTest(kat_filepath.c_str(), [&](FileTest *t) { - std::string count, mlen, smlen; - std::vector seed, msg, pk, sk, sm; - - ASSERT_TRUE(t->GetAttribute(&count, "count")); - ASSERT_TRUE(t->GetBytes(&seed, "seed")); - ASSERT_TRUE(t->GetAttribute(&mlen, "mlen")); - ASSERT_TRUE(t->GetBytes(&msg, "msg")); - ASSERT_TRUE(t->GetBytes(&pk, "pk")); - ASSERT_TRUE(t->GetBytes(&sk, "sk")); - ASSERT_TRUE(t->GetAttribute(&smlen, "smlen")); - ASSERT_TRUE(t->GetBytes(&sm, "sm")); - - size_t pk_len = GetParam().public_key_len; - size_t sk_len = GetParam().secret_key_len; - size_t sig_len = GetParam().signature_len; - - // The KAT files generated by the dilithium team use the optional APIs that - // create a signature for a message m and append the message to the end of - // the signature. We only want to bring the APIs that create and verify just - // the signature, therefore each signature is a constant - // DILITHIUM3_SIGNATURE_BYTES and we truncate the signed message down to a - // constant DILITHIUM3_SIGNATURE_BYTES. - - std::vector signature(sig_len); - sm.resize(sig_len); - - // Convert string read from KAT to int - size_t mlen_int = std::stoi(mlen); - - // Here we fix the DRBG (AES-CTR) so that we are able to seed it with the - // seed from the KAT (testing only) - pq_custom_randombytes_use_deterministic_for_testing(); - pq_custom_randombytes_init_for_testing(seed.data()); - - // Generate our dilithium public and private key pair - EVP_PKEY_CTX *dilithium_pkey_ctx = EVP_PKEY_CTX_new_id(GetParam().nid, nullptr); - ASSERT_NE(dilithium_pkey_ctx, nullptr); - - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey, nullptr); - - ASSERT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx)); - ASSERT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx, &dilithium_pkey)); - const DILITHIUM3_KEY *dilithium3Key = (DILITHIUM3_KEY *)(dilithium_pkey->pkey.ptr); //called dilithium3 but is generic - EXPECT_EQ(Bytes(pk), Bytes(dilithium3Key->pub, pk_len)); - EXPECT_EQ(Bytes(sk), Bytes(dilithium3Key->priv, sk_len)); - - // Generate a signature for the message - bssl::ScopedEVP_MD_CTX md_ctx; - // We have to use EVP_DigestSign because dilithium supports the use of - // non-hash-then-sign (just like ed25519) so we first init EVP_DigestSign - // WITHOUT a hash function. - ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), NULL, NULL, NULL, dilithium_pkey)); - ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature.data(), &sig_len, msg.data(), mlen_int)); - EXPECT_EQ(Bytes(sm), Bytes(signature.data(), sig_len)); - - // Verify the signature for the message - ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), signature.data(), sig_len, msg.data(), mlen_int)); - - EVP_PKEY_free(dilithium_pkey); - EVP_PKEY_CTX_free(dilithium_pkey_ctx); - md_ctx.Reset(); - }); -} - -#else - -TEST(Dilithium3Test, EvpDisabled) { - ASSERT_EQ(nullptr, EVP_PKEY_CTX_new_id(NID_DILITHIUM3_R3, nullptr)); - bssl::UniquePtr pkey(EVP_PKEY_new()); - ASSERT_FALSE(EVP_PKEY_set_type(pkey.get(), NID_DILITHIUM3_R3)); -} - -#endif diff --git a/crypto/dilithium/p_pqdsa.c b/crypto/dilithium/p_pqdsa.c new file mode 100644 index 0000000000..c44cd6d692 --- /dev/null +++ b/crypto/dilithium/p_pqdsa.c @@ -0,0 +1,287 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include +#include +#include + +#include "../crypto/internal.h" +#include "../fipsmodule/evp/internal.h" +#include "../evp_extra/internal.h" +#include "ml_dsa.h" +#include "internal.h" + +// PQDSA PKEY functions + +typedef struct { + const PQDSA *pqdsa; +} PQDSA_PKEY_CTX; + +static int pkey_pqdsa_init(EVP_PKEY_CTX *ctx) { + PQDSA_PKEY_CTX *dctx; + dctx = OPENSSL_zalloc(sizeof(PQDSA_PKEY_CTX)); + if (dctx == NULL) { + return 0; + } + + ctx->data = dctx; + + return 1; +} + +static void pkey_pqdsa_cleanup(EVP_PKEY_CTX *ctx) { + OPENSSL_free(ctx->data); +} + +static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + GUARD_PTR(ctx); + PQDSA_PKEY_CTX *dctx = ctx->data; + GUARD_PTR(dctx); + const PQDSA *pqdsa = dctx->pqdsa; + if (pqdsa == NULL) { + if (ctx->pkey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key); + } + + PQDSA_KEY *key = PQDSA_KEY_new(); + if (key == NULL || + !PQDSA_KEY_init(key, pqdsa) || + !pqdsa->method->keygen(key->public_key, key->private_key) || + !EVP_PKEY_assign(pkey, EVP_PKEY_PQDSA, key)) { + PQDSA_KEY_free(key); + return 0; + } + return 1; +} + +static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, + size_t *sig_len, const uint8_t *message, + size_t message_len) { + PQDSA_PKEY_CTX *dctx = ctx->data; + const PQDSA *pqdsa = dctx->pqdsa; + if (pqdsa == NULL) { + if (ctx->pkey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key); + } + + // Caller is getting parameter values. + if (sig == NULL) { + if (sig_len != NULL) { + *sig_len = pqdsa->signature_len; + return 1; + } + } + + if (*sig_len != pqdsa->signature_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + // Check that the context is properly configured. + if (ctx->pkey == NULL || + ctx->pkey->pkey.pqdsa_key == NULL || + ctx->pkey->type != EVP_PKEY_PQDSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + + PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; + if (!key->private_key) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET); + return 0; + } + + if (!pqdsa->method->sign(key->private_key, sig, sig_len, message, message_len, NULL, 0)) { + OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); + return 0; + } + return 1; +} + +static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t sig_len, const uint8_t *message, + size_t message_len) { + PQDSA_PKEY_CTX *dctx = ctx->data; + const PQDSA *pqdsa = dctx->pqdsa; + + if (pqdsa == NULL) { + if (ctx->pkey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key); + } + // Check that the context is properly configured. + if (ctx->pkey == NULL || + ctx->pkey->pkey.pqdsa_key == NULL || + ctx->pkey->type != EVP_PKEY_PQDSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + + PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; + + if (sig_len != pqdsa->signature_len || + !pqdsa->method->verify(key->public_key, sig, sig_len, message, message_len, NULL, 0)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); + return 0; + } + + return 1; +} + +// Additional PQDSA specific EVP functions. + +// This function sets pqdsa parameters defined by |nid| in |pkey|. +int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid) { + const PQDSA *pqdsa = PQDSA_find_dsa_by_nid(nid); + + if (pqdsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + return 0; + } + + evp_pkey_set_method(pkey, &pqdsa_asn1_meth); + + PQDSA_KEY *key = PQDSA_KEY_new(); + if (key == NULL) { + // PQDSA_KEY_new sets the appropriate error. + return 0; + } + + key->pqdsa = pqdsa; + pkey->pkey.pqdsa_key = key; + + return 1; +} + +// Takes an EVP_PKEY_CTX object |ctx| and sets pqdsa parameters defined +// by |nid| +int EVP_PKEY_CTX_pqdsa_set_params(EVP_PKEY_CTX *ctx, int nid) { + if (ctx == NULL || ctx->data == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + // It's not allowed to change context parameters if + // a PKEY is already associated with the context. + if (ctx->pkey != NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION); + return 0; + } + + const PQDSA *pqdsa = PQDSA_find_dsa_by_nid(nid); + if (pqdsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + return 0; + } + + PQDSA_PKEY_CTX *dctx = ctx->data; + dctx->pqdsa = pqdsa; + + return 1; +} + +// Returns a fresh EVP_PKEY object of type EVP_PKEY_PQDSA, +// and sets PQDSA parameters defined by |nid|. +static EVP_PKEY *EVP_PKEY_pqdsa_new(int nid) { + EVP_PKEY *ret = EVP_PKEY_new(); + if (ret == NULL || !EVP_PKEY_pqdsa_set_params(ret, nid)) { + EVP_PKEY_free(ret); + return NULL; + } + + return ret; +} + +EVP_PKEY *EVP_PKEY_pqdsa_new_raw_public_key(int nid, const uint8_t *in, size_t len) { + if (in == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + EVP_PKEY *ret = EVP_PKEY_pqdsa_new(nid); + if (ret == NULL || ret->pkey.pqdsa_key == NULL) { + // EVP_PKEY_pqdsa_new sets the appropriate error. + goto err; + } + + const PQDSA *pqdsa = PQDSA_KEY_get0_dsa(ret->pkey.pqdsa_key); + if (pqdsa->public_key_len != len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); + goto err; + } + + if (!PQDSA_KEY_set_raw_public_key(ret->pkey.pqdsa_key, in)) { + // PQDSA_KEY_set_raw_public_key sets the appropriate error. + goto err; + } + + return ret; + + err: + EVP_PKEY_free(ret); + return NULL; +} + +EVP_PKEY *EVP_PKEY_pqdsa_new_raw_private_key(int nid, const uint8_t *in, size_t len) { + if (in == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + EVP_PKEY *ret = EVP_PKEY_pqdsa_new(nid); + if (ret == NULL || ret->pkey.pqdsa_key == NULL) { + // EVP_PKEY_kem_new sets the appropriate error. + goto err; + } + + const PQDSA *pqdsa = PQDSA_KEY_get0_dsa(ret->pkey.pqdsa_key); + if (pqdsa->private_key_len != len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); + goto err; + } + + if (!PQDSA_KEY_set_raw_private_key(ret->pkey.pqdsa_key, in)) { + // PQDSA_KEY_set_raw_private_key sets the appropriate error. + goto err; + } + + return ret; + + err: + EVP_PKEY_free(ret); + return NULL; +} + +const EVP_PKEY_METHOD pqdsa_pkey_meth = { + EVP_PKEY_PQDSA, + pkey_pqdsa_init /* init */, + NULL /* copy */, + pkey_pqdsa_cleanup /* cleanup */, + pkey_pqdsa_keygen, + NULL /* sign_init */, + NULL /* sign */, + pkey_pqdsa_sign_message, + NULL /* verify_init */, + NULL /* verify */, + pkey_pqdsa_verify_signature, + NULL /* verify_recover */, + NULL /* encrypt */, + NULL /* decrypt */, + NULL /* derive */, + NULL /* paramgen */, + NULL /* ctrl */, + NULL /* ctrl_str */, + NULL /* keygen deterministic */, + NULL /* encapsulate deterministic */, + NULL /* encapsulate */, + NULL /* decapsulate */, +}; diff --git a/crypto/dilithium/p_pqdsa_asn1.c b/crypto/dilithium/p_pqdsa_asn1.c new file mode 100644 index 0000000000..ffb0a5a764 --- /dev/null +++ b/crypto/dilithium/p_pqdsa_asn1.c @@ -0,0 +1,223 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include + +#include +#include +#include + +#include "../evp_extra/internal.h" +#include "../fipsmodule/evp/internal.h" +#include "../internal.h" +#include "ml_dsa.h" +#include "internal.h" + +static void pqdsa_free(EVP_PKEY *pkey) { + PQDSA_KEY_free(pkey->pkey.pqdsa_key); + pkey->pkey.pqdsa_key = NULL; +} + +static int pqdsa_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, + size_t *out_len) { + if (pkey->pkey.pqdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + PQDSA_KEY *key = pkey->pkey.pqdsa_key; + const PQDSA *pqdsa = key->pqdsa; + + if (key->private_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + return 0; + } + + if (pqdsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + if (out == NULL) { + *out_len = key->pqdsa->private_key_len; + return 1; + } + + if (*out_len < key->pqdsa->private_key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + OPENSSL_memcpy(out, key->private_key, pqdsa->private_key_len); + *out_len = pqdsa->private_key_len; + return 1; +} + +static int pqdsa_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, + size_t *out_len) { + if (pkey->pkey.pqdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + PQDSA_KEY *key = pkey->pkey.pqdsa_key; + const PQDSA *pqdsa = key->pqdsa; + + if (pqdsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + if (key->public_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + + if (out == NULL) { + *out_len = pqdsa->public_key_len; + return 1; + } + + if (*out_len < key->pqdsa->public_key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + OPENSSL_memcpy(out, key->public_key, pqdsa->public_key_len); + *out_len = pqdsa->public_key_len; + return 1; +} + +static int pqdsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { + // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 4. + // the only parameter that can be included is the OID which has length 9 + if (CBS_len(params) != 9) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + // set the pqdsa params on the fresh pkey + if (!EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(params))) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + return PQDSA_KEY_set_raw_public_key(out->pkey.pqdsa_key,CBS_data(key)); +} + +static int pqdsa_pub_encode(CBB *out, const EVP_PKEY *pkey) { + PQDSA_KEY *key = pkey->pkey.pqdsa_key; + const PQDSA *pqdsa = key->pqdsa; + if (key->public_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + + // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 4. + // TODO: finalize this definition - OCTETSTRING to BITSTRING conversion. + CBB spki, algorithm, oid, key_bitstring; + if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, pqdsa->oid, pqdsa->oid_len) || + !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || + !CBB_add_u8(&key_bitstring, 0 /* padding */) || + !CBB_add_bytes(&key_bitstring, key->public_key, pqdsa->public_key_len) || + !CBB_flush(out)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); + return 0; + } + + return 1; +} + +static int pqdsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + PQDSA_KEY *a_key = a->pkey.pqdsa_key; + PQDSA_KEY *b_key = b->pkey.pqdsa_key; + + return OPENSSL_memcmp(a_key->public_key, + b_key->public_key, + a->pkey.pqdsa_key->pqdsa->public_key_len) == 0; +} + +static int pqdsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey) { + // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 6. + // the only parameter that can be included is the OID which has length 9 + if (CBS_len(params) != 9 ) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + // set the pqdsa params on the fresh pkey + if (!EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(params))) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + return PQDSA_KEY_set_raw_private_key(out->pkey.pqdsa_key,CBS_data(key)); +} + +static int pqdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { + PQDSA_KEY *key = pkey->pkey.pqdsa_key; + const PQDSA *pqdsa = key->pqdsa; + if (key->private_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + return 0; + } + // See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 6. + CBB pkcs8, algorithm, oid, private_key; + if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || + !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, pqdsa->oid, pqdsa->oid_len) || + !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&private_key, key->private_key, pqdsa->private_key_len) || + !CBB_flush(out)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); + return 0; + } + + return 1; +} + +static int pqdsa_size(const EVP_PKEY *pkey) { + if (pkey->pkey.pqdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + return pkey->pkey.pqdsa_key->pqdsa->signature_len; +} + +static int pqdsa_bits(const EVP_PKEY *pkey) { + if (pkey->pkey.pqdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + return 8 * (pkey->pkey.pqdsa_key->pqdsa->public_key_len); +} + +const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth = { + //2.16.840.1.101.3.4.3 + EVP_PKEY_PQDSA, + + {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03}, + 8, + + "PQ DSA", + "AWS-LC PQ DSA method", + + pqdsa_pub_decode, + pqdsa_pub_encode, + pqdsa_pub_cmp, + pqdsa_priv_decode, + pqdsa_priv_encode, + NULL /*priv_encode_v2*/, + NULL /* pqdsa_set_priv_raw */, + NULL /*pqdsa_set_pub_raw */ , + pqdsa_get_priv_raw, + pqdsa_get_pub_raw, + NULL /* pkey_opaque */, + pqdsa_size, + pqdsa_bits, + NULL /* param_missing */, + NULL /* param_copy */, + NULL /* param_cmp */, + pqdsa_free, +}; diff --git a/crypto/dilithium/p_pqdsa_test.cc b/crypto/dilithium/p_pqdsa_test.cc new file mode 100644 index 0000000000..a343d2969b --- /dev/null +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -0,0 +1,746 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include +#include +#include +#include +#include +#include +#include "../test/test_util.h" + +#include +#include "../crypto/evp_extra/internal.h" +#include "../fipsmodule/evp/internal.h" +#include "../internal.h" +#include "internal.h" + +#ifdef ENABLE_DILITHIUM + +#include "../test/file_test.h" +#include "../test/test_util.h" +#include "../rand_extra/pq_custom_randombytes.h" +#include "ml_dsa.h" + +// mldsa65kPublicKey is an example ML-DSA-65 public key +static const uint8_t mldsa65kPublicKey[] = { +0x9B, 0x77, 0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x2, 0x9B, 0xA5, +0xD4, 0xE5, 0x93, 0xA1, 0xAC, 0xE7, 0x3E, 0x8C, 0x61, 0xB7, 0xCB, 0xA1, 0x3E, +0x74, 0x8A, 0xC9, 0xC0, 0xA0, 0x63, 0x4A, 0xF6, 0xF4, 0x1C, 0x72, 0x37, 0xB0, +0x31, 0x9E, 0xB7, 0x51, 0x55, 0xCF, 0x5B, 0x4E, 0x3, 0x46, 0x7C, 0x26, 0xBE, +0x84, 0x73, 0xD8, 0x50, 0xDF, 0x72, 0x87, 0xC0, 0x18, 0xED, 0xE7, 0xE4, 0x12, +0x4F, 0xCA, 0x4E, 0x1A, 0xFA, 0x76, 0x82, 0xD4, 0xA6, 0x3E, 0xDA, 0xEC, 0x74, +0x53, 0xFF, 0xDD, 0x69, 0x5C, 0x9F, 0xFD, 0x69, 0xA3, 0xED, 0x4F, 0xEB, 0xFB, +0xEF, 0xD2, 0x98, 0x8B, 0x45, 0x6, 0xBA, 0xD5, 0xF8, 0x9E, 0xA, 0x2D, 0xA2, +0xC7, 0x96, 0x4B, 0x79, 0xE9, 0xA9, 0xA6, 0x73, 0x69, 0xF8, 0x8C, 0x1, 0x69, +0xF2, 0x66, 0x5, 0x37, 0x31, 0x65, 0xA9, 0x9, 0x3E, 0xE, 0x73, 0x95, 0x67, +0xC9, 0x33, 0xA6, 0x57, 0xDF, 0xDD, 0xC0, 0x55, 0x1A, 0x89, 0x6F, 0xC8, 0x30, +0x71, 0x68, 0x3C, 0x2A, 0x7E, 0x61, 0x86, 0xAC, 0x70, 0x6A, 0x27, 0x31, 0x9B, +0x9A, 0xEC, 0x8F, 0x37, 0x2B, 0x71, 0x91, 0x91, 0x6C, 0x8B, 0x35, 0xED, 0xF1, +0x97, 0x87, 0x58, 0xD1, 0x4F, 0xF2, 0x6, 0x23, 0xE6, 0x1C, 0x44, 0x63, 0x2, +0x9E, 0x9, 0x76, 0x6C, 0x72, 0xBD, 0xD, 0xB3, 0xE2, 0x1D, 0x92, 0xAA, 0x8D, +0x7B, 0x78, 0xD8, 0xB3, 0xA7, 0x5A, 0xAB, 0xBF, 0x22, 0xBB, 0x30, 0x5B, 0xFB, +0xB4, 0x3C, 0x52, 0xD2, 0xA2, 0xED, 0x3B, 0x99, 0x43, 0xCB, 0x29, 0x66, 0x2A, +0xBD, 0x52, 0x1B, 0x1C, 0xB4, 0xE5, 0xE3, 0x6E, 0xFF, 0xAD, 0xEF, 0x8B, 0xE1, +0xF9, 0xB5, 0x5E, 0xCB, 0xF2, 0x8E, 0xCD, 0x53, 0x39, 0xBE, 0xBE, 0x61, 0x72, +0x86, 0x31, 0x65, 0xA0, 0xFC, 0xC1, 0xFC, 0x31, 0x79, 0x93, 0xDF, 0x76, 0x13, +0x71, 0xE4, 0x61, 0xF, 0x6B, 0x32, 0x78, 0xD2, 0x24, 0xB7, 0x8C, 0xE8, 0x84, +0xE3, 0xB8, 0xF6, 0x4, 0xF3, 0x30, 0xE9, 0x5B, 0xA5, 0xD8, 0x94, 0xA7, 0xA3, +0xF0, 0xE8, 0xAC, 0x70, 0x32, 0x42, 0xB5, 0x8, 0xEE, 0x2A, 0x77, 0xFA, 0x4, +0x49, 0xE9, 0x7A, 0xB7, 0xA, 0x95, 0x5, 0x86, 0x33, 0xA5, 0xE4, 0x5A, 0xC6, +0xE1, 0xE7, 0x48, 0xBD, 0xBA, 0x80, 0xE7, 0x21, 0x61, 0x45, 0x24, 0x5E, 0xA9, +0x7F, 0x2D, 0x75, 0xF, 0xE9, 0xEE, 0x79, 0x88, 0x64, 0xF3, 0xE7, 0xC, 0xA0, +0xEB, 0x93, 0x2C, 0x6B, 0xD3, 0x51, 0x12, 0xE7, 0x62, 0x8D, 0x71, 0x10, 0x6D, +0x5B, 0x3A, 0x27, 0xF4, 0xEA, 0x80, 0xFC, 0xCD, 0x58, 0x81, 0x43, 0xEB, 0xA0, +0x4E, 0xF5, 0xA1, 0x68, 0x67, 0x74, 0x7C, 0x14, 0x12, 0xA6, 0x78, 0xC2, 0x8, +0x58, 0x3F, 0x20, 0x96, 0x52, 0xD2, 0x61, 0xDA, 0xED, 0x5F, 0x7F, 0xAD, 0x40, +0x93, 0x21, 0xEB, 0xC4, 0x37, 0x5C, 0xD1, 0x72, 0xE6, 0x6, 0x37, 0xD9, 0xF6, +0x9, 0xD4, 0xC9, 0x6D, 0xED, 0x7, 0xF6, 0xD2, 0x15, 0x94, 0xFD, 0xF6, 0xC3, +0x9, 0x60, 0x6D, 0x6A, 0x23, 0x50, 0x8C, 0xDD, 0x61, 0xDD, 0x66, 0x81, 0xB0, +0xAC, 0x7C, 0xE7, 0x7F, 0xED, 0x3C, 0x2F, 0x19, 0xB5, 0xF9, 0xB7, 0x2E, 0x35, +0xF7, 0xF4, 0x98, 0xE, 0x6A, 0x9E, 0x6D, 0xAC, 0xF1, 0xF, 0x90, 0x25, 0xED, +0xC5, 0x94, 0x9E, 0x10, 0x29, 0x97, 0x47, 0x5, 0x3D, 0x3, 0x6F, 0x69, 0xAE, +0x84, 0x8, 0x9B, 0x33, 0xC, 0x1F, 0x26, 0x65, 0xC7, 0x86, 0x25, 0x10, 0x11, +0x97, 0x33, 0x3D, 0x98, 0x43, 0xB5, 0x7F, 0x9C, 0x19, 0x62, 0xE5, 0x46, 0x6D, +0x3B, 0xA2, 0xDC, 0xD4, 0x17, 0x85, 0x9A, 0xE8, 0x2C, 0xF3, 0x1, 0x5F, 0x39, +0xD1, 0xBC, 0x7, 0x8E, 0xAC, 0xC9, 0x28, 0xC, 0x7B, 0xD8, 0x2, 0xFE, 0x46, +0x12, 0xA8, 0xBD, 0xE, 0x6B, 0x23, 0x65, 0x5B, 0xAA, 0xFC, 0x32, 0x20, 0xF7, +0xCC, 0xC7, 0x6, 0x80, 0x9, 0xA, 0x95, 0xD9, 0x69, 0xED, 0x3C, 0x6C, 0xEB, +0x62, 0x28, 0xE6, 0x4E, 0xF4, 0xFA, 0x9B, 0x5C, 0x36, 0x7, 0xE0, 0x25, 0x20, +0xB8, 0xF4, 0x1F, 0x2E, 0x78, 0x21, 0xEE, 0xFA, 0x9E, 0x80, 0x14, 0xAD, 0xAD, +0x83, 0x39, 0x2E, 0xD0, 0xE9, 0x56, 0xE3, 0x88, 0xC, 0xC4, 0xD7, 0xBE, 0xB1, +0xE4, 0xD0, 0x42, 0xE6, 0xED, 0xDC, 0x44, 0x65, 0x51, 0x1F, 0x95, 0x9A, 0xAA, +0xBF, 0x83, 0x7B, 0xD7, 0x14, 0x23, 0x18, 0x81, 0x91, 0xA, 0x7, 0x97, 0x10, +0x6F, 0x3C, 0x16, 0xF2, 0xF0, 0x3E, 0xE1, 0x45, 0x40, 0xB0, 0x39, 0x98, 0x33, +0x55, 0xFF, 0x7E, 0x75, 0x31, 0xE0, 0x10, 0x16, 0x81, 0x36, 0x56, 0x86, 0x34, +0x1C, 0x61, 0x10, 0x25, 0xAE, 0x98, 0x6E, 0xBE, 0xC9, 0x47, 0xCD, 0x14, 0x1C, +0x52, 0x8C, 0x27, 0xEE, 0x28, 0xDA, 0x18, 0x96, 0x4D, 0x16, 0x6D, 0x17, 0x2E, +0x5B, 0x7E, 0x88, 0x70, 0xC8, 0x3D, 0x31, 0x34, 0xE5, 0xEA, 0x8, 0x40, 0x25, +0x7B, 0x3, 0x75, 0x47, 0xAD, 0x19, 0x2, 0x7E, 0xCC, 0xB6, 0x43, 0xD1, 0xC9, +0xB2, 0x95, 0x7F, 0x9F, 0x93, 0xC4, 0xD7, 0x33, 0x5A, 0x7E, 0xA4, 0x51, 0x58, +0xC5, 0xA7, 0x23, 0x25, 0xF8, 0xF4, 0xDE, 0xEF, 0x84, 0x72, 0xE, 0x8D, 0xE7, +0x9E, 0x1E, 0x40, 0xB3, 0xA6, 0x58, 0x34, 0x4E, 0xB8, 0x56, 0x6B, 0xA1, 0x50, +0x2B, 0x1C, 0xF9, 0xA6, 0x88, 0x21, 0x34, 0x79, 0x99, 0x5F, 0x24, 0xD6, 0x96, +0x67, 0xB5, 0x7E, 0x9C, 0xD2, 0xFB, 0x11, 0x40, 0xA6, 0xE6, 0x20, 0xD2, 0x8C, +0x38, 0x62, 0x9B, 0xC1, 0xD7, 0x57, 0x42, 0xE0, 0xD7, 0x34, 0xF3, 0x90, 0xF9, +0x60, 0xDD, 0xEA, 0x24, 0x67, 0x6A, 0xC0, 0xC7, 0xEF, 0xA7, 0x1B, 0xDC, 0xAD, +0x3D, 0xD, 0x17, 0x90, 0x66, 0x70, 0xB2, 0x98, 0x24, 0x1B, 0x58, 0x79, 0xAC, +0x3E, 0x61, 0x9C, 0x67, 0xB4, 0xEE, 0x9, 0x6, 0x20, 0xCE, 0x39, 0x3, 0x57, +0xD4, 0xB5, 0x44, 0x3C, 0x35, 0x80, 0xDD, 0xEF, 0xC3, 0xC5, 0xC4, 0x93, 0x79, +0xF8, 0x84, 0x60, 0x31, 0x27, 0xB7, 0xF8, 0xEB, 0x63, 0xE8, 0x75, 0x74, 0x31, +0x29, 0xF4, 0xE7, 0x6, 0x51, 0x74, 0x72, 0x71, 0x9D, 0xA1, 0x3F, 0x3C, 0x73, +0xCF, 0x7, 0xA9, 0x98, 0x23, 0x1F, 0x62, 0x9C, 0x9E, 0x27, 0xFD, 0x1E, 0xC8, +0x1C, 0xB9, 0xBD, 0x16, 0xB5, 0x4C, 0x1A, 0xC2, 0x8D, 0xCF, 0x4D, 0xB8, 0xC2, +0x4D, 0x94, 0xE6, 0x12, 0x6D, 0x14, 0xFA, 0x2B, 0xF4, 0x4A, 0x2B, 0xD9, 0x7D, +0xEF, 0xF8, 0x81, 0x2C, 0xF7, 0x7B, 0x98, 0x44, 0x12, 0x58, 0xD5, 0x82, 0xAA, +0xED, 0x49, 0x40, 0x87, 0xBA, 0x11, 0x29, 0x7E, 0xFD, 0x4, 0x67, 0x20, 0x5D, +0x2B, 0x79, 0x42, 0x7, 0x3, 0x5C, 0x36, 0xD7, 0xBE, 0x72, 0xCA, 0x13, 0xCF, +0x93, 0x2D, 0xD8, 0xA9, 0xEE, 0x6, 0xB, 0xCF, 0x5A, 0x46, 0x88, 0x57, 0x9E, +0x18, 0x92, 0x3B, 0x5F, 0x2F, 0x86, 0xCD, 0x3D, 0x49, 0xF6, 0xA3, 0x5, 0xE6, +0xE4, 0x68, 0xA4, 0x79, 0xA6, 0xEE, 0x85, 0xF4, 0x2B, 0xF6, 0x6E, 0x1B, 0x7A, +0xBD, 0x77, 0xEA, 0x6A, 0xC9, 0x31, 0x34, 0x8E, 0x5F, 0xC2, 0xF3, 0x87, 0x3D, +0x8F, 0xD7, 0xB0, 0x16, 0x28, 0x3F, 0x2C, 0x87, 0xA0, 0xA3, 0x56, 0xE8, 0x21, +0x83, 0x53, 0xCB, 0xE9, 0x1D, 0x28, 0x57, 0x93, 0xDB, 0x5B, 0xE9, 0xF0, 0x7B, +0x7F, 0xF4, 0x6A, 0x51, 0x48, 0xFC, 0xAB, 0xF5, 0x3B, 0x44, 0xA7, 0x5E, 0x67, +0x3A, 0x6B, 0x43, 0x9C, 0xD1, 0x3, 0xDF, 0xF8, 0xD5, 0x7F, 0x7B, 0x9, 0x62, +0xBF, 0x28, 0xBD, 0xC6, 0x3E, 0xC3, 0x6C, 0x91, 0x1, 0x45, 0x3F, 0xE2, 0x1F, +0xEF, 0x2A, 0x8F, 0xB2, 0x1B, 0x72, 0x35, 0x4D, 0x18, 0x6F, 0x4D, 0x57, 0xBF, +0x6A, 0x69, 0x2, 0x69, 0x4A, 0xE5, 0x5F, 0x74, 0xF7, 0x69, 0x5B, 0x89, 0x8, +0xCE, 0xCE, 0x15, 0x56, 0x3F, 0x21, 0x1A, 0xB8, 0xEC, 0x4D, 0xB0, 0x7E, 0xF, +0x89, 0xB0, 0x5C, 0x6D, 0xDB, 0x53, 0x9E, 0xA9, 0x27, 0x28, 0x52, 0xE5, 0x9E, +0x1F, 0xEF, 0x84, 0x1A, 0x9A, 0xAE, 0x86, 0x8B, 0x25, 0x3B, 0xC6, 0x3B, 0x8E, +0x9C, 0x32, 0xD9, 0x89, 0x3B, 0xA2, 0xCB, 0x59, 0x35, 0xC3, 0x71, 0xEE, 0x22, +0xC, 0x61, 0xEA, 0x59, 0x33, 0x25, 0x39, 0xAF, 0xF0, 0x12, 0x81, 0x55, 0x4A, +0x9D, 0xC, 0x3E, 0x5E, 0x34, 0x9F, 0xA7, 0xD8, 0xC5, 0xB5, 0xA, 0xC3, 0xA2, +0x0, 0x3F, 0x59, 0x3D, 0x7, 0x5F, 0x2B, 0xC1, 0x6F, 0x6A, 0xE3, 0x94, 0x90, +0xAF, 0x81, 0x11, 0x82, 0x89, 0xF4, 0x9D, 0x8B, 0x5, 0xE2, 0x7C, 0x22, 0x2, +0xEC, 0x0, 0x38, 0x39, 0xED, 0x4, 0xB2, 0xC9, 0xD8, 0xA1, 0x1B, 0xED, 0xB9, +0xE1, 0x62, 0x82, 0xC4, 0xCC, 0xA0, 0x61, 0xEE, 0x7A, 0x17, 0xA0, 0x99, 0xAC, +0xAC, 0x85, 0xA7, 0x5F, 0xC9, 0xC3, 0xC5, 0x63, 0x8F, 0x5A, 0xE7, 0x41, 0xAC, +0xB7, 0x89, 0x13, 0x38, 0xD8, 0x58, 0xBF, 0x71, 0xA5, 0x4F, 0x9D, 0x4C, 0x72, +0x57, 0x88, 0x2E, 0xAB, 0xD4, 0x74, 0xDE, 0x46, 0x9F, 0xF4, 0xBA, 0xB1, 0x55, +0x6A, 0x18, 0xF4, 0x87, 0xB9, 0x24, 0xA7, 0xD9, 0xF4, 0x9A, 0x3C, 0xEF, 0xF4, +0xA2, 0x2D, 0xF, 0xC9, 0xE4, 0x45, 0xC2, 0xC9, 0x6F, 0x2D, 0xB6, 0xDA, 0xE6, +0x89, 0x38, 0x80, 0x2A, 0x89, 0xE2, 0xF5, 0x3D, 0x77, 0x5E, 0x61, 0x6E, 0x9C, +0xF9, 0x87, 0x89, 0xD4, 0x70, 0x23, 0x79, 0x93, 0xDA, 0xCE, 0x62, 0x89, 0xEB, +0x13, 0x77, 0xB0, 0x49, 0xB2, 0xF9, 0xFC, 0x84, 0xD3, 0x6, 0xD2, 0x8D, 0x5A, +0x94, 0x64, 0xC1, 0xA8, 0x9A, 0x60, 0x57, 0x8A, 0x8F, 0x62, 0x4A, 0x78, 0x12, +0x6B, 0x87, 0x6F, 0x6D, 0xC8, 0x32, 0xF3, 0xC6, 0x8D, 0xDB, 0x3A, 0x67, 0x95, +0xCD, 0xAF, 0x48, 0x28, 0x79, 0xC2, 0xB6, 0xDB, 0xD8, 0xFE, 0x82, 0x15, 0xE6, +0xE4, 0xEC, 0x79, 0xE2, 0xB4, 0x21, 0x5C, 0x30, 0x45, 0xD7, 0x3B, 0xA0, 0x1A, +0x3B, 0xAA, 0x3D, 0x6C, 0x1C, 0xC3, 0x1E, 0xDE, 0x4D, 0x75, 0x1D, 0x9A, 0x96, +0x51, 0xF9, 0x4F, 0x10, 0x28, 0x7E, 0x88, 0xEE, 0x3B, 0x93, 0x4A, 0xB, 0x9, +0x44, 0x9C, 0x20, 0x34, 0xF6, 0xEE, 0x6F, 0x26, 0xB9, 0x4C, 0x76, 0xCC, 0xE1, +0x6F, 0x9, 0x91, 0xAF, 0x48, 0x8C, 0xC4, 0x31, 0xA2, 0xF9, 0x44, 0x77, 0x19, +0xA7, 0x0, 0x33, 0x77, 0x31, 0xF2, 0xF5, 0xF7, 0x30, 0xDF, 0xAB, 0xFE, 0x7E, +0xE6, 0x83, 0xE1, 0xC9, 0x2A, 0xC8, 0xE0, 0xA6, 0xAC, 0x5A, 0x28, 0x7F, 0xC4, +0xB, 0xEB, 0x55, 0xD9, 0x5D, 0xBD, 0xB5, 0xD2, 0xF6, 0xB4, 0xA9, 0x76, 0x2B, +0x35, 0x10, 0x36, 0x3B, 0xCC, 0x61, 0x6C, 0x79, 0xCE, 0xC3, 0x9A, 0x2, 0x9A, +0x0, 0xBA, 0x43, 0x20, 0x3F, 0x26, 0x36, 0x66, 0x7, 0x11, 0x68, 0x51, 0x47, +0xBE, 0x78, 0xED, 0x4A, 0xFA, 0xBC, 0xDA, 0xCD, 0xFD, 0x2, 0xDB, 0xD1, 0x8B, +0xE0, 0xBD, 0x13, 0xFE, 0xED, 0x26, 0x77, 0xE4, 0x83, 0xAE, 0xB7, 0xAB, 0xFD, +0x2A, 0x5E, 0xA3, 0x28, 0xFD, 0x90, 0x40, 0x3D, 0x34, 0xF7, 0xF8, 0x35, 0x80, +0xF6, 0x6F, 0xA0, 0xE9, 0xCD, 0x9A, 0x54, 0x6F, 0x41, 0xA5, 0xC7, 0xED, 0xEA, +0xDC, 0x52, 0x23, 0xF1, 0x96, 0x19, 0x8E, 0x2B, 0x94, 0x3F, 0xD9, 0x27, 0x60, +0x1E, 0x27, 0xC1, 0x39, 0x68, 0x78, 0x7B, 0x47, 0x8F, 0xCC, 0xCD, 0xBE, 0xE4, +0xBD, 0xB, 0x73, 0x3, 0xFB, 0xFE, 0xC0, 0x50, 0x38, 0x70, 0xDF, 0x81, 0x5D, +0x22, 0x4C, 0x5B, 0xCB, 0x27, 0x5D, 0xD2, 0x94, 0x64, 0xA, 0x88, 0x67, 0x31, +0xE9, 0x8, 0xF0, 0x88, 0x20, 0xF2, 0x86, 0xCA, 0xBD, 0x18, 0x5F, 0x34, 0xD0, +0x96, 0xD, 0x4A, 0x62, 0x4D, 0xBE, 0xE8, 0xA6, 0x4, 0xA6, 0x69, 0xCE, 0xCD, +0xE9, 0x5A, 0x1D, 0xD2, 0xF8, 0xCF, 0x19, 0x6, 0x17, 0x5, 0x82, 0x6B, 0x60, +0x3E, 0x5E, 0x6B, 0x1D, 0x1E, 0x13, 0x51, 0x5D, 0xFE, 0x95, 0x38, 0x33, 0x62, +0x9B, 0xBF, 0xD5, 0x3E, 0x3B, 0x8B, 0xD2, 0x6F, 0x24, 0x6D, 0x24, 0xC9, 0xD, +0x2D, 0x52, 0xBF, 0xDA, 0xCE, 0x5E, 0xFE, 0x9D, 0xB8, 0x5D, 0x61, 0x57, 0xBC, +0x8C, 0x7A, 0x17, 0x75, 0x80, 0xEE, 0x52, 0x2F, 0xF5, 0x25, 0x48, 0x3A, 0x9E, +0x27, 0xF4, 0xEB, 0xE1, 0x1, 0xE4, 0xA7, 0x48, 0x93, 0xAA, 0x92, 0x68, 0xC0, +0x3B, 0x1A, 0x5A, 0xC5, 0x6D, 0xD0, 0x91, 0xB9, 0x8D, 0x44, 0xD4, 0xE1, 0x9C, +0x74, 0xEA, 0x14, 0xFA, 0xF6, 0x1E, 0x1, 0xC0, 0x89, 0x24, 0x90, 0x71, 0xAF, +0xF5, 0x2D, 0x6C, 0x35, 0x13, 0xA6, 0x73, 0x14, 0xAC, 0xE5, 0xAE, 0x88, 0x2F, +0x9D, 0x77, 0x3B, 0x8F, 0x61, 0xB1, 0x47, 0x66, 0x72, 0x14, 0x91, 0x40, 0xD7, +0x50, 0xDC, 0xEA, 0xFF, 0x49, 0x9E, 0x17, 0x75, 0x25, 0x49, 0x7C, 0x57, 0x41, +0xA7, 0x8C, 0x4D, 0x3B, 0x94, 0x9D, 0x65, 0x83, 0x62, 0x6F, 0x16, 0xBF, 0xC, +0x87, 0x3, 0x61, 0xB4, 0x3B, 0x60, 0x6D, 0x7, 0x56, 0xB8, 0x1F, 0x89, 0xAD, +0x0, 0x25, 0x10, 0x4A, 0x34, 0x4C, 0x9A, 0x26, 0xDA, 0x6, 0x25, 0x9C, 0x91, +0xA6, 0xA5, 0xAD, 0x4D, 0x6E, 0xE9, 0x2F, 0x18, 0xC4, 0x1D, 0x9, 0xE1, 0xAA, +0x66, 0x1, 0x31, 0x6D, 0x12, 0x30, 0xED, 0x97, 0x3F, 0x67, 0xCE, 0x4E, 0x26, +0xB, 0xF5, 0x5E, 0x81, 0xA7, 0x1F, 0x83, 0x68, 0x91, 0xC3, 0xD0, 0x4C, 0x2E, +0xD4, 0xDE, 0xEF, 0x34, 0xF9, 0x61, 0x83, 0x6F, 0xD6, 0x6E, 0x40, 0x87, 0x48, +0x7E, 0xCF, 0x56, 0x42, 0x21, 0xBA, 0x40, 0x64, 0x17, 0xFA, 0x97, 0xFF, 0x8D, +0xC8, 0x32, 0xFA, 0xB7, 0x45, 0xB0, 0xEC, 0xBD, 0xE, 0x51, 0x63, 0x90, 0x5, +0x68, 0x7A, 0x45, 0x86, 0x68, 0x2A, 0xE, 0x81, 0x5F, 0xDD, 0x12, 0xAD, 0x48, +0xF6, 0x87, 0x2E, 0x8D, 0xF6, 0x86, 0xC3, 0x6D, 0x69, 0xD5, 0x4E, 0x52, 0x8A, +0x8E, 0xE8, 0x1, 0x56, 0x11, 0xCC, 0x2E, 0x3F, 0xB5, 0x46, 0x1D, 0xF6, 0x6E, +0x4A, 0xEE, 0x1C, 0x60, 0x15, 0x85, 0xF6, 0x40, 0xFD, 0x56, 0xDC, 0x10, 0x1, +0xC3, 0xBD, 0xAE, 0x5A, 0x13, 0x1F, 0x15, 0x16, 0x10, 0x92, 0xC5, 0x2, 0xC2, +0x81, 0xB5, 0x6A, 0x4D, 0x37, 0x29, 0x40, 0x8B, 0xAA, 0x5F, 0xC9, 0x4C, 0x26, +0x7B, 0x2C, 0x21, 0x9E, 0xE2, 0xF2, 0x5A, 0x20, 0x88, 0x3F, 0x40, 0x30, 0xC5, +0x64, 0xE }; + +// mldsa65kPublicKeySPKI is the above example ML-DSA-65 public key encoded +static const uint8_t mldsa65kPublicKeySPKI[] = { +0x30, 0x82, 0x7, 0xB2, 0x30, 0xB, 0x6, 0x9, 0x60, 0x86, 0x48, 0x1, 0x65, +0x3, 0x4, 0x3, 0x12, 0x3, 0x82, 0x7, 0xA1, 0x0, 0x9B, 0x77, 0xAB, 0x96, +0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x2, 0x9B, 0xA5, 0xD4, 0xE5, 0x93, 0xA1, +0xAC, 0xE7, 0x3E, 0x8C, 0x61, 0xB7, 0xCB, 0xA1, 0x3E, 0x74, 0x8A, 0xC9, 0xC0, +0xA0, 0x63, 0x4A, 0xF6, 0xF4, 0x1C, 0x72, 0x37, 0xB0, 0x31, 0x9E, 0xB7, 0x51, +0x55, 0xCF, 0x5B, 0x4E, 0x3, 0x46, 0x7C, 0x26, 0xBE, 0x84, 0x73, 0xD8, 0x50, +0xDF, 0x72, 0x87, 0xC0, 0x18, 0xED, 0xE7, 0xE4, 0x12, 0x4F, 0xCA, 0x4E, 0x1A, +0xFA, 0x76, 0x82, 0xD4, 0xA6, 0x3E, 0xDA, 0xEC, 0x74, 0x53, 0xFF, 0xDD, 0x69, +0x5C, 0x9F, 0xFD, 0x69, 0xA3, 0xED, 0x4F, 0xEB, 0xFB, 0xEF, 0xD2, 0x98, 0x8B, +0x45, 0x6, 0xBA, 0xD5, 0xF8, 0x9E, 0xA, 0x2D, 0xA2, 0xC7, 0x96, 0x4B, 0x79, +0xE9, 0xA9, 0xA6, 0x73, 0x69, 0xF8, 0x8C, 0x1, 0x69, 0xF2, 0x66, 0x5, 0x37, +0x31, 0x65, 0xA9, 0x9, 0x3E, 0xE, 0x73, 0x95, 0x67, 0xC9, 0x33, 0xA6, 0x57, +0xDF, 0xDD, 0xC0, 0x55, 0x1A, 0x89, 0x6F, 0xC8, 0x30, 0x71, 0x68, 0x3C, 0x2A, +0x7E, 0x61, 0x86, 0xAC, 0x70, 0x6A, 0x27, 0x31, 0x9B, 0x9A, 0xEC, 0x8F, 0x37, +0x2B, 0x71, 0x91, 0x91, 0x6C, 0x8B, 0x35, 0xED, 0xF1, 0x97, 0x87, 0x58, 0xD1, +0x4F, 0xF2, 0x6, 0x23, 0xE6, 0x1C, 0x44, 0x63, 0x2, 0x9E, 0x9, 0x76, 0x6C, +0x72, 0xBD, 0xD, 0xB3, 0xE2, 0x1D, 0x92, 0xAA, 0x8D, 0x7B, 0x78, 0xD8, 0xB3, +0xA7, 0x5A, 0xAB, 0xBF, 0x22, 0xBB, 0x30, 0x5B, 0xFB, 0xB4, 0x3C, 0x52, 0xD2, +0xA2, 0xED, 0x3B, 0x99, 0x43, 0xCB, 0x29, 0x66, 0x2A, 0xBD, 0x52, 0x1B, 0x1C, +0xB4, 0xE5, 0xE3, 0x6E, 0xFF, 0xAD, 0xEF, 0x8B, 0xE1, 0xF9, 0xB5, 0x5E, 0xCB, +0xF2, 0x8E, 0xCD, 0x53, 0x39, 0xBE, 0xBE, 0x61, 0x72, 0x86, 0x31, 0x65, 0xA0, +0xFC, 0xC1, 0xFC, 0x31, 0x79, 0x93, 0xDF, 0x76, 0x13, 0x71, 0xE4, 0x61, 0xF, +0x6B, 0x32, 0x78, 0xD2, 0x24, 0xB7, 0x8C, 0xE8, 0x84, 0xE3, 0xB8, 0xF6, 0x4, +0xF3, 0x30, 0xE9, 0x5B, 0xA5, 0xD8, 0x94, 0xA7, 0xA3, 0xF0, 0xE8, 0xAC, 0x70, +0x32, 0x42, 0xB5, 0x8, 0xEE, 0x2A, 0x77, 0xFA, 0x4, 0x49, 0xE9, 0x7A, 0xB7, +0xA, 0x95, 0x5, 0x86, 0x33, 0xA5, 0xE4, 0x5A, 0xC6, 0xE1, 0xE7, 0x48, 0xBD, +0xBA, 0x80, 0xE7, 0x21, 0x61, 0x45, 0x24, 0x5E, 0xA9, 0x7F, 0x2D, 0x75, 0xF, +0xE9, 0xEE, 0x79, 0x88, 0x64, 0xF3, 0xE7, 0xC, 0xA0, 0xEB, 0x93, 0x2C, 0x6B, +0xD3, 0x51, 0x12, 0xE7, 0x62, 0x8D, 0x71, 0x10, 0x6D, 0x5B, 0x3A, 0x27, 0xF4, +0xEA, 0x80, 0xFC, 0xCD, 0x58, 0x81, 0x43, 0xEB, 0xA0, 0x4E, 0xF5, 0xA1, 0x68, +0x67, 0x74, 0x7C, 0x14, 0x12, 0xA6, 0x78, 0xC2, 0x8, 0x58, 0x3F, 0x20, 0x96, +0x52, 0xD2, 0x61, 0xDA, 0xED, 0x5F, 0x7F, 0xAD, 0x40, 0x93, 0x21, 0xEB, 0xC4, +0x37, 0x5C, 0xD1, 0x72, 0xE6, 0x6, 0x37, 0xD9, 0xF6, 0x9, 0xD4, 0xC9, 0x6D, +0xED, 0x7, 0xF6, 0xD2, 0x15, 0x94, 0xFD, 0xF6, 0xC3, 0x9, 0x60, 0x6D, 0x6A, +0x23, 0x50, 0x8C, 0xDD, 0x61, 0xDD, 0x66, 0x81, 0xB0, 0xAC, 0x7C, 0xE7, 0x7F, +0xED, 0x3C, 0x2F, 0x19, 0xB5, 0xF9, 0xB7, 0x2E, 0x35, 0xF7, 0xF4, 0x98, 0xE, +0x6A, 0x9E, 0x6D, 0xAC, 0xF1, 0xF, 0x90, 0x25, 0xED, 0xC5, 0x94, 0x9E, 0x10, +0x29, 0x97, 0x47, 0x5, 0x3D, 0x3, 0x6F, 0x69, 0xAE, 0x84, 0x8, 0x9B, 0x33, +0xC, 0x1F, 0x26, 0x65, 0xC7, 0x86, 0x25, 0x10, 0x11, 0x97, 0x33, 0x3D, 0x98, +0x43, 0xB5, 0x7F, 0x9C, 0x19, 0x62, 0xE5, 0x46, 0x6D, 0x3B, 0xA2, 0xDC, 0xD4, +0x17, 0x85, 0x9A, 0xE8, 0x2C, 0xF3, 0x1, 0x5F, 0x39, 0xD1, 0xBC, 0x7, 0x8E, +0xAC, 0xC9, 0x28, 0xC, 0x7B, 0xD8, 0x2, 0xFE, 0x46, 0x12, 0xA8, 0xBD, 0xE, +0x6B, 0x23, 0x65, 0x5B, 0xAA, 0xFC, 0x32, 0x20, 0xF7, 0xCC, 0xC7, 0x6, 0x80, +0x9, 0xA, 0x95, 0xD9, 0x69, 0xED, 0x3C, 0x6C, 0xEB, 0x62, 0x28, 0xE6, 0x4E, +0xF4, 0xFA, 0x9B, 0x5C, 0x36, 0x7, 0xE0, 0x25, 0x20, 0xB8, 0xF4, 0x1F, 0x2E, +0x78, 0x21, 0xEE, 0xFA, 0x9E, 0x80, 0x14, 0xAD, 0xAD, 0x83, 0x39, 0x2E, 0xD0, +0xE9, 0x56, 0xE3, 0x88, 0xC, 0xC4, 0xD7, 0xBE, 0xB1, 0xE4, 0xD0, 0x42, 0xE6, +0xED, 0xDC, 0x44, 0x65, 0x51, 0x1F, 0x95, 0x9A, 0xAA, 0xBF, 0x83, 0x7B, 0xD7, +0x14, 0x23, 0x18, 0x81, 0x91, 0xA, 0x7, 0x97, 0x10, 0x6F, 0x3C, 0x16, 0xF2, +0xF0, 0x3E, 0xE1, 0x45, 0x40, 0xB0, 0x39, 0x98, 0x33, 0x55, 0xFF, 0x7E, 0x75, +0x31, 0xE0, 0x10, 0x16, 0x81, 0x36, 0x56, 0x86, 0x34, 0x1C, 0x61, 0x10, 0x25, +0xAE, 0x98, 0x6E, 0xBE, 0xC9, 0x47, 0xCD, 0x14, 0x1C, 0x52, 0x8C, 0x27, 0xEE, +0x28, 0xDA, 0x18, 0x96, 0x4D, 0x16, 0x6D, 0x17, 0x2E, 0x5B, 0x7E, 0x88, 0x70, +0xC8, 0x3D, 0x31, 0x34, 0xE5, 0xEA, 0x8, 0x40, 0x25, 0x7B, 0x3, 0x75, 0x47, +0xAD, 0x19, 0x2, 0x7E, 0xCC, 0xB6, 0x43, 0xD1, 0xC9, 0xB2, 0x95, 0x7F, 0x9F, +0x93, 0xC4, 0xD7, 0x33, 0x5A, 0x7E, 0xA4, 0x51, 0x58, 0xC5, 0xA7, 0x23, 0x25, +0xF8, 0xF4, 0xDE, 0xEF, 0x84, 0x72, 0xE, 0x8D, 0xE7, 0x9E, 0x1E, 0x40, 0xB3, +0xA6, 0x58, 0x34, 0x4E, 0xB8, 0x56, 0x6B, 0xA1, 0x50, 0x2B, 0x1C, 0xF9, 0xA6, +0x88, 0x21, 0x34, 0x79, 0x99, 0x5F, 0x24, 0xD6, 0x96, 0x67, 0xB5, 0x7E, 0x9C, +0xD2, 0xFB, 0x11, 0x40, 0xA6, 0xE6, 0x20, 0xD2, 0x8C, 0x38, 0x62, 0x9B, 0xC1, +0xD7, 0x57, 0x42, 0xE0, 0xD7, 0x34, 0xF3, 0x90, 0xF9, 0x60, 0xDD, 0xEA, 0x24, +0x67, 0x6A, 0xC0, 0xC7, 0xEF, 0xA7, 0x1B, 0xDC, 0xAD, 0x3D, 0xD, 0x17, 0x90, +0x66, 0x70, 0xB2, 0x98, 0x24, 0x1B, 0x58, 0x79, 0xAC, 0x3E, 0x61, 0x9C, 0x67, +0xB4, 0xEE, 0x9, 0x6, 0x20, 0xCE, 0x39, 0x3, 0x57, 0xD4, 0xB5, 0x44, 0x3C, +0x35, 0x80, 0xDD, 0xEF, 0xC3, 0xC5, 0xC4, 0x93, 0x79, 0xF8, 0x84, 0x60, 0x31, +0x27, 0xB7, 0xF8, 0xEB, 0x63, 0xE8, 0x75, 0x74, 0x31, 0x29, 0xF4, 0xE7, 0x6, +0x51, 0x74, 0x72, 0x71, 0x9D, 0xA1, 0x3F, 0x3C, 0x73, 0xCF, 0x7, 0xA9, 0x98, +0x23, 0x1F, 0x62, 0x9C, 0x9E, 0x27, 0xFD, 0x1E, 0xC8, 0x1C, 0xB9, 0xBD, 0x16, +0xB5, 0x4C, 0x1A, 0xC2, 0x8D, 0xCF, 0x4D, 0xB8, 0xC2, 0x4D, 0x94, 0xE6, 0x12, +0x6D, 0x14, 0xFA, 0x2B, 0xF4, 0x4A, 0x2B, 0xD9, 0x7D, 0xEF, 0xF8, 0x81, 0x2C, +0xF7, 0x7B, 0x98, 0x44, 0x12, 0x58, 0xD5, 0x82, 0xAA, 0xED, 0x49, 0x40, 0x87, +0xBA, 0x11, 0x29, 0x7E, 0xFD, 0x4, 0x67, 0x20, 0x5D, 0x2B, 0x79, 0x42, 0x7, +0x3, 0x5C, 0x36, 0xD7, 0xBE, 0x72, 0xCA, 0x13, 0xCF, 0x93, 0x2D, 0xD8, 0xA9, +0xEE, 0x6, 0xB, 0xCF, 0x5A, 0x46, 0x88, 0x57, 0x9E, 0x18, 0x92, 0x3B, 0x5F, +0x2F, 0x86, 0xCD, 0x3D, 0x49, 0xF6, 0xA3, 0x5, 0xE6, 0xE4, 0x68, 0xA4, 0x79, +0xA6, 0xEE, 0x85, 0xF4, 0x2B, 0xF6, 0x6E, 0x1B, 0x7A, 0xBD, 0x77, 0xEA, 0x6A, +0xC9, 0x31, 0x34, 0x8E, 0x5F, 0xC2, 0xF3, 0x87, 0x3D, 0x8F, 0xD7, 0xB0, 0x16, +0x28, 0x3F, 0x2C, 0x87, 0xA0, 0xA3, 0x56, 0xE8, 0x21, 0x83, 0x53, 0xCB, 0xE9, +0x1D, 0x28, 0x57, 0x93, 0xDB, 0x5B, 0xE9, 0xF0, 0x7B, 0x7F, 0xF4, 0x6A, 0x51, +0x48, 0xFC, 0xAB, 0xF5, 0x3B, 0x44, 0xA7, 0x5E, 0x67, 0x3A, 0x6B, 0x43, 0x9C, +0xD1, 0x3, 0xDF, 0xF8, 0xD5, 0x7F, 0x7B, 0x9, 0x62, 0xBF, 0x28, 0xBD, 0xC6, +0x3E, 0xC3, 0x6C, 0x91, 0x1, 0x45, 0x3F, 0xE2, 0x1F, 0xEF, 0x2A, 0x8F, 0xB2, +0x1B, 0x72, 0x35, 0x4D, 0x18, 0x6F, 0x4D, 0x57, 0xBF, 0x6A, 0x69, 0x2, 0x69, +0x4A, 0xE5, 0x5F, 0x74, 0xF7, 0x69, 0x5B, 0x89, 0x8, 0xCE, 0xCE, 0x15, 0x56, +0x3F, 0x21, 0x1A, 0xB8, 0xEC, 0x4D, 0xB0, 0x7E, 0xF, 0x89, 0xB0, 0x5C, 0x6D, +0xDB, 0x53, 0x9E, 0xA9, 0x27, 0x28, 0x52, 0xE5, 0x9E, 0x1F, 0xEF, 0x84, 0x1A, +0x9A, 0xAE, 0x86, 0x8B, 0x25, 0x3B, 0xC6, 0x3B, 0x8E, 0x9C, 0x32, 0xD9, 0x89, +0x3B, 0xA2, 0xCB, 0x59, 0x35, 0xC3, 0x71, 0xEE, 0x22, 0xC, 0x61, 0xEA, 0x59, +0x33, 0x25, 0x39, 0xAF, 0xF0, 0x12, 0x81, 0x55, 0x4A, 0x9D, 0xC, 0x3E, 0x5E, +0x34, 0x9F, 0xA7, 0xD8, 0xC5, 0xB5, 0xA, 0xC3, 0xA2, 0x0, 0x3F, 0x59, 0x3D, +0x7, 0x5F, 0x2B, 0xC1, 0x6F, 0x6A, 0xE3, 0x94, 0x90, 0xAF, 0x81, 0x11, 0x82, +0x89, 0xF4, 0x9D, 0x8B, 0x5, 0xE2, 0x7C, 0x22, 0x2, 0xEC, 0x0, 0x38, 0x39, +0xED, 0x4, 0xB2, 0xC9, 0xD8, 0xA1, 0x1B, 0xED, 0xB9, 0xE1, 0x62, 0x82, 0xC4, +0xCC, 0xA0, 0x61, 0xEE, 0x7A, 0x17, 0xA0, 0x99, 0xAC, 0xAC, 0x85, 0xA7, 0x5F, +0xC9, 0xC3, 0xC5, 0x63, 0x8F, 0x5A, 0xE7, 0x41, 0xAC, 0xB7, 0x89, 0x13, 0x38, +0xD8, 0x58, 0xBF, 0x71, 0xA5, 0x4F, 0x9D, 0x4C, 0x72, 0x57, 0x88, 0x2E, 0xAB, +0xD4, 0x74, 0xDE, 0x46, 0x9F, 0xF4, 0xBA, 0xB1, 0x55, 0x6A, 0x18, 0xF4, 0x87, +0xB9, 0x24, 0xA7, 0xD9, 0xF4, 0x9A, 0x3C, 0xEF, 0xF4, 0xA2, 0x2D, 0xF, 0xC9, +0xE4, 0x45, 0xC2, 0xC9, 0x6F, 0x2D, 0xB6, 0xDA, 0xE6, 0x89, 0x38, 0x80, 0x2A, +0x89, 0xE2, 0xF5, 0x3D, 0x77, 0x5E, 0x61, 0x6E, 0x9C, 0xF9, 0x87, 0x89, 0xD4, +0x70, 0x23, 0x79, 0x93, 0xDA, 0xCE, 0x62, 0x89, 0xEB, 0x13, 0x77, 0xB0, 0x49, +0xB2, 0xF9, 0xFC, 0x84, 0xD3, 0x6, 0xD2, 0x8D, 0x5A, 0x94, 0x64, 0xC1, 0xA8, +0x9A, 0x60, 0x57, 0x8A, 0x8F, 0x62, 0x4A, 0x78, 0x12, 0x6B, 0x87, 0x6F, 0x6D, +0xC8, 0x32, 0xF3, 0xC6, 0x8D, 0xDB, 0x3A, 0x67, 0x95, 0xCD, 0xAF, 0x48, 0x28, +0x79, 0xC2, 0xB6, 0xDB, 0xD8, 0xFE, 0x82, 0x15, 0xE6, 0xE4, 0xEC, 0x79, 0xE2, +0xB4, 0x21, 0x5C, 0x30, 0x45, 0xD7, 0x3B, 0xA0, 0x1A, 0x3B, 0xAA, 0x3D, 0x6C, +0x1C, 0xC3, 0x1E, 0xDE, 0x4D, 0x75, 0x1D, 0x9A, 0x96, 0x51, 0xF9, 0x4F, 0x10, +0x28, 0x7E, 0x88, 0xEE, 0x3B, 0x93, 0x4A, 0xB, 0x9, 0x44, 0x9C, 0x20, 0x34, +0xF6, 0xEE, 0x6F, 0x26, 0xB9, 0x4C, 0x76, 0xCC, 0xE1, 0x6F, 0x9, 0x91, 0xAF, +0x48, 0x8C, 0xC4, 0x31, 0xA2, 0xF9, 0x44, 0x77, 0x19, 0xA7, 0x0, 0x33, 0x77, +0x31, 0xF2, 0xF5, 0xF7, 0x30, 0xDF, 0xAB, 0xFE, 0x7E, 0xE6, 0x83, 0xE1, 0xC9, +0x2A, 0xC8, 0xE0, 0xA6, 0xAC, 0x5A, 0x28, 0x7F, 0xC4, 0xB, 0xEB, 0x55, 0xD9, +0x5D, 0xBD, 0xB5, 0xD2, 0xF6, 0xB4, 0xA9, 0x76, 0x2B, 0x35, 0x10, 0x36, 0x3B, +0xCC, 0x61, 0x6C, 0x79, 0xCE, 0xC3, 0x9A, 0x2, 0x9A, 0x0, 0xBA, 0x43, 0x20, +0x3F, 0x26, 0x36, 0x66, 0x7, 0x11, 0x68, 0x51, 0x47, 0xBE, 0x78, 0xED, 0x4A, +0xFA, 0xBC, 0xDA, 0xCD, 0xFD, 0x2, 0xDB, 0xD1, 0x8B, 0xE0, 0xBD, 0x13, 0xFE, +0xED, 0x26, 0x77, 0xE4, 0x83, 0xAE, 0xB7, 0xAB, 0xFD, 0x2A, 0x5E, 0xA3, 0x28, +0xFD, 0x90, 0x40, 0x3D, 0x34, 0xF7, 0xF8, 0x35, 0x80, 0xF6, 0x6F, 0xA0, 0xE9, +0xCD, 0x9A, 0x54, 0x6F, 0x41, 0xA5, 0xC7, 0xED, 0xEA, 0xDC, 0x52, 0x23, 0xF1, +0x96, 0x19, 0x8E, 0x2B, 0x94, 0x3F, 0xD9, 0x27, 0x60, 0x1E, 0x27, 0xC1, 0x39, +0x68, 0x78, 0x7B, 0x47, 0x8F, 0xCC, 0xCD, 0xBE, 0xE4, 0xBD, 0xB, 0x73, 0x3, +0xFB, 0xFE, 0xC0, 0x50, 0x38, 0x70, 0xDF, 0x81, 0x5D, 0x22, 0x4C, 0x5B, 0xCB, +0x27, 0x5D, 0xD2, 0x94, 0x64, 0xA, 0x88, 0x67, 0x31, 0xE9, 0x8, 0xF0, 0x88, +0x20, 0xF2, 0x86, 0xCA, 0xBD, 0x18, 0x5F, 0x34, 0xD0, 0x96, 0xD, 0x4A, 0x62, +0x4D, 0xBE, 0xE8, 0xA6, 0x4, 0xA6, 0x69, 0xCE, 0xCD, 0xE9, 0x5A, 0x1D, 0xD2, +0xF8, 0xCF, 0x19, 0x6, 0x17, 0x5, 0x82, 0x6B, 0x60, 0x3E, 0x5E, 0x6B, 0x1D, +0x1E, 0x13, 0x51, 0x5D, 0xFE, 0x95, 0x38, 0x33, 0x62, 0x9B, 0xBF, 0xD5, 0x3E, +0x3B, 0x8B, 0xD2, 0x6F, 0x24, 0x6D, 0x24, 0xC9, 0xD, 0x2D, 0x52, 0xBF, 0xDA, +0xCE, 0x5E, 0xFE, 0x9D, 0xB8, 0x5D, 0x61, 0x57, 0xBC, 0x8C, 0x7A, 0x17, 0x75, +0x80, 0xEE, 0x52, 0x2F, 0xF5, 0x25, 0x48, 0x3A, 0x9E, 0x27, 0xF4, 0xEB, 0xE1, +0x1, 0xE4, 0xA7, 0x48, 0x93, 0xAA, 0x92, 0x68, 0xC0, 0x3B, 0x1A, 0x5A, 0xC5, +0x6D, 0xD0, 0x91, 0xB9, 0x8D, 0x44, 0xD4, 0xE1, 0x9C, 0x74, 0xEA, 0x14, 0xFA, +0xF6, 0x1E, 0x1, 0xC0, 0x89, 0x24, 0x90, 0x71, 0xAF, 0xF5, 0x2D, 0x6C, 0x35, +0x13, 0xA6, 0x73, 0x14, 0xAC, 0xE5, 0xAE, 0x88, 0x2F, 0x9D, 0x77, 0x3B, 0x8F, +0x61, 0xB1, 0x47, 0x66, 0x72, 0x14, 0x91, 0x40, 0xD7, 0x50, 0xDC, 0xEA, 0xFF, +0x49, 0x9E, 0x17, 0x75, 0x25, 0x49, 0x7C, 0x57, 0x41, 0xA7, 0x8C, 0x4D, 0x3B, +0x94, 0x9D, 0x65, 0x83, 0x62, 0x6F, 0x16, 0xBF, 0xC, 0x87, 0x3, 0x61, 0xB4, +0x3B, 0x60, 0x6D, 0x7, 0x56, 0xB8, 0x1F, 0x89, 0xAD, 0x0, 0x25, 0x10, 0x4A, +0x34, 0x4C, 0x9A, 0x26, 0xDA, 0x6, 0x25, 0x9C, 0x91, 0xA6, 0xA5, 0xAD, 0x4D, +0x6E, 0xE9, 0x2F, 0x18, 0xC4, 0x1D, 0x9, 0xE1, 0xAA, 0x66, 0x1, 0x31, 0x6D, +0x12, 0x30, 0xED, 0x97, 0x3F, 0x67, 0xCE, 0x4E, 0x26, 0xB, 0xF5, 0x5E, 0x81, +0xA7, 0x1F, 0x83, 0x68, 0x91, 0xC3, 0xD0, 0x4C, 0x2E, 0xD4, 0xDE, 0xEF, 0x34, +0xF9, 0x61, 0x83, 0x6F, 0xD6, 0x6E, 0x40, 0x87, 0x48, 0x7E, 0xCF, 0x56, 0x42, +0x21, 0xBA, 0x40, 0x64, 0x17, 0xFA, 0x97, 0xFF, 0x8D, 0xC8, 0x32, 0xFA, 0xB7, +0x45, 0xB0, 0xEC, 0xBD, 0xE, 0x51, 0x63, 0x90, 0x5, 0x68, 0x7A, 0x45, 0x86, +0x68, 0x2A, 0xE, 0x81, 0x5F, 0xDD, 0x12, 0xAD, 0x48, 0xF6, 0x87, 0x2E, 0x8D, +0xF6, 0x86, 0xC3, 0x6D, 0x69, 0xD5, 0x4E, 0x52, 0x8A, 0x8E, 0xE8, 0x1, 0x56, +0x11, 0xCC, 0x2E, 0x3F, 0xB5, 0x46, 0x1D, 0xF6, 0x6E, 0x4A, 0xEE, 0x1C, 0x60, +0x15, 0x85, 0xF6, 0x40, 0xFD, 0x56, 0xDC, 0x10, 0x1, 0xC3, 0xBD, 0xAE, 0x5A, +0x13, 0x1F, 0x15, 0x16, 0x10, 0x92, 0xC5, 0x2, 0xC2, 0x81, 0xB5, 0x6A, 0x4D, +0x37, 0x29, 0x40, 0x8B, 0xAA, 0x5F, 0xC9, 0x4C, 0x26, 0x7B, 0x2C, 0x21, 0x9E, +0xE2, 0xF2, 0x5A, 0x20, 0x88, 0x3F, 0x40, 0x30, 0xC5, 0x64, 0xE }; + +struct PQDSATestVector { + const char name[20]; + const int nid; + const size_t public_key_len; + const size_t private_key_len; + const size_t signature_len; + const char *kat_filename; + const uint8_t *kPublicKey; + const uint8_t *kPublicKeySPKI; + const size_t kPublicKeySPKI_len; +}; + +#define CMP_VEC_AND_PTR(vec, ptr, len) \ + { \ + std::vector tmp(len); \ + tmp.assign(ptr, ptr + len); \ + EXPECT_EQ(Bytes(vec), Bytes(tmp)); \ + } + +#define CMP_VEC_AND_PKEY_PUBLIC(vec, pkey, len) \ +CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->public_key, len) + +#define CMP_VEC_AND_PKEY_SECRET(vec, pkey, len) \ +CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->private_key, len) + +static const struct PQDSATestVector parameterSet[] = { + {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt", mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1974}, +}; + +class PQDSAParameterTest : public testing::TestWithParam {}; + +INSTANTIATE_TEST_SUITE_P(All, PQDSAParameterTest, testing::ValuesIn(parameterSet), + [](const testing::TestParamInfo ¶ms) + -> std::string { return params.param.name; }); + + +TEST_P(PQDSAParameterTest, KAT) { + std::string kat_filepath = "crypto/"; + kat_filepath += GetParam().kat_filename; + + FileTestGTest(kat_filepath.c_str(), [&](FileTest *t) { + std::string count, mlen, smlen; + std::vector seed, msg, pk, sk, sm; + + ASSERT_TRUE(t->GetAttribute(&count, "count")); + ASSERT_TRUE(t->GetBytes(&seed, "seed")); + ASSERT_TRUE(t->GetAttribute(&mlen, "mlen")); + ASSERT_TRUE(t->GetBytes(&msg, "msg")); + ASSERT_TRUE(t->GetBytes(&pk, "pk")); + ASSERT_TRUE(t->GetBytes(&sk, "sk")); + ASSERT_TRUE(t->GetAttribute(&smlen, "smlen")); + ASSERT_TRUE(t->GetBytes(&sm, "sm")); + + size_t pk_len = GetParam().public_key_len; + size_t sk_len = GetParam().private_key_len; + size_t sig_len = GetParam().signature_len; + + // The KAT files generated by the dilithium team use the optional APIs that + // create a signature for a message m and append the message to the end of + // the signature. We only want to bring the APIs that create and verify just + // the signature, therefore each signature is a constant + // DILITHIUM3_SIGNATURE_BYTES and we truncate the KAT's signed message down, + // "sm" down to a constant DILITHIUM3_SIGNATURE_BYTES. + + std::vector signature(sig_len); + sm.resize(sig_len); + + // Convert string read from KAT to int + size_t mlen_int = std::stoi(mlen); + + // Here we fix the DRBG (AES-CTR) so that we are able to seed it with the + // seed from the KAT (testing only) + pq_custom_randombytes_use_deterministic_for_testing(); + pq_custom_randombytes_init_for_testing(seed.data()); + + // Generate our dilithium public and private key pair + bssl::UniquePtr pctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(pctx); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(pctx.get(),GetParam().nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(pctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(pctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + + // Compare the expected public/secret key from KATs with generated values + CMP_VEC_AND_PKEY_PUBLIC(pk, pkey, pk_len); + CMP_VEC_AND_PKEY_SECRET(sk, pkey, sk_len); + + // Generate a signature for the message + // We use EVP_DigestSign because dilithium supports the use of + // non-hash-then-sign (just like ed25519) so we first init EVP_DigestSign + // WITHOUT a hash function. + bssl::ScopedEVP_MD_CTX ctx; + ASSERT_TRUE(EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get())); + ASSERT_TRUE(EVP_DigestSign(ctx.get(), signature.data(), &sig_len, msg.data(), mlen_int)); + EXPECT_EQ(Bytes(sm), Bytes(signature.data(), sig_len)); + ctx.Reset(); + + // Verify the signature + ASSERT_TRUE(EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get())); + ASSERT_TRUE(EVP_DigestVerify(ctx.get(), signature.data(), sig_len, msg.data(), mlen_int)); + }); +} + +TEST_P(PQDSAParameterTest, KeyGen) { + // Basic key generation tests for MLDSA + // Generate a MLDSA key + int nid = GetParam().nid; + size_t pk_len = GetParam().public_key_len; + size_t sk_len = GetParam().private_key_len; + + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(),nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + + // Extract public key and check it is of the correct size + uint8_t *buf = nullptr; + size_t buf_size; + EXPECT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), buf, &buf_size)); + EXPECT_EQ(pk_len, buf_size); + + buf = (uint8_t *)OPENSSL_malloc(buf_size); + ASSERT_NE(buf, nullptr); + EXPECT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), buf, &buf_size)); + + buf_size = 0; + EXPECT_FALSE(EVP_PKEY_get_raw_public_key(pkey.get(), buf, &buf_size)); + + uint32_t err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); + EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err)); + OPENSSL_free(buf); + buf = nullptr; + + // Extract private key and check it is of the correct size + EXPECT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), buf, &buf_size)); + EXPECT_EQ((size_t)sk_len, buf_size); + + buf = (uint8_t *)OPENSSL_malloc(buf_size); + ASSERT_NE(buf, nullptr); + EXPECT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), buf, &buf_size)); + + buf_size = 0; + EXPECT_FALSE(EVP_PKEY_get_raw_private_key(pkey.get(), buf, &buf_size)); + err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); + EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err)); + OPENSSL_free(buf); +} + +TEST_P(PQDSAParameterTest, KeyCmp) { + // Generate two MLDSA keys are check that they are not equal. + const int nid = GetParam().nid; + + // Generate first keypair + bssl::UniquePtr ctx1(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx1); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx1.get(),nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx1.get())); + EVP_PKEY *raw1 = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx1.get(), &raw1)); + bssl::UniquePtr pkey1(raw1); + + // Generate second keypair + bssl::UniquePtr ctx2(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx2); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx2.get(),nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx2.get())); + EVP_PKEY *raw2 = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx2.get(), &raw2)); + bssl::UniquePtr pkey2(raw2); + + // Compare keys + EXPECT_EQ(0, EVP_PKEY_cmp(pkey1.get(), pkey2.get())); +} + +TEST_P(PQDSAParameterTest, KeySize) { + // Test the key size of MLDSA key is as expected + int nid = GetParam().nid; + int pk_len = GetParam().public_key_len; + int sig_len = GetParam().signature_len; + + // generate an MLDSA keypair + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(),nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + + EXPECT_EQ(sig_len, EVP_PKEY_size(pkey.get())); + EXPECT_EQ(8*(pk_len), EVP_PKEY_bits(pkey.get())); +} + +TEST_P(PQDSAParameterTest, NewKeyFromBytes) { + // Test the generation of a MLDSA key from bytes + int nid = GetParam().nid; + size_t pk_len = GetParam().public_key_len; + size_t sk_len = GetParam().private_key_len; + + // Source key + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(), nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + + // New raw pkey to store raw public key + bssl::UniquePtr new_pkey(EVP_PKEY_pqdsa_new_raw_public_key(nid, pkey->pkey.pqdsa_key->public_key, pk_len)); + + // check that public key is present and secret key is not present + ASSERT_NE(new_pkey, nullptr); + EXPECT_NE(new_pkey->pkey.pqdsa_key->public_key, nullptr); + EXPECT_EQ(new_pkey->pkey.pqdsa_key->private_key, nullptr); + + // check that EVP_PKEY_get_raw_private_key fails correctly + uint8_t *buf = nullptr; + size_t buf_size; + EXPECT_FALSE(EVP_PKEY_get_raw_private_key(new_pkey.get(), buf, &buf_size)); + uint32_t err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); + EXPECT_EQ(EVP_R_NOT_A_PRIVATE_KEY, ERR_GET_REASON(err)); + + // EVP_PKEY_cmp returns 1 on success + EXPECT_EQ(1, EVP_PKEY_cmp(pkey.get(), new_pkey.get())); + + // New raw pkey to store raw secret key + bssl::UniquePtr private_pkey(EVP_PKEY_pqdsa_new_raw_private_key(nid, pkey->pkey.pqdsa_key->private_key, sk_len)); + + // check that secret key is present and public key is not present + ASSERT_NE(private_pkey, nullptr); + EXPECT_EQ(private_pkey->pkey.pqdsa_key->public_key, nullptr); + EXPECT_NE(private_pkey->pkey.pqdsa_key->private_key, nullptr); + EXPECT_EQ(0, OPENSSL_memcmp(private_pkey->pkey.pqdsa_key->private_key, pkey->pkey.pqdsa_key->private_key, sk_len)); +} + +TEST_P(PQDSAParameterTest, RawFunctions) { + // Test EVP_PKEY_get_raw_public_key for extracting public keys + // Test EVP_PKEY_get_raw_private_key for extracting private keys + // Test EVP_PKEY_pqdsa_new_raw_public_key for generating a new PKEY from raw pub + // Test EVP_parse_public_key can parse the DER to a PKEY + // Test EVP_PKEY_pqdsa_new_raw_private_key for generating a new PKEY from raw priv + + int nid = GetParam().nid; + size_t pk_len = GetParam().public_key_len; + size_t sk_len = GetParam().private_key_len; + + // Generate mldsa key + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(),nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + + // The public key must be extractable. + std::vector pub_buf(pk_len); + size_t pub_len; + ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &pub_len)); + EXPECT_EQ(pub_len, pk_len); + ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pub_buf.data(), &pub_len)); + + bssl::UniquePtr pkey_pk_new(EVP_PKEY_pqdsa_new_raw_public_key(nid, pub_buf.data(), pk_len)); + ASSERT_TRUE(pkey_pk_new); + + // The public key must encode properly. + bssl::ScopedCBB cbb; + uint8_t *der; + size_t der_len; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pkey_pk_new.get())); + ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); + bssl::UniquePtr free_der(der); + + // The public key must parse properly. + CBS cbs; + CBS_init(&cbs, der, der_len); + bssl::UniquePtr pkey_from_der(EVP_parse_public_key(&cbs)); + ASSERT_TRUE(pkey_from_der.get()); + EXPECT_EQ(1, EVP_PKEY_cmp(pkey.get(), pkey_from_der.get())); + + // The secret key must be extractable. + std::vector priv_buf(sk_len); + size_t priv_len; + ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &priv_len)); + EXPECT_EQ(priv_len, sk_len); + ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), priv_buf.data(), &priv_len)); + + bssl::UniquePtr pkey_sk_new(EVP_PKEY_pqdsa_new_raw_private_key(nid, priv_buf.data(), sk_len)); + ASSERT_TRUE(pkey_sk_new); + + // The private key must encode properly. + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(EVP_marshal_private_key(cbb.get(), pkey_sk_new.get())); + ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); + free_der.reset(der); + + // private key parse + CBS_init(&cbs, der, der_len); + bssl::UniquePtr pkey_priv_from_der(EVP_parse_private_key(&cbs)); + ASSERT_TRUE(pkey_priv_from_der); + + EXPECT_EQ(Bytes(pkey_priv_from_der->pkey.pqdsa_key->private_key, priv_len), + Bytes(priv_buf.data(), sk_len)); +} + +TEST_P(PQDSAParameterTest, SIGOperations) { + // Test basic functionality for MLDSA + int nid = GetParam().nid; + size_t sig_len = GetParam().signature_len; + + // Generate a mldsa key + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(),nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + + // Sign a message + bssl::ScopedEVP_MD_CTX md_ctx; + std::vector signature1(sig_len); + + // msg2 differs from msg1 by one byte + std::vector msg1 = { + 0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49, + 0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x32, 0x2e}; + std::vector msg2 = { + 0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49, + 0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x31, 0x2e}; + + ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, + nullptr, pkey.get())); + ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature1.data(), &sig_len, + msg1.data(), msg1.size())); + + // Verify the correct signed message + ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), signature1.data(), sig_len, + msg1.data(), msg1.size())); + + // Verify the signed message fails upon a different message + ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature1.data(), sig_len, + msg2.data(), msg2.size())); + + // Sign the different message + + std::vector signature2(sig_len); + md_ctx.Reset(); + ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, + nullptr, pkey.get())); + + ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature2.data(), &sig_len, + msg2.data(), msg2.size())); + + // Check that the two signatures are not equal + EXPECT_NE(0, OPENSSL_memcmp(signature1.data(), signature2.data(), sig_len)); + + // Verify the signed message fails upon a different signature + ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature2.data(), sig_len, + msg1.data(), msg1.size())); + md_ctx.Reset(); +} + +TEST_P(PQDSAParameterTest, MarshalParse) { + // Test the example public key kPublicKey encodes correctly as kPublicKeySPKI + // Test that the DER encoding can be parsed as a PKEY + + int nid = GetParam().nid; + size_t pk_len = GetParam().public_key_len; + const uint8_t * kPublicKey = GetParam().kPublicKey; + const uint8_t * kPublicKeySPKI = GetParam().kPublicKeySPKI; + size_t kPublicKeySPKI_len = GetParam().kPublicKeySPKI_len; + + bssl::UniquePtr pkey_pk_new(EVP_PKEY_pqdsa_new_raw_public_key(nid, kPublicKey, pk_len)); + ASSERT_TRUE(pkey_pk_new); + + // Encode the public key as DER + bssl::ScopedCBB cbb; + uint8_t *der; + size_t der_len; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pkey_pk_new.get())); + ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); + bssl::UniquePtr free_der(der); + + // Test that the encoded public key encodes as expected + EXPECT_EQ(Bytes(kPublicKeySPKI, kPublicKeySPKI_len), Bytes(der, der_len)); + + // decode the DER structure, then parse as a PKEY. + CBS cbs; + CBS_init(&cbs, der, der_len); + bssl::UniquePtr pkey_from_der(EVP_parse_public_key(&cbs)); + ASSERT_TRUE(pkey_from_der); +} + +#else + +TEST(PQDSATest, EvpDisabled) { + ASSERT_EQ(nullptr, EVP_PKEY_CTX_new_id(EVP_PKEY_NONE, nullptr)); + bssl::UniquePtr pkey(EVP_PKEY_new()); + ASSERT_FALSE(EVP_PKEY_set_type(pkey.get(), EVP_PKEY_NONE)); +} + +#endif diff --git a/crypto/dilithium/pqdsa.c b/crypto/dilithium/pqdsa.c new file mode 100644 index 0000000000..708b3e9c9d --- /dev/null +++ b/crypto/dilithium/pqdsa.c @@ -0,0 +1,119 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC +#include +#include + +#include +#include "../evp_extra/internal.h" +#include "../fipsmodule/delocate.h" +#include "internal.h" +#include "ml_dsa.h" + +// ML-DSA OIDs as defined within: +// https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration +//2.16.840.1.101.3.4.3.18 +static const uint8_t kOIDMLDSA65[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12}; + +// PQDSA functions: these are init/new/clear/free/get_sig functions for PQDSA_KEY +// These are analagous to the ec_key functions in crypto/fipsmodule/ec/ec_key.c + +PQDSA_KEY *PQDSA_KEY_new(void) { + PQDSA_KEY *ret = OPENSSL_zalloc(sizeof(PQDSA_KEY)); + if (ret == NULL) { + return NULL; + } + + return ret; +} + +static void PQDSA_KEY_clear(PQDSA_KEY *key) { + key->pqdsa = NULL; + OPENSSL_free(key->public_key); + OPENSSL_free(key->private_key); + key->public_key = NULL; + key->private_key = NULL; +} + +int PQDSA_KEY_init(PQDSA_KEY *key, const PQDSA *pqdsa) { + if (key == NULL || pqdsa == NULL) { + return 0; + } + // If the key is already initialized clear it. + PQDSA_KEY_clear(key); + + key->pqdsa = pqdsa; + key->public_key = OPENSSL_malloc(pqdsa->public_key_len); + key->private_key = OPENSSL_malloc(pqdsa->private_key_len); + if (key->public_key == NULL || key->private_key == NULL) { + PQDSA_KEY_clear(key); + return 0; + } + return 1; +} + +void PQDSA_KEY_free(PQDSA_KEY *key) { + if (key == NULL) { + return; + } + PQDSA_KEY_clear(key); + OPENSSL_free(key); +} + +const PQDSA *PQDSA_KEY_get0_dsa(PQDSA_KEY* key) { + return key->pqdsa; +} + +int PQDSA_KEY_set_raw_public_key(PQDSA_KEY *key, const uint8_t *in) { + key->public_key = OPENSSL_memdup(in, key->pqdsa->public_key_len); + if (key->public_key == NULL) { + return 0; + } + + return 1; +} + +int PQDSA_KEY_set_raw_private_key(PQDSA_KEY *key, const uint8_t *in) { + key->private_key = OPENSSL_memdup(in, key->pqdsa->private_key_len); + if (key->private_key == NULL) { + return 0; + } + + return 1; +} + +DEFINE_LOCAL_DATA(PQDSA_METHOD, sig_ml_dsa_65_method) { + out->keygen = ml_dsa_65_keypair; + out->sign = ml_dsa_65_sign; + out->verify = ml_dsa_65_verify; +} + +DEFINE_LOCAL_DATA(PQDSA, sig_ml_dsa_65) { + out->nid = NID_MLDSA65; + out->oid = kOIDMLDSA65; + out->oid_len = sizeof(kOIDMLDSA65); + out->comment = "MLDSA65 "; + out->public_key_len = MLDSA65_PUBLIC_KEY_BYTES; + out->private_key_len = MLDSA65_PRIVATE_KEY_BYTES; + out->signature_len = MLDSA65_SIGNATURE_BYTES; + out->keygen_seed_len = MLDSA65_KEYGEN_SEED_BYTES; + out->sign_seed_len = MLDSA65_SIGNATURE_SEED_BYTES; + out->method = sig_ml_dsa_65_method(); +} + +const PQDSA *PQDSA_find_dsa_by_nid(int nid) { + switch (nid) { + case NID_MLDSA65: + return sig_ml_dsa_65(); + default: + return NULL; + } +} + +const EVP_PKEY_ASN1_METHOD *PQDSA_find_asn1_by_nid(int nid) { + switch (nid) { + case NID_MLDSA65: + return &pqdsa_asn1_meth; + default: + return NULL; + } +} diff --git a/crypto/dilithium/sig_dilithium.h b/crypto/dilithium/sig_dilithium.h deleted file mode 100644 index 21131c29fa..0000000000 --- a/crypto/dilithium/sig_dilithium.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 OR ISC - -#ifndef SIG_DILITHIUM_H -#define SIG_DILITHIUM_H - -#include -#include -#include -#include - -#define DILITHIUM3_PUBLIC_KEY_BYTES 1952 -#define DILITHIUM3_PRIVATE_KEY_BYTES 4032 -#define DILITHIUM3_SIGNATURE_BYTES 3309 - -// ml_dsa_65_keypair generates an ML-DSA-65 keypair and assigns a public key to -// |public_key| and a private key to |secret_key|. It returns 0 upon success. -int ml_dsa_65_keypair(uint8_t *public_key, - uint8_t *secret_key); - -// ml_dsa_65_sign generates an ML-DSA-65 signature. Where |sig| is a pointer to -// output signature, |sig_len| is a pointer to output length of signature, -// |message| is a pointer to message to be signed, |message_len| is the length -// of the message, |ctx| is a pointer to the context string, |ctx_len| is the -// length of the context string (max length 255 bytes), and |secret_key| is a -// pointer to bit-packed secret key. It returns 0 upon success. -int ml_dsa_65_sign(uint8_t *sig, size_t *sig_len, - const uint8_t *message, - size_t message_len, - const uint8_t *ctx, - size_t ctx_len, - const uint8_t *secret_key); - -// ml_dsa_65_verify generates an ML-DSA-65 signature. Where |sig| is a pointer -// to input signature, |sig_len| is the length of the signature, |message| is -// a pointer to message, |message_len| is the length of the message, |ctx| is a -// pointer to the context string, |ctx_len| is the length of the context string -// (max length 255 bytes) and |public_key| is a pointer to bit-packed public key. -// Returns 0 if signature could be verified successfully and -1 otherwise. -int ml_dsa_65_verify(const uint8_t *message, - size_t message_len, - const uint8_t *sig, - size_t sig_len, - const uint8_t *ctx, - size_t ctx_len, - const uint8_t *public_key); -#endif diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index a486459f63..20c660895c 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -68,7 +68,16 @@ #include "../bytestring/internal.h" #include "../internal.h" #include "internal.h" - +#include "../dilithium/internal.h" + +// parse_key_type takes the algorithm cbs sequence |cbs| and extracts the OID. +// The OID is then searched against ASN.1 methods for a method with that OID. +// As the |OID| is read from |cbs| the buffer is advanced. +// For the case of |NID_rsa| the method |rsa_asn1_meth| is returned. +// For the case of |EVP_PKEY_PQDSA| the method |pqdsa_asn1.meth| is returned, as +// the OID is not returned (and the |cbs| buffer is advanced) we return the OID +// as |cbs|. (This allows the specific OID, e.g. NID_MLDSA65 to be parsed by +// the type-specific decoding functions within the algorithm parameter.) static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { CBS oid; if (!CBS_get_asn1(cbs, &oid, CBS_ASN1_OBJECT)) { @@ -90,7 +99,21 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { if (OBJ_cbs2nid(&oid) == NID_rsa) { return &rsa_asn1_meth; } - +#ifdef ENABLE_DILITHIUM + // The pkey_id for the pqdsa_asn1_meth is EVP_PKEY_PQDSA, as this holds all + // asn1 functions for pqdsa types. However, the incoming CBS has the OID for + // the specific algorithm. So we must search explicitly for the algorithm. + const EVP_PKEY_ASN1_METHOD * ret = PQDSA_find_asn1_by_nid(OBJ_cbs2nid(&oid)); + if (ret != NULL) { + // if |cbs| is empty after parsing |oid| from it, we overwrite the contents + // with |oid| so that we can call pub_decode/priv_decode with the |algorithm| + // populated as |oid|. + if (CBS_len(cbs) == 0) { + OPENSSL_memcpy(cbs, &oid, sizeof(oid)); + return ret; + } + } +#endif return NULL; } @@ -105,6 +128,7 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return NULL; } + const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); @@ -170,6 +194,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return NULL; } + const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); diff --git a/crypto/evp_extra/evp_extra_test.cc b/crypto/evp_extra/evp_extra_test.cc index 9308fe2e42..0b948980bc 100644 --- a/crypto/evp_extra/evp_extra_test.cc +++ b/crypto/evp_extra/evp_extra_test.cc @@ -699,323 +699,321 @@ static const uint8_t kInvalidPrivateKey[] = { #ifdef ENABLE_DILITHIUM -// kExampleDilithium3KeyDER is a Dilithium private key in ASN.1, DER format. +// kExampleMLDSA65KeyDER is a ML-DSA private key in ASN.1, DER format. // Of course, you should never use this key anywhere but in an example. -static const uint8_t kExampleDilithium3KeyDER[] = { - 0x30, 0x82, 0x0F, 0xD6, 0x02, 0x01, 0x00, 0x30, 0x0D, 0x06, 0x0B, 0x2B, 0x06, - 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x06, 0x05, 0x04, 0x82, 0x0F, 0xC0, - 0xFB, 0x71, 0xBE, 0xC3, 0xBE, 0x92, 0x41, 0xCF, 0xAE, 0xA3, 0xE1, 0xEE, 0x29, - 0x47, 0x11, 0x6D, 0xC0, 0xAB, 0x32, 0x1D, 0x1A, 0x22, 0x3B, 0xD0, 0xD1, 0x3C, - 0x09, 0x44, 0x47, 0xD1, 0x84, 0xF7, 0x37, 0xA8, 0x5D, 0xF9, 0x39, 0x68, 0xD2, - 0xDD, 0x5E, 0xFE, 0x51, 0x89, 0xAC, 0xDB, 0xB5, 0x58, 0xF9, 0x06, 0xDB, 0x8F, - 0x60, 0x0A, 0x13, 0x90, 0x54, 0x8C, 0x69, 0x90, 0x27, 0x86, 0xBD, 0x54, 0x6D, - 0x2A, 0x35, 0x33, 0xE2, 0x33, 0x5E, 0xCD, 0x73, 0x38, 0x08, 0x81, 0x2F, 0xF8, - 0x1D, 0xB2, 0xDE, 0x82, 0xCE, 0x80, 0xCD, 0xBC, 0x32, 0x04, 0x44, 0xE5, 0x0A, - 0x54, 0x92, 0x93, 0x32, 0x83, 0x55, 0xA5, 0xF1, 0x4F, 0x26, 0x23, 0x88, 0x09, - 0x7B, 0x1C, 0xD5, 0x8A, 0x9E, 0x40, 0x01, 0x24, 0x76, 0x9C, 0x32, 0x97, 0x46, - 0x9D, 0x7D, 0x53, 0xD9, 0xFF, 0x48, 0x12, 0xC8, 0x1A, 0x54, 0x23, 0x83, 0x71, - 0x15, 0x65, 0x53, 0x28, 0x40, 0x32, 0x35, 0x78, 0x58, 0x37, 0x15, 0x64, 0x11, - 0x34, 0x78, 0x00, 0x25, 0x03, 0x65, 0x38, 0x48, 0x76, 0x36, 0x03, 0x86, 0x17, - 0x67, 0x78, 0x43, 0x58, 0x22, 0x47, 0x55, 0x20, 0x35, 0x85, 0x44, 0x53, 0x76, - 0x10, 0x45, 0x23, 0x35, 0x67, 0x11, 0x52, 0x11, 0x01, 0x33, 0x33, 0x63, 0x32, - 0x18, 0x67, 0x00, 0x48, 0x42, 0x80, 0x08, 0x27, 0x33, 0x21, 0x41, 0x44, 0x22, - 0x52, 0x52, 0x55, 0x32, 0x61, 0x58, 0x41, 0x50, 0x66, 0x44, 0x84, 0x86, 0x37, - 0x85, 0x13, 0x40, 0x10, 0x26, 0x80, 0x04, 0x37, 0x58, 0x40, 0x06, 0x50, 0x52, - 0x61, 0x72, 0x34, 0x15, 0x55, 0x16, 0x32, 0x66, 0x11, 0x23, 0x42, 0x25, 0x66, - 0x10, 0x41, 0x22, 0x57, 0x54, 0x76, 0x84, 0x15, 0x27, 0x21, 0x56, 0x84, 0x67, - 0x51, 0x61, 0x18, 0x70, 0x12, 0x77, 0x25, 0x32, 0x67, 0x18, 0x81, 0x52, 0x81, - 0x04, 0x40, 0x23, 0x71, 0x18, 0x17, 0x77, 0x82, 0x60, 0x26, 0x43, 0x84, 0x71, - 0x07, 0x73, 0x70, 0x40, 0x06, 0x43, 0x04, 0x16, 0x10, 0x40, 0x55, 0x68, 0x07, - 0x76, 0x44, 0x65, 0x25, 0x37, 0x22, 0x12, 0x10, 0x84, 0x61, 0x63, 0x55, 0x61, - 0x30, 0x15, 0x04, 0x32, 0x75, 0x30, 0x35, 0x84, 0x15, 0x84, 0x04, 0x33, 0x66, - 0x10, 0x07, 0x40, 0x22, 0x25, 0x73, 0x11, 0x64, 0x72, 0x88, 0x72, 0x56, 0x54, - 0x26, 0x06, 0x56, 0x24, 0x74, 0x75, 0x06, 0x03, 0x21, 0x57, 0x54, 0x30, 0x81, - 0x52, 0x45, 0x26, 0x26, 0x82, 0x02, 0x67, 0x28, 0x80, 0x84, 0x81, 0x67, 0x15, - 0x52, 0x25, 0x62, 0x00, 0x54, 0x24, 0x10, 0x00, 0x85, 0x06, 0x22, 0x18, 0x26, - 0x36, 0x52, 0x48, 0x01, 0x63, 0x50, 0x65, 0x47, 0x62, 0x84, 0x43, 0x03, 0x51, - 0x11, 0x06, 0x12, 0x16, 0x24, 0x05, 0x41, 0x38, 0x12, 0x18, 0x08, 0x63, 0x45, - 0x68, 0x68, 0x00, 0x32, 0x85, 0x34, 0x14, 0x75, 0x30, 0x48, 0x34, 0x68, 0x66, - 0x60, 0x85, 0x50, 0x34, 0x51, 0x33, 0x56, 0x23, 0x70, 0x21, 0x83, 0x23, 0x34, - 0x43, 0x26, 0x43, 0x77, 0x67, 0x80, 0x03, 0x88, 0x87, 0x52, 0x18, 0x62, 0x78, - 0x75, 0x57, 0x21, 0x65, 0x31, 0x30, 0x38, 0x31, 0x26, 0x73, 0x45, 0x44, 0x73, - 0x67, 0x88, 0x13, 0x73, 0x65, 0x21, 0x03, 0x46, 0x08, 0x43, 0x55, 0x37, 0x71, - 0x12, 0x17, 0x26, 0x31, 0x32, 0x31, 0x28, 0x22, 0x54, 0x15, 0x38, 0x74, 0x03, - 0x58, 0x15, 0x67, 0x08, 0x08, 0x03, 0x01, 0x64, 0x78, 0x76, 0x86, 0x62, 0x24, - 0x26, 0x85, 0x50, 0x63, 0x64, 0x27, 0x28, 0x83, 0x37, 0x44, 0x82, 0x78, 0x72, - 0x05, 0x60, 0x76, 0x60, 0x20, 0x07, 0x60, 0x22, 0x66, 0x12, 0x22, 0x64, 0x51, - 0x82, 0x82, 0x08, 0x76, 0x72, 0x61, 0x75, 0x22, 0x06, 0x20, 0x70, 0x10, 0x23, - 0x46, 0x38, 0x87, 0x18, 0x63, 0x20, 0x36, 0x54, 0x01, 0x12, 0x40, 0x48, 0x08, - 0x16, 0x58, 0x75, 0x08, 0x18, 0x38, 0x38, 0x74, 0x43, 0x74, 0x57, 0x11, 0x67, - 0x54, 0x51, 0x40, 0x23, 0x63, 0x51, 0x10, 0x83, 0x53, 0x02, 0x15, 0x33, 0x26, - 0x32, 0x78, 0x26, 0x53, 0x07, 0x82, 0x15, 0x57, 0x78, 0x68, 0x00, 0x16, 0x48, - 0x67, 0x36, 0x24, 0x07, 0x72, 0x33, 0x52, 0x13, 0x20, 0x52, 0x20, 0x08, 0x46, - 0x54, 0x15, 0x60, 0x30, 0x07, 0x07, 0x82, 0x37, 0x57, 0x85, 0x26, 0x28, 0x02, - 0x66, 0x80, 0x87, 0x74, 0x60, 0x60, 0x85, 0x23, 0x81, 0x35, 0x44, 0x78, 0x34, - 0x47, 0x60, 0x65, 0x42, 0x06, 0x75, 0x42, 0x31, 0x23, 0x42, 0x23, 0x77, 0x01, - 0x07, 0x22, 0x20, 0x88, 0x28, 0x87, 0x66, 0x44, 0x72, 0x33, 0x36, 0x15, 0x10, - 0x35, 0x63, 0x06, 0x03, 0x04, 0x86, 0x61, 0x26, 0x67, 0x43, 0x58, 0x44, 0x41, - 0x84, 0x26, 0x52, 0x87, 0x40, 0x27, 0x21, 0x73, 0x21, 0x60, 0x43, 0x74, 0x38, - 0x20, 0x06, 0x88, 0x78, 0x04, 0x81, 0x63, 0x75, 0x12, 0x76, 0x52, 0x46, 0x84, - 0x46, 0x56, 0x28, 0x36, 0x63, 0x14, 0x64, 0x07, 0x87, 0x23, 0x66, 0x21, 0x68, - 0x34, 0x15, 0x83, 0x31, 0x41, 0x46, 0x53, 0x28, 0x84, 0x31, 0x23, 0x22, 0x17, - 0x54, 0x62, 0x66, 0x68, 0x45, 0x17, 0x28, 0x35, 0x58, 0x21, 0x01, 0x36, 0x80, - 0x13, 0x52, 0x46, 0x02, 0x14, 0x31, 0x38, 0x72, 0x77, 0x87, 0x82, 0x77, 0x77, - 0x26, 0x18, 0x17, 0x67, 0x88, 0x37, 0x00, 0x04, 0x21, 0x26, 0x65, 0x85, 0x06, - 0x32, 0x24, 0x47, 0x26, 0x41, 0x86, 0x77, 0x85, 0x80, 0x85, 0x05, 0x16, 0x40, - 0x61, 0x53, 0x23, 0x32, 0x14, 0x32, 0x40, 0x43, 0x15, 0x64, 0x16, 0x20, 0x75, - 0x70, 0x10, 0x21, 0x60, 0x00, 0x81, 0x45, 0x24, 0x15, 0x58, 0x73, 0x04, 0x06, - 0x30, 0x58, 0x02, 0x74, 0x14, 0x24, 0x14, 0x56, 0x56, 0x68, 0x63, 0x08, 0x48, - 0x20, 0x66, 0x31, 0x52, 0x84, 0x15, 0x47, 0x72, 0x22, 0x34, 0x83, 0x24, 0x81, - 0x43, 0x38, 0x13, 0x61, 0x51, 0x38, 0x47, 0x17, 0x20, 0x45, 0x20, 0x17, 0x57, - 0x37, 0x37, 0x75, 0x80, 0x71, 0x57, 0x77, 0x71, 0x17, 0x74, 0x63, 0x22, 0x84, - 0x13, 0x68, 0x75, 0x82, 0x08, 0x12, 0x67, 0x71, 0x87, 0x54, 0x57, 0x06, 0x26, - 0x30, 0x15, 0x80, 0x24, 0x54, 0x22, 0x12, 0x86, 0x47, 0x57, 0x35, 0x77, 0x36, - 0x04, 0x36, 0x33, 0x13, 0x68, 0x03, 0x63, 0x23, 0x38, 0x44, 0x37, 0x10, 0x48, - 0x16, 0x87, 0x05, 0x02, 0x86, 0x10, 0x33, 0x81, 0x05, 0x71, 0x67, 0x18, 0x50, - 0x71, 0x83, 0x08, 0x12, 0x83, 0x75, 0x50, 0x17, 0x00, 0x05, 0x28, 0x73, 0x08, - 0x77, 0x17, 0x84, 0x28, 0x81, 0x35, 0x28, 0x13, 0x41, 0x81, 0x74, 0x80, 0x40, - 0x21, 0x01, 0x38, 0x47, 0x23, 0x80, 0x77, 0x45, 0x38, 0x35, 0x62, 0x87, 0x00, - 0x74, 0x00, 0x25, 0x55, 0x41, 0x44, 0x37, 0x37, 0x44, 0x35, 0x80, 0x45, 0x06, - 0x01, 0x73, 0x88, 0x14, 0x50, 0x24, 0x32, 0x81, 0x18, 0x43, 0x03, 0x01, 0x67, - 0x26, 0x65, 0x20, 0x38, 0x60, 0x34, 0x55, 0x85, 0x25, 0x53, 0x33, 0x85, 0x03, - 0x87, 0x18, 0x24, 0x00, 0x65, 0x38, 0x10, 0x00, 0x14, 0x34, 0x51, 0x14, 0x52, - 0x41, 0x37, 0x01, 0x63, 0x75, 0x16, 0x15, 0x70, 0x87, 0x78, 0x64, 0x21, 0x22, - 0x41, 0x23, 0x45, 0x65, 0x10, 0x83, 0x80, 0x36, 0x75, 0x22, 0x24, 0x42, 0x08, - 0x32, 0x53, 0x21, 0x75, 0x44, 0x38, 0x83, 0x40, 0x37, 0x22, 0x66, 0x44, 0x53, - 0x47, 0x20, 0x60, 0x36, 0x20, 0x33, 0x03, 0x65, 0x25, 0x74, 0x38, 0x13, 0x42, - 0x67, 0x83, 0x81, 0x61, 0x72, 0x82, 0x72, 0x37, 0x02, 0x24, 0x25, 0x22, 0x46, - 0x26, 0x10, 0x15, 0x24, 0x64, 0x33, 0x56, 0x11, 0x27, 0x42, 0x10, 0x22, 0x80, - 0x73, 0x52, 0x13, 0x36, 0x43, 0x84, 0x50, 0x82, 0x72, 0x81, 0x34, 0x77, 0x36, - 0x03, 0x30, 0x07, 0x51, 0x61, 0x26, 0x01, 0x78, 0x58, 0x78, 0x40, 0x71, 0x83, - 0x74, 0x38, 0x21, 0x84, 0x48, 0x25, 0x00, 0x33, 0x63, 0x17, 0x42, 0x81, 0x52, - 0x63, 0x66, 0x56, 0x43, 0x06, 0x88, 0x14, 0x17, 0x60, 0x51, 0x68, 0x86, 0x46, - 0x50, 0x03, 0x04, 0x31, 0x45, 0x13, 0x30, 0x87, 0x05, 0x66, 0x16, 0x74, 0x18, - 0x33, 0x72, 0x41, 0x01, 0x06, 0x72, 0x57, 0x46, 0x46, 0x14, 0x20, 0x54, 0x38, - 0x88, 0x35, 0x10, 0x65, 0x26, 0x20, 0x85, 0x44, 0x37, 0x70, 0x50, 0x86, 0x82, - 0x83, 0x46, 0x61, 0x34, 0x45, 0x54, 0x62, 0x40, 0x14, 0x46, 0x63, 0x46, 0x20, - 0x54, 0x42, 0x73, 0x57, 0x54, 0x27, 0x43, 0x00, 0x64, 0x01, 0x25, 0x70, 0x25, - 0x68, 0x50, 0x84, 0x26, 0x68, 0x23, 0x65, 0x88, 0x81, 0x42, 0x37, 0x37, 0x01, - 0x47, 0x66, 0x15, 0x45, 0x00, 0x74, 0x78, 0x88, 0x10, 0x42, 0x88, 0x27, 0x64, - 0x32, 0x11, 0x46, 0x75, 0x40, 0x86, 0x50, 0x11, 0x83, 0x75, 0x60, 0x36, 0x45, - 0x43, 0x11, 0x07, 0x76, 0x48, 0x58, 0x53, 0x82, 0x41, 0x71, 0x74, 0x12, 0x44, - 0x76, 0x36, 0x26, 0x85, 0x00, 0x35, 0x64, 0x75, 0x00, 0x76, 0x66, 0x64, 0x14, - 0x22, 0x66, 0x02, 0x64, 0x41, 0x05, 0x21, 0x23, 0x81, 0x37, 0x84, 0x55, 0x78, - 0x33, 0x23, 0x74, 0x25, 0x04, 0x36, 0x41, 0x42, 0x56, 0x37, 0x36, 0x45, 0x60, - 0x17, 0x16, 0x50, 0x64, 0x58, 0x54, 0x05, 0x52, 0x58, 0x03, 0x23, 0x47, 0x38, - 0x72, 0x56, 0x74, 0x77, 0x36, 0x56, 0x68, 0x42, 0x83, 0x52, 0x32, 0x70, 0x58, - 0x41, 0x34, 0x27, 0x31, 0x51, 0x37, 0x43, 0x81, 0x13, 0x06, 0x33, 0x63, 0x85, - 0x26, 0x02, 0x50, 0x00, 0x22, 0x73, 0x13, 0x36, 0x63, 0x24, 0x67, 0x52, 0x37, - 0x83, 0x26, 0x83, 0x70, 0x45, 0x27, 0x82, 0x43, 0x07, 0x37, 0x41, 0x45, 0x01, - 0x54, 0x02, 0x10, 0x58, 0x35, 0x25, 0x17, 0x78, 0x41, 0x23, 0x86, 0x74, 0x31, - 0x38, 0x32, 0x02, 0x17, 0x35, 0x71, 0x27, 0x32, 0x22, 0x82, 0x70, 0x80, 0x38, - 0x04, 0x64, 0x46, 0x18, 0x02, 0x24, 0x61, 0x62, 0x65, 0x00, 0x20, 0x65, 0x70, - 0x00, 0x74, 0x70, 0x70, 0x62, 0x01, 0x31, 0x50, 0x35, 0x05, 0x11, 0x75, 0x35, - 0x25, 0x01, 0x40, 0x73, 0x87, 0x34, 0x37, 0x50, 0x43, 0x37, 0x03, 0x24, 0x06, - 0x50, 0x05, 0x10, 0x03, 0x15, 0x64, 0x21, 0x20, 0x10, 0x75, 0x46, 0x48, 0x70, - 0x65, 0x42, 0x45, 0x53, 0x12, 0x67, 0x47, 0x00, 0x18, 0x64, 0x25, 0x37, 0x44, - 0x42, 0x60, 0x31, 0x31, 0x84, 0x61, 0x70, 0x62, 0x55, 0x64, 0x87, 0x65, 0x63, - 0x02, 0x01, 0x10, 0x81, 0x77, 0x03, 0x74, 0x27, 0x17, 0x87, 0x61, 0x87, 0x65, - 0x43, 0x20, 0x32, 0x58, 0x54, 0x52, 0x00, 0x02, 0x45, 0x37, 0x62, 0x17, 0x56, - 0x32, 0x18, 0x20, 0x62, 0x30, 0x65, 0x77, 0x54, 0x27, 0x21, 0x73, 0x07, 0x85, - 0x21, 0x41, 0x10, 0x82, 0x00, 0x20, 0x12, 0x64, 0x05, 0x78, 0x78, 0x83, 0x25, - 0x58, 0x67, 0x33, 0x70, 0x55, 0x01, 0x08, 0x32, 0x31, 0x33, 0x54, 0x14, 0x13, - 0x27, 0x76, 0x74, 0x14, 0x46, 0x10, 0x66, 0x64, 0x32, 0x21, 0x46, 0x15, 0x77, - 0x72, 0x52, 0x51, 0x14, 0x50, 0x16, 0x57, 0x50, 0x12, 0x71, 0x73, 0x17, 0x45, - 0x85, 0x63, 0x50, 0x75, 0x88, 0x17, 0x36, 0x37, 0x62, 0x58, 0x87, 0x50, 0x46, - 0x18, 0x26, 0x5D, 0x81, 0x52, 0x01, 0x12, 0x63, 0x00, 0x6D, 0x81, 0x3D, 0xD3, - 0xD6, 0x26, 0x80, 0xFD, 0xA4, 0x94, 0x63, 0x92, 0xE8, 0x97, 0x35, 0x4F, 0x6A, - 0x69, 0xA0, 0x59, 0xD9, 0x78, 0x2F, 0x50, 0xEF, 0xAD, 0xCB, 0x25, 0x79, 0xCC, - 0xE5, 0xBE, 0x33, 0xCD, 0x34, 0x7E, 0x28, 0xFE, 0x94, 0x9B, 0x13, 0x47, 0x1F, - 0x19, 0x4E, 0x54, 0x58, 0xFC, 0x42, 0x30, 0x2C, 0xE2, 0x95, 0xBD, 0x11, 0xA2, - 0x1C, 0x8B, 0x50, 0x29, 0xA7, 0x29, 0xB6, 0x1D, 0x4B, 0x3B, 0x26, 0x05, 0xBD, - 0xDF, 0xCC, 0x8E, 0x7F, 0xD5, 0x57, 0x6F, 0x25, 0x74, 0x64, 0x5A, 0x39, 0x93, - 0x01, 0xB2, 0xA8, 0xBA, 0xF6, 0xFA, 0x6B, 0xA0, 0xEB, 0xB1, 0xE8, 0xFC, 0xC9, - 0x3C, 0x88, 0x8A, 0x86, 0x4C, 0x2B, 0xF9, 0x6F, 0xFB, 0x83, 0xA6, 0xFD, 0xBA, - 0x9E, 0x5B, 0x44, 0x99, 0xBF, 0x6D, 0xE9, 0xEB, 0x3A, 0x66, 0xD0, 0xB8, 0x2B, - 0x3B, 0x28, 0xF1, 0x6B, 0x63, 0x3E, 0x9F, 0x1B, 0xC2, 0x08, 0xAB, 0x23, 0x97, - 0xDF, 0x14, 0xF0, 0xA8, 0xBF, 0x52, 0xF1, 0x6B, 0x98, 0x09, 0x57, 0x9F, 0x10, - 0x79, 0x0C, 0x55, 0x10, 0x6F, 0x16, 0x89, 0xEF, 0x31, 0x91, 0x6B, 0xC8, 0x7A, - 0xFF, 0x41, 0x13, 0xE6, 0x66, 0x7A, 0x55, 0x72, 0xC7, 0xF9, 0x34, 0xC0, 0x4A, - 0xCD, 0x21, 0x17, 0x10, 0x1F, 0x08, 0x42, 0x9E, 0x53, 0x89, 0x40, 0xF8, 0x98, - 0xC2, 0xC2, 0x1A, 0xF3, 0x1D, 0xB5, 0xF3, 0xB9, 0x4C, 0xCA, 0xB7, 0xB9, 0x8E, - 0x82, 0x67, 0x83, 0x83, 0x82, 0xAF, 0xB6, 0xEE, 0xBB, 0xFF, 0xA4, 0x99, 0xA9, - 0xF6, 0x9D, 0xCF, 0x22, 0x27, 0x0F, 0xE2, 0x02, 0xCC, 0x69, 0x8E, 0x93, 0x2E, - 0x26, 0x81, 0x95, 0x1E, 0x33, 0xBD, 0xA0, 0xD5, 0xBE, 0xD5, 0xD4, 0x89, 0xFE, - 0xF7, 0x7E, 0x19, 0x38, 0x37, 0x94, 0x5D, 0x44, 0xE1, 0xAD, 0x80, 0x85, 0xF9, - 0x53, 0x26, 0x13, 0xF1, 0x92, 0xAB, 0xC0, 0xCA, 0x9D, 0xC0, 0x71, 0x10, 0x06, - 0xC5, 0xB3, 0x09, 0xDF, 0xAA, 0xA8, 0x7D, 0x8D, 0xEC, 0x0B, 0x1A, 0xDF, 0x92, - 0xC8, 0x55, 0x4D, 0x2A, 0x8F, 0xBC, 0x9D, 0x72, 0x58, 0xC4, 0x74, 0x5B, 0x1A, - 0x1E, 0x33, 0x60, 0x77, 0x49, 0x97, 0x97, 0x19, 0x28, 0x5C, 0x8D, 0x0E, 0xC6, - 0x35, 0xDE, 0x44, 0xED, 0x15, 0x21, 0x54, 0x20, 0x26, 0x59, 0x10, 0xA2, 0x6E, - 0x2D, 0xE6, 0x0A, 0xA5, 0xB9, 0xB8, 0x9B, 0x51, 0x88, 0x19, 0x1B, 0x15, 0x54, - 0xC5, 0x9C, 0x14, 0x1B, 0x44, 0x13, 0xB0, 0xB9, 0xE5, 0x98, 0xFA, 0x8C, 0x7B, - 0x62, 0x0B, 0x70, 0xF6, 0x0F, 0x63, 0xAA, 0x7C, 0x2C, 0x9D, 0xD3, 0x43, 0x7F, - 0x86, 0xCB, 0x3E, 0xE2, 0xCB, 0x24, 0x65, 0x80, 0xDE, 0x5F, 0x34, 0x59, 0xC0, - 0x19, 0x94, 0xEF, 0x76, 0x34, 0x49, 0x97, 0x5A, 0xF0, 0x08, 0x09, 0xA3, 0xA0, - 0xC2, 0x60, 0x1B, 0x45, 0xC0, 0x30, 0x15, 0x54, 0x53, 0xB7, 0x5F, 0x4D, 0xA3, - 0x61, 0x5E, 0x74, 0xF3, 0x93, 0xD4, 0x86, 0x1B, 0x2C, 0x09, 0xF4, 0x60, 0x53, - 0xA3, 0x8D, 0x5C, 0x6C, 0x04, 0x35, 0x5B, 0x74, 0x7A, 0x65, 0xBA, 0x0F, 0x24, - 0xAC, 0xB4, 0xB0, 0x70, 0x35, 0x16, 0x65, 0xB6, 0x74, 0x17, 0x1F, 0x02, 0xF1, - 0xA7, 0x4C, 0xE4, 0x72, 0x40, 0xDF, 0x99, 0x1F, 0x0B, 0x1A, 0x2E, 0x3E, 0x2B, - 0xB1, 0x9E, 0x4A, 0x54, 0x46, 0xD2, 0x43, 0x89, 0xA2, 0x6D, 0x93, 0x45, 0x6E, - 0x36, 0x90, 0xC1, 0x32, 0x11, 0x1E, 0xBC, 0xF4, 0x44, 0x54, 0x9C, 0xEE, 0x0E, - 0x3F, 0xAE, 0x2D, 0x65, 0x07, 0x91, 0xA1, 0xF4, 0x79, 0xAA, 0xB1, 0xFA, 0xC8, - 0xB9, 0x46, 0x85, 0xA8, 0x34, 0x07, 0x96, 0x15, 0xB2, 0xB9, 0xBC, 0x39, 0xF5, - 0x0C, 0x5B, 0x17, 0x97, 0x4E, 0xE7, 0xCC, 0x4F, 0x25, 0xC3, 0x6C, 0x9B, 0xB5, - 0x84, 0x25, 0x0E, 0xEE, 0x91, 0xF2, 0xF1, 0x53, 0x5A, 0xC6, 0x01, 0xF7, 0x86, - 0x97, 0xCD, 0xE8, 0x08, 0xD6, 0x04, 0x9E, 0x0A, 0x44, 0x69, 0xB3, 0xA0, 0x66, - 0x87, 0xF6, 0x41, 0x93, 0xC2, 0x24, 0x15, 0xEB, 0xD4, 0x23, 0x52, 0xF2, 0xEB, - 0x9F, 0x9B, 0x38, 0x8B, 0xAF, 0x96, 0x49, 0xE1, 0xD7, 0x4E, 0x00, 0x0A, 0x5F, - 0x7A, 0x6B, 0x78, 0xC6, 0x69, 0x0C, 0x47, 0x54, 0xB3, 0x38, 0x13, 0x04, 0x6C, - 0x41, 0x38, 0x14, 0xAD, 0x0F, 0x94, 0x0C, 0x2B, 0xB7, 0x22, 0x64, 0x99, 0xD3, - 0x27, 0x52, 0x1D, 0x7D, 0xFE, 0xF8, 0xE0, 0xFC, 0xE4, 0x01, 0x8B, 0x80, 0x06, - 0x9D, 0xC3, 0x93, 0x3A, 0xAD, 0xF4, 0x9C, 0x85, 0x10, 0xC8, 0x5B, 0xC0, 0x24, - 0x68, 0xE4, 0x11, 0x37, 0xEF, 0x72, 0x50, 0x18, 0x21, 0x6E, 0xAD, 0x49, 0xC1, - 0xFD, 0x67, 0xFF, 0x14, 0xBE, 0xBE, 0xF4, 0x29, 0xE9, 0xE5, 0xF9, 0x39, 0xF8, - 0x92, 0xFD, 0xD2, 0x53, 0x36, 0x9F, 0x23, 0x25, 0xC5, 0xEC, 0xB8, 0xD8, 0xA8, - 0xF5, 0x7F, 0x6D, 0xE9, 0x14, 0x54, 0x87, 0x99, 0xBC, 0xD5, 0xC3, 0xF2, 0xF7, - 0xA4, 0x62, 0xCB, 0x02, 0xDF, 0x4D, 0x5C, 0x71, 0xAD, 0x5A, 0xC1, 0xD2, 0xA0, - 0x86, 0xF4, 0xEC, 0x49, 0x45, 0x7B, 0x30, 0x37, 0x73, 0xCC, 0x21, 0x85, 0xBF, - 0xC0, 0xF2, 0xF3, 0x65, 0x14, 0x69, 0xEE, 0x5E, 0x08, 0x91, 0xFD, 0x70, 0xEF, - 0xE4, 0xF1, 0x4F, 0x57, 0x56, 0x87, 0x6D, 0x9F, 0x2D, 0x18, 0x6F, 0x47, 0x38, - 0xF0, 0xCE, 0xDB, 0xB2, 0x32, 0x55, 0xE8, 0x8D, 0x74, 0x38, 0x34, 0x04, 0xB3, - 0x00, 0xF3, 0x26, 0xCB, 0x00, 0xE3, 0x94, 0x82, 0x73, 0x0C, 0x6A, 0x27, 0x8B, - 0x0B, 0x74, 0xC8, 0xB7, 0x48, 0xDE, 0x32, 0xC4, 0x0B, 0x18, 0xA5, 0x97, 0x60, - 0x82, 0x2A, 0xB7, 0xA5, 0xDB, 0x11, 0x7D, 0xA6, 0xDA, 0xEC, 0x7F, 0x83, 0x89, - 0xF1, 0x3E, 0x69, 0x66, 0x2A, 0xAB, 0x44, 0x05, 0x65, 0x40, 0xB1, 0xB2, 0xF0, - 0x37, 0xA1, 0x1B, 0x21, 0x07, 0x8B, 0x10, 0xB1, 0xDD, 0xE4, 0xD4, 0xA3, 0x1A, - 0xD6, 0xE7, 0x4A, 0x4B, 0x15, 0xCC, 0x54, 0xE2, 0x66, 0x82, 0x66, 0x19, 0x20, - 0x92, 0x70, 0x3E, 0xA9, 0x51, 0x7E, 0x15, 0xF7, 0x73, 0x8A, 0x7A, 0x35, 0xD5, - 0xC7, 0x96, 0xB4, 0xD2, 0x56, 0xEA, 0x6F, 0x7C, 0xDD, 0xDB, 0xA6, 0x92, 0x68, - 0xD1, 0x9D, 0x5F, 0x28, 0xC6, 0xA2, 0xD5, 0x26, 0xAE, 0x79, 0x8F, 0xAF, 0x6E, - 0x7D, 0x26, 0x36, 0xB8, 0x6D, 0xF7, 0x3A, 0x5F, 0xCE, 0x4B, 0x52, 0xBB, 0xAE, - 0x5C, 0xEE, 0xFC, 0x45, 0x06, 0xE4, 0x82, 0x46, 0xC2, 0x94, 0xC0, 0x5E, 0xC5, - 0x7E, 0x0F, 0x96, 0x83, 0xF0, 0xD7, 0x4C, 0x6A, 0x9D, 0x78, 0x7C, 0x77, 0xDF, - 0xB5, 0x7E, 0x40, 0x38, 0x11, 0xA7, 0x43, 0xF4, 0x3B, 0x44, 0x17, 0xDF, 0xD5, - 0x37, 0x72, 0xFC, 0x5C, 0x44, 0x31, 0x36, 0x62, 0x77, 0x57, 0xAD, 0x06, 0x43, - 0xAE, 0xF2, 0x83, 0x45, 0x08, 0x0C, 0xDA, 0x1B, 0xD9, 0x48, 0x81, 0xEE, 0x08, - 0xB7, 0xC3, 0xEC, 0x59, 0x1F, 0x3C, 0xAB, 0x14, 0x84, 0x50, 0x57, 0x9F, 0xA8, - 0x86, 0xC4, 0x26, 0x79, 0x34, 0xF8, 0x04, 0x14, 0xA4, 0xDE, 0x60, 0x91, 0xE7, - 0xAA, 0x1A, 0xD6, 0x05, 0x71, 0xB1, 0xE6, 0x7B, 0x69, 0x9A, 0xB8, 0x53, 0xB7, - 0x4B, 0x5A, 0xC1, 0x6B, 0xCE, 0x26, 0x28, 0x67, 0x2B, 0x26, 0x11, 0xFA, 0xAD, - 0x03, 0xA0, 0x48, 0xDE, 0x77, 0x99, 0x7D, 0x8D, 0x59, 0x69, 0xDE, 0xCB, 0x4B, - 0x03, 0x57, 0xF2, 0x3B, 0xAB, 0xC0, 0x26, 0x06, 0x5A, 0x93, 0x11, 0xEC, 0x01, - 0xEA, 0x20, 0xBB, 0xBC, 0x3D, 0x9F, 0x2F, 0xAF, 0xA6, 0x27, 0x73, 0x06, 0xE8, - 0xF6, 0x58, 0xE0, 0x4F, 0x75, 0xD9, 0xC2, 0xF3, 0x29, 0xEF, 0xB2, 0x08, 0xC3, - 0x0E, 0x9F, 0xAD, 0x44, 0x4C, 0xF1, 0xBB, 0xE9, 0x12, 0x2A, 0x40, 0xEB, 0xFA, - 0x1E, 0x1F, 0x89, 0x57, 0x2B, 0xAF, 0x6F, 0x9C, 0x05, 0xC9, 0x0E, 0xA5, 0x18, - 0xA3, 0xFF, 0x8A, 0x7D, 0x11, 0x08, 0x63, 0xE3, 0x5E, 0x26, 0x9B, 0xE8, 0xE3, - 0x10, 0x40, 0x9D, 0x61, 0x4B, 0x7A, 0x53, 0x96, 0xF3, 0x8B, 0x5B, 0x18, 0xA0, - 0x51, 0x25, 0xF2, 0x7B, 0x07, 0xAB, 0x9C, 0x36, 0xE8, 0xC5, 0xD9, 0x2D, 0xCE, - 0xB3, 0x77, 0x05, 0xCE, 0xFC, 0x9E, 0x95, 0x2C, 0xE0, 0x6A, 0x27, 0xE6, 0x6D, - 0xF2, 0xB3, 0xA6, 0x86, 0xE0, 0x09, 0xB0, 0x90, 0xF6, 0xB3, 0x6E, 0x9F, 0xB1, - 0x6B, 0x18, 0x03, 0xA1, 0x91, 0x2F, 0x86, 0xFF, 0xC0, 0x11, 0x59, 0xBE, 0x9C, - 0x80, 0x17, 0x84, 0x9D, 0x5B, 0x81, 0x1C, 0x31, 0x52, 0x58, 0xBB, 0xE9, 0x33, - 0x38, 0x64, 0x81, 0x86, 0x6C, 0x5A, 0x9E, 0x6E, 0x47, 0x9D, 0x4F, 0xF9, 0x5B, - 0xD9, 0x5B, 0x57, 0xCD, 0xCC, 0x71, 0xE2, 0x69, 0x50, 0x9D, 0x35, 0xB4, 0x83, - 0x3A, 0xAC, 0xAD, 0x02, 0x0E, 0x39, 0xDB, 0x91, 0xC5, 0x39, 0x62, 0x67, 0x18, - 0x5E, 0xEB, 0x8C, 0x6B, 0x84, 0x49, 0xB1, 0x93, 0x2D, 0x7B, 0x0C, 0x91, 0xA6, - 0xB5, 0x94, 0x2B, 0xF8, 0x4F, 0x6A, 0x31, 0x99, 0xC6, 0x21, 0x7E, 0xE2, 0x88, - 0xBD, 0x83, 0xC1, 0x87, 0xB0, 0xB7, 0xA3, 0x39, 0xC8, 0x39, 0xB9, 0xA6, 0x7B, - 0x08, 0x2B, 0x61, 0x3D, 0xFB, 0xA0, 0x44, 0x2C, 0xA3, 0x7C, 0x40, 0xF9, 0xA4, - 0x03, 0xB1, 0x63, 0x3C, 0xDF, 0xAD, 0x7B, 0x53, 0x79, 0xAA, 0xDB, 0x7E, 0xD2, - 0x10, 0x99, 0x32, 0xB4, 0xF7, 0x7E, 0x15, 0xED, 0x9B, 0x6A, 0xB4, 0x95, 0xFE, - 0x5A, 0x2F, 0x1F, 0xA4, 0x09, 0x78, 0xC8, 0x82, 0x5A, 0xAC, 0xDC, 0x55, 0x3B, - 0x09, 0x5B, 0x47, 0x5C, 0x16, 0x37, 0x0B, 0x8B, 0x2C, 0x5F, 0x81, 0xCB, 0x3F, - 0x1E, 0xF1, 0x56, 0x66, 0x12, 0xF3, 0xCF, 0x4C, 0x73, 0x15, 0xBB, 0xC3, 0xAC, - 0x53, 0x63, 0xB1, 0x9E, 0x27, 0x14, 0x3E, 0xB2, 0x19, 0x74, 0xEB, 0x2B, 0x31, - 0x94, 0x50, 0xE4, 0x55, 0x2E, 0x6D, 0xFB, 0x85, 0x8C, 0x76, 0xD4, 0x16, 0x58, - 0xA9, 0xFD, 0xC7, 0x8A, 0x1E, 0x72, 0x83, 0xC2, 0x60, 0x97, 0x6C, 0x90, 0x90, - 0x2F, 0x0C, 0x2B, 0x85, 0x83, 0xEC, 0x05, 0xB6, 0x7C, 0xC6, 0x0F, 0x68, 0x16, - 0x17, 0x94, 0x4D, 0x0D, 0x0D, 0x0D, 0x94, 0x70, 0xDE, 0xA1, 0x6D, 0xB0, 0x43, - 0x7D, 0x0F, 0xFE, 0xA7, 0xC6, 0x14, 0xE7, 0x76, 0x5B, 0xD5, 0x4D, 0x0E, 0x39, - 0x9C, 0x59, 0x46, 0x54, 0xF8, 0xEC, 0xFA, 0x07, 0x17, 0xB2, 0xCB, 0x41, 0x15, - 0xE8, 0x08, 0xC0, 0x45, 0xAC, 0x8A, 0xBF, 0x47, 0xFC, 0xDB, 0x19, 0x87, 0xD8, - 0xE9, 0xE5, 0xB5, 0xAE, 0x07, 0xAB, 0x9A, 0x4B, 0x81, 0x4F, 0x6D, 0x26, 0xD5, - 0x10, 0xFB, 0x99, 0xFF, 0xCC, 0x11, 0x31, 0x64, 0xF9, 0x78, 0xF5, 0x9D, 0x6A, - 0xC1, 0xCA, 0x4A, 0xC2, 0x79, 0x22, 0xF9, 0x76, 0x8C, 0x1F, 0xD7, 0xF8, 0xE9, - 0x9D, 0x2C, 0xBB, 0x7A, 0x54, 0xFD, 0xF1, 0x3F, 0x69, 0x3A, 0xC9, 0xE0, 0x26, - 0x8B, 0x64, 0xBD, 0x60, 0x8B, 0x22, 0xD1, 0xAA, 0x95, 0x1B, 0xD9, 0x73, 0x49, - 0xF6, 0xCA, 0x37, 0xA7, 0xB7, 0xE9, 0xA9, 0x15, 0xA8, 0x4A, 0xDC, 0xDF, 0xEA, - 0xFA, 0xC6, 0x99, 0x6F, 0xBE, 0x6A, 0xBC, 0xB7, 0x6D, 0x2E, 0xB0, 0x64, 0x9F, - 0xD2, 0x90, 0xFC, 0xE0, 0xCA, 0x60, 0x13, 0x33, 0xB3, 0xD5, 0x13, 0xBF, 0x17, - 0xEB, 0x58, 0xBF, 0x2D, 0x6A, 0x87, 0xB1, 0x37, 0xD6, 0xB2, 0xE1, 0x8C, 0xD0, - 0x69, 0x79, 0xF6, 0x08, 0x65, 0xCB, 0x3E, 0x2B, 0x10, 0x42, 0xFA, 0xCF, 0xCC, - 0xE9, 0xD1, 0x82, 0xF1, 0x21, 0xBB, 0xEA, 0xDD, 0x3B, 0x65, 0x01, 0xE2, 0x9A, - 0x56, 0x6F, 0x95, 0xAE, 0xAB, 0x6F, 0xCA, 0x45, 0xD1, 0x84, 0x11, 0x65, 0xA4, - 0x50, 0xEE, 0x36, 0x8E, 0xA7, 0x5E, 0x85, 0xBD, 0x22, 0x22, 0x50, 0x97, 0x63, - 0x7B, 0x47, 0xEE, 0xBE, 0xF1, 0x54, 0x54, 0xC7, 0xB9, 0xCA, 0xE7, 0x25, 0xFA, - 0x9C, 0x6E, 0xEC, 0x2B, 0x9C, 0x03, 0x89, 0x48, 0x50, 0xF8, 0xBB, 0x1E, 0xED, - 0x2B, 0xF2, 0x78, 0x5E, 0x69, 0x20, 0xBE, 0xA3, 0xB9, 0x2F, 0x80, 0x10, 0x64, - 0x23, 0xDA, 0x6F, 0x15, 0xB5, 0x7F, 0xF7, 0xD3, 0xD4, 0x50, 0x1D, 0x37, 0x32, - 0xB4, 0xCB, 0xD5, 0xA4, 0x29, 0x3E, 0xFE, 0x85, 0x8A, 0xB0, 0x53, 0xE3, 0x72, - 0x57, 0x08, 0x6E, 0x72, 0x58, 0xC4, 0x43, 0x3B, 0x34, 0xAE, 0x77, 0xB9, 0x2C, - 0x3D, 0x01, 0xE7, 0x98, 0x13, 0x48, 0x3A, 0x77, 0x5D, 0x9A, 0x84, 0xE8, 0xD2, - 0x66, 0x79, 0x91, 0x8D, 0x22, 0x81, 0x13, 0x9B, 0xDC, 0xEB, 0x0A, 0x30, 0xAF, - 0x6F, 0x70, 0x6D, 0x88, 0xD3, 0x40, 0x39, 0xB6, 0x88, 0x55, 0x51, 0xCF, 0xAD, - 0x9A, 0x09, 0x1E, 0x5C, 0x9D, 0x66, 0xD0, 0x63, 0x8C, 0x0C, 0x7C, 0x5F, 0x1E, - 0x1F, 0x42, 0x41, 0xA9, 0xB7, 0x12, 0x52, 0xA7, 0xF9, 0x96, 0x49, 0xAA, 0x03, - 0xAB, 0x83, 0x3D, 0x46, 0x22, 0x67, 0x36, 0xBF, 0x2A, 0x75, 0xAB, 0xB1, 0x11, - 0xD0, 0xA5, 0x20, 0x2A, 0x40, 0x7A, 0x6C, 0x38, 0x86, 0xBF, 0xD1, 0x3A, 0xFC, - 0x1F, 0xBB, 0x84, 0x71, 0x52, 0xB6, 0x5E, 0x5F, 0xC3, 0x46, 0xF5, 0x0F, 0x09, - 0xD2, 0xC2, 0x0F, 0x5E, 0x69, 0x3E, 0x3C, 0x64, 0x2C, 0x22, 0x15, 0xBC, 0x61, - 0x0D, 0x27, 0x37, 0xDB, 0x18, 0x5F, 0xE1, 0x7B, 0x1A, 0x2B, 0xDC, 0x10, 0x04, - 0x27, 0x31, 0x7D, 0x4B, 0x22, 0x57, 0x14, 0x65, 0x57, 0xA5, 0x59, 0x58, 0x85, - 0x04, 0xEC, 0x1F, 0x71, 0x23, 0x2F, 0x1E, 0xEC, 0x4F, 0xE3, 0x01, 0xCE, 0x3C, - 0xFA, 0x51, 0xBC, 0xE8, 0xD2, 0x84, 0xCB, 0x92, 0x44, 0xD8, 0xE3, 0x82, 0x61, - 0xDE, 0x74, 0x38, 0x7A, 0x44, 0x5F, 0xF5, 0xF5, 0x36, 0x8F, 0x23, 0xD0, 0x7B, - 0x0A, 0xA0, 0x4B, 0x26, 0x2F, 0xCC, 0x82, 0x24, 0x37, 0x94, 0x6B, 0x21, 0xC2, - 0xAD, 0xAB, 0x03, 0x2B, 0x23, 0x8F, 0xE6, 0xF0, 0x54, 0xA8, 0xA6, 0x1D, 0x9A, - 0x0F, 0xC5, 0x37, 0x46, 0x28, 0x49, 0x59, 0x37, 0x2A, 0x9B, 0x5E, 0xB5, 0x96, - 0x69, 0x8C, 0xF7, 0x57, 0x9A, 0x71, 0xBA, 0x05, 0xCD, 0x08, 0x47, 0xE1, 0x3B, - 0x6A, 0xAD, 0x7A, 0x3B, 0x86, 0xDF, 0xE1, 0x60, 0xBB, 0x7C, 0xE8, 0x57, 0x6B, - 0x3F, 0x1F, 0x99, 0xEA, 0xCE, 0xFC, 0x23, 0xA2, 0x10, 0x8F, 0x04, 0x9A, 0x17, - 0x6D, 0x6A, 0xEB, 0xEC, 0x32, 0xD7, 0xAF, 0x1E, 0x4B, 0xA6, 0x76, 0x53, 0x14, - 0xAE, 0x5C, 0x19, 0x27, 0x38, 0x5D, 0xEE, 0x1F, 0xFA, 0xB1, 0xEF, 0x9F, 0x5F, - 0x96, 0x88, 0x40, 0x89, 0xF7, 0x02, 0x2B, 0xC6, 0x38, 0xF5, 0x32, 0xE5, 0x86, - 0x51, 0x3F, 0x54, 0x8C, 0x0E, 0x87, 0xCF, 0x1C, 0x0C, 0xF6, 0xFC, 0xF1, 0x5D, - 0xB2, 0x3D, 0x1A, 0x20, 0x79, 0x31, 0x7D, 0x94, 0xDB, 0xE8, 0x3E, 0x8E, 0xA5, - 0xE1, 0x44, 0xC9, 0xD7, 0x8E, 0x0F, 0x1E, 0x1E, 0x45, 0x3E, 0xB0, 0x26, 0x11, - 0xBA, 0x80, 0xFB, 0xA0, 0x91, 0xBD, 0xBE, 0xFA, 0xA2, 0x92, 0x73, 0x44, 0x8F, - 0xCA, 0x18, 0xE0, 0x37, 0x90, 0x21, 0x98, 0xF3, 0xA7, 0x5A, 0xE1, 0x66, 0x8A, - 0x44, 0x84, 0xBB, 0x16, 0x97, 0x74, 0xCE, 0x89, 0x4C, 0x07, 0x1C, 0x09, 0xD4, - 0xB4, 0x7D, 0xC2, 0x7F, 0x01, 0x0E, 0xAB, 0x0F, 0x2E, 0x2E, 0x49, 0xC6, 0x3E, - 0x80, 0x6D, 0x87, 0xCF, 0xC9, 0xA9, 0x84, 0x59, 0x80, 0x15, 0x53, 0x05, 0xE7, - 0xFC, 0x0D, 0x62, 0x52, 0x06, 0xBA, 0xFF, 0xCA, 0xBB, 0xBA, 0x3F, 0x33, 0xDF, - 0xE1, 0x4D, 0xCF, 0xE8, 0x6F, 0x52, 0x41, 0x10, 0x99, 0xE1, 0x0B, 0xC7, 0x3A, - 0xDE, 0xAD, 0x36, 0x4B, 0x89, 0x20, 0x0B, 0x1D, 0x27, 0xD5, 0x6C, 0x35, 0xF5, - 0x2B, 0x39, 0xEE, 0xF6, 0xF4, 0x8E, 0xEE, 0x21, 0x6F, 0x24, 0x66, 0xD3, 0x4E, - 0x02, 0x09, 0xF1, 0xDF, 0xE7, 0xDC, 0x05, 0x07, 0x27, 0xF5, 0x75, 0x6F, 0xDE, - 0xD7, 0x56, 0xF5, 0x46, 0x92, 0x61, 0x8A, 0xDC, 0xBF, 0x6A, 0xFD, 0x48, 0xA4, - 0x77, 0x43, 0x13, 0x84, 0x69, 0xE9, 0x50, 0x4A, 0x65, 0x03, 0x64, 0x07, 0x15, - 0x05, 0xCA, 0x9F, 0x45, 0xCB, 0x3B, 0xE2, 0x2D, 0x13, 0xA6, 0x61, 0x7B, 0x1A, - 0x0C, 0x4C, 0x84, 0x9A, 0xAE, 0xE9, 0x54, 0x72, 0x12, 0x14, 0xD6, 0xC5, 0xD3, - 0xBC, 0x72, 0x2E, 0x3A, 0x79, 0xF3, 0x0A, 0xD8, 0x21, 0x0A, 0x85, 0xD0, 0xBC, - 0xEB, 0x89, 0x6C, 0x7D, 0x3A, 0x61, 0xB9, 0x1B, 0x47, 0x24, 0xAE, 0x13, 0xCB, - 0xA8, 0xF7, 0xBE, 0x62, 0x50, 0xC6, 0x63, 0xEA, 0xDE, 0xD0, 0x25, 0x94, 0xE1, - 0x4A, 0x1A, 0xB6, 0xEC, 0x1F, 0x70, 0x1A, 0xF0, 0xFD, 0xD2, 0x7E, 0x27, 0x16, - 0x11, 0xEB, 0xFD, 0x86, 0x85, 0xFA, 0xA3, 0x62, 0xF8, 0x4E, 0x4C, 0xBB, 0x0D, - 0x60, 0x73, 0x76, 0x4A, 0x5B, 0x15, 0x15, 0x3A, 0x76, 0x4B, 0x2D, 0xCD, 0xF8, - 0xD5, 0x06, 0x2C, 0x10, 0x98, 0x6C, 0x54, 0xA1, 0x92, 0xDE, 0xED, 0xFC, 0x59, - 0xD8, 0x7C, 0x94, 0xAF, 0x62, 0x75, 0xD6, 0x73, 0x87, 0x7A, 0xED, 0xC2, 0x63, - 0xF8, 0x2B, 0x28, 0x79, 0x7D, 0xD5, 0xD7, 0xFB, 0xF7, 0x33, 0x7F, 0x9B, 0xF7, - 0xFC, 0xFC, 0xF6, 0x67, 0x38, 0x8A, 0x4B, 0xEB, 0x6F, 0x1B, 0x96, 0x32, 0x45, - 0x34, 0x6E, 0xF5, 0x79, 0xB0, 0x0E, 0xAA, 0x54, 0xC4, 0x8E, 0xBB, 0x67, 0x5A, - 0x15, 0x47, 0x84, 0xE6, 0x57, 0x85, 0x9E, 0x61, 0x83, 0x79, 0xD5, 0x1D, 0x27, - 0xBE, 0x5F, 0x40, 0xF5, 0x18, 0x02, 0x8E, 0x1D, 0x77, 0xB8, 0x28, 0x08, 0xD3, - 0xF1, 0x34, 0xED, 0x67, 0xFD, 0xBA, 0x36, 0x3E, 0x66, 0xF2, 0x8C, 0xF7, 0x55, - 0x85, 0x25, 0x72, 0x49, 0x31, 0x56, 0xE4, 0xC5, 0x83, 0x1F, 0x44, 0x09, 0x69, - 0x8D, 0xC5, 0xE7, 0x36, 0xB2, 0xF2, 0x4D, 0xD0, 0xAC, 0x09, 0xD9, 0x55, 0x4F, - 0xB0, 0x8F, 0xAC, 0x2F, 0xC7, 0x6F, 0xE2, 0x23, 0x23, 0x50, 0x67, 0x18, 0xFF, - 0x05, 0xE4, 0xB8, 0x94, 0x5C, 0xF1, 0xE3, 0x65, 0x20, 0x48, 0xE4, 0x0F, 0x76, - 0xA5, 0xE3, 0x91, 0xB4, 0xD5, 0x51, 0x57, 0x90, 0x0C, 0xF3, 0x73, 0xF1, 0x10, - 0x3C, 0xE1, 0xBB, 0xCC, 0xD1, 0xDD, 0xCA, 0xF9, 0xDD, 0x2A, 0x0D, 0x99, 0xE2, - 0x60, 0x4B, 0xCE, 0x72, 0x79, 0x0C, 0x9C, 0xFC, 0x35, 0x19, 0xBA, 0xA9, 0xA3, - 0x5E, 0xA1, 0x17, 0x59, 0x02, 0x9E, 0x26, 0x28, 0xEA, 0x44, 0x50, 0x05, 0x7C, - 0x7C, 0x63, 0x64, 0xCB, 0xE9, 0xB2, 0x55, 0xC1, 0x28, 0x65, 0x88, 0xF2, 0x1A, - 0x25, 0x03, 0xAD, 0x71, 0x94, 0xEA, 0x8F, 0xFE, 0x0E, 0x0A, 0x07, 0xD3, 0x95, - 0xC8, 0x53, -}; +static const uint8_t kExampleMLDSA65KeyDER[] = { +0x30, 0x82, 0xF, 0xD4, 0x2, 0x1, 0x0, 0x30, 0xB, 0x6, 0x9, 0x60, 0x86, +0x48, 0x1, 0x65, 0x3, 0x4, 0x3, 0x12, 0x4, 0x82, 0xF, 0xC0, 0x9B, 0x77, +0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x2, 0x9B, 0xA5, 0xD4, 0xE5, +0x93, 0xA1, 0xAC, 0xE7, 0x3E, 0x8C, 0x61, 0xB7, 0xCB, 0xA1, 0x3E, 0x74, 0x8A, +0xC9, 0xC0, 0xA0, 0x63, 0x31, 0x99, 0xCE, 0x5B, 0x64, 0x5C, 0x4, 0xBC, 0xAA, +0x47, 0x73, 0x13, 0x4E, 0x53, 0x9F, 0x83, 0x81, 0x49, 0x98, 0x80, 0x58, 0xB2, +0xA1, 0xDB, 0xD8, 0xDB, 0xEB, 0xAD, 0x42, 0xD0, 0xFF, 0xEE, 0x18, 0x1A, 0x15, +0x58, 0x9C, 0x84, 0x7F, 0x2A, 0x73, 0x57, 0x63, 0x60, 0x82, 0xF7, 0xC6, 0xA3, +0xD1, 0x55, 0xC3, 0x4C, 0xE3, 0xA0, 0x49, 0xBC, 0x17, 0xB4, 0x31, 0x99, 0xBF, +0x75, 0xCB, 0xF2, 0xFB, 0x6B, 0x58, 0x52, 0x12, 0xC3, 0xBC, 0xED, 0xDC, 0x32, +0xBE, 0x9, 0x2C, 0xBB, 0x6A, 0x54, 0x6D, 0x9D, 0x5D, 0x97, 0xD3, 0xCC, 0x20, +0x31, 0x9C, 0x7E, 0x2B, 0x5C, 0x42, 0x9E, 0x2E, 0xCB, 0x41, 0x38, 0x84, 0x2, +0x3, 0x24, 0x75, 0x37, 0x23, 0x73, 0x38, 0x85, 0x0, 0x62, 0x42, 0x24, 0x76, +0x38, 0x88, 0x21, 0x31, 0x76, 0x74, 0x55, 0x51, 0x28, 0x34, 0x8, 0x41, 0x32, +0x67, 0x40, 0x11, 0x81, 0x62, 0x48, 0x27, 0x51, 0x85, 0x33, 0x61, 0x12, 0x22, +0x24, 0x30, 0x28, 0x75, 0x20, 0x3, 0x63, 0x11, 0x71, 0x88, 0x38, 0x88, 0x58, +0x84, 0x16, 0x66, 0x14, 0x22, 0x27, 0x28, 0x11, 0x44, 0x37, 0x76, 0x15, 0x24, +0x8, 0x56, 0x40, 0x13, 0x71, 0x74, 0x46, 0x88, 0x14, 0x37, 0x13, 0x0, 0x1, +0x48, 0x44, 0x4, 0x83, 0x67, 0x88, 0x16, 0x0, 0x13, 0x17, 0x6, 0x38, 0x18, +0x76, 0x15, 0x14, 0x67, 0x16, 0x76, 0x57, 0x24, 0x53, 0x86, 0x31, 0x34, 0x16, +0x34, 0x3, 0x8, 0x68, 0x65, 0x77, 0x36, 0x86, 0x37, 0x30, 0x76, 0x20, 0x51, +0x33, 0x82, 0x28, 0x72, 0x45, 0x35, 0x83, 0x6, 0x58, 0x58, 0x37, 0x71, 0x86, +0x0, 0x84, 0x18, 0x11, 0x54, 0x87, 0x12, 0x78, 0x75, 0x23, 0x45, 0x81, 0x17, +0x42, 0x1, 0x0, 0x34, 0x32, 0x55, 0x38, 0x88, 0x25, 0x52, 0x62, 0x5, 0x41, +0x86, 0x88, 0x67, 0x24, 0x81, 0x46, 0x74, 0x31, 0x53, 0x53, 0x45, 0x17, 0x26, +0x48, 0x85, 0x76, 0x24, 0x24, 0x36, 0x18, 0x50, 0x18, 0x18, 0x60, 0x76, 0x4, +0x87, 0x22, 0x0, 0x66, 0x74, 0x52, 0x18, 0x32, 0x7, 0x61, 0x27, 0x68, 0x70, +0x65, 0x78, 0x85, 0x66, 0x60, 0x5, 0x14, 0x77, 0x23, 0x74, 0x70, 0x41, 0x55, +0x12, 0x26, 0x86, 0x35, 0x28, 0x66, 0x30, 0x83, 0x42, 0x52, 0x26, 0x18, 0x34, +0x16, 0x48, 0x23, 0x35, 0x62, 0x37, 0x67, 0x82, 0x50, 0x1, 0x78, 0x70, 0x16, +0x11, 0x35, 0x58, 0x58, 0x8, 0x82, 0x55, 0x61, 0x85, 0x17, 0x46, 0x70, 0x77, +0x77, 0x37, 0x42, 0x35, 0x56, 0x53, 0x85, 0x7, 0x64, 0x13, 0x34, 0x51, 0x25, +0x78, 0x12, 0x21, 0x14, 0x74, 0x81, 0x32, 0x41, 0x0, 0x60, 0x78, 0x71, 0x22, +0x22, 0x56, 0x48, 0x57, 0x24, 0x65, 0x40, 0x36, 0x3, 0x3, 0x17, 0x86, 0x31, +0x44, 0x48, 0x55, 0x60, 0x55, 0x84, 0x68, 0x76, 0x16, 0x15, 0x40, 0x82, 0x64, +0x88, 0x47, 0x88, 0x44, 0x58, 0x46, 0x5, 0x2, 0x47, 0x27, 0x64, 0x20, 0x74, +0x14, 0x74, 0x2, 0x18, 0x21, 0x50, 0x42, 0x43, 0x14, 0x63, 0x5, 0x36, 0x8, +0x38, 0x80, 0x86, 0x80, 0x61, 0x15, 0x80, 0x56, 0x53, 0x13, 0x70, 0x64, 0x66, +0x20, 0x17, 0x21, 0x50, 0x68, 0x7, 0x53, 0x34, 0x73, 0x17, 0x50, 0x68, 0x72, +0x43, 0x2, 0x0, 0x80, 0x7, 0x37, 0x85, 0x72, 0x12, 0x87, 0x73, 0x46, 0x45, +0x56, 0x66, 0x2, 0x72, 0x70, 0x78, 0x34, 0x51, 0x65, 0x31, 0x77, 0x75, 0x52, +0x17, 0x82, 0x84, 0x34, 0x26, 0x51, 0x21, 0x31, 0x18, 0x33, 0x28, 0x84, 0x57, +0x10, 0x30, 0x47, 0x26, 0x27, 0x53, 0x58, 0x10, 0x73, 0x42, 0x67, 0x58, 0x27, +0x36, 0x56, 0x77, 0x25, 0x43, 0x87, 0x75, 0x65, 0x82, 0x51, 0x56, 0x60, 0x65, +0x70, 0x5, 0x7, 0x33, 0x48, 0x37, 0x82, 0x60, 0x11, 0x23, 0x18, 0x15, 0x22, +0x42, 0x10, 0x46, 0x81, 0x47, 0x44, 0x22, 0x73, 0x76, 0x28, 0x30, 0x63, 0x10, +0x24, 0x72, 0x12, 0x17, 0x78, 0x50, 0x1, 0x75, 0x57, 0x42, 0x88, 0x21, 0x22, +0x77, 0x68, 0x22, 0x43, 0x84, 0x14, 0x51, 0x73, 0x68, 0x54, 0x62, 0x8, 0x83, +0x75, 0x41, 0x10, 0x15, 0x14, 0x57, 0x73, 0x42, 0x13, 0x20, 0x52, 0x76, 0x72, +0x34, 0x18, 0x10, 0x0, 0x18, 0x17, 0x55, 0x30, 0x88, 0x47, 0x23, 0x0, 0x76, +0x44, 0x85, 0x25, 0x4, 0x3, 0x88, 0x0, 0x70, 0x10, 0x70, 0x1, 0x80, 0x12, +0x4, 0x73, 0x20, 0x72, 0x21, 0x24, 0x37, 0x4, 0x1, 0x63, 0x76, 0x4, 0x71, +0x30, 0x31, 0x17, 0x20, 0x18, 0x37, 0x23, 0x44, 0x3, 0x8, 0x77, 0x63, 0x73, +0x61, 0x43, 0x70, 0x11, 0x6, 0x84, 0x73, 0x26, 0x38, 0x78, 0x23, 0x61, 0x12, +0x45, 0x84, 0x76, 0x31, 0x23, 0x67, 0x37, 0x7, 0x73, 0x13, 0x46, 0x42, 0x51, +0x13, 0x12, 0x5, 0x15, 0x28, 0x57, 0x64, 0x62, 0x82, 0x42, 0x6, 0x83, 0x25, +0x12, 0x20, 0x40, 0x48, 0x21, 0x47, 0x73, 0x38, 0x13, 0x32, 0x10, 0x73, 0x36, +0x57, 0x3, 0x0, 0x31, 0x54, 0x78, 0x40, 0x23, 0x21, 0x14, 0x35, 0x13, 0x62, +0x83, 0x56, 0x35, 0x87, 0x44, 0x65, 0x74, 0x5, 0x66, 0x76, 0x26, 0x35, 0x17, +0x18, 0x67, 0x12, 0x6, 0x0, 0x42, 0x85, 0x71, 0x20, 0x62, 0x81, 0x22, 0x5, +0x76, 0x32, 0x77, 0x60, 0x65, 0x84, 0x64, 0x14, 0x60, 0x8, 0x55, 0x65, 0x21, +0x18, 0x8, 0x77, 0x72, 0x37, 0x70, 0x28, 0x24, 0x13, 0x18, 0x60, 0x83, 0x73, +0x33, 0x71, 0x16, 0x63, 0x72, 0x55, 0x64, 0x24, 0x11, 0x30, 0x84, 0x54, 0x33, +0x15, 0x33, 0x26, 0x66, 0x32, 0x35, 0x72, 0x52, 0x52, 0x35, 0x85, 0x85, 0x72, +0x5, 0x81, 0x84, 0x34, 0x78, 0x70, 0x65, 0x34, 0x10, 0x76, 0x76, 0x20, 0x76, +0x33, 0x33, 0x22, 0x76, 0x75, 0x28, 0x3, 0x4, 0x21, 0x28, 0x73, 0x3, 0x57, +0x72, 0x3, 0x35, 0x37, 0x66, 0x88, 0x23, 0x88, 0x27, 0x43, 0x32, 0x26, 0x5, +0x20, 0x36, 0x32, 0x78, 0x54, 0x83, 0x38, 0x86, 0x81, 0x78, 0x1, 0x63, 0x21, +0x75, 0x82, 0x1, 0x73, 0x18, 0x0, 0x42, 0x54, 0x67, 0x26, 0x52, 0x38, 0x18, +0x65, 0x87, 0x36, 0x86, 0x53, 0x84, 0x20, 0x6, 0x23, 0x62, 0x73, 0x4, 0x14, +0x83, 0x77, 0x0, 0x57, 0x86, 0x84, 0x70, 0x48, 0x2, 0x71, 0x28, 0x41, 0x42, +0x12, 0x13, 0x73, 0x43, 0x22, 0x65, 0x60, 0x72, 0x75, 0x28, 0x42, 0x17, 0x24, +0x67, 0x38, 0x27, 0x86, 0x58, 0x68, 0x25, 0x42, 0x2, 0x56, 0x62, 0x67, 0x5, +0x34, 0x54, 0x64, 0x68, 0x25, 0x15, 0x55, 0x88, 0x43, 0x58, 0x73, 0x77, 0x65, +0x46, 0x48, 0x36, 0x6, 0x86, 0x32, 0x80, 0x80, 0x18, 0x72, 0x2, 0x54, 0x54, +0x72, 0x10, 0x65, 0x70, 0x41, 0x63, 0x47, 0x35, 0x40, 0x75, 0x2, 0x70, 0x43, +0x18, 0x26, 0x78, 0x51, 0x52, 0x74, 0x43, 0x14, 0x51, 0x53, 0x77, 0x67, 0x53, +0x24, 0x11, 0x11, 0x57, 0x74, 0x18, 0x12, 0x27, 0x73, 0x30, 0x6, 0x42, 0x75, +0x16, 0x17, 0x58, 0x4, 0x81, 0x5, 0x48, 0x54, 0x78, 0x53, 0x71, 0x6, 0x28, +0x41, 0x63, 0x81, 0x67, 0x0, 0x18, 0x25, 0x24, 0x14, 0x70, 0x85, 0x70, 0x80, +0x72, 0x48, 0x23, 0x21, 0x47, 0x13, 0x74, 0x72, 0x4, 0x27, 0x20, 0x75, 0x6, +0x80, 0x12, 0x24, 0x18, 0x57, 0x75, 0x45, 0x33, 0x80, 0x47, 0x28, 0x25, 0x80, +0x86, 0x6, 0x67, 0x23, 0x51, 0x80, 0x6, 0x72, 0x34, 0x30, 0x16, 0x25, 0x15, +0x52, 0x16, 0x57, 0x77, 0x45, 0x1, 0x48, 0x83, 0x35, 0x58, 0x68, 0x77, 0x3, +0x20, 0x34, 0x70, 0x23, 0x66, 0x14, 0x85, 0x0, 0x5, 0x34, 0x32, 0x37, 0x83, +0x56, 0x45, 0x86, 0x32, 0x41, 0x56, 0x64, 0x83, 0x37, 0x77, 0x26, 0x80, 0x45, +0x16, 0x86, 0x64, 0x36, 0x85, 0x25, 0x16, 0x44, 0x47, 0x2, 0x62, 0x75, 0x86, +0x57, 0x82, 0x38, 0x34, 0x85, 0x21, 0x74, 0x15, 0x55, 0x26, 0x53, 0x16, 0x70, +0x82, 0x87, 0x17, 0x4, 0x63, 0x28, 0x21, 0x41, 0x61, 0x66, 0x16, 0x78, 0x37, +0x5, 0x81, 0x13, 0x26, 0x16, 0x56, 0x56, 0x85, 0x4, 0x72, 0x40, 0x64, 0x74, +0x13, 0x85, 0x20, 0x27, 0x14, 0x62, 0x72, 0x67, 0x70, 0x33, 0x25, 0x78, 0x48, +0x1, 0x17, 0x77, 0x14, 0x33, 0x41, 0x65, 0x5, 0x8, 0x0, 0x71, 0x44, 0x88, +0x8, 0x48, 0x2, 0x60, 0x12, 0x88, 0x5, 0x74, 0x56, 0x4, 0x77, 0x4, 0x52, +0x4, 0x31, 0x11, 0x81, 0x78, 0x88, 0x21, 0x11, 0x26, 0x51, 0x60, 0x67, 0x20, +0x37, 0x52, 0x1, 0x63, 0x85, 0x16, 0x68, 0x47, 0x65, 0x25, 0x2, 0x1, 0x18, +0x32, 0x0, 0x57, 0x33, 0x37, 0x38, 0x25, 0x27, 0x36, 0x21, 0x6, 0x40, 0x3, +0x74, 0x43, 0x24, 0x35, 0x86, 0x53, 0x88, 0x53, 0x16, 0x16, 0x2, 0x88, 0x44, +0x22, 0x25, 0x72, 0x63, 0x85, 0x17, 0x81, 0x56, 0x47, 0x16, 0x65, 0x2, 0x24, +0x5, 0x58, 0x55, 0x86, 0x72, 0x18, 0x21, 0x71, 0x86, 0x65, 0x61, 0x88, 0x85, +0x84, 0x70, 0x47, 0x27, 0x63, 0x73, 0x1, 0x26, 0x27, 0x85, 0x54, 0x85, 0x55, +0x45, 0x73, 0x30, 0x36, 0x44, 0x36, 0x45, 0x52, 0x43, 0x8, 0x14, 0x22, 0x64, +0x77, 0x36, 0x43, 0x14, 0x33, 0x66, 0x10, 0x56, 0x84, 0x42, 0x18, 0x77, 0x71, +0x27, 0x86, 0x84, 0x21, 0x26, 0x3, 0x22, 0x14, 0x47, 0x0, 0x51, 0x84, 0x28, +0x52, 0x66, 0x40, 0x66, 0x55, 0x85, 0x67, 0x2, 0x74, 0x6, 0x15, 0x72, 0x87, +0x40, 0x24, 0x71, 0x43, 0x74, 0x10, 0x27, 0x53, 0x42, 0x10, 0x3, 0x77, 0x1, +0x84, 0x8, 0x18, 0x22, 0x86, 0x71, 0x77, 0x48, 0x22, 0x42, 0x50, 0x66, 0x85, +0x34, 0x57, 0x88, 0x31, 0x81, 0x73, 0x66, 0x68, 0x75, 0x50, 0x10, 0x32, 0x73, +0x87, 0x57, 0x77, 0x40, 0x4, 0x3, 0x14, 0x87, 0x31, 0x38, 0x22, 0x65, 0x68, +0x68, 0x88, 0x10, 0x32, 0x71, 0x77, 0x5, 0x51, 0x76, 0x68, 0x40, 0x52, 0x36, +0x63, 0x2, 0x76, 0x84, 0x50, 0x76, 0x27, 0x6, 0x77, 0x58, 0x52, 0x52, 0x74, +0x78, 0x77, 0x77, 0x50, 0x30, 0x84, 0x54, 0x28, 0x53, 0x70, 0x82, 0x7, 0x21, +0x6, 0x64, 0x35, 0x62, 0x80, 0x55, 0x10, 0x71, 0x82, 0x2, 0x66, 0x81, 0x40, +0x57, 0x61, 0x7, 0x16, 0x2, 0x72, 0x67, 0x6, 0x24, 0x88, 0x23, 0x88, 0x63, +0x83, 0x81, 0x14, 0x40, 0x7, 0x17, 0x15, 0x20, 0x63, 0x76, 0x22, 0x75, 0x81, +0x70, 0x43, 0x81, 0x80, 0x43, 0x4, 0x51, 0x78, 0x40, 0x63, 0x36, 0x0, 0x77, +0x40, 0x24, 0x53, 0x11, 0x44, 0x65, 0x62, 0x56, 0x77, 0x20, 0x21, 0x25, 0x8, +0x25, 0x63, 0x34, 0x54, 0x76, 0x53, 0x6, 0x13, 0x1, 0x80, 0x25, 0x77, 0x44, +0x38, 0x17, 0x32, 0x36, 0x13, 0x32, 0x27, 0x0, 0x37, 0x60, 0x63, 0x74, 0x6, +0x52, 0x5, 0x72, 0x83, 0x83, 0x84, 0x28, 0x71, 0x15, 0x38, 0x17, 0x47, 0x8, +0x37, 0x42, 0x67, 0x86, 0x38, 0x62, 0x65, 0x26, 0x23, 0x84, 0x22, 0x38, 0x66, +0x6, 0xD9, 0x77, 0xF8, 0x41, 0xCB, 0x87, 0xD3, 0x3F, 0x76, 0xEB, 0x57, 0x71, +0xFF, 0xBF, 0x14, 0x3B, 0x4C, 0x53, 0x1, 0xA8, 0x24, 0xAC, 0xB4, 0x71, 0x4A, +0xD8, 0xAF, 0xCB, 0x45, 0x70, 0x6E, 0xF8, 0x89, 0xB6, 0x31, 0xA7, 0x8B, 0x4A, +0xCF, 0x6C, 0x42, 0x8E, 0x8, 0xCE, 0x55, 0x7D, 0x0, 0x1B, 0xA3, 0x3B, 0x9D, +0x2D, 0xC0, 0xF9, 0x85, 0x66, 0xA6, 0x3F, 0x5C, 0x77, 0xC0, 0xE1, 0x12, 0xF3, +0xEE, 0xBD, 0x4F, 0x9C, 0xB1, 0xD5, 0x1, 0x50, 0x22, 0x9C, 0xDD, 0xBF, 0xE9, +0xB7, 0xF5, 0x59, 0xC4, 0xB0, 0x9C, 0x2D, 0xB5, 0xA7, 0x4B, 0xB4, 0xD1, 0x2A, +0x91, 0x86, 0xC8, 0x28, 0x31, 0x73, 0xC0, 0x43, 0x2B, 0xBD, 0xDE, 0xDF, 0xA1, +0x2C, 0xAD, 0x9, 0x59, 0xB0, 0xF3, 0x95, 0x63, 0xA1, 0x7A, 0x88, 0x85, 0xA3, +0xFB, 0xF4, 0xD7, 0xF4, 0x1C, 0x68, 0xCD, 0x3F, 0x9C, 0x7A, 0xE5, 0xA9, 0x76, +0xB9, 0xC0, 0x89, 0xEE, 0x51, 0xD6, 0xB6, 0xF3, 0x4A, 0xF7, 0x5, 0xA1, 0x0, +0x6C, 0xF, 0x62, 0xC4, 0x65, 0x21, 0xB5, 0x9C, 0xD8, 0x77, 0x64, 0x94, 0x59, +0xBD, 0xA2, 0x14, 0x97, 0x45, 0x45, 0x58, 0xFF, 0x24, 0xD7, 0x9E, 0x47, 0x38, +0x32, 0xD6, 0x97, 0x98, 0xB7, 0xD7, 0xEF, 0x25, 0xDD, 0xFD, 0xAE, 0x91, 0xF7, +0x1E, 0x53, 0x9A, 0x8C, 0x11, 0xDE, 0xF3, 0xB6, 0x1D, 0xE0, 0x2A, 0xC8, 0x46, +0x47, 0xF8, 0x39, 0x59, 0xC4, 0x62, 0x8B, 0xD2, 0x7E, 0xDB, 0x23, 0xC5, 0xA3, +0x21, 0xF8, 0x16, 0xAE, 0x24, 0xFB, 0x19, 0x8D, 0x4D, 0xC3, 0x37, 0x96, 0x95, +0xA8, 0xA5, 0xA2, 0x8F, 0x4D, 0x77, 0xBC, 0x2E, 0xFB, 0xFE, 0xC8, 0xED, 0x76, +0x42, 0x1C, 0x2A, 0x3B, 0x41, 0xF7, 0xA0, 0xC5, 0xF3, 0xE9, 0x67, 0x7C, 0xC6, +0x88, 0xE7, 0x1A, 0x36, 0x65, 0x32, 0xFC, 0x15, 0x15, 0xF5, 0xA4, 0x9F, 0xA5, +0xF0, 0x67, 0xB1, 0xE6, 0x21, 0x4E, 0x9D, 0x29, 0x29, 0x50, 0xEB, 0x68, 0x36, +0x11, 0x9, 0xA5, 0x9C, 0xBD, 0x69, 0x1C, 0xA5, 0xB9, 0x8F, 0x68, 0x96, 0x1F, +0xA1, 0xDA, 0xFD, 0xF4, 0xED, 0xA2, 0xA6, 0xA7, 0xD2, 0x81, 0x9D, 0x91, 0x56, +0x9, 0xF4, 0x29, 0x24, 0x24, 0xA2, 0x8F, 0xC2, 0xB0, 0xEE, 0x2, 0xD9, 0x96, +0x8B, 0x9D, 0x9E, 0x1A, 0x48, 0xA7, 0x7A, 0x2D, 0x1D, 0x5A, 0xBF, 0x21, 0x60, +0x57, 0xB2, 0x28, 0x3, 0xBD, 0x4B, 0xEE, 0xE1, 0x71, 0x71, 0xF8, 0xC7, 0x3B, +0x1F, 0x2F, 0x6C, 0x2C, 0xBF, 0x1C, 0x51, 0x32, 0xFF, 0xF6, 0x3B, 0x53, 0x57, +0xBD, 0xC9, 0x9A, 0x58, 0xB4, 0xEA, 0x6, 0xBC, 0xDB, 0xB2, 0x2E, 0x86, 0x5D, +0xBB, 0x6A, 0x44, 0xF1, 0x8C, 0x4A, 0x6F, 0x4A, 0x8D, 0xEA, 0x93, 0x19, 0x36, +0xAC, 0x41, 0xA9, 0x92, 0x26, 0x4E, 0x8, 0xA5, 0xA5, 0xE9, 0xC6, 0xBD, 0xB6, +0xC2, 0x4F, 0xFF, 0xD1, 0xA5, 0x89, 0x30, 0xBF, 0x82, 0xE5, 0xEF, 0x1C, 0x47, +0x4B, 0xC, 0x3C, 0xFB, 0x46, 0x9D, 0xDA, 0x30, 0x35, 0xF8, 0x4, 0x9A, 0xD2, +0x60, 0xB7, 0x2C, 0x92, 0x1A, 0xB7, 0xCC, 0xEC, 0x1C, 0x5E, 0xED, 0x41, 0xCA, +0x11, 0xA1, 0x61, 0xDD, 0x6B, 0x4C, 0xA3, 0x1D, 0x95, 0x2A, 0x1A, 0x76, 0xC4, +0x35, 0xE5, 0xA9, 0x75, 0xCD, 0x20, 0x70, 0x91, 0xB0, 0xD3, 0x0, 0x70, 0x9B, +0xE9, 0xDC, 0xB3, 0xC7, 0x72, 0x62, 0xB7, 0xAD, 0x1, 0x4F, 0x6D, 0x23, 0x19, +0x67, 0xD8, 0xE8, 0x78, 0x84, 0x2E, 0xF1, 0xF8, 0x7A, 0x88, 0x13, 0xF2, 0xAA, +0x56, 0x8, 0xE7, 0x69, 0xE5, 0xE4, 0x12, 0x71, 0xBE, 0xFF, 0x9D, 0x94, 0x6D, +0xCA, 0xD2, 0xB5, 0x2A, 0x47, 0xAC, 0xCA, 0x6E, 0x3F, 0x27, 0x47, 0xF8, 0x6C, +0xBA, 0x8E, 0x61, 0x6C, 0xFB, 0x11, 0x50, 0x3D, 0x2E, 0x75, 0x28, 0xFA, 0x3A, +0xAD, 0x5B, 0x4B, 0x7A, 0x21, 0x35, 0x6B, 0x9E, 0xE1, 0xBE, 0xA0, 0xF9, 0x6C, +0x13, 0xE3, 0xC7, 0x84, 0xEB, 0x60, 0x76, 0x8F, 0x33, 0x8C, 0x57, 0xE1, 0x35, +0x2A, 0x1B, 0x5B, 0xD9, 0xA3, 0x77, 0x22, 0x93, 0x48, 0xB1, 0xF2, 0xA5, 0xB1, +0xCA, 0x35, 0x4D, 0x7A, 0x10, 0x0, 0xFB, 0x2E, 0xCD, 0x97, 0x80, 0x23, 0x6C, +0xD8, 0xA5, 0x49, 0x8D, 0xB3, 0x46, 0x5D, 0xEA, 0xE8, 0xF5, 0xFD, 0xDA, 0xE3, +0x9E, 0xDE, 0xF0, 0xB2, 0xF7, 0x5C, 0x82, 0x10, 0x9E, 0xC2, 0x4B, 0x4E, 0xD5, +0x45, 0x54, 0x15, 0xB1, 0xA5, 0xA7, 0xE5, 0xE0, 0xA5, 0xFE, 0x99, 0xB2, 0x6B, +0x30, 0x90, 0x55, 0xE1, 0xAF, 0x4, 0xB2, 0x15, 0x18, 0x60, 0x26, 0x99, 0x98, +0x3E, 0x67, 0xBC, 0x14, 0x45, 0x37, 0x2A, 0xA3, 0x23, 0x58, 0xCA, 0x82, 0x1C, +0x98, 0x7C, 0xC4, 0xB1, 0xE2, 0xED, 0xE5, 0xDF, 0x41, 0xDC, 0x7D, 0x13, 0xDF, +0xC1, 0xC1, 0xA7, 0xE, 0x24, 0x3D, 0xA2, 0x9D, 0x95, 0x44, 0x9, 0x7A, 0x42, +0x2B, 0x0, 0x23, 0x1C, 0x3D, 0xBC, 0x3E, 0x2B, 0x67, 0x6F, 0xB4, 0xC2, 0x49, +0xEB, 0xD, 0xFF, 0x6D, 0x19, 0x34, 0xBF, 0xDE, 0x2A, 0x9, 0x6C, 0x2F, 0x2B, +0x7D, 0xDE, 0x17, 0x54, 0x16, 0xEF, 0x4, 0x86, 0x89, 0xCA, 0x67, 0xA4, 0xE7, +0xBA, 0xF9, 0x7E, 0x8A, 0x42, 0xB2, 0xEB, 0x4F, 0xE8, 0x7B, 0xAD, 0x71, 0xBC, +0x1C, 0xF, 0x1D, 0x40, 0xB1, 0x84, 0xB2, 0x46, 0x46, 0xFB, 0x6A, 0xA7, 0x67, +0x30, 0x9B, 0xD0, 0x1A, 0x7A, 0xC1, 0xE9, 0xE7, 0x1, 0xA4, 0x1B, 0xC9, 0xE, +0x79, 0x6C, 0xE8, 0x46, 0x47, 0xCF, 0xA, 0x64, 0x42, 0xB1, 0xB1, 0x70, 0xB0, +0xB6, 0x6E, 0xDD, 0x93, 0xBA, 0x56, 0x78, 0xBA, 0x63, 0x87, 0x7F, 0x6E, 0x36, +0xC6, 0xFF, 0x90, 0xF5, 0xFC, 0xEE, 0x76, 0x61, 0x5C, 0x53, 0xD4, 0x4C, 0xE4, +0x9C, 0x59, 0xFF, 0x6B, 0x59, 0x44, 0x8E, 0x60, 0xDF, 0xFA, 0x25, 0x63, 0x4, +0xD0, 0xB6, 0x36, 0xF8, 0xF9, 0xB2, 0xD9, 0xDE, 0xD6, 0x29, 0xCD, 0x15, 0x90, +0x47, 0x8F, 0xCA, 0x5C, 0x1D, 0x42, 0x8D, 0x47, 0xF0, 0x72, 0xD5, 0x9, 0x92, +0x72, 0xE5, 0xB4, 0x2A, 0xAB, 0xD9, 0x6, 0x40, 0xDD, 0x3E, 0x7D, 0x85, 0x8, +0x7E, 0x12, 0x7E, 0x6A, 0xD, 0xB7, 0x9F, 0x98, 0xC7, 0x47, 0x63, 0xBB, 0xC6, +0x3C, 0x7, 0x68, 0x5F, 0xC3, 0x82, 0xAC, 0x6A, 0xD6, 0x4D, 0x29, 0x68, 0xFF, +0xD5, 0x46, 0xD4, 0x87, 0xE6, 0x4A, 0xFF, 0x22, 0x93, 0x2A, 0x4, 0x8, 0xA7, +0x9B, 0xF3, 0xA1, 0x7E, 0x4C, 0x2C, 0xFF, 0xEA, 0x7D, 0x97, 0x4B, 0x5B, 0x8F, +0xDE, 0x6F, 0x0, 0x80, 0xAB, 0x62, 0x96, 0x5E, 0x3A, 0x25, 0x39, 0xD3, 0x65, +0x9B, 0x7, 0x1D, 0x67, 0x80, 0x9A, 0x9B, 0xEF, 0x84, 0xF1, 0x66, 0xCF, 0xEB, +0x83, 0xBE, 0x5F, 0xA3, 0x7E, 0x92, 0x36, 0xAF, 0x80, 0xBE, 0x20, 0x88, 0x23, +0x9A, 0x23, 0x98, 0xB4, 0x90, 0xC7, 0x27, 0x6A, 0xA9, 0xBC, 0xC1, 0x71, 0x4D, +0xFF, 0x1B, 0x60, 0xF8, 0xA5, 0xE1, 0xB0, 0x5A, 0x6A, 0xC7, 0x87, 0xF, 0xB9, +0x3C, 0x99, 0xB0, 0x49, 0x65, 0x37, 0x28, 0xE7, 0x11, 0xC, 0xB8, 0xB9, 0x6B, +0xDC, 0x3C, 0x28, 0xF9, 0xFA, 0x96, 0x1A, 0x84, 0xDF, 0x20, 0x1E, 0xC, 0x8C, +0x5B, 0xA2, 0x22, 0x3E, 0x5B, 0x74, 0x38, 0x72, 0x45, 0x8D, 0xFA, 0x7D, 0x9F, +0xC3, 0x1F, 0x49, 0xA, 0xD9, 0x32, 0x8E, 0x2B, 0xDC, 0x86, 0x91, 0x15, 0xE6, +0xEA, 0xD4, 0x87, 0xE4, 0x6C, 0xE0, 0x31, 0xB4, 0xBF, 0x31, 0xB6, 0xD1, 0x94, +0xF8, 0x4E, 0x4B, 0xF3, 0x22, 0x7F, 0x88, 0x2F, 0xB2, 0x1F, 0x8E, 0xCA, 0x7, +0x6C, 0xCE, 0xAE, 0x25, 0x82, 0xB6, 0xE1, 0x30, 0x91, 0xE8, 0xB3, 0xD2, 0x24, +0x11, 0x31, 0xC6, 0x58, 0xC5, 0xB3, 0xBC, 0x45, 0xA8, 0x41, 0x6, 0x31, 0x89, +0xC9, 0x43, 0x2, 0x63, 0x9F, 0xEA, 0x9B, 0x69, 0x44, 0x8F, 0xD6, 0x44, 0x70, +0xCB, 0x83, 0x52, 0xDE, 0x39, 0x16, 0x77, 0x79, 0x7F, 0x23, 0xAC, 0x5C, 0x5F, +0x9F, 0x2B, 0xD2, 0x28, 0x73, 0xC0, 0x8D, 0x88, 0x7F, 0xEF, 0xA5, 0x30, 0xE6, +0x8B, 0x35, 0x4C, 0xD1, 0xA5, 0x6E, 0xE7, 0x4F, 0x19, 0x31, 0x78, 0x1, 0x98, +0xC5, 0xA6, 0x3D, 0x1E, 0xE8, 0x78, 0x85, 0x19, 0xDD, 0xAC, 0x8C, 0xBF, 0x1, +0xEE, 0x44, 0xA1, 0xD1, 0xA, 0xAB, 0x13, 0x99, 0x9D, 0x45, 0x73, 0x7, 0xF9, +0xD7, 0x9, 0x97, 0x93, 0x0, 0x94, 0x2, 0x68, 0xF9, 0xE8, 0x88, 0xC4, 0x9E, +0x53, 0xD6, 0x74, 0xF7, 0x9A, 0xAD, 0xC7, 0xE2, 0x1E, 0xBE, 0x57, 0x7B, 0xD, +0x5D, 0xE6, 0x7D, 0x3C, 0xF5, 0xF0, 0xE6, 0x1, 0xE5, 0x95, 0x1E, 0xA8, 0xB0, +0xA4, 0x92, 0xF4, 0xB0, 0x64, 0x7E, 0x63, 0x72, 0x52, 0xE7, 0x75, 0x30, 0x84, +0xE7, 0x9F, 0x51, 0x68, 0xA6, 0xB8, 0xFE, 0x2B, 0xF2, 0x58, 0xA4, 0x9, 0x2F, +0xB9, 0x0, 0xEB, 0xB0, 0x34, 0xD7, 0x5F, 0x3E, 0x3E, 0x76, 0xC1, 0x5D, 0x11, +0xCC, 0xB2, 0x4A, 0xBB, 0x7, 0x27, 0xFC, 0x8B, 0x47, 0xEC, 0x44, 0x4A, 0x8C, +0x6D, 0xE8, 0x42, 0x29, 0xAD, 0xED, 0x45, 0x3F, 0x2C, 0xDA, 0x3F, 0x4F, 0x9A, +0xDE, 0x54, 0xEB, 0x1D, 0xE4, 0x31, 0x54, 0xF7, 0xAF, 0x58, 0x81, 0x72, 0xED, +0xB9, 0xEC, 0x9, 0x2B, 0x38, 0xB1, 0xE5, 0x94, 0xE5, 0xC6, 0xE0, 0x7E, 0x3B, +0x48, 0x56, 0xAE, 0x15, 0x8C, 0xF7, 0xE5, 0x89, 0x23, 0xB0, 0xA9, 0x78, 0xC5, +0x5E, 0x3C, 0xB0, 0x3B, 0x1F, 0x1E, 0xA7, 0x34, 0x2D, 0xB3, 0x6E, 0xCC, 0x1A, +0xAB, 0x8E, 0x80, 0x39, 0xF5, 0x8A, 0x2F, 0x66, 0x4C, 0xF5, 0xDA, 0xCE, 0x2E, +0x6E, 0xCC, 0x12, 0xE4, 0xDB, 0xD5, 0x94, 0xBA, 0x18, 0xC9, 0x1E, 0xB4, 0xD1, +0x18, 0x6A, 0x5E, 0x37, 0x6A, 0x3A, 0x78, 0x70, 0x50, 0x7D, 0xC9, 0x65, 0x4D, +0x31, 0xE8, 0xB0, 0x89, 0xA5, 0xAA, 0x3D, 0x1, 0x46, 0x53, 0x84, 0xBC, 0xEE, +0x78, 0x38, 0x25, 0x99, 0x2D, 0xA7, 0x7B, 0xAA, 0x6, 0xB8, 0x28, 0xE9, 0x1, +0xD2, 0xDE, 0x84, 0x56, 0x2, 0xBA, 0x49, 0xFB, 0xA2, 0xAD, 0x8E, 0xEC, 0x73, +0xA, 0xF4, 0xB8, 0x24, 0xB8, 0xD0, 0x75, 0xC8, 0xB5, 0xCF, 0xF5, 0xE8, 0xC7, +0x4B, 0xDF, 0xEC, 0x43, 0xBC, 0x59, 0xD8, 0xFD, 0xA9, 0xC5, 0x26, 0xD9, 0x65, +0xB7, 0xB8, 0x22, 0x1E, 0x2E, 0x70, 0xD3, 0x86, 0xF4, 0xF4, 0x84, 0x81, 0x5A, +0x3D, 0x33, 0xCC, 0x82, 0x45, 0x99, 0xC1, 0x1B, 0x47, 0xCD, 0xEF, 0xAE, 0x19, +0xA0, 0x1C, 0xA5, 0x7D, 0x74, 0x1F, 0x7C, 0xA3, 0x4, 0x3D, 0x97, 0x70, 0x8F, +0x2D, 0xCA, 0x6D, 0xAD, 0x2C, 0x9A, 0x53, 0x45, 0x51, 0xA1, 0xE3, 0x47, 0x2C, +0x80, 0x7D, 0x2, 0x7B, 0x8A, 0xD4, 0x7A, 0x8B, 0x58, 0x11, 0x81, 0x60, 0x2A, +0xC4, 0x4D, 0x26, 0xE, 0xAC, 0x41, 0x89, 0x5E, 0x49, 0xC9, 0xC5, 0x39, 0x9B, +0xCA, 0xD3, 0xB3, 0xE3, 0x19, 0xE7, 0xF2, 0xE6, 0x57, 0x1E, 0x2A, 0x5A, 0x29, +0x78, 0x14, 0xAD, 0x97, 0x7A, 0x2, 0xE5, 0xD8, 0x15, 0x8C, 0xEC, 0xA6, 0x3, +0x9A, 0x11, 0xF9, 0x95, 0x31, 0xED, 0xF2, 0x8C, 0xF1, 0xEF, 0x6B, 0xA5, 0x39, +0xAD, 0xF7, 0x8, 0xDA, 0x1D, 0x4D, 0xC6, 0xAF, 0x93, 0x60, 0xE7, 0x57, 0x31, +0xE4, 0x9E, 0x70, 0x66, 0xD5, 0x8A, 0xB4, 0x3C, 0x15, 0x6F, 0x95, 0xAF, 0xA9, +0x6B, 0xD5, 0xE, 0xDE, 0x37, 0x1D, 0x4C, 0xFA, 0x71, 0xCA, 0xAA, 0x96, 0x5, +0x13, 0x38, 0x13, 0x6D, 0xE5, 0xC6, 0x3F, 0xC5, 0x60, 0xFC, 0xFC, 0xCE, 0xA4, +0xDB, 0xC9, 0x91, 0xE3, 0x59, 0x2C, 0x9D, 0xB0, 0x76, 0xB8, 0x9A, 0x7D, 0xF4, +0x96, 0x37, 0x4, 0xEE, 0xCF, 0x8C, 0xE2, 0x5D, 0x36, 0xE8, 0xAA, 0x4E, 0x4B, +0x7B, 0xD0, 0x4D, 0xB4, 0x24, 0xA8, 0x42, 0x12, 0xD, 0xDC, 0xA, 0xAF, 0xBB, +0x52, 0xE6, 0xF2, 0xD1, 0x7, 0xE4, 0x15, 0x16, 0x36, 0xBA, 0x43, 0xD2, 0x3B, +0x17, 0x66, 0xFF, 0x6D, 0x75, 0x7F, 0x1F, 0xC7, 0xE1, 0x5C, 0x27, 0xE6, 0xF3, +0x92, 0x7D, 0x54, 0x96, 0xC6, 0x5C, 0x5A, 0x5D, 0xFB, 0x94, 0xBD, 0x5A, 0x79, +0x7, 0xCF, 0xFC, 0x1E, 0x4F, 0x87, 0x7B, 0x7E, 0xFC, 0x25, 0x90, 0x62, 0x34, +0x94, 0x92, 0xFB, 0x83, 0xB1, 0xCE, 0xA2, 0x5B, 0x6A, 0xAB, 0x98, 0x23, 0x50, +0xD4, 0x14, 0xB3, 0x8, 0xD6, 0x45, 0xAB, 0xCF, 0x7C, 0xB, 0x94, 0xB7, 0x56, +0x63, 0x43, 0x1A, 0x46, 0x3C, 0xF3, 0x3D, 0x7, 0x19, 0x27, 0x9D, 0x3, 0x3E, +0x48, 0x85, 0xF7, 0xF5, 0x1D, 0x5F, 0xD8, 0x14, 0xEE, 0x3A, 0x9D, 0xDD, 0xF6, +0x1D, 0x7B, 0x3, 0x45, 0x30, 0x84, 0x51, 0xE2, 0x54, 0xBB, 0x96, 0x21, 0xD6, +0x93, 0x94, 0x46, 0x8, 0xAF, 0x6C, 0x32, 0x1F, 0x9F, 0x6B, 0xDF, 0x72, 0x80, +0xFB, 0xA8, 0xF3, 0xCD, 0x32, 0x52, 0x46, 0x4A, 0xAC, 0xB1, 0xA0, 0x25, 0x64, +0x8D, 0x41, 0xA7, 0x9C, 0xD9, 0x2D, 0xAE, 0x83, 0x90, 0xC9, 0xF9, 0x26, 0x91, +0xB2, 0xE3, 0x4, 0x6E, 0xA9, 0x46, 0x96, 0x5E, 0xA1, 0x5E, 0xEB, 0x2, 0xCB, +0x2, 0x1B, 0x21, 0xF7, 0x78, 0xB0, 0x10, 0x8F, 0x29, 0x9C, 0xFB, 0xAC, 0xFE, +0xC8, 0x8A, 0x79, 0x4, 0xC6, 0xED, 0xD, 0x9D, 0x27, 0xE5, 0x11, 0x65, 0x66, +0x14, 0xCD, 0xD, 0xCD, 0x85, 0x1D, 0x51, 0xE1, 0x64, 0xBC, 0x7E, 0x91, 0xD0, +0x54, 0xAB, 0x13, 0xFC, 0xF1, 0x22, 0x7C, 0x86, 0x17, 0xE6, 0x76, 0x76, 0xD6, +0x86, 0x5A, 0x3E, 0x92, 0xE6, 0x5F, 0x2E, 0x2F, 0xFC, 0xF0, 0xA8, 0x24, 0x91, +0xDF, 0xA8, 0x2, 0x72, 0xDC, 0x8A, 0xA6, 0x86, 0x85, 0xBE, 0xC6, 0x78, 0xFC, +0xDD, 0xC, 0xB0, 0x4B, 0x4D, 0xD4, 0xBE, 0x24, 0xB9, 0x3, 0x3, 0x54, 0x9F, +0xAB, 0x6, 0x5, 0x91, 0x4E, 0x41, 0xE9, 0x7E, 0x99, 0x18, 0x3C, 0xB1, 0x96, +0xF0, 0x99, 0x6A, 0xEC, 0xF6, 0x60, 0x7E, 0xE2, 0xD3, 0x6E, 0xED, 0xA8, 0xFC, +0x5F, 0x7, 0x34, 0x65, 0x4A, 0x27, 0x5C, 0x64, 0xD3, 0xF8, 0xA8, 0x6C, 0x92, +0x89, 0x6B, 0x21, 0xAD, 0x7D, 0x35, 0x17, 0xB0, 0x60, 0x93, 0xFA, 0x3E, 0x35, +0x52, 0x9C, 0x8E, 0x38, 0xA1, 0x11, 0xA2, 0x70, 0xB9, 0x8A, 0x8E, 0x3C, 0xCD, +0x57, 0x2, 0x48, 0x1, 0x3D, 0xFC, 0xA1, 0x75, 0x95, 0xF9, 0x90, 0xD, 0x3A, +0xF5, 0x6B, 0xBB, 0xDC, 0xC6, 0x2C, 0x82, 0x2B, 0xE4, 0x4C, 0x2, 0xDC, 0xD0, +0x80, 0x4F, 0x93, 0x22, 0x8D, 0xED, 0xE3, 0x92, 0x26, 0xC7, 0x64, 0x47, 0xDC, +0x85, 0x65, 0x9, 0x3D, 0x5B, 0x82, 0x34, 0x2F, 0x52, 0x93, 0x42, 0xD8, 0x68, +0x35, 0xF8, 0xA9, 0xCC, 0x87, 0x42, 0x9, 0x99, 0xFE, 0x5F, 0x70, 0xBB, 0x16, +0xD5, 0xFC, 0x60, 0x5D, 0x17, 0x92, 0x63, 0xBA, 0x1B, 0x69, 0xD5, 0xDC, 0x62, +0x2A, 0x66, 0x6, 0xD7, 0xD0, 0x46, 0x29, 0xC5, 0x0, 0x1, 0x77, 0x7D, 0xB2, +0x9B, 0x69, 0x7F, 0xCE, 0xBD, 0xFD, 0xC8, 0x11, 0x1C, 0x4E, 0x30, 0x6A, 0x66, +0x5F, 0x17, 0xD7, 0xCB, 0x91, 0x7E, 0x7F, 0xA7, 0x4C, 0xCE, 0xDC, 0xF2, 0x5B, +0x3C, 0x6A, 0xAB, 0x4B, 0x56, 0xD6, 0x4B, 0x9A, 0xA2, 0x88, 0xB, 0xC6, 0x7C, +0x10, 0x8, 0xF5, 0x8E, 0xD5, 0xF2, 0x38, 0x78, 0x9, 0xBC, 0x7F, 0x23, 0x4E, +0x67, 0xBD, 0x88, 0xDC, 0x91, 0xB3, 0xFE, 0x6B, 0x99, 0x99, 0xE1, 0xF3, 0xB6, +0xC1, 0x6E, 0x44, 0xBA, 0xEF, 0xE0, 0xBF, 0xBD, 0x2F, 0xBA, 0x92, 0xFB, 0xA5, +0x29, 0xB, 0x33, 0x9E, 0xAD, 0x66, 0x85, 0x3F, 0xD0, 0x61, 0x9A, 0x44, 0xA6, +0xDF, 0x96, 0xA, 0x1D, 0x78, 0xC2, 0x8D, 0x64, 0x86, 0xD9, 0xC, 0xBF, 0x21, +0x14, 0xA2, 0x96, 0x2C, 0x5B, 0x13, 0x1B, 0xA6, 0xDB, 0xD5, 0xE6, 0xD7, 0xC4, +0xFE, 0x52, 0xE3, 0x77, 0x8B, 0x37, 0x47, 0x24, 0x57, 0x94, 0x70, 0x55, 0x53, +0xC3, 0x8, 0x8F, 0xDA, 0x20, 0xBF, 0x85, 0x97, 0x74, 0x79, 0xB, 0x0, 0xB, +0x1E, 0xF1, 0x1A, 0x83, 0x40, 0xC7, 0x51, 0xFD, 0xDD, 0x3D, 0xB7, 0xC, 0x92, +0x72, 0x16, 0xCA, 0xFA, 0x8E, 0x43, 0x9E, 0xA3, 0x73, 0xFF, 0x12, 0x47, 0x26, +0x64, 0xA8, 0xC6, 0x36, 0xC4, 0xB0, 0x77, 0x9A, 0x84, 0xEC, 0x1D, 0xCD, 0xF3, +0x91, 0x48, 0x2A, 0xAD, 0x37, 0xEE, 0x47, 0xA4, 0x47, 0xD6, 0x26, 0x64, 0xAA, +0xE0, 0x6B, 0x25, 0xFE, 0xD5, 0xB, 0x7, 0x65, 0x30, 0xAB, 0xFC, 0xC0, 0xB7, +0x90, 0x8F, 0xA9, 0x3F, 0xC8, 0x9, 0x9A, 0xF7, 0x8F, 0x33, 0x8A, 0xB3, 0xEE, +0xFC, 0xA3, 0x6E, 0x50, 0xA, 0x84, 0xAB, 0xF8, 0x1F, 0x89, 0xEB, 0x5D, 0xDE, +0x35, 0x4B, 0x4E, 0x23, 0x8D, 0x52, 0x47, 0x54, 0x3F, 0x9B, 0x9B, 0x4F, 0xBD, +0xEB, 0x36, 0x81, 0x33, 0xB, 0x86, 0x9E, 0x19, 0x14, 0xC0, 0x49, 0xB5, 0x74, +0xEB, 0x79, 0xF7, 0xC2, 0x34, 0xF2, 0xEF, 0x10, 0x3A, 0xB0, 0x17, 0x8D, 0x16, +0x71, 0x2, 0xEE, 0x8A, 0x4C, 0x5B, 0xF1, 0xC7, 0x2F, 0xDE, 0x57, 0x24, 0x5F, +0x5D, 0x1A, 0x1A, 0xC5, 0xBB, 0xFB, 0xD3, 0x5F, 0xB0, 0xB5, 0xCF, 0x1A, 0x1C, +0x68, 0x84, 0x78, 0x23, 0x80, 0x84, 0x47, 0x3, 0xE8, 0x4B, 0x45, 0x9B, 0x5B, +0xD9, 0x9F, 0x3, 0x9B, 0xC9, 0xDF, 0xAF, 0xDD, 0x51, 0xBF, 0xCE, 0x59, 0xD7, +0x79, 0x67, 0x61, 0xCF, 0x55, 0x2A, 0x11, 0xD2, 0x42, 0xB7, 0x4A, 0x62, 0x1D, +0xC4, 0xDC, 0x6D, 0xBB, 0xC4, 0x9A, 0x60, 0xE2, 0x73, 0x40, 0x47, 0x60, 0x3E, +0x5F, 0x53, 0x37, 0xAE, 0x5B, 0x9E, 0x4D, 0xF7, 0xE4, 0x7B, 0x61, 0xA, 0x86, +0xA8, 0xDC, 0x2D, 0x65, 0x75, 0xE2, 0x8A, 0x2D, 0xC8, 0x73, 0xD8, 0x18, 0xAF, +0xAC, 0xC6, 0x6C, 0xDA, 0x67, 0x28, 0x52, 0xE8, 0xAE, 0xE4, 0x66, 0xF1, 0xD1, +0xC8, 0x1B, 0xD0, 0x9F, 0xA1, 0x42, 0xE, 0xC9, 0x75, 0x1E, 0x39, 0x2E, 0xD2, +0x43, 0x1, 0x76, 0x3B, 0xF7, 0x88, 0xAF, 0xC0, 0x3C, 0x96, 0xD, 0xF3, 0xE, +0x42, 0xFC, 0x80, 0xA, 0xAE, 0xF8, 0x3A, 0x16, 0x87, 0xA0, 0x5F, 0x7D, 0x5A, +0x4C, 0x56, 0x90, 0xCE, 0x2B, 0x82, 0x5A, 0x2B, 0x49, 0xD5, 0x2C, 0x11, 0x83, +0x96, 0xB9, 0xF6, 0xDB, 0xA9, 0x66, 0xD6, 0xAC, 0x9B, 0x9, 0x3C, 0x6C, 0x15, +0xE3, 0x1D, 0xF6, 0xF7, 0xEE, 0x9F, 0xA, 0xC5, 0x91, 0x14, 0x33, 0x4B, 0xDB, +0xC4, 0xEE, 0xC, 0xFB, 0xE4, 0xD1, 0x43, 0xC2, 0x1B, 0xC3, 0x2, 0x9B, 0x6B }; #endif @@ -1497,8 +1495,8 @@ TEST(EVPExtraTest, d2i_PrivateKey) { ParsePrivateKey(EVP_PKEY_EC, kExampleECKeyDER, sizeof(kExampleECKeyDER))); #ifdef ENABLE_DILITHIUM - EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_DILITHIUM3, kExampleDilithium3KeyDER, - sizeof(kExampleDilithium3KeyDER))); + EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_PQDSA, kExampleMLDSA65KeyDER, + sizeof(kExampleMLDSA65KeyDER))); #endif EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, kExampleBadECKeyDER, diff --git a/crypto/evp_extra/internal.h b/crypto/evp_extra/internal.h index b645330a62..8d731b018e 100644 --- a/crypto/evp_extra/internal.h +++ b/crypto/evp_extra/internal.h @@ -7,7 +7,7 @@ #include #include "../fipsmodule/evp/internal.h" -#include "../dilithium/sig_dilithium.h" +#include "../dilithium/ml_dsa.h" #define PKCS8_VERSION_ONE 0 #define PKCS8_VERSION_TWO 1 @@ -19,15 +19,6 @@ typedef struct { char has_private; } X25519_KEY; -#ifdef ENABLE_DILITHIUM - -typedef struct { - uint8_t *pub; - uint8_t *priv; -} DILITHIUM3_KEY; - -#endif - extern const size_t asn1_evp_pkey_methods_size; extern const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[]; extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meth; @@ -37,7 +28,7 @@ extern const EVP_PKEY_ASN1_METHOD rsa_pss_asn1_meth; extern const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth; extern const EVP_PKEY_ASN1_METHOD x25519_asn1_meth; #ifdef ENABLE_DILITHIUM -extern const EVP_PKEY_ASN1_METHOD dilithium3_asn1_meth; +extern const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth; #endif extern const EVP_PKEY_ASN1_METHOD kem_asn1_meth; extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth; @@ -45,7 +36,9 @@ extern const EVP_PKEY_ASN1_METHOD dh_asn1_meth; extern const EVP_PKEY_METHOD x25519_pkey_meth; extern const EVP_PKEY_METHOD hkdf_pkey_meth; -extern const EVP_PKEY_METHOD dilithium3_pkey_meth; +#ifdef ENABLE_DILITHIUM +extern const EVP_PKEY_METHOD pqdsa_pkey_meth; +#endif extern const EVP_PKEY_METHOD hmac_pkey_meth; extern const EVP_PKEY_METHOD dh_pkey_meth; extern const EVP_PKEY_METHOD dsa_pkey_meth; diff --git a/crypto/evp_extra/p_methods.c b/crypto/evp_extra/p_methods.c index ddfd818c8c..9f870b086c 100644 --- a/crypto/evp_extra/p_methods.c +++ b/crypto/evp_extra/p_methods.c @@ -10,7 +10,7 @@ static const EVP_PKEY_METHOD *const non_fips_pkey_evp_methods[] = { &x25519_pkey_meth, #ifdef ENABLE_DILITHIUM - &dilithium3_pkey_meth, + &pqdsa_pkey_meth, #endif &dh_pkey_meth, &dsa_pkey_meth @@ -24,7 +24,7 @@ const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[] = { &ed25519_asn1_meth, &x25519_asn1_meth, #ifdef ENABLE_DILITHIUM - &dilithium3_asn1_meth, + &pqdsa_asn1_meth, #endif &kem_asn1_meth, &hmac_asn1_meth, diff --git a/crypto/evp_extra/print.c b/crypto/evp_extra/print.c index 8c55aa0d0d..02f9a9f870 100644 --- a/crypto/evp_extra/print.c +++ b/crypto/evp_extra/print.c @@ -66,7 +66,8 @@ #include "../fipsmodule/rsa/internal.h" #ifdef ENABLE_DILITHIUM -#include "../dilithium/sig_dilithium.h" +#include "../dilithium/ml_dsa.h" +#include "../dilithium/internal.h" #endif @@ -313,9 +314,9 @@ static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent) { #ifdef ENABLE_DILITHIUM -// Dilithium keys. +// MLDSA keys. -static int do_dilithium3_print(BIO *bp, const EVP_PKEY *pkey, int off, int ptype) { +static int do_mldsa_65_print(BIO *bp, const EVP_PKEY *pkey, int off, int ptype) { if (pkey == NULL) { OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER); return 0; @@ -325,21 +326,21 @@ static int do_dilithium3_print(BIO *bp, const EVP_PKEY *pkey, int off, int ptype return 0; } - const DILITHIUM3_KEY *key = pkey->pkey.ptr; + const PQDSA *pqdsa = pkey->pkey.pqdsa_key->pqdsa; int bit_len = 0; if (ptype == 2) { - bit_len = DILITHIUM3_PRIVATE_KEY_BYTES; + bit_len = pqdsa->private_key_len; if (BIO_printf(bp, "Private-Key: (%d bit)\n", bit_len) <= 0) { return 0; } - print_hex(bp, key->priv, bit_len, off); + print_hex(bp, pkey->pkey.pqdsa_key->private_key, bit_len, off); } else { - bit_len = DILITHIUM3_PUBLIC_KEY_BYTES; + bit_len = pqdsa->public_key_len; if (BIO_printf(bp, "Public-Key: (%d bit)\n", bit_len) <= 0) { return 0; } - int ret = print_hex(bp, key->pub, bit_len, off); + int ret = print_hex(bp, pkey->pkey.pqdsa_key->public_key, bit_len, off); if (!ret) { return 0; } @@ -348,12 +349,12 @@ static int do_dilithium3_print(BIO *bp, const EVP_PKEY *pkey, int off, int ptype return 1; } -static int dilithium3_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent) { - return do_dilithium3_print(bp, pkey, indent, 1); +static int mldsa_65_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent) { + return do_mldsa_65_print(bp, pkey, indent, 1); } -static int dilithium3_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent) { - return do_dilithium3_print(bp, pkey, indent, 2); +static int mldsa_65_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent) { + return do_mldsa_65_print(bp, pkey, indent, 2); } #endif @@ -386,9 +387,9 @@ static EVP_PKEY_PRINT_METHOD kPrintMethods[] = { }, #ifdef ENABLE_DILITHIUM { - EVP_PKEY_DILITHIUM3, - dilithium3_pub_print, - dilithium3_priv_print, + EVP_PKEY_PQDSA, + mldsa_65_pub_print, + mldsa_65_priv_print, NULL /* param_print */, }, #endif diff --git a/crypto/fipsmodule/evp/internal.h b/crypto/fipsmodule/evp/internal.h index 1bc164c30f..ca98eb5462 100644 --- a/crypto/fipsmodule/evp/internal.h +++ b/crypto/fipsmodule/evp/internal.h @@ -150,6 +150,7 @@ struct evp_pkey_st { DH *dh; EC_KEY *ec; KEM_KEY *kem_key; + PQDSA_KEY * pqdsa_key; } pkey; // ameth contains a pointer to a method table that contains many ASN.1 diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h index f11703868d..eb284bb0d0 100644 --- a/crypto/obj/obj_dat.h +++ b/crypto/obj/obj_dat.h @@ -56,7 +56,7 @@ /* This file is generated by crypto/obj/objects.go. */ -#define NUM_NID 993 +#define NUM_NID 997 static const uint8_t kObjectData[] = { /* NID_rsadsi */ @@ -7281,6 +7281,45 @@ static const uint8_t kObjectData[] = { 0x0f, 0x63, 0x37, + /* NID_PQDSA */ + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x03, + /* NID_MLDSA44 */ + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x03, + 0x11, + /* NID_MLDSA65 */ + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x03, + 0x12, + /* NID_MLDSA87 */ + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x03, + 0x13, }; static const ASN1_OBJECT kObjects[NUM_NID] = { @@ -8961,6 +9000,10 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { &kObjectData[6315], 0}, {"SecP256r1MLKEM768", "SecP256r1MLKEM768", NID_SecP256r1MLKEM768, 5, &kObjectData[6320], 0}, + {"PQDSA", "PQDSA", NID_PQDSA, 8, &kObjectData[6325], 0}, + {"MLDSA44", "MLDSA44", NID_MLDSA44, 9, &kObjectData[6333], 0}, + {"MLDSA65", "MLDSA65", NID_MLDSA65, 9, &kObjectData[6342], 0}, + {"MLDSA87", "MLDSA87", NID_MLDSA87, 9, &kObjectData[6351], 0}, }; static const uint16_t kNIDsInShortNameOrder[] = { @@ -9091,6 +9134,9 @@ static const uint16_t kNIDsInShortNameOrder[] = { 114 /* MD5-SHA1 */, 95 /* MDC2 */, 911 /* MGF1 */, + 994 /* MLDSA44 */, + 995 /* MLDSA65 */, + 996 /* MLDSA87 */, 990 /* MLKEM1024 */, 987 /* MLKEM1024IPD */, 988 /* MLKEM512 */, @@ -9123,6 +9169,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 69 /* PBKDF2 */, 162 /* PBMAC1 */, 127 /* PKIX */, + 993 /* PQDSA */, 935 /* PSPECIFIED */, 98 /* RC2-40-CBC */, 166 /* RC2-64-CBC */, @@ -10006,6 +10053,9 @@ static const uint16_t kNIDsInLongNameOrder[] = { 972 /* KYBER512_R3 */, 973 /* KYBER768_R3 */, 504 /* MIME MHS */, + 994 /* MLDSA44 */, + 995 /* MLDSA65 */, + 996 /* MLDSA87 */, 990 /* MLKEM1024 */, 987 /* MLKEM1024IPD */, 988 /* MLKEM512 */, @@ -10048,6 +10098,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 69 /* PBKDF2 */, 162 /* PBMAC1 */, 127 /* PKIX */, + 993 /* PQDSA */, 858 /* Permanent Identifier */, 164 /* Policy Qualifier CPS */, 165 /* Policy Qualifier User Notice */, @@ -10934,8 +10985,8 @@ static const uint16_t kNIDsInLongNameOrder[] = { static const uint16_t kNIDsInOIDOrder[] = { 434 /* 0.9 (OBJ_data) */, 182 /* 1.2 (OBJ_member_body) */, - 676 /* 1.3 (OBJ_identified_organization) */, 379 /* 1.3 (OBJ_org) */, + 676 /* 1.3 (OBJ_identified_organization) */, 11 /* 2.5 (OBJ_X500) */, 647 /* 2.23 (OBJ_international_organizations) */, 380 /* 1.3.6 (OBJ_dod) */, @@ -11519,6 +11570,7 @@ static const uint16_t kNIDsInOIDOrder[] = { 785 /* 1.3.6.1.5.5.7.48.5 (OBJ_caRepository) */, 780 /* 1.3.6.1.5.5.8.1.1 (OBJ_hmac_md5) */, 781 /* 1.3.6.1.5.5.8.1.2 (OBJ_hmac_sha1) */, + 993 /* 2.16.840.1.101.3.4.3 (OBJ_PQDSA) */, 970 /* 2.16.840.1.101.3.4.4 (OBJ_kem) */, 58 /* 2.16.840.1.113730.1 (OBJ_netscape_cert_extension) */, 59 /* 2.16.840.1.113730.2 (OBJ_netscape_data_type) */, @@ -11655,6 +11707,9 @@ static const uint16_t kNIDsInOIDOrder[] = { 980 /* 2.16.840.1.101.3.4.2.12 (OBJ_shake256) */, 802 /* 2.16.840.1.101.3.4.3.1 (OBJ_dsa_with_SHA224) */, 803 /* 2.16.840.1.101.3.4.3.2 (OBJ_dsa_with_SHA256) */, + 994 /* 2.16.840.1.101.3.4.3.17 (OBJ_MLDSA44) */, + 995 /* 2.16.840.1.101.3.4.3.18 (OBJ_MLDSA65) */, + 996 /* 2.16.840.1.101.3.4.3.19 (OBJ_MLDSA87) */, 988 /* 2.16.840.1.101.3.4.4.1 (OBJ_MLKEM512) */, 989 /* 2.16.840.1.101.3.4.4.2 (OBJ_MLKEM768) */, 990 /* 2.16.840.1.101.3.4.4.3 (OBJ_MLKEM1024) */, diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num index 21f71036d7..72782a89e7 100644 --- a/crypto/obj/obj_mac.num +++ b/crypto/obj/obj_mac.num @@ -980,3 +980,7 @@ MLKEM768 989 MLKEM1024 990 X25519MLKEM768 991 SecP256r1MLKEM768 992 +PQDSA 993 +MLDSA44 994 +MLDSA65 995 +MLDSA87 996 diff --git a/crypto/obj/obj_xref.c b/crypto/obj/obj_xref.c index 3b59258593..65319f2fdd 100644 --- a/crypto/obj/obj_xref.c +++ b/crypto/obj/obj_xref.c @@ -93,7 +93,7 @@ static const nid_triple kTriples[] = { // digest "undef" indicates the caller should handle this explicitly. {NID_rsassaPss, NID_undef, NID_rsaEncryption}, {NID_ED25519, NID_undef, NID_ED25519}, - {NID_DILITHIUM3_R3, NID_undef, NID_DILITHIUM3_R3}, + {NID_MLDSA65, NID_undef, NID_MLDSA65} }; int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, int *out_pkey_nid) { diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt index 67877c73e9..791704d5a3 100644 --- a/crypto/obj/objects.txt +++ b/crypto/obj/objects.txt @@ -922,9 +922,9 @@ nist_hashalgs 5 : SHA512-224 : sha512-224 nist_hashalgs 6 : SHA512-256 : sha512-256 # OIDs for dsa-with-sha224 and dsa-with-sha256 -!Alias dsa_with_sha2 nistAlgorithms 3 -dsa_with_sha2 1 : dsa_with_SHA224 -dsa_with_sha2 2 : dsa_with_SHA256 +!Alias nist_dsa nistAlgorithms 3 +nist_dsa 1 : dsa_with_SHA224 +nist_dsa 2 : dsa_with_SHA256 # Hold instruction CRL entry extension !Cname hold-instruction-code @@ -1401,3 +1401,11 @@ nist_kem 3 : MLKEM1024 # https://github.com/IETF-Hackathon/pqc-certificates/blob/master/docs/oid_mapping.md # as we await NIST to release official OIDs. 1 3 6 1 4 1 2 267 7 6 5 : DILITHIUM3_R3 + +# OIDs for ML-DSA-44, ML-DSA-65, and ML-DSA-87 according to +# https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +# https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration +nist_dsa : PQDSA +nist_dsa 17 : MLDSA44 +nist_dsa 18 : MLDSA65 +nist_dsa 19 : MLDSA87 \ No newline at end of file diff --git a/crypto/x509/algorithm.c b/crypto/x509/algorithm.c index 5f42231b32..05d500184b 100644 --- a/crypto/x509/algorithm.c +++ b/crypto/x509/algorithm.c @@ -62,6 +62,8 @@ #include #include +#include "../dilithium/internal.h" +#include "../fipsmodule/evp/internal.h" #include "internal.h" // Restrict the digests that are allowed in X509 certificates @@ -97,8 +99,8 @@ int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { } #ifdef ENABLE_DILITHIUM - if (EVP_PKEY_id(pkey) == EVP_PKEY_DILITHIUM3) { - return X509_ALGOR_set0(algor, OBJ_nid2obj(NID_DILITHIUM3_R3), V_ASN1_UNDEF, NULL); + if (EVP_PKEY_id(pkey) == EVP_PKEY_PQDSA) { + return X509_ALGOR_set0(algor, OBJ_nid2obj(pkey->pkey.pqdsa_key->pqdsa->nid), V_ASN1_UNDEF, NULL); } #endif @@ -141,7 +143,12 @@ int x509_digest_verify_init(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg, // when |sigalg_nid| is |NID_rsassaPss|. if (pkey_nid != EVP_PKEY_id(pkey) && !(sigalg_nid == NID_rsassaPss && pkey_nid == NID_rsaEncryption && - EVP_PKEY_id(pkey) == EVP_PKEY_RSA_PSS)) { + EVP_PKEY_id(pkey) == EVP_PKEY_RSA_PSS) +#ifdef ENABLE_DILITHIUM + && !(sigalg_nid == NID_MLDSA65 && pkey_nid == NID_MLDSA65 && + EVP_PKEY_id(pkey) == EVP_PKEY_PQDSA) +#endif + ) { OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE); return 0; } @@ -158,7 +165,7 @@ int x509_digest_verify_init(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg, return x509_rsa_pss_to_ctx(ctx, sigalg, pkey); } #ifdef ENABLE_DILITHIUM - if (sigalg_nid == NID_ED25519 || sigalg_nid == NID_DILITHIUM3_R3) { + if (sigalg_nid == NID_ED25519 || sigalg_nid == NID_MLDSA65) { #else if (sigalg_nid == NID_ED25519) { #endif diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 941d505874..0b5501f3c7 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -39,6 +39,7 @@ #include "../evp_extra/internal.h" #include "../internal.h" #include "../test/test_util.h" +#include "../dilithium/internal.h" #if defined(OPENSSL_THREADS) #include @@ -576,363 +577,372 @@ w1AH9efZBw== )"; #ifdef ENABLE_DILITHIUM - -static const char kDilithium3Cert[] = R"( +// This certificate is the example certificate provided in section 3 of +//https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ +static const char kMLDSA65Cert[] = R"( -----BEGIN CERTIFICATE----- -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 -FRoeJg== +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 +Lw== -----END CERTIFICATE----- )"; -// kDilithium3CertNull is an invalid self-signed Dilithium3 with an explicit +// kMLDSA65CertNull is an invalid self-signed MLDSA65 with an explicit // NULL in the signature algorithm. -static const char kDilithium3CertNull[] = R"( +static const char kMLDSA65CertNull[] = R"( -----BEGIN CERTIFICATE----- -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 +HCIv -----END CERTIFICATE----- )"; -// kDilithium3CertParam is an invalid self-signed Dilithium3 with an explicit +// kMLDSA65CertParam is an invalid self-signed MLDSA65 with an explicit // NULL in the AlgorithmIdentifier parameters. -static const char kDilithium3CertParam[] = R"( +static const char kMLDSA65CertParam[] = R"( -----BEGIN CERTIFICATE----- -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 +DhQcIi8= -----END CERTIFICATE----- )"; @@ -2946,33 +2956,34 @@ TEST(X509Test, Ed25519Sign) { #ifdef ENABLE_DILITHIUM -TEST(X509Test, Dilithium3SignVerifyCert) { - // This test generates a Dilithium3 keypair, generates and signs a +TEST(X509Test, MLDSA65SignVerifyCert) { + // This test generates a MLDSA65 keypair, generates and signs a // certificate, then verifies the certificate's signature. - EVP_PKEY_CTX *pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DILITHIUM3, nullptr); - ASSERT_NE(pkey_ctx, nullptr); - EVP_PKEY *pkey = EVP_PKEY_new(); - ASSERT_NE(pkey, nullptr); - EXPECT_TRUE(EVP_PKEY_keygen_init(pkey_ctx)); - EXPECT_TRUE(EVP_PKEY_keygen(pkey_ctx, &pkey)); + + // Generate mldsa key + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(), NID_MLDSA65)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr)); bssl::UniquePtr leaf = - MakeTestCert("Intermediate", "Leaf", pkey, /*is_ca=*/false); + MakeTestCert("Intermediate", "Leaf", pkey.get(), /*is_ca=*/false); ASSERT_TRUE(leaf); bssl::ScopedEVP_MD_CTX md_ctx; - EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey); + EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey.get()); ASSERT_TRUE(X509_sign_ctx(leaf.get(), md_ctx.get())); - ASSERT_TRUE(X509_verify(leaf.get(), pkey)); - - EVP_PKEY_CTX_free(pkey_ctx); - EVP_PKEY_free(pkey); + ASSERT_TRUE(X509_verify(leaf.get(), pkey.get())); } -TEST(X509Test, TestDilithium3) { - // This test decodes a Dilithium3 certificate from the PEM encoding, +TEST(X509Test, TestMLDSA65) { + // This test decodes a MLDSA65 certificate from the PEM encoding, // extracts the public key, and then verifies the certificate. - bssl::UniquePtr cert(CertFromPEM(kDilithium3Cert)); + bssl::UniquePtr cert(CertFromPEM(kMLDSA65Cert)); ASSERT_TRUE(cert); bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); @@ -2981,11 +2992,11 @@ TEST(X509Test, TestDilithium3) { ASSERT_TRUE(X509_verify(cert.get(), pkey.get())); } -TEST(X509Test, TestBadSigAlgDilithium3) { - // This test generates a Dilithium3 certificate from the PEM encoding - // kDilithium3CertNull that has an explicit NULL in the signature algorithm. +TEST(X509Test, TestBadSigAlgMLDSA65) { + // This test generates a MLDSA65 certificate from the PEM encoding + // kMLDSA65CertNull that has an explicit NULL in the signature algorithm. // After extracting the public key, verification should fail. - bssl::UniquePtr cert(CertFromPEM(kDilithium3CertNull)); + bssl::UniquePtr cert(CertFromPEM(kMLDSA65CertNull)); ASSERT_TRUE(cert); bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); @@ -2998,11 +3009,11 @@ TEST(X509Test, TestBadSigAlgDilithium3) { ERR_clear_error(); } -TEST(X509Test, TestBadParamsDilithium3) { - // This test generates a Dilithium3 certificate from the PEM encoding - // kDilithium3CertParam that has an explicit NULL in the signature algorithm. +TEST(X509Test, TestBadParamsMLDSA65) { + // This test generates a MLDSA65 certificate from the PEM encoding + // kMLDSA65CertParam that has an explicit NULL in the parameters field. // After extracting the public key, verification should fail. - bssl::UniquePtr cert(CertFromPEM(kDilithium3CertParam)); + bssl::UniquePtr cert(CertFromPEM(kMLDSA65CertParam)); ASSERT_TRUE(cert); bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); diff --git a/include/openssl/base.h b/include/openssl/base.h index 649337cc6d..413f72320e 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -114,7 +114,7 @@ extern "C" { // A consumer may use this symbol in the preprocessor to temporarily build // against multiple revisions of BoringSSL at the same time. It is not // recommended to do so for longer than is necessary. -#define AWSLC_API_VERSION 31 +#define AWSLC_API_VERSION 32 // This string tracks the most current production release version on Github // https://github.com/aws/aws-lc/releases. @@ -348,6 +348,7 @@ typedef struct evp_pkey_st EVP_PKEY; typedef struct hmac_ctx_st HMAC_CTX; typedef struct md4_state_st MD4_CTX; typedef struct md5_state_st MD5_CTX; +typedef struct pqdsa_key_st PQDSA_KEY; typedef struct ocsp_req_ctx_st OCSP_REQ_CTX; typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; typedef struct pkcs7_st PKCS7; diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 4ce750cbcb..437c5da77a 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -204,7 +204,7 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int #define EVP_PKEY_DH NID_dhKeyAgreement #ifdef ENABLE_DILITHIUM -#define EVP_PKEY_DILITHIUM3 NID_DILITHIUM3_R3 +#define EVP_PKEY_PQDSA NID_PQDSA #endif #define EVP_PKEY_KEM NID_kem @@ -946,6 +946,26 @@ OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_kem_new_raw_key(int nid, // to the secret key in |key|. OPENSSL_EXPORT int EVP_PKEY_kem_check_key(EVP_PKEY *key); +// PQDSA specific functions. + +#ifdef ENABLE_DILITHIUM +// EVP_PKEY_CTX_pqdsa_set_params sets in |ctx| the parameters associated with +// the signature scheme defined by the given |nid|. It returns one on success +// and zero on error. +OPENSSL_EXPORT int EVP_PKEY_CTX_pqdsa_set_params(EVP_PKEY_CTX *ctx, int nid); + +// EVP_PKEY_pqdsa_new_raw_public_key generates a new EVP_PKEY object of type +// EVP_PKEY_PQDSA, initializes the PQDSA key based on |nid| and populates the +// public key part of the PQDSA key with the contents of |in|. It returns the +// pointer to the allocated PKEY on sucess and NULL on error. +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_pqdsa_new_raw_public_key(int nid, const uint8_t *in, size_t len); + +// EVP_PKEY_pqdsa_new_raw_private_key generates a new EVP_PKEY object of type +// EVP_PKEY_PQDSA, initializes the PQDSA key based on |nid| and populates the +// secret key part of the PQDSA key with the contents of |in|. It returns the +// pointer to the allocated PKEY on sucess and NULL on error. +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_pqdsa_new_raw_private_key(int nid, const uint8_t *in, size_t len); +#endif // Diffie-Hellman-specific control functions. diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 52cd599341..2ec2a9105b 100644 --- a/include/openssl/nid.h +++ b/include/openssl/nid.h @@ -4363,6 +4363,22 @@ extern "C" { #define NID_SecP256r1MLKEM768 992 #define OBJ_SecP256r1MLKEM768 1L, 3L, 9999L, 99L, 55L +#define SN_PQDSA "PQDSA" +#define NID_PQDSA 993 +#define OBJ_PQDSA 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L + +#define SN_MLDSA44 "MLDSA44" +#define NID_MLDSA44 994 +#define OBJ_MLDSA44 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L, 17L + +#define SN_MLDSA65 "MLDSA65" +#define NID_MLDSA65 995 +#define OBJ_MLDSA65 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L, 18L + +#define SN_MLDSA87 "MLDSA87" +#define NID_MLDSA87 996 +#define OBJ_MLDSA87 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L, 19L + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/tool/speed.cc b/tool/speed.cc index 7c17d89c45..62b4871318 100644 --- a/tool/speed.cc +++ b/tool/speed.cc @@ -867,7 +867,7 @@ static bool SpeedKEM(std::string selected) { SpeedSingleKEM("Kyber1024_R3", NID_KYBER1024_R3, selected); } -#if defined(ENABLE_DILITHIUM) && AWSLC_API_VERSION > 20 +#if defined(ENABLE_DILITHIUM) && AWSLC_API_VERSION > 31 static bool SpeedDigestSignNID(const std::string &name, int nid, const std::string &selected) { @@ -875,8 +875,11 @@ static bool SpeedDigestSignNID(const std::string &name, int nid, return true; } - // Setup CTX for Sign/Verify Operations - BM_NAMESPACE::UniquePtr pkey_ctx(EVP_PKEY_CTX_new_id(nid, nullptr)); + // Setup CTX for Sign/Verify Operations of type EVP_PKEY_PQDSA + BM_NAMESPACE::UniquePtr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); + + // Setup CTX for specific signature alg NID + EVP_PKEY_CTX_pqdsa_set_params(pkey_ctx.get(), nid); // Setup CTX for Keygen Operations if (!pkey_ctx || EVP_PKEY_keygen_init(pkey_ctx.get()) != 1) { @@ -930,7 +933,7 @@ static bool SpeedDigestSignNID(const std::string &name, int nid, } static bool SpeedDigestSign(const std::string &selected) { - return SpeedDigestSignNID("Dilithium3", EVP_PKEY_DILITHIUM3, selected); + return SpeedDigestSignNID("MLDSA65", NID_MLDSA65, selected); } #endif @@ -2861,7 +2864,7 @@ bool Speed(const std::vector &args) { #if AWSLC_API_VERSION > 16 !SpeedKEM(selected) || #endif -#if defined(ENABLE_DILITHIUM) && AWSLC_API_VERSION > 20 +#if defined(ENABLE_DILITHIUM) && AWSLC_API_VERSION > 31 !SpeedDigestSign(selected) || #endif !SpeedAEADSeal(EVP_aead_aes_128_gcm(), "AEAD-AES-128-GCM", kTLSADLen, selected) ||