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) ||