From 617924155e69cfee8f8fcc230ce225c59264919d Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Mon, 4 Nov 2024 12:23:16 -0800 Subject: [PATCH 01/28] Generic NIST-DSA PKEY and ASN1 to support ML-DSA --- crypto/dilithium/internal.h | 66 ++ crypto/dilithium/p_dilithium3.c | 317 +++++++-- crypto/dilithium/p_dilithium3_asn1.c | 243 +++---- crypto/dilithium/p_dilithium_test.cc | 979 ++++++++++----------------- crypto/dilithium/sig_dilithium.h | 8 +- crypto/dilithium/sig_dilithium3.c | 2 +- crypto/evp_extra/evp_extra_test.cc | 322 +-------- crypto/evp_extra/internal.h | 4 +- crypto/evp_extra/p_methods.c | 4 +- crypto/evp_extra/print.c | 29 +- crypto/fipsmodule/evp/internal.h | 1 + crypto/obj/obj_dat.h | 59 +- crypto/obj/obj_mac.num | 4 + crypto/obj/obj_xref.c | 2 +- crypto/obj/objects.txt | 14 +- crypto/x509/algorithm.c | 6 +- crypto/x509/x509_test.cc | 756 +++++++++++---------- include/openssl/base.h | 3 +- include/openssl/evp.h | 12 +- include/openssl/nid.h | 16 + tool/speed.cc | 13 +- 21 files changed, 1315 insertions(+), 1545 deletions(-) create mode 100644 crypto/dilithium/internal.h diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h new file mode 100644 index 0000000000..0c1d36fc1d --- /dev/null +++ b/crypto/dilithium/internal.h @@ -0,0 +1,66 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef AWSLC_HEADER_SIG_INTERNAL_H +#define AWSLC_HEADER_SIG_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +// NISTDSA_METHOD structure and helper functions. +typedef struct { + int (*keygen)(uint8_t *public_key, + uint8_t *secret_key); + + int (*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); + + int (*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); + +} NISTDSA_METHOD; + +// NISTDSA 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 secret_key_len; + size_t signature_len; + size_t keygen_seed_len; + size_t sign_seed_len; + const NISTDSA_METHOD *method; +} NISTDSA; + +// NISTDSA_KEY structure and helper functions. +struct nistdsa_st { + const NISTDSA *nistdsa; + uint8_t *public_key; + uint8_t *secret_key; +}; + +int NISTDSA_KEY_init(NISTDSA_KEY *key, const NISTDSA *nistdsa); +const NISTDSA * SIG_find_dsa_by_nid(int nid); +const NISTDSA *NISTDSA_KEY_get0_sig(NISTDSA_KEY* key); +NISTDSA_KEY *NISTDSA_KEY_new(void); +void NISTDSA_KEY_free(NISTDSA_KEY *key); + +#if defined(__cplusplus) +} // extern C +#endif + +#endif // AWSLC_HEADER_DSA_TEST_INTERNAL_H diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index 23b565cbf3..2b1f51c615 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -9,117 +9,300 @@ #include "../fipsmodule/evp/internal.h" #include "../evp_extra/internal.h" #include "sig_dilithium.h" +#include "internal.h" +#include "../fipsmodule/delocate.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; - } +// ML-DSA OIDs from 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}; + +// NISTDSA functions: these are init/new/clear/free/get_sig functions for NISTDSA_KEY +// These will be moved to a separate file location after CR for clearer review. +// These are analagous to the ec_key functions in crypto/fipsmodule/ec/ec_key.c - if (pkey == NULL || ctx == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); - goto err; +typedef struct { + const NISTDSA *nistdsa; +} NISTDSA_PKEY_CTX; + +NISTDSA_KEY *NISTDSA_KEY_new(void) { + NISTDSA_KEY *ret = OPENSSL_zalloc(sizeof(NISTDSA_KEY)); + if (ret == NULL) { + return NULL; } - evp_pkey_set_method(pkey, &dilithium3_asn1_meth); + return ret; +} - if (ml_dsa_65_keypair(key->pub, key->priv) != 0) { - goto err; +static void NISTDSA_KEY_clear(NISTDSA_KEY *key) { + key->nistdsa = NULL; + OPENSSL_free(key->public_key); + OPENSSL_free(key->secret_key); + key->public_key = NULL; + key->secret_key = NULL; +} + +int NISTDSA_KEY_init(NISTDSA_KEY *key, const NISTDSA *nistdsa) { + if (key == NULL || nistdsa == NULL) { + return 0; } + // If the key is already initialized clear it. + NISTDSA_KEY_clear(key); - OPENSSL_free(pkey->pkey.ptr); - pkey->pkey.ptr = key; + key->nistdsa = nistdsa; + key->public_key = OPENSSL_malloc(nistdsa->public_key_len); + key->secret_key = OPENSSL_malloc(nistdsa->secret_key_len); + if (key->public_key == NULL || key->secret_key == NULL) { + NISTDSA_KEY_clear(key); + return 0; + } return 1; +} -err: - if (key != NULL) { - OPENSSL_free(key->pub); - OPENSSL_free(key->priv); +void NISTDSA_KEY_free(NISTDSA_KEY *key) { + if (key == NULL) { + return; } + NISTDSA_KEY_clear(key); OPENSSL_free(key); - return 0; +} +const NISTDSA *NISTDSA_KEY_get0_sig(NISTDSA_KEY* key) { + return key->nistdsa; } -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); +// NISTDSA PKEY functions + +static int pkey_nistdsa_init(EVP_PKEY_CTX *ctx) { + NISTDSA_PKEY_CTX *dctx; + dctx = OPENSSL_zalloc(sizeof(NISTDSA_PKEY_CTX)); + if (dctx == NULL) { return 0; } - DILITHIUM3_KEY *key = ctx->pkey->pkey.ptr; + ctx->data = dctx; - if (!key->priv) { - OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + return 1; +} + +static void pkey_nistdsa_cleanup(EVP_PKEY_CTX *ctx) { + OPENSSL_free(ctx->data); +} + +static int pkey_nistdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + GUARD_PTR(ctx); + NISTDSA_PKEY_CTX *dctx = ctx->data; + GUARD_PTR(dctx); + const NISTDSA *nistdsa = dctx->nistdsa; + if (nistdsa == NULL) { + if (ctx->pkey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + nistdsa = NISTDSA_KEY_get0_sig(ctx->pkey->pkey.nistdsa_key); + } + + NISTDSA_KEY *key = NISTDSA_KEY_new(); + if (key == NULL || + !NISTDSA_KEY_init(key, nistdsa) || + !nistdsa->method->keygen(key->public_key, key->secret_key) || + !EVP_PKEY_set_type(pkey, EVP_PKEY_NISTDSA)) { + NISTDSA_KEY_free(key); return 0; + } + + pkey->pkey.nistdsa_key = key; + return 1; +} + +static int pkey_nistdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, + size_t *siglen, const uint8_t *tbs, + size_t tbslen) { + NISTDSA_PKEY_CTX *dctx = ctx->data; + const NISTDSA *nistdsa = dctx->nistdsa; + if (nistdsa == NULL) { + if (ctx->pkey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + nistdsa = NISTDSA_KEY_get0_sig(ctx->pkey->pkey.nistdsa_key); } + // Caller is getting parameter values. if (sig == NULL) { - *siglen = DILITHIUM3_SIGNATURE_BYTES; + *siglen = nistdsa->signature_len; return 1; } - if (*siglen < DILITHIUM3_SIGNATURE_BYTES) { + if (*siglen < nistdsa->signature_len) { 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) { + // Check that the context is properly configured. + if (ctx->pkey == NULL || + ctx->pkey->pkey.nistdsa_key == NULL || + ctx->pkey->type != EVP_PKEY_NISTDSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + + NISTDSA_KEY *key = ctx->pkey->pkey.nistdsa_key; + if (!key->secret_key) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + return 0; + } + + if (nistdsa->method->sign(sig, siglen, tbs, tbslen, NULL, + 0, key->secret_key) != 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, +static int pkey_nistdsa_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; + NISTDSA_PKEY_CTX *dctx = ctx->data; + const NISTDSA *nistdsa = dctx->nistdsa; + + if (nistdsa == NULL) { + if (ctx->pkey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + nistdsa = NISTDSA_KEY_get0_sig(ctx->pkey->pkey.nistdsa_key); } + // Check that the context is properly configured. + if (ctx->pkey == NULL || + ctx->pkey->pkey.nistdsa_key == NULL || + ctx->pkey->type != EVP_PKEY_NISTDSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } - DILITHIUM3_KEY *key = ctx->pkey->pkey.ptr; + NISTDSA_KEY *key = ctx->pkey->pkey.nistdsa_key; - if (siglen != DILITHIUM3_SIGNATURE_BYTES || - ml_dsa_65_verify(tbs, tbslen, sig, siglen, NULL, 0, key->pub) != 0) { + if (siglen != nistdsa->signature_len || + nistdsa->method->verify(tbs, tbslen, sig, siglen, + NULL, 0, key->public_key) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); + return 0; + } + + return 1; +} + +// This function sets nistdsa parameters defined by |nid| in |pkey|. +// If |pkey| already has a public key set, this public key is preserved. +int EVP_PKEY_nistdsa_set_params(EVP_PKEY *pkey, int nid) { + const NISTDSA *nistdsa = SIG_find_dsa_by_nid(nid); + + if (nistdsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + return 0; + } + + // if the public key has already been set either by EVP_parse_public_key or + // some other method that returns a PKEY without setting params, then + // we preserve that PKEY and just populate the params + if (pkey->pkey.nistdsa_key != NULL) { + pkey->pkey.nistdsa_key->nistdsa = nistdsa; + return 1; + } + + evp_pkey_set_method(pkey, &nistdsa_asn1_meth); + + NISTDSA_KEY *key = NISTDSA_KEY_new(); + if (key == NULL) { + // NISTDSA_KEY_new sets the appropriate error. return 0; } + + key->nistdsa = nistdsa; + pkey->pkey.nistdsa_key = key; + 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 */, +// Takes an EVP_PKEY_CTX object |ctx| and sets nistdsa parameters defined +// by |nid| +int EVP_PKEY_CTX_nistdsa_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 NISTDSA *nistdsa = SIG_find_dsa_by_nid(nid); + if (nistdsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + return 0; + } + + NISTDSA_PKEY_CTX *dctx = ctx->data; + dctx->nistdsa = nistdsa; + + return 1; +} + +const EVP_PKEY_METHOD nistdsa_pkey_meth = { + EVP_PKEY_NISTDSA, + pkey_nistdsa_init /* init */, + NULL /* copy */, + pkey_nistdsa_cleanup /* cleanup */, + pkey_nistdsa_keygen, + NULL /* sign_init */, + NULL /* sign */, + pkey_nistdsa_sign_message, + NULL /* verify_init */, + NULL /* verify */, + pkey_nistdsa_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 */, }; + +DEFINE_LOCAL_DATA(NISTDSA_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(NISTDSA, sig_ml_dsa_65) { + out->nid = NID_MLDSA65; + out->oid = kOIDMLDSA65; + out->oid_len = sizeof(kOIDMLDSA65); + out->comment = "MLDSA65 "; + out->public_key_len = MLDSA65_PUBLIC_KEY_BYTES; + out->secret_key_len = MLDSA65_PRIVATE_KEY_BYTES; + out->signature_len = MLDSA65_SIGNATURE_BYTES; + out->keygen_seed_len = MLDSA65_KEYGEN_SEED_BYTES; + out->sign_seed_len = MLDSA65_SIGNATURE_SEED_BYTES; + out->method = sig_ml_dsa_65_method(); +} + +const NISTDSA *SIG_find_dsa_by_nid(int nid) { + switch (nid) { + case NID_MLDSA65: + return sig_ml_dsa_65(); + default: + return NULL; + } +} diff --git a/crypto/dilithium/p_dilithium3_asn1.c b/crypto/dilithium/p_dilithium3_asn1.c index ecd3faf818..7fafbf16e4 100644 --- a/crypto/dilithium/p_dilithium3_asn1.c +++ b/crypto/dilithium/p_dilithium3_asn1.c @@ -11,29 +11,24 @@ #include "../fipsmodule/evp/internal.h" #include "../internal.h" #include "sig_dilithium.h" +#include "internal.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 void nistdsa_free(EVP_PKEY *pkey) { + NISTDSA_KEY_free(pkey->pkey.nistdsa_key); + pkey->pkey.nistdsa_key = NULL; } -static int dilithium3_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, + +static int nistdsa_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); + + NISTDSA_KEY *key = OPENSSL_malloc(sizeof(NISTDSA_KEY)); + if (key == NULL) { return 0; } - // At time of writing, all |set_priv_raw| and |dilithium3_set_priv_raw| + // At time of writing, all |set_priv_raw| and |nistdsa_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) { @@ -41,108 +36,117 @@ static int dilithium3_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, 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; + // NOTE: No checks are done in this function, the caller has to ensure + // that the pointers are valid and |in| has the correct size. + key->public_key = NULL; + key->secret_key = OPENSSL_memdup(privkey, privkey_len); + nistdsa_free(pkey); + pkey->pkey.nistdsa_key = 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; - } +static int nistdsa_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { + //generate a fresh nistdsa_key + NISTDSA_KEY *key = OPENSSL_malloc(sizeof(NISTDSA_KEY)); - 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; + // NOTE: No checks are done in this function, the caller has to ensure + // that the pointers are valid and |in| has the correct size. + key->public_key = OPENSSL_memdup(in, len); + key->secret_key = NULL; - dilithium3_free(pkey); - pkey->pkey.ptr = key; + nistdsa_free(pkey); + pkey->pkey.nistdsa_key = key; return 1; } -static int dilithium3_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, +static int nistdsa_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) { + if (pkey->pkey.nistdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + NISTDSA_KEY *key = pkey->pkey.nistdsa_key; + const NISTDSA *nistdsa = key->nistdsa; + + if (key->secret_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; } + if (nistdsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + if (out == NULL) { - *out_len = DILITHIUM3_PRIVATE_KEY_BYTES; + *out_len = key->nistdsa->secret_key_len; return 1; } - if (*out_len < DILITHIUM3_PRIVATE_KEY_BYTES) { + if (*out_len < key->nistdsa->secret_key_len) { 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; + OPENSSL_memcpy(out, key->secret_key, nistdsa->secret_key_len); + *out_len = nistdsa->secret_key_len; return 1; } -static int dilithium3_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, +static int nistdsa_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) { + if (pkey->pkey.nistdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + + NISTDSA_KEY *key = pkey->pkey.nistdsa_key; + const NISTDSA *nistdsa = key->nistdsa; + + if (nistdsa == 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 = DILITHIUM3_PUBLIC_KEY_BYTES; + *out_len = nistdsa->public_key_len; return 1; } - if (*out_len < DILITHIUM3_PUBLIC_KEY_BYTES) { + if (*out_len < key->nistdsa->public_key_len) { 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; + OPENSSL_memcpy(out, key->public_key, nistdsa->public_key_len); + *out_len = nistdsa->public_key_len; return 1; } -static int dilithium3_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { +static int nistdsa_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)); + return nistdsa_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) { +static int nistdsa_pub_encode(CBB *out, const EVP_PKEY *pkey) { + NISTDSA_KEY *key = pkey->pkey.nistdsa_key; + const NISTDSA *nistdsa = key->nistdsa; + if (key->public_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } @@ -153,39 +157,42 @@ static int dilithium3_pub_encode(CBB *out, const EVP_PKEY *pkey) { 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_bytes(&oid, pkey->ameth->oid, pkey->ameth->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_add_bytes(&key_bitstring, key->public_key, nistdsa->public_key_len) || !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 nistdsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + NISTDSA_KEY *a_key = a->pkey.nistdsa_key; + NISTDSA_KEY *b_key = b->pkey.nistdsa_key; + + return OPENSSL_memcmp(a_key->public_key, + b_key->public_key, + a->pkey.nistdsa_key->nistdsa->public_key_len) == 0; } -static int dilithium3_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey) { +static int nistdsa_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); + return nistdsa_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) { +static int nistdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { + NISTDSA_KEY *key = pkey->pkey.nistdsa_key; + const NISTDSA *nistdsa = key->nistdsa; + if (key->secret_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; } @@ -195,54 +202,58 @@ static int dilithium3_priv_encode(CBB *out, const EVP_PKEY *pkey) { !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_bytes(&oid, pkey->ameth->oid, pkey->ameth->oid_len) || !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || - !CBB_add_bytes(&private_key, key->priv, DILITHIUM3_PRIVATE_KEY_BYTES) || + !CBB_add_bytes(&private_key, key->secret_key, nistdsa->secret_key_len) || !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 nistdsa_size(const EVP_PKEY *pkey) { + if (pkey->pkey.nistdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + return pkey->pkey.nistdsa_key->nistdsa->signature_len; } -static int dilithium3_bits(const EVP_PKEY *pkey) { - return 8 * (DILITHIUM3_PUBLIC_KEY_BYTES); +static int nistdsa_bits(const EVP_PKEY *pkey) { + if (pkey->pkey.nistdsa_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + return 8 * (pkey->pkey.nistdsa_key->nistdsa->public_key_len); } -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, +const EVP_PKEY_ASN1_METHOD nistdsa_asn1_meth = { + //2.16.840.1.101.3.4.3 + EVP_PKEY_NISTDSA, + + {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03}, + 8, + + "NIST DSA", + "AWS-LC NIST DSA method", + + nistdsa_pub_decode, + nistdsa_pub_encode, + nistdsa_pub_cmp, + nistdsa_priv_decode, + nistdsa_priv_encode, + NULL /*priv_encode_v2*/, + nistdsa_set_priv_raw, + nistdsa_set_pub_raw, + nistdsa_get_priv_raw, + nistdsa_get_pub_raw, + NULL /* pkey_opaque */, + nistdsa_size, + nistdsa_bits, + NULL /* param_missing */, + NULL /* param_copy */, + NULL /* param_cmp */, + nistdsa_free, }; - - - diff --git a/crypto/dilithium/p_dilithium_test.cc b/crypto/dilithium/p_dilithium_test.cc index b1aef073ad..4a0a052e01 100644 --- a/crypto/dilithium/p_dilithium_test.cc +++ b/crypto/dilithium/p_dilithium_test.cc @@ -13,6 +13,7 @@ #include "../crypto/evp_extra/internal.h" #include "../fipsmodule/evp/internal.h" #include "../internal.h" +#include "internal.h" #ifdef ENABLE_DILITHIUM @@ -21,368 +22,142 @@ #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 mldsa65kPublicKey[] = {0x9B, 0x77, 0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x02, 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, 0x03, 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, 0x06, 0xBA, 0xD5, 0xF8, 0x9E, 0x0A, 0x2D, 0xA2, 0xC7, 0x96, 0x4B, 0x79, 0xE9, 0xA9, 0xA6, 0x73, 0x69, 0xF8, 0x8C, 0x01, 0x69, 0xF2, 0x66, 0x05, 0x37, 0x31, 0x65, 0xA9, 0x09, 0x3E, 0x0E, 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, 0x06, 0x23, 0xE6, 0x1C, 0x44, 0x63, 0x02, 0x9E, 0x09, 0x76, 0x6C, 0x72, 0xBD, 0x0D, 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, 0x0F, 0x6B, 0x32, 0x78, 0xD2, 0x24, 0xB7, 0x8C, 0xE8, 0x84, 0xE3, 0xB8, 0xF6, 0x04, 0xF3, 0x30, 0xE9, 0x5B, 0xA5, 0xD8, 0x94, 0xA7, 0xA3, 0xF0, 0xE8, 0xAC, 0x70, 0x32, 0x42, 0xB5, 0x08, 0xEE, 0x2A, 0x77, 0xFA, 0x04, 0x49, 0xE9, 0x7A, 0xB7, 0x0A, 0x95, 0x05, 0x86, 0x33, 0xA5, 0xE4, 0x5A, 0xC6, 0xE1, 0xE7, 0x48, 0xBD, 0xBA, 0x80, 0xE7, 0x21, 0x61, 0x45, 0x24, 0x5E, 0xA9, 0x7F, 0x2D, 0x75, 0x0F, 0xE9, 0xEE, 0x79, 0x88, 0x64, 0xF3, 0xE7, 0x0C, 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, 0x08, 0x58, 0x3F, 0x20, 0x96, 0x52, 0xD2, 0x61, 0xDA, 0xED, 0x5F, 0x7F, 0xAD, 0x40, 0x93, 0x21, 0xEB, 0xC4, 0x37, 0x5C, 0xD1, 0x72, 0xE6, 0x06, 0x37, 0xD9, 0xF6, 0x09, 0xD4, 0xC9, 0x6D, 0xED, 0x07, 0xF6, 0xD2, 0x15, 0x94, 0xFD, 0xF6, 0xC3, 0x09, 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, 0x0E, 0x6A, 0x9E, 0x6D, 0xAC, 0xF1, 0x0F, 0x90, 0x25, 0xED, 0xC5, 0x94, 0x9E, 0x10, 0x29, 0x97, 0x47, 0x05, 0x3D, 0x03, 0x6F, 0x69, 0xAE, 0x84, 0x08, 0x9B, 0x33, 0x0C, 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, 0x01, 0x5F, 0x39, 0xD1, 0xBC, 0x07, 0x8E, 0xAC, 0xC9, 0x28, 0x0C, 0x7B, 0xD8, 0x02, 0xFE, 0x46, 0x12, 0xA8, 0xBD, 0x0E, 0x6B, 0x23, 0x65, 0x5B, 0xAA, 0xFC, 0x32, 0x20, 0xF7, 0xCC, 0xC7, 0x06, 0x80, 0x09, 0x0A, 0x95, 0xD9, 0x69, 0xED, 0x3C, 0x6C, 0xEB, 0x62, 0x28, 0xE6, 0x4E, 0xF4, 0xFA, 0x9B, 0x5C, 0x36, 0x07, 0xE0, 0x25, 0x20, 0xB8, 0xF4, 0x1F, 0x2E, 0x78, 0x21, 0xEE, 0xFA, 0x9E, 0x80, 0x14, 0xAD, 0xAD, 0x83, 0x39, 0x2E, 0xD0, 0xE9, 0x56, 0xE3, 0x88, 0x0C, 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, 0x0A, 0x07, 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, 0x08, 0x40, 0x25, 0x7B, 0x03, 0x75, 0x47, 0xAD, 0x19, 0x02, 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, 0x0E, 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, 0x0D, 0x17, 0x90, 0x66, 0x70, 0xB2, 0x98, 0x24, 0x1B, 0x58, 0x79, 0xAC, 0x3E, 0x61, 0x9C, 0x67, 0xB4, 0xEE, 0x09, 0x06, 0x20, 0xCE, 0x39, 0x03, 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, 0x06, 0x51, 0x74, 0x72, 0x71, 0x9D, 0xA1, 0x3F, 0x3C, 0x73, 0xCF, 0x07, 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, 0x04, 0x67, 0x20, 0x5D, 0x2B, 0x79, 0x42, 0x07, 0x03, 0x5C, 0x36, 0xD7, 0xBE, 0x72, 0xCA, 0x13, 0xCF, 0x93, 0x2D, 0xD8, 0xA9, 0xEE, 0x06, 0x0B, 0xCF, 0x5A, 0x46, 0x88, 0x57, 0x9E, 0x18, 0x92, 0x3B, 0x5F, 0x2F, 0x86, 0xCD, 0x3D, 0x49, 0xF6, 0xA3, 0x05, 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, 0x03, 0xDF, 0xF8, 0xD5, 0x7F, 0x7B, 0x09, 0x62, 0xBF, 0x28, 0xBD, 0xC6, 0x3E, 0xC3, 0x6C, 0x91, 0x01, 0x45, 0x3F, 0xE2, 0x1F, 0xEF, 0x2A, 0x8F, 0xB2, 0x1B, 0x72, 0x35, 0x4D, 0x18, 0x6F, 0x4D, 0x57, 0xBF, 0x6A, 0x69, 0x02, 0x69, 0x4A, 0xE5, 0x5F, 0x74, 0xF7, 0x69, 0x5B, 0x89, 0x08, 0xCE, 0xCE, 0x15, 0x56, 0x3F, 0x21, 0x1A, 0xB8, 0xEC, 0x4D, 0xB0, 0x7E, 0x0F, 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, 0x0C, 0x61, 0xEA, 0x59, 0x33, 0x25, 0x39, 0xAF, 0xF0, 0x12, 0x81, 0x55, 0x4A, 0x9D, 0x0C, 0x3E, 0x5E, 0x34, 0x9F, 0xA7, 0xD8, 0xC5, 0xB5, 0x0A, 0xC3, 0xA2, 0x00, 0x3F, 0x59, 0x3D, 0x07, 0x5F, 0x2B, 0xC1, 0x6F, 0x6A, 0xE3, 0x94, 0x90, 0xAF, 0x81, 0x11, 0x82, 0x89, 0xF4, 0x9D, 0x8B, 0x05, 0xE2, 0x7C, 0x22, 0x02, 0xEC, 0x00, 0x38, 0x39, 0xED, 0x04, 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, 0x0F, 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, 0x06, 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, 0x0B, 0x09, 0x44, 0x9C, 0x20, 0x34, 0xF6, 0xEE, 0x6F, 0x26, 0xB9, 0x4C, 0x76, 0xCC, 0xE1, 0x6F, 0x09, 0x91, 0xAF, 0x48, 0x8C, 0xC4, 0x31, 0xA2, 0xF9, 0x44, 0x77, 0x19, 0xA7, 0x00, 0x33, 0x77, 0x31, 0xF2, 0xF5, 0xF7, 0x30, 0xDF, 0xAB, 0xFE, 0x7E, 0xE6, 0x83, 0xE1, 0xC9, 0x2A, 0xC8, 0xE0, 0xA6, 0xAC, 0x5A, 0x28, 0x7F, 0xC4, 0x0B, 0xEB, 0x55, 0xD9, 0x5D, 0xBD, 0xB5, 0xD2, 0xF6, 0xB4, 0xA9, 0x76, 0x2B, 0x35, 0x10, 0x36, 0x3B, 0xCC, 0x61, 0x6C, 0x79, 0xCE, 0xC3, 0x9A, 0x02, 0x9A, 0x00, 0xBA, 0x43, 0x20, 0x3F, 0x26, 0x36, 0x66, 0x07, 0x11, 0x68, 0x51, 0x47, 0xBE, 0x78, 0xED, 0x4A, 0xFA, 0xBC, 0xDA, 0xCD, 0xFD, 0x02, 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, 0x0B, 0x73, 0x03, 0xFB, 0xFE, 0xC0, 0x50, 0x38, 0x70, 0xDF, 0x81, 0x5D, 0x22, 0x4C, 0x5B, 0xCB, 0x27, 0x5D, 0xD2, 0x94, 0x64, 0x0A, 0x88, 0x67, 0x31, 0xE9, 0x08, 0xF0, 0x88, 0x20, 0xF2, 0x86, 0xCA, 0xBD, 0x18, 0x5F, 0x34, 0xD0, 0x96, 0x0D, 0x4A, 0x62, 0x4D, 0xBE, 0xE8, 0xA6, 0x04, 0xA6, 0x69, 0xCE, 0xCD, 0xE9, 0x5A, 0x1D, 0xD2, 0xF8, 0xCF, 0x19, 0x06, 0x17, 0x05, 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, 0x0D, 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, 0x01, 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, 0x01, 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, 0x0C, 0x87, 0x03, 0x61, 0xB4, 0x3B, 0x60, 0x6D, 0x07, 0x56, 0xB8, 0x1F, 0x89, 0xAD, 0x00, 0x25, 0x10, 0x4A, 0x34, 0x4C, 0x9A, 0x26, 0xDA, 0x06, 0x25, 0x9C, 0x91, 0xA6, 0xA5, 0xAD, 0x4D, 0x6E, 0xE9, 0x2F, 0x18, 0xC4, 0x1D, 0x09, 0xE1, 0xAA, 0x66, 0x01, 0x31, 0x6D, 0x12, 0x30, 0xED, 0x97, 0x3F, 0x67, 0xCE, 0x4E, 0x26, 0x0B, 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, 0x0E, 0x51, 0x63, 0x90, 0x05, 0x68, 0x7A, 0x45, 0x86, 0x68, 0x2A, 0x0E, 0x81, 0x5F, 0xDD, 0x12, 0xAD, 0x48, 0xF6, 0x87, 0x2E, 0x8D, 0xF6, 0x86, 0xC3, 0x6D, 0x69, 0xD5, 0x4E, 0x52, 0x8A, 0x8E, 0xE8, 0x01, 0x56, 0x11, 0xCC, 0x2E, 0x3F, 0xB5, 0x46, 0x1D, 0xF6, 0x6E, 0x4A, 0xEE, 0x1C, 0x60, 0x15, 0x85, 0xF6, 0x40, 0xFD, 0x56, 0xDC, 0x10, 0x01, 0xC3, 0xBD, 0xAE, 0x5A, 0x13, 0x1F, 0x15, 0x16, 0x10, 0x92, 0xC5, 0x02, 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, 0x0E, +}; +static const uint8_t mldsa65kPublicKeySPKI[] = { 0x30, 0x82, 0x07, 0xB1, 0x30, 0x0A, 0x06, 0x08, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x03, 0x82, 0x07, 0xA1, 0x00, 0x9B, 0x77, 0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x02, 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, 0x03, 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, 0x06, 0xBA, 0xD5, 0xF8, 0x9E, 0x0A, 0x2D, 0xA2, 0xC7, 0x96, 0x4B, 0x79, 0xE9, 0xA9, 0xA6, 0x73, 0x69, 0xF8, 0x8C, 0x01, 0x69, 0xF2, 0x66, 0x05, 0x37, 0x31, 0x65, 0xA9, 0x09, 0x3E, 0x0E, 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, 0x06, 0x23, 0xE6, 0x1C, 0x44, 0x63, 0x02, 0x9E, 0x09, 0x76, 0x6C, 0x72, 0xBD, 0x0D, 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, 0x0F, 0x6B, 0x32, 0x78, 0xD2, 0x24, 0xB7, 0x8C, 0xE8, 0x84, 0xE3, 0xB8, 0xF6, 0x04, 0xF3, 0x30, 0xE9, 0x5B, 0xA5, 0xD8, 0x94, 0xA7, 0xA3, 0xF0, 0xE8, 0xAC, 0x70, 0x32, 0x42, 0xB5, 0x08, 0xEE, 0x2A, 0x77, 0xFA, 0x04, 0x49, 0xE9, 0x7A, 0xB7, 0x0A, 0x95, 0x05, 0x86, 0x33, 0xA5, 0xE4, 0x5A, 0xC6, 0xE1, 0xE7, 0x48, 0xBD, 0xBA, 0x80, 0xE7, 0x21, 0x61, 0x45, 0x24, 0x5E, 0xA9, 0x7F, 0x2D, 0x75, 0x0F, 0xE9, 0xEE, 0x79, 0x88, 0x64, 0xF3, 0xE7, 0x0C, 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, 0x08, 0x58, 0x3F, 0x20, 0x96, 0x52, 0xD2, 0x61, 0xDA, 0xED, 0x5F, 0x7F, 0xAD, 0x40, 0x93, 0x21, 0xEB, 0xC4, 0x37, 0x5C, 0xD1, 0x72, 0xE6, 0x06, 0x37, 0xD9, 0xF6, 0x09, 0xD4, 0xC9, 0x6D, 0xED, 0x07, 0xF6, 0xD2, 0x15, 0x94, 0xFD, 0xF6, 0xC3, 0x09, 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, 0x0E, 0x6A, 0x9E, 0x6D, 0xAC, 0xF1, 0x0F, 0x90, 0x25, 0xED, 0xC5, 0x94, 0x9E, 0x10, 0x29, 0x97, 0x47, 0x05, 0x3D, 0x03, 0x6F, 0x69, 0xAE, 0x84, 0x08, 0x9B, 0x33, 0x0C, 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, 0x01, 0x5F, 0x39, 0xD1, 0xBC, 0x07, 0x8E, 0xAC, 0xC9, 0x28, 0x0C, 0x7B, 0xD8, 0x02, 0xFE, 0x46, 0x12, 0xA8, 0xBD, 0x0E, 0x6B, 0x23, 0x65, 0x5B, 0xAA, 0xFC, 0x32, 0x20, 0xF7, 0xCC, 0xC7, 0x06, 0x80, 0x09, 0x0A, 0x95, 0xD9, 0x69, 0xED, 0x3C, 0x6C, 0xEB, 0x62, 0x28, 0xE6, 0x4E, 0xF4, 0xFA, 0x9B, 0x5C, 0x36, 0x07, 0xE0, 0x25, 0x20, 0xB8, 0xF4, 0x1F, 0x2E, 0x78, 0x21, 0xEE, 0xFA, 0x9E, 0x80, 0x14, 0xAD, 0xAD, 0x83, 0x39, 0x2E, 0xD0, 0xE9, 0x56, 0xE3, 0x88, 0x0C, 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, 0x0A, 0x07, 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, 0x08, 0x40, 0x25, 0x7B, 0x03, 0x75, 0x47, 0xAD, 0x19, 0x02, 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, 0x0E, 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, 0x0D, 0x17, 0x90, 0x66, 0x70, 0xB2, 0x98, 0x24, 0x1B, 0x58, 0x79, 0xAC, 0x3E, 0x61, 0x9C, 0x67, 0xB4, 0xEE, 0x09, 0x06, 0x20, 0xCE, 0x39, 0x03, 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, 0x06, 0x51, 0x74, 0x72, 0x71, 0x9D, 0xA1, 0x3F, 0x3C, 0x73, 0xCF, 0x07, 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, 0x04, 0x67, 0x20, 0x5D, 0x2B, 0x79, 0x42, 0x07, 0x03, 0x5C, 0x36, 0xD7, 0xBE, 0x72, 0xCA, 0x13, 0xCF, 0x93, 0x2D, 0xD8, 0xA9, 0xEE, 0x06, 0x0B, 0xCF, 0x5A, 0x46, 0x88, 0x57, 0x9E, 0x18, 0x92, 0x3B, 0x5F, 0x2F, 0x86, 0xCD, 0x3D, 0x49, 0xF6, 0xA3, 0x05, 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, 0x03, 0xDF, 0xF8, 0xD5, 0x7F, 0x7B, 0x09, 0x62, 0xBF, 0x28, 0xBD, 0xC6, 0x3E, 0xC3, 0x6C, 0x91, 0x01, 0x45, 0x3F, 0xE2, 0x1F, 0xEF, 0x2A, 0x8F, 0xB2, 0x1B, 0x72, 0x35, 0x4D, 0x18, 0x6F, 0x4D, 0x57, 0xBF, 0x6A, 0x69, 0x02, 0x69, 0x4A, 0xE5, 0x5F, 0x74, 0xF7, 0x69, 0x5B, 0x89, 0x08, 0xCE, 0xCE, 0x15, 0x56, 0x3F, 0x21, 0x1A, 0xB8, 0xEC, 0x4D, 0xB0, 0x7E, 0x0F, 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, 0x0C, 0x61, 0xEA, 0x59, 0x33, 0x25, 0x39, 0xAF, 0xF0, 0x12, 0x81, 0x55, 0x4A, 0x9D, 0x0C, 0x3E, 0x5E, 0x34, 0x9F, 0xA7, 0xD8, 0xC5, 0xB5, 0x0A, 0xC3, 0xA2, 0x00, 0x3F, 0x59, 0x3D, 0x07, 0x5F, 0x2B, 0xC1, 0x6F, 0x6A, 0xE3, 0x94, 0x90, 0xAF, 0x81, 0x11, 0x82, 0x89, 0xF4, 0x9D, 0x8B, 0x05, 0xE2, 0x7C, 0x22, 0x02, 0xEC, 0x00, 0x38, 0x39, 0xED, 0x04, 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, 0x0F, 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, 0x06, 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, 0x0B, 0x09, 0x44, 0x9C, 0x20, 0x34, 0xF6, 0xEE, 0x6F, 0x26, 0xB9, 0x4C, 0x76, 0xCC, 0xE1, 0x6F, 0x09, 0x91, 0xAF, 0x48, 0x8C, 0xC4, 0x31, 0xA2, 0xF9, 0x44, 0x77, 0x19, 0xA7, 0x00, 0x33, 0x77, 0x31, 0xF2, 0xF5, 0xF7, 0x30, 0xDF, 0xAB, 0xFE, 0x7E, 0xE6, 0x83, 0xE1, 0xC9, 0x2A, 0xC8, 0xE0, 0xA6, 0xAC, 0x5A, 0x28, 0x7F, 0xC4, 0x0B, 0xEB, 0x55, 0xD9, 0x5D, 0xBD, 0xB5, 0xD2, 0xF6, 0xB4, 0xA9, 0x76, 0x2B, 0x35, 0x10, 0x36, 0x3B, 0xCC, 0x61, 0x6C, 0x79, 0xCE, 0xC3, 0x9A, 0x02, 0x9A, 0x00, 0xBA, 0x43, 0x20, 0x3F, 0x26, 0x36, 0x66, 0x07, 0x11, 0x68, 0x51, 0x47, 0xBE, 0x78, 0xED, 0x4A, 0xFA, 0xBC, 0xDA, 0xCD, 0xFD, 0x02, 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, 0x0B, 0x73, 0x03, 0xFB, 0xFE, 0xC0, 0x50, 0x38, 0x70, 0xDF, 0x81, 0x5D, 0x22, 0x4C, 0x5B, 0xCB, 0x27, 0x5D, 0xD2, 0x94, 0x64, 0x0A, 0x88, 0x67, 0x31, 0xE9, 0x08, 0xF0, 0x88, 0x20, 0xF2, 0x86, 0xCA, 0xBD, 0x18, 0x5F, 0x34, 0xD0, 0x96, 0x0D, 0x4A, 0x62, 0x4D, 0xBE, 0xE8, 0xA6, 0x04, 0xA6, 0x69, 0xCE, 0xCD, 0xE9, 0x5A, 0x1D, 0xD2, 0xF8, 0xCF, 0x19, 0x06, 0x17, 0x05, 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, 0x0D, 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, 0x01, 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, 0x01, 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, 0x0C, 0x87, 0x03, 0x61, 0xB4, 0x3B, 0x60, 0x6D, 0x07, 0x56, 0xB8, 0x1F, 0x89, 0xAD, 0x00, 0x25, 0x10, 0x4A, 0x34, 0x4C, 0x9A, 0x26, 0xDA, 0x06, 0x25, 0x9C, 0x91, 0xA6, 0xA5, 0xAD, 0x4D, 0x6E, 0xE9, 0x2F, 0x18, 0xC4, 0x1D, 0x09, 0xE1, 0xAA, 0x66, 0x01, 0x31, 0x6D, 0x12, 0x30, 0xED, 0x97, 0x3F, 0x67, 0xCE, 0x4E, 0x26, 0x0B, 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, 0x0E, 0x51, 0x63, 0x90, 0x05, 0x68, 0x7A, 0x45, 0x86, 0x68, 0x2A, 0x0E, 0x81, 0x5F, 0xDD, 0x12, 0xAD, 0x48, 0xF6, 0x87, 0x2E, 0x8D, 0xF6, 0x86, 0xC3, 0x6D, 0x69, 0xD5, 0x4E, 0x52, 0x8A, 0x8E, 0xE8, 0x01, 0x56, 0x11, 0xCC, 0x2E, 0x3F, 0xB5, 0x46, 0x1D, 0xF6, 0x6E, 0x4A, 0xEE, 0x1C, 0x60, 0x15, 0x85, 0xF6, 0x40, 0xFD, 0x56, 0xDC, 0x10, 0x01, 0xC3, 0xBD, 0xAE, 0x5A, 0x13, 0x1F, 0x15, 0x16, 0x10, 0x92, 0xC5, 0x02, 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, 0x0E, }; -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, +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; + const uint8_t *kPublicKey; + const uint8_t *kPublicKeySPKI; + const size_t kPublicKeySPKI_len; }; -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); +#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.nistdsa_key->public_key, len) + +#define CMP_VEC_AND_PKEY_SECRET(vec, pkey, len) \ +CMP_VEC_AND_PTR(vec, pkey->pkey.nistdsa_key->secret_key, len) + +static const struct ML_DSA parameterSet[] = { + {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt",mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1973}, +}; + +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); - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey, nullptr); + // Convert string read from KAT to int + size_t mlen_int = std::stoi(mlen); - 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); + // 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()); - const DILITHIUM3_KEY *dilithium3Key = (DILITHIUM3_KEY *)(dilithium_pkey->pkey.ptr); - EXPECT_NE(dilithium3Key->priv, nullptr); + // Generate our dilithium public and private key pair + bssl::UniquePtr pctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + ASSERT_TRUE(pctx); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_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(MLDSAParameterTest, 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().secret_key_len; + + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(),nid)); + 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(dilithium_pkey, buf, &buf_size)); - EXPECT_EQ((size_t)DILITHIUM3_PUBLIC_KEY_BYTES, 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(dilithium_pkey, buf, &buf_size)); + EXPECT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), buf, &buf_size)); buf_size = 0; - EXPECT_FALSE(EVP_PKEY_get_raw_public_key(dilithium_pkey, buf, &buf_size)); + 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)); @@ -391,258 +166,223 @@ TEST(Dilithium3Test, KeyGeneration) { 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); + 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(dilithium_pkey, buf, &buf_size)); + EXPECT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), buf, &buf_size)); buf_size = 0; - EXPECT_FALSE(EVP_PKEY_get_raw_private_key(dilithium_pkey, buf, &buf_size)); + 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); - - 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)); +TEST_P(MLDSAParameterTest, 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_NISTDSA, nullptr)); + ASSERT_TRUE(ctx1); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_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_NISTDSA, nullptr)); + ASSERT_TRUE(ctx2); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_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())); +} - 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_P(MLDSAParameterTest, 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_NISTDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_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(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); +TEST_P(MLDSAParameterTest, 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().secret_key_len; + // Source key + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(), nid)); + 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_new_raw_public_key(EVP_PKEY_NISTDSA, + nullptr, + pkey->pkey.nistdsa_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.nistdsa_key->public_key, nullptr); + EXPECT_EQ(new_pkey->pkey.nistdsa_key->secret_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_public, buf, &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 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); + // EVP_PKEY_cmp compares the public keys so this should return 1 + EXPECT_EQ(1, EVP_PKEY_cmp(pkey.get(), new_pkey.get())); - EXPECT_TRUE(EVP_PKEY_keygen_init(dilithium_pkey_ctx)); - EXPECT_TRUE(EVP_PKEY_keygen(dilithium_pkey_ctx, &dilithium_pkey)); + // New raw pkey to store raw secret key + bssl::UniquePtr private_pkey(EVP_PKEY_new_raw_private_key(EVP_PKEY_NISTDSA, + nullptr, + pkey->pkey.nistdsa_key->secret_key, + sk_len)); - 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); + // check that secret key is present and public key is not present + ASSERT_NE(private_pkey, nullptr); + EXPECT_EQ(private_pkey->pkey.nistdsa_key->public_key, nullptr); + EXPECT_NE(private_pkey->pkey.nistdsa_key->secret_key, nullptr); + EXPECT_EQ(0, OPENSSL_memcmp(private_pkey->pkey.nistdsa_key->secret_key, pkey->pkey.nistdsa_key->secret_key, sk_len)); } -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())); +TEST_P(MLDSAParameterTest, 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_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_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().secret_key_len; + + // Generate mldsa key + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(),nid)); + 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. - uint8_t pub_buf[1952]; + std::vector pub_buf(pk_len); 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)); + 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)); + + // Generate a new pkey with only public key set from the extracted public key + bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + nullptr, + pub_buf.data(), + pk_len)); + ASSERT_TRUE(pkey_pk_new); + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey_pk_new.get(), nid); // 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(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); - 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)); + 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 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 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)); - // 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); -} + // Generate a new pkey with only secret key set from the extracted secret key + bssl::UniquePtr pkey_sk_new(EVP_PKEY_new_raw_private_key(EVP_PKEY_NISTDSA, + nullptr, + priv_buf.data(), + sk_len)); + ASSERT_TRUE(pkey_sk_new); + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey_sk_new.get(), nid); -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; + // The private key must encode properly. ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pubkey.get())); + ASSERT_TRUE(EVP_marshal_private_key(cbb.get(), pkey_sk_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), Bytes(der, der_len)); + free_der.reset(der); - // We now decode the DER structure, then parse as a PKEY. - CBS cbs; + // private key parse 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); + bssl::UniquePtr pkey_priv_from_der(EVP_parse_private_key(&cbs)); + ASSERT_TRUE(pkey_priv_from_der); + + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey_priv_from_der.get(), nid); + // check that the private key from pkey_priv_from_der matches the original key + EXPECT_EQ(Bytes(pkey_priv_from_der->pkey.nistdsa_key->secret_key, + pkey_priv_from_der->pkey.nistdsa_key->nistdsa->secret_key_len), + Bytes(priv_buf.data(), sk_len)); } -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); +TEST_P(MLDSAParameterTest, SIGOperations) { + // Test basic functionality for MLDSA + int nid = GetParam().nid; + size_t sig_len = GetParam().signature_len; - 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)); + // Generate a mldsa key + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(),nid)); + 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; - uint8_t signature[DILITHIUM3_SIGNATURE_BYTES]; - size_t signature_len = DILITHIUM3_SIGNATURE_BYTES; + std::vector signature(sig_len); + std::vector msg = { 0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49, 0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x32, 0x2e}; @@ -650,131 +390,90 @@ TEST(Dilithium3Test, SIGOperations) { 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, + ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, + nullptr, pkey.get())); + ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature.data(), &sig_len, msg.data(), msg.size())); // Verify the correct signed message - ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), signature, signature_len, + ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), signature.data(), sig_len, msg.data(), msg.size())); // Verify the signed message fails upon a bad message - ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature, signature_len, + ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature.data(), sig_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, + + std::vector signature1(sig_len); + ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature1.data(), &sig_len, badmsg.data(), badmsg.size())); // Check that the two signatures are not equal - EXPECT_NE(0, OPENSSL_memcmp(signature, signature1, signature_len)); + EXPECT_NE(0, OPENSSL_memcmp(signature.data(), signature1.data(), sig_len)); // Verify the signed message fails upon a bad signature - ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature1, signature_len, + ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature1.data(), sig_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); +TEST_P(MLDSAParameterTest, MarshalParse) { + // Test the example public key kPublicKey encodes correctly as kPublicKeySPKI + // Test that the DER encoding can be parsed as a PKEY + // Test that extacting the public key from the PKEY is the same as the original key + + 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; + + // Generate a new pkey with only public key set from the extracted public key + bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + nullptr, + kPublicKey, + pk_len)); + ASSERT_TRUE(pkey_pk_new); + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey_pk_new.get(), nid); - EVP_PKEY *dilithium_pkey = EVP_PKEY_new(); - ASSERT_NE(dilithium_pkey, nullptr); + // 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); - 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)); + // Test that the encoded public key encodes as expected + EXPECT_EQ(Bytes(kPublicKeySPKI, kPublicKeySPKI_len), Bytes(der, der_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)); + // 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); - // Verify the signature for the message - ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), signature.data(), sig_len, msg.data(), mlen_int)); + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey_from_der.get(), nid); - EVP_PKEY_free(dilithium_pkey); - EVP_PKEY_CTX_free(dilithium_pkey_ctx); - md_ctx.Reset(); - }); + // Extract the public key and check it is equivalent to original key + std::vector pub_buf(pk_len); + size_t pub_len; + ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey_from_der.get(), nullptr, &pub_len)); + EXPECT_EQ(pub_len, pk_len); + ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey_from_der.get(), pub_buf.data(), &pub_len)); + EXPECT_EQ(Bytes(kPublicKey, pk_len), Bytes(pub_buf.data(), pub_len)); } #else TEST(Dilithium3Test, EvpDisabled) { - ASSERT_EQ(nullptr, EVP_PKEY_CTX_new_id(NID_DILITHIUM3_R3, nullptr)); + 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(), NID_DILITHIUM3_R3)); + ASSERT_FALSE(EVP_PKEY_set_type(pkey.get(), EVP_PKEY_NONE)); } #endif diff --git a/crypto/dilithium/sig_dilithium.h b/crypto/dilithium/sig_dilithium.h index 21131c29fa..e29aa9f701 100644 --- a/crypto/dilithium/sig_dilithium.h +++ b/crypto/dilithium/sig_dilithium.h @@ -9,9 +9,11 @@ #include #include -#define DILITHIUM3_PUBLIC_KEY_BYTES 1952 -#define DILITHIUM3_PRIVATE_KEY_BYTES 4032 -#define DILITHIUM3_SIGNATURE_BYTES 3309 +#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 // 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. diff --git a/crypto/dilithium/sig_dilithium3.c b/crypto/dilithium/sig_dilithium3.c index 2be7dd4dc5..704c76b41f 100644 --- a/crypto/dilithium/sig_dilithium3.c +++ b/crypto/dilithium/sig_dilithium3.c @@ -28,7 +28,7 @@ int ml_dsa_65_keypair(uint8_t *public_key /* OUT */, uint8_t *secret_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, secret_key) == 0); } int ml_dsa_65_sign(uint8_t *sig /* OUT */, diff --git a/crypto/evp_extra/evp_extra_test.cc b/crypto/evp_extra/evp_extra_test.cc index 079d19f3e0..473a145f47 100644 --- a/crypto/evp_extra/evp_extra_test.cc +++ b/crypto/evp_extra/evp_extra_test.cc @@ -698,322 +698,10 @@ 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, 0x0F, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x0A, 0x06, 0x08, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x04, 0x82, 0x0F, 0xC0, 0x9B, 0x77, 0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x02, 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, 0x04, 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, 0x09, 0x2C, 0xBB, 0x6A, 0x54, 0x6D, 0x9D, 0x5D, 0x97, 0xD3, 0xCC, 0x20, 0x31, 0x9C, 0x7E, 0x2B, 0x5C, 0x42, 0x9E, 0x2E, 0xCB, 0x41, 0x38, 0x84, 0x02, 0x03, 0x24, 0x75, 0x37, 0x23, 0x73, 0x38, 0x85, 0x00, 0x62, 0x42, 0x24, 0x76, 0x38, 0x88, 0x21, 0x31, 0x76, 0x74, 0x55, 0x51, 0x28, 0x34, 0x08, 0x41, 0x32, 0x67, 0x40, 0x11, 0x81, 0x62, 0x48, 0x27, 0x51, 0x85, 0x33, 0x61, 0x12, 0x22, 0x24, 0x30, 0x28, 0x75, 0x20, 0x03, 0x63, 0x11, 0x71, 0x88, 0x38, 0x88, 0x58, 0x84, 0x16, 0x66, 0x14, 0x22, 0x27, 0x28, 0x11, 0x44, 0x37, 0x76, 0x15, 0x24, 0x08, 0x56, 0x40, 0x13, 0x71, 0x74, 0x46, 0x88, 0x14, 0x37, 0x13, 0x00, 0x01, 0x48, 0x44, 0x04, 0x83, 0x67, 0x88, 0x16, 0x00, 0x13, 0x17, 0x06, 0x38, 0x18, 0x76, 0x15, 0x14, 0x67, 0x16, 0x76, 0x57, 0x24, 0x53, 0x86, 0x31, 0x34, 0x16, 0x34, 0x03, 0x08, 0x68, 0x65, 0x77, 0x36, 0x86, 0x37, 0x30, 0x76, 0x20, 0x51, 0x33, 0x82, 0x28, 0x72, 0x45, 0x35, 0x83, 0x06, 0x58, 0x58, 0x37, 0x71, 0x86, 0x00, 0x84, 0x18, 0x11, 0x54, 0x87, 0x12, 0x78, 0x75, 0x23, 0x45, 0x81, 0x17, 0x42, 0x01, 0x00, 0x34, 0x32, 0x55, 0x38, 0x88, 0x25, 0x52, 0x62, 0x05, 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, 0x04, 0x87, 0x22, 0x00, 0x66, 0x74, 0x52, 0x18, 0x32, 0x07, 0x61, 0x27, 0x68, 0x70, 0x65, 0x78, 0x85, 0x66, 0x60, 0x05, 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, 0x01, 0x78, 0x70, 0x16, 0x11, 0x35, 0x58, 0x58, 0x08, 0x82, 0x55, 0x61, 0x85, 0x17, 0x46, 0x70, 0x77, 0x77, 0x37, 0x42, 0x35, 0x56, 0x53, 0x85, 0x07, 0x64, 0x13, 0x34, 0x51, 0x25, 0x78, 0x12, 0x21, 0x14, 0x74, 0x81, 0x32, 0x41, 0x00, 0x60, 0x78, 0x71, 0x22, 0x22, 0x56, 0x48, 0x57, 0x24, 0x65, 0x40, 0x36, 0x03, 0x03, 0x17, 0x86, 0x31, 0x44, 0x48, 0x55, 0x60, 0x55, 0x84, 0x68, 0x76, 0x16, 0x15, 0x40, 0x82, 0x64, 0x88, 0x47, 0x88, 0x44, 0x58, 0x46, 0x05, 0x02, 0x47, 0x27, 0x64, 0x20, 0x74, 0x14, 0x74, 0x02, 0x18, 0x21, 0x50, 0x42, 0x43, 0x14, 0x63, 0x05, 0x36, 0x08, 0x38, 0x80, 0x86, 0x80, 0x61, 0x15, 0x80, 0x56, 0x53, 0x13, 0x70, 0x64, 0x66, 0x20, 0x17, 0x21, 0x50, 0x68, 0x07, 0x53, 0x34, 0x73, 0x17, 0x50, 0x68, 0x72, 0x43, 0x02, 0x00, 0x80, 0x07, 0x37, 0x85, 0x72, 0x12, 0x87, 0x73, 0x46, 0x45, 0x56, 0x66, 0x02, 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, 0x05, 0x07, 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, 0x01, 0x75, 0x57, 0x42, 0x88, 0x21, 0x22, 0x77, 0x68, 0x22, 0x43, 0x84, 0x14, 0x51, 0x73, 0x68, 0x54, 0x62, 0x08, 0x83, 0x75, 0x41, 0x10, 0x15, 0x14, 0x57, 0x73, 0x42, 0x13, 0x20, 0x52, 0x76, 0x72, 0x34, 0x18, 0x10, 0x00, 0x18, 0x17, 0x55, 0x30, 0x88, 0x47, 0x23, 0x00, 0x76, 0x44, 0x85, 0x25, 0x04, 0x03, 0x88, 0x00, 0x70, 0x10, 0x70, 0x01, 0x80, 0x12, 0x04, 0x73, 0x20, 0x72, 0x21, 0x24, 0x37, 0x04, 0x01, 0x63, 0x76, 0x04, 0x71, 0x30, 0x31, 0x17, 0x20, 0x18, 0x37, 0x23, 0x44, 0x03, 0x08, 0x77, 0x63, 0x73, 0x61, 0x43, 0x70, 0x11, 0x06, 0x84, 0x73, 0x26, 0x38, 0x78, 0x23, 0x61, 0x12, 0x45, 0x84, 0x76, 0x31, 0x23, 0x67, 0x37, 0x07, 0x73, 0x13, 0x46, 0x42, 0x51, 0x13, 0x12, 0x05, 0x15, 0x28, 0x57, 0x64, 0x62, 0x82, 0x42, 0x06, 0x83, 0x25, 0x12, 0x20, 0x40, 0x48, 0x21, 0x47, 0x73, 0x38, 0x13, 0x32, 0x10, 0x73, 0x36, 0x57, 0x03, 0x00, 0x31, 0x54, 0x78, 0x40, 0x23, 0x21, 0x14, 0x35, 0x13, 0x62, 0x83, 0x56, 0x35, 0x87, 0x44, 0x65, 0x74, 0x05, 0x66, 0x76, 0x26, 0x35, 0x17, 0x18, 0x67, 0x12, 0x06, 0x00, 0x42, 0x85, 0x71, 0x20, 0x62, 0x81, 0x22, 0x05, 0x76, 0x32, 0x77, 0x60, 0x65, 0x84, 0x64, 0x14, 0x60, 0x08, 0x55, 0x65, 0x21, 0x18, 0x08, 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, 0x05, 0x81, 0x84, 0x34, 0x78, 0x70, 0x65, 0x34, 0x10, 0x76, 0x76, 0x20, 0x76, 0x33, 0x33, 0x22, 0x76, 0x75, 0x28, 0x03, 0x04, 0x21, 0x28, 0x73, 0x03, 0x57, 0x72, 0x03, 0x35, 0x37, 0x66, 0x88, 0x23, 0x88, 0x27, 0x43, 0x32, 0x26, 0x05, 0x20, 0x36, 0x32, 0x78, 0x54, 0x83, 0x38, 0x86, 0x81, 0x78, 0x01, 0x63, 0x21, 0x75, 0x82, 0x01, 0x73, 0x18, 0x00, 0x42, 0x54, 0x67, 0x26, 0x52, 0x38, 0x18, 0x65, 0x87, 0x36, 0x86, 0x53, 0x84, 0x20, 0x06, 0x23, 0x62, 0x73, 0x04, 0x14, 0x83, 0x77, 0x00, 0x57, 0x86, 0x84, 0x70, 0x48, 0x02, 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, 0x02, 0x56, 0x62, 0x67, 0x05, 0x34, 0x54, 0x64, 0x68, 0x25, 0x15, 0x55, 0x88, 0x43, 0x58, 0x73, 0x77, 0x65, 0x46, 0x48, 0x36, 0x06, 0x86, 0x32, 0x80, 0x80, 0x18, 0x72, 0x02, 0x54, 0x54, 0x72, 0x10, 0x65, 0x70, 0x41, 0x63, 0x47, 0x35, 0x40, 0x75, 0x02, 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, 0x06, 0x42, 0x75, 0x16, 0x17, 0x58, 0x04, 0x81, 0x05, 0x48, 0x54, 0x78, 0x53, 0x71, 0x06, 0x28, 0x41, 0x63, 0x81, 0x67, 0x00, 0x18, 0x25, 0x24, 0x14, 0x70, 0x85, 0x70, 0x80, 0x72, 0x48, 0x23, 0x21, 0x47, 0x13, 0x74, 0x72, 0x04, 0x27, 0x20, 0x75, 0x06, 0x80, 0x12, 0x24, 0x18, 0x57, 0x75, 0x45, 0x33, 0x80, 0x47, 0x28, 0x25, 0x80, 0x86, 0x06, 0x67, 0x23, 0x51, 0x80, 0x06, 0x72, 0x34, 0x30, 0x16, 0x25, 0x15, 0x52, 0x16, 0x57, 0x77, 0x45, 0x01, 0x48, 0x83, 0x35, 0x58, 0x68, 0x77, 0x03, 0x20, 0x34, 0x70, 0x23, 0x66, 0x14, 0x85, 0x00, 0x05, 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, 0x02, 0x62, 0x75, 0x86, 0x57, 0x82, 0x38, 0x34, 0x85, 0x21, 0x74, 0x15, 0x55, 0x26, 0x53, 0x16, 0x70, 0x82, 0x87, 0x17, 0x04, 0x63, 0x28, 0x21, 0x41, 0x61, 0x66, 0x16, 0x78, 0x37, 0x05, 0x81, 0x13, 0x26, 0x16, 0x56, 0x56, 0x85, 0x04, 0x72, 0x40, 0x64, 0x74, 0x13, 0x85, 0x20, 0x27, 0x14, 0x62, 0x72, 0x67, 0x70, 0x33, 0x25, 0x78, 0x48, 0x01, 0x17, 0x77, 0x14, 0x33, 0x41, 0x65, 0x05, 0x08, 0x00, 0x71, 0x44, 0x88, 0x08, 0x48, 0x02, 0x60, 0x12, 0x88, 0x05, 0x74, 0x56, 0x04, 0x77, 0x04, 0x52, 0x04, 0x31, 0x11, 0x81, 0x78, 0x88, 0x21, 0x11, 0x26, 0x51, 0x60, 0x67, 0x20, 0x37, 0x52, 0x01, 0x63, 0x85, 0x16, 0x68, 0x47, 0x65, 0x25, 0x02, 0x01, 0x18, 0x32, 0x00, 0x57, 0x33, 0x37, 0x38, 0x25, 0x27, 0x36, 0x21, 0x06, 0x40, 0x03, 0x74, 0x43, 0x24, 0x35, 0x86, 0x53, 0x88, 0x53, 0x16, 0x16, 0x02, 0x88, 0x44, 0x22, 0x25, 0x72, 0x63, 0x85, 0x17, 0x81, 0x56, 0x47, 0x16, 0x65, 0x02, 0x24, 0x05, 0x58, 0x55, 0x86, 0x72, 0x18, 0x21, 0x71, 0x86, 0x65, 0x61, 0x88, 0x85, 0x84, 0x70, 0x47, 0x27, 0x63, 0x73, 0x01, 0x26, 0x27, 0x85, 0x54, 0x85, 0x55, 0x45, 0x73, 0x30, 0x36, 0x44, 0x36, 0x45, 0x52, 0x43, 0x08, 0x14, 0x22, 0x64, 0x77, 0x36, 0x43, 0x14, 0x33, 0x66, 0x10, 0x56, 0x84, 0x42, 0x18, 0x77, 0x71, 0x27, 0x86, 0x84, 0x21, 0x26, 0x03, 0x22, 0x14, 0x47, 0x00, 0x51, 0x84, 0x28, 0x52, 0x66, 0x40, 0x66, 0x55, 0x85, 0x67, 0x02, 0x74, 0x06, 0x15, 0x72, 0x87, 0x40, 0x24, 0x71, 0x43, 0x74, 0x10, 0x27, 0x53, 0x42, 0x10, 0x03, 0x77, 0x01, 0x84, 0x08, 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, 0x04, 0x03, 0x14, 0x87, 0x31, 0x38, 0x22, 0x65, 0x68, 0x68, 0x88, 0x10, 0x32, 0x71, 0x77, 0x05, 0x51, 0x76, 0x68, 0x40, 0x52, 0x36, 0x63, 0x02, 0x76, 0x84, 0x50, 0x76, 0x27, 0x06, 0x77, 0x58, 0x52, 0x52, 0x74, 0x78, 0x77, 0x77, 0x50, 0x30, 0x84, 0x54, 0x28, 0x53, 0x70, 0x82, 0x07, 0x21, 0x06, 0x64, 0x35, 0x62, 0x80, 0x55, 0x10, 0x71, 0x82, 0x02, 0x66, 0x81, 0x40, 0x57, 0x61, 0x07, 0x16, 0x02, 0x72, 0x67, 0x06, 0x24, 0x88, 0x23, 0x88, 0x63, 0x83, 0x81, 0x14, 0x40, 0x07, 0x17, 0x15, 0x20, 0x63, 0x76, 0x22, 0x75, 0x81, 0x70, 0x43, 0x81, 0x80, 0x43, 0x04, 0x51, 0x78, 0x40, 0x63, 0x36, 0x00, 0x77, 0x40, 0x24, 0x53, 0x11, 0x44, 0x65, 0x62, 0x56, 0x77, 0x20, 0x21, 0x25, 0x08, 0x25, 0x63, 0x34, 0x54, 0x76, 0x53, 0x06, 0x13, 0x01, 0x80, 0x25, 0x77, 0x44, 0x38, 0x17, 0x32, 0x36, 0x13, 0x32, 0x27, 0x00, 0x37, 0x60, 0x63, 0x74, 0x06, 0x52, 0x05, 0x72, 0x83, 0x83, 0x84, 0x28, 0x71, 0x15, 0x38, 0x17, 0x47, 0x08, 0x37, 0x42, 0x67, 0x86, 0x38, 0x62, 0x65, 0x26, 0x23, 0x84, 0x22, 0x38, 0x66, 0x06, 0xD9, 0x77, 0xF8, 0x41, 0xCB, 0x87, 0xD3, 0x3F, 0x76, 0xEB, 0x57, 0x71, 0xFF, 0xBF, 0x14, 0x3B, 0x4C, 0x53, 0x01, 0xA8, 0x24, 0xAC, 0xB4, 0x71, 0x4A, 0xD8, 0xAF, 0xCB, 0x45, 0x70, 0x6E, 0xF8, 0x89, 0xB6, 0x31, 0xA7, 0x8B, 0x4A, 0xCF, 0x6C, 0x42, 0x8E, 0x08, 0xCE, 0x55, 0x7D, 0x00, 0x1B, 0xA3, 0x3B, 0x9D, 0x2D, 0xC0, 0xF9, 0x85, 0x66, 0xA6, 0x3F, 0x5C, 0x77, 0xC0, 0xE1, 0x12, 0xF3, 0xEE, 0xBD, 0x4F, 0x9C, 0xB1, 0xD5, 0x01, 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, 0x09, 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, 0x05, 0xA1, 0x00, 0x6C, 0x0F, 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, 0x09, 0xA5, 0x9C, 0xBD, 0x69, 0x1C, 0xA5, 0xB9, 0x8F, 0x68, 0x96, 0x1F, 0xA1, 0xDA, 0xFD, 0xF4, 0xED, 0xA2, 0xA6, 0xA7, 0xD2, 0x81, 0x9D, 0x91, 0x56, 0x09, 0xF4, 0x29, 0x24, 0x24, 0xA2, 0x8F, 0xC2, 0xB0, 0xEE, 0x02, 0xD9, 0x96, 0x8B, 0x9D, 0x9E, 0x1A, 0x48, 0xA7, 0x7A, 0x2D, 0x1D, 0x5A, 0xBF, 0x21, 0x60, 0x57, 0xB2, 0x28, 0x03, 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, 0x06, 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, 0x08, 0xA5, 0xA5, 0xE9, 0xC6, 0xBD, 0xB6, 0xC2, 0x4F, 0xFF, 0xD1, 0xA5, 0x89, 0x30, 0xBF, 0x82, 0xE5, 0xEF, 0x1C, 0x47, 0x4B, 0x0C, 0x3C, 0xFB, 0x46, 0x9D, 0xDA, 0x30, 0x35, 0xF8, 0x04, 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, 0x00, 0x70, 0x9B, 0xE9, 0xDC, 0xB3, 0xC7, 0x72, 0x62, 0xB7, 0xAD, 0x01, 0x4F, 0x6D, 0x23, 0x19, 0x67, 0xD8, 0xE8, 0x78, 0x84, 0x2E, 0xF1, 0xF8, 0x7A, 0x88, 0x13, 0xF2, 0xAA, 0x56, 0x08, 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, 0x00, 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, 0x04, 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, 0x0E, 0x24, 0x3D, 0xA2, 0x9D, 0x95, 0x44, 0x09, 0x7A, 0x42, 0x2B, 0x00, 0x23, 0x1C, 0x3D, 0xBC, 0x3E, 0x2B, 0x67, 0x6F, 0xB4, 0xC2, 0x49, 0xEB, 0x0D, 0xFF, 0x6D, 0x19, 0x34, 0xBF, 0xDE, 0x2A, 0x09, 0x6C, 0x2F, 0x2B, 0x7D, 0xDE, 0x17, 0x54, 0x16, 0xEF, 0x04, 0x86, 0x89, 0xCA, 0x67, 0xA4, 0xE7, 0xBA, 0xF9, 0x7E, 0x8A, 0x42, 0xB2, 0xEB, 0x4F, 0xE8, 0x7B, 0xAD, 0x71, 0xBC, 0x1C, 0x0F, 0x1D, 0x40, 0xB1, 0x84, 0xB2, 0x46, 0x46, 0xFB, 0x6A, 0xA7, 0x67, 0x30, 0x9B, 0xD0, 0x1A, 0x7A, 0xC1, 0xE9, 0xE7, 0x01, 0xA4, 0x1B, 0xC9, 0x0E, 0x79, 0x6C, 0xE8, 0x46, 0x47, 0xCF, 0x0A, 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, 0x04, 0xD0, 0xB6, 0x36, 0xF8, 0xF9, 0xB2, 0xD9, 0xDE, 0xD6, 0x29, 0xCD, 0x15, 0x90, 0x47, 0x8F, 0xCA, 0x5C, 0x1D, 0x42, 0x8D, 0x47, 0xF0, 0x72, 0xD5, 0x09, 0x92, 0x72, 0xE5, 0xB4, 0x2A, 0xAB, 0xD9, 0x06, 0x40, 0xDD, 0x3E, 0x7D, 0x85, 0x08, 0x7E, 0x12, 0x7E, 0x6A, 0x0D, 0xB7, 0x9F, 0x98, 0xC7, 0x47, 0x63, 0xBB, 0xC6, 0x3C, 0x07, 0x68, 0x5F, 0xC3, 0x82, 0xAC, 0x6A, 0xD6, 0x4D, 0x29, 0x68, 0xFF, 0xD5, 0x46, 0xD4, 0x87, 0xE6, 0x4A, 0xFF, 0x22, 0x93, 0x2A, 0x04, 0x08, 0xA7, 0x9B, 0xF3, 0xA1, 0x7E, 0x4C, 0x2C, 0xFF, 0xEA, 0x7D, 0x97, 0x4B, 0x5B, 0x8F, 0xDE, 0x6F, 0x00, 0x80, 0xAB, 0x62, 0x96, 0x5E, 0x3A, 0x25, 0x39, 0xD3, 0x65, 0x9B, 0x07, 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, 0x0F, 0xB9, 0x3C, 0x99, 0xB0, 0x49, 0x65, 0x37, 0x28, 0xE7, 0x11, 0x0C, 0xB8, 0xB9, 0x6B, 0xDC, 0x3C, 0x28, 0xF9, 0xFA, 0x96, 0x1A, 0x84, 0xDF, 0x20, 0x1E, 0x0C, 0x8C, 0x5B, 0xA2, 0x22, 0x3E, 0x5B, 0x74, 0x38, 0x72, 0x45, 0x8D, 0xFA, 0x7D, 0x9F, 0xC3, 0x1F, 0x49, 0x0A, 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, 0x07, 0x6C, 0xCE, 0xAE, 0x25, 0x82, 0xB6, 0xE1, 0x30, 0x91, 0xE8, 0xB3, 0xD2, 0x24, 0x11, 0x31, 0xC6, 0x58, 0xC5, 0xB3, 0xBC, 0x45, 0xA8, 0x41, 0x06, 0x31, 0x89, 0xC9, 0x43, 0x02, 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, 0x01, 0x98, 0xC5, 0xA6, 0x3D, 0x1E, 0xE8, 0x78, 0x85, 0x19, 0xDD, 0xAC, 0x8C, 0xBF, 0x01, 0xEE, 0x44, 0xA1, 0xD1, 0x0A, 0xAB, 0x13, 0x99, 0x9D, 0x45, 0x73, 0x07, 0xF9, 0xD7, 0x09, 0x97, 0x93, 0x00, 0x94, 0x02, 0x68, 0xF9, 0xE8, 0x88, 0xC4, 0x9E, 0x53, 0xD6, 0x74, 0xF7, 0x9A, 0xAD, 0xC7, 0xE2, 0x1E, 0xBE, 0x57, 0x7B, 0x0D, 0x5D, 0xE6, 0x7D, 0x3C, 0xF5, 0xF0, 0xE6, 0x01, 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, 0x09, 0x2F, 0xB9, 0x00, 0xEB, 0xB0, 0x34, 0xD7, 0x5F, 0x3E, 0x3E, 0x76, 0xC1, 0x5D, 0x11, 0xCC, 0xB2, 0x4A, 0xBB, 0x07, 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, 0x09, 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, 0x01, 0x46, 0x53, 0x84, 0xBC, 0xEE, 0x78, 0x38, 0x25, 0x99, 0x2D, 0xA7, 0x7B, 0xAA, 0x06, 0xB8, 0x28, 0xE9, 0x01, 0xD2, 0xDE, 0x84, 0x56, 0x02, 0xBA, 0x49, 0xFB, 0xA2, 0xAD, 0x8E, 0xEC, 0x73, 0x0A, 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, 0x04, 0x3D, 0x97, 0x70, 0x8F, 0x2D, 0xCA, 0x6D, 0xAD, 0x2C, 0x9A, 0x53, 0x45, 0x51, 0xA1, 0xE3, 0x47, 0x2C, 0x80, 0x7D, 0x02, 0x7B, 0x8A, 0xD4, 0x7A, 0x8B, 0x58, 0x11, 0x81, 0x60, 0x2A, 0xC4, 0x4D, 0x26, 0x0E, 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, 0x02, 0xE5, 0xD8, 0x15, 0x8C, 0xEC, 0xA6, 0x03, 0x9A, 0x11, 0xF9, 0x95, 0x31, 0xED, 0xF2, 0x8C, 0xF1, 0xEF, 0x6B, 0xA5, 0x39, 0xAD, 0xF7, 0x08, 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, 0x0E, 0xDE, 0x37, 0x1D, 0x4C, 0xFA, 0x71, 0xCA, 0xAA, 0x96, 0x05, 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, 0x04, 0xEE, 0xCF, 0x8C, 0xE2, 0x5D, 0x36, 0xE8, 0xAA, 0x4E, 0x4B, 0x7B, 0xD0, 0x4D, 0xB4, 0x24, 0xA8, 0x42, 0x12, 0x0D, 0xDC, 0x0A, 0xAF, 0xBB, 0x52, 0xE6, 0xF2, 0xD1, 0x07, 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, 0x07, 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, 0x08, 0xD6, 0x45, 0xAB, 0xCF, 0x7C, 0x0B, 0x94, 0xB7, 0x56, 0x63, 0x43, 0x1A, 0x46, 0x3C, 0xF3, 0x3D, 0x07, 0x19, 0x27, 0x9D, 0x03, 0x3E, 0x48, 0x85, 0xF7, 0xF5, 0x1D, 0x5F, 0xD8, 0x14, 0xEE, 0x3A, 0x9D, 0xDD, 0xF6, 0x1D, 0x7B, 0x03, 0x45, 0x30, 0x84, 0x51, 0xE2, 0x54, 0xBB, 0x96, 0x21, 0xD6, 0x93, 0x94, 0x46, 0x08, 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, 0x04, 0x6E, 0xA9, 0x46, 0x96, 0x5E, 0xA1, 0x5E, 0xEB, 0x02, 0xCB, 0x02, 0x1B, 0x21, 0xF7, 0x78, 0xB0, 0x10, 0x8F, 0x29, 0x9C, 0xFB, 0xAC, 0xFE, 0xC8, 0x8A, 0x79, 0x04, 0xC6, 0xED, 0x0D, 0x9D, 0x27, 0xE5, 0x11, 0x65, 0x66, 0x14, 0xCD, 0x0D, 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, 0x02, 0x72, 0xDC, 0x8A, 0xA6, 0x86, 0x85, 0xBE, 0xC6, 0x78, 0xFC, 0xDD, 0x0C, 0xB0, 0x4B, 0x4D, 0xD4, 0xBE, 0x24, 0xB9, 0x03, 0x03, 0x54, 0x9F, 0xAB, 0x06, 0x05, 0x91, 0x4E, 0x41, 0xE9, 0x7E, 0x99, 0x18, 0x3C, 0xB1, 0x96, 0xF0, 0x99, 0x6A, 0xEC, 0xF6, 0x60, 0x7E, 0xE2, 0xD3, 0x6E, 0xED, 0xA8, 0xFC, 0x5F, 0x07, 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, 0x02, 0x48, 0x01, 0x3D, 0xFC, 0xA1, 0x75, 0x95, 0xF9, 0x90, 0x0D, 0x3A, 0xF5, 0x6B, 0xBB, 0xDC, 0xC6, 0x2C, 0x82, 0x2B, 0xE4, 0x4C, 0x02, 0xDC, 0xD0, 0x80, 0x4F, 0x93, 0x22, 0x8D, 0xED, 0xE3, 0x92, 0x26, 0xC7, 0x64, 0x47, 0xDC, 0x85, 0x65, 0x09, 0x3D, 0x5B, 0x82, 0x34, 0x2F, 0x52, 0x93, 0x42, 0xD8, 0x68, 0x35, 0xF8, 0xA9, 0xCC, 0x87, 0x42, 0x09, 0x99, 0xFE, 0x5F, 0x70, 0xBB, 0x16, 0xD5, 0xFC, 0x60, 0x5D, 0x17, 0x92, 0x63, 0xBA, 0x1B, 0x69, 0xD5, 0xDC, 0x62, 0x2A, 0x66, 0x06, 0xD7, 0xD0, 0x46, 0x29, 0xC5, 0x00, 0x01, 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, 0x0B, 0xC6, 0x7C, 0x10, 0x08, 0xF5, 0x8E, 0xD5, 0xF2, 0x38, 0x78, 0x09, 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, 0x0B, 0x33, 0x9E, 0xAD, 0x66, 0x85, 0x3F, 0xD0, 0x61, 0x9A, 0x44, 0xA6, 0xDF, 0x96, 0x0A, 0x1D, 0x78, 0xC2, 0x8D, 0x64, 0x86, 0xD9, 0x0C, 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, 0x08, 0x8F, 0xDA, 0x20, 0xBF, 0x85, 0x97, 0x74, 0x79, 0x0B, 0x00, 0x0B, 0x1E, 0xF1, 0x1A, 0x83, 0x40, 0xC7, 0x51, 0xFD, 0xDD, 0x3D, 0xB7, 0x0C, 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, 0x0B, 0x07, 0x65, 0x30, 0xAB, 0xFC, 0xC0, 0xB7, 0x90, 0x8F, 0xA9, 0x3F, 0xC8, 0x09, 0x9A, 0xF7, 0x8F, 0x33, 0x8A, 0xB3, 0xEE, 0xFC, 0xA3, 0x6E, 0x50, 0x0A, 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, 0x0B, 0x86, 0x9E, 0x19, 0x14, 0xC0, 0x49, 0xB5, 0x74, 0xEB, 0x79, 0xF7, 0xC2, 0x34, 0xF2, 0xEF, 0x10, 0x3A, 0xB0, 0x17, 0x8D, 0x16, 0x71, 0x02, 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, 0x03, 0xE8, 0x4B, 0x45, 0x9B, 0x5B, 0xD9, 0x9F, 0x03, 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, 0x0A, 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, 0x0E, 0xC9, 0x75, 0x1E, 0x39, 0x2E, 0xD2, 0x43, 0x01, 0x76, 0x3B, 0xF7, 0x88, 0xAF, 0xC0, 0x3C, 0x96, 0x0D, 0xF3, 0x0E, 0x42, 0xFC, 0x80, 0x0A, 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, 0x09, 0x3C, 0x6C, 0x15, 0xE3, 0x1D, 0xF6, 0xF7, 0xEE, 0x9F, 0x0A, 0xC5, 0x91, 0x14, 0x33, 0x4B, 0xDB, 0xC4, 0xEE, 0x0C, 0xFB, 0xE4, 0xD1, 0x43, 0xC2, 0x1B, 0xC3, 0x02, 0x9B, 0x6B, }; #endif @@ -1491,8 +1179,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_NISTDSA, 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 85b4f123df..f9ed81a6ce 100644 --- a/crypto/evp_extra/internal.h +++ b/crypto/evp_extra/internal.h @@ -37,7 +37,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 nistdsa_asn1_meth; #endif extern const EVP_PKEY_ASN1_METHOD kem_asn1_meth; extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth; @@ -45,7 +45,7 @@ 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; +extern const EVP_PKEY_METHOD nistdsa_pkey_meth; extern const EVP_PKEY_METHOD hmac_pkey_meth; extern const EVP_PKEY_METHOD dh_pkey_meth; diff --git a/crypto/evp_extra/p_methods.c b/crypto/evp_extra/p_methods.c index a7e86ef657..f97711100e 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, + &nistdsa_pkey_meth, #endif &dh_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, + &nistdsa_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..900c3e3654 100644 --- a/crypto/evp_extra/print.c +++ b/crypto/evp_extra/print.c @@ -67,6 +67,7 @@ #ifdef ENABLE_DILITHIUM #include "../dilithium/sig_dilithium.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 NISTDSA *nistdsa = pkey->pkey.nistdsa_key->nistdsa; int bit_len = 0; if (ptype == 2) { - bit_len = DILITHIUM3_PRIVATE_KEY_BYTES; + bit_len = nistdsa->secret_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.nistdsa_key->secret_key, bit_len, off); } else { - bit_len = DILITHIUM3_PUBLIC_KEY_BYTES; + bit_len = nistdsa->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.nistdsa_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_NISTDSA, + 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 4891bffdfa..48ad94097c 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; + NISTDSA_KEY * nistdsa_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..f544d4356c 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_NISTDSA */ + 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}, + {"NISTDSA", "NISTDSA", NID_NISTDSA, 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 */, @@ -9098,6 +9144,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 989 /* MLKEM768 */, 986 /* MLKEM768IPD */, 388 /* Mail */, + 993 /* NISTDSA */, 57 /* Netscape */, 366 /* Nonce */, 17 /* O */, @@ -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 */, @@ -10024,6 +10074,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 648 /* Microsoft Smartcardlogin */, 136 /* Microsoft Trust List Signing */, 649 /* Microsoft Universal Principal Name */, + 993 /* NISTDSA */, 72 /* Netscape Base Url */, 76 /* Netscape CA Policy Url */, 74 /* Netscape CA Revocation Url */, @@ -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_NISTDSA) */, 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..176315c53a 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 +NISTDSA 993 +MLDSA44 994 +MLDSA65 995 +MLDSA87 996 diff --git a/crypto/obj/obj_xref.c b/crypto/obj/obj_xref.c index 3b59258593..6a58328e39 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_NISTDSA, NID_undef, NID_NISTDSA}, }; 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..87f6017a25 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 : NISTDSA +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..cd90e532df 100644 --- a/crypto/x509/algorithm.c +++ b/crypto/x509/algorithm.c @@ -97,8 +97,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_NISTDSA) { + return X509_ALGOR_set0(algor, OBJ_nid2obj(EVP_PKEY_NISTDSA), V_ASN1_UNDEF, NULL); } #endif @@ -158,7 +158,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_NISTDSA) { #else if (sigalg_nid == NID_ED25519) { #endif diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 178edde9d5..d99e7df34f 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 @@ -579,120 +580,119 @@ w1AH9efZBw== static const char kDilithium3Cert[] = R"( -----BEGIN CERTIFICATE----- -MIIVMDCCCCugAwIBAgIBADANBgsrBgEEAQKCCwcGBTAXMRUwEwYDVQQDDAxJbnRl -cm1lZGlhdGUwHhcNMTYwOTI2MDAwMDAwWhcNMTYwOTI4MDAwMDAwWjAPMQ0wCwYD -VQQDDARMZWFmMIIHtDANBgsrBgEEAQKCCwcGBQOCB6EA/U+qvppKqZ+p3hqzkURR -diwYPcMpATiImktCv5MYqctNJ99kKOtG+SVE3jXBAUcEsEJ6l1sBtAsMUPzxMwN4 -9PPD4ksxPxw9WqfvZFYZd+ymGtGoJDy/bx7hvMopYYtgKInUqnBI2Wy79FGqNJTE -RtCAww1IiyyoK32DrRU+xM2loMQpL+ivjkJHbPD7+W93iVyZdh9NdilrIA/G8FDZ -XZEFjp4AqPofQsy8byzjRHm3CnmpLY0HdUEdu7EXuOXLDAz5rTGPki7D6BBoE3ic -hgXSCgQbI682W8OrXXQ18zHqzgjAYmXLquaem7CahtF2aSRa7HWB1TrFHwhdvAAD -eg0nkYStY9o6JU9CUdU+md2ExncI2QAyUoBjLB0/aoq+KmGvijpCZrHEhvYyLDs0 -DGzZbV6h4IJWOA2ojrBxuUgyZoosX7UM9oSeg64bS/0M5ufEYY43SDUPrQtkqafH -qoGt5GldVyNvuMmF2Q8nIc9KNKNnNiUZmRL9dgU7pRgrvnbHOSYTeWMnI61F/vnj -BHBIA6iIu0VaJDYmQJoun6DUjhDVWLU1+hXxCyEddviLwk9dkMT6H59+kWeXi4WD -nuT7fa5pSKG41CqPGpACLmeEtiqySt6tCRQe1XA7HaI/6owjFZ+AT6ef41NrXa5w -bgc3tmzXOqhg826+rF7SnMt494RlnBsIpzvK4BmC+QYzpH2B/Yv9tF2f0rsnYomI -hDpouYJV7rGP6++ktcbLufvI1WAPqqS6JEkwQuU6Bj3rdk+EKQMqPjTD2dbpfqZL -tiCapfuSeV1HZ7oTk336VabZRNX27C3lWaReW9hyf0YOLGXVQeFobFN5D1Ns1YXD -CR+Tkonj9BPvFqj3beIJs2j6idZ1Snc5rsnNDiFe8tKCL6yZW/CPG4ndZslzHPdX -tLonQg8H3fdCvUacUX3ktRJVFk5XCImSzPT5jDtzdHfsmL6jys9rvK3p7qmlu6GM -pvxJInKp+sbsC+CLQpZlFEyOX+lC3vR4v6Fg740IPXmzY1cQX0DoRM2Fd5dfLIbc -9wFRRL2T0CVTRYpjqn3QMy5RWpFNLxbRraMMTCHqBWFki9C2MKZpAV52F2FQUGSH -pWDkck9T6zGliVGhJ0+NLwwnmkM5OHoYGiXj9cvP+zRtv1NBJUBZhgKRLky17tcF -EhQKV8d29Cj3XLoD/XAWnJU6Mn3/40xQ0F/fxf2AjitCZblOrUe15XW7l0jxci2U -amE0RS5sJh1KMSvihyb7b7UHBqkUI1d/uuR/VsvyZaGtMKt3aP02EL6RJIy7TjkQ -SACI+b/N0cNFaR4P/agejXtYx3FQDU1QRn3wU06VOVczJ9Hxu9D1x3sBwDlzmzYU -y+CwizWErGnRO9DDs8Yg/jsQm61cvifZF4LrFI+slmsq4WYDF4Xd5xe7sibv1TEQ -0kkmKksYnY1pJQVjNBipz96lso2Y4OoNi3aNgV1yfodffw2mEyjKWa6CWQn930de -b0yOvn2xhQQ2FkQGPfLjcmk2OttSBftJP0IvTS6bD4ixSWVX57QyP3rvb8mS4QUd -gEJaRu89nz77Z8YZePru8Cw8wlgYM7brJKEOuhWpA8506ppLU3G9Dd8YuVw2CalZ -52FroBH4UJStINi6oQ+S8ZWajI3UKKbBLMezFlivND60lkFWH1w41PWi/lHFWhF0 -Yd8O4wR4Drva+/4VIj0zyEW2LhMbdn/4QFYJkZJjIZecqQL/xGsRVdoOAopA119X -QQMC0jOF3uRRwrAusushSs3fVlbIuYMOmN2ZpT62uFpg5ts8WAP/iJtTsveHrqWG -ghy5TfWRba3GnXN9xT9xDhdmZXWKjLJU6DoWVBwyJ8HKmukn2OoyinqTMXD2PieZ -geoiwuSGu2fqe0dSnvwD1e4Z8Tdu+y/V5KBtXZ8eYPIHtahZYRE3rTUuQWJrVq4G -qA5OQ+FRRN5BD+WAzLq5l7zIbNzY+xtgQO0oBlpfVRW6o1WLysfPRPeZMyOayx0a -OIdwsetqhIxRNJeCX1qgPQ/l7Mr7/GswdHYfzKxkH/vn1g5J5KMkenDB1krcml4N -ctIpiEQhOIM9044IHkID0v+Wlj8QCQlSYslxeEAqL3iEJXcPl7cChCOSMCZbgO9s -Pc8BLnniULvvMNY9NE6h8Mh4m1Z+TaCdtwV8RwvxJHBY/xFN5m4D6O8hM1kV64FB -BlSiFij5/mSKLgK7mGSVUbvWMMT3lXPX3/vV9BYIsATK4c+LSk1+1EDccwUIJMgY -xcOehTljf36tw/RZIMcsRpSgcGwMtHWfJ98NIJUyYAlYwGlSoJVAXz7SQz1ec9DI -8BEWrLAE78g1PH/jUDnPGiFH/aYQBi4q4Nnl92tlaFVl2/vMTPg1w/qhgEES5MaW -szo0uA6g8+kUUGW6cV5ZLJLqmHlOLxPKbqqyj3So9KJ8akCG+cB0DWIIcNs1qwYC -mi5hkwuWprFy2wVqp7a84ldFf7tmPKScqnRPECnFct7MoLpAo6yUyol6wPexbx/r -xhIRu44waEkcyKwsZLBUQ8NsRA2DPGY45ZhKRoHcTO3aINl2/NdHGdzN6BUQ4tzb -rNwGe+sYREfJwZqzJDCfA6SjEDAOMAwGA1UdEwEB/wQCMAAwDQYLKwYBBAECggsH -BgUDggzuAEFLUZA+19YzobrkjgfNZ7UOrM9SJh4qsLcT7b4SPNsNpsNCn8Dr/pC8 -AqTynQfLZbFVZ34gNSaWtkM6Nh7smQd6Ai9BBKDyShP7DZ7jzCW13coAvIZeTmSR -iUxRyytfLomfBJM6gv2EFCdPfegE808O5tP+Y/vTX1HP+gJoobV7wB8NFiQmzpuc -FxaxL2wOasPBXahoelMUIY2XGdvnOo/Y863mhCcD8ROgBMkBRIC1G4nZGComtTZv -5DaHQhAgPxHbfcA2vIO3rKMOMWmqlXpeSLsqB6nOOOkgtTgTACymiyTnG5MDJG9I -kA+6w+FgXNQwF1sE0qSBeNrDj91WjLga7KytQ1aI+3BCEFoSWimOP/MjUUtRPyqe -NH7oBV6FQ141IP3H24zKb7bvXhBvEjS5ueiUJAjHu5ep8+D1TNvGb1XKghyoYpyX -Z/bwFq3sHUOnFYTlPQ/rSt9wGwY7pO30um1+vcmuqIZj5Rdd6d4UUYBvKq89h2h2 -HS0XY6Ntzbaipen1BDy7agORDWNHwBTKaHuTc5mMPdxO05cLsbVdDjKx7SHa0q+j -PkeHe3uETvXcQTTl6gVmZAaaagQPrJCQQcH14DKr75RItYVsRHDYUJCssClV+btZ -rZ8svXzZWgZWdToOvKbLiV2VFJdyi/aLiDmy9yGic3Qg/sbrLDMWSjg6Z4BCPVz5 -8CRktjllDp7D9SOlH50d+nYqimbfIfeDmIHFe7g2m6r9UFhUxDUNbLdsUKx66B9F -w0VQRDvFlwCgwQVhGQP2HYPFszKZ0VtUWZ5c1BruF34IwOZUMtb7iQuDNUAwWMcK -o1nADkn4p8tLtbJdIebLJA+PJCLUxYFvlavl+igFRepoiZmEA1+okHTmwwU88vrg -hWfSPx/eveMmy6wM0c4eJ1s5omb0He9A58MiqjjbiNko47ElsDG2CeaGgpbm3mqB -BAGM8TALswNKSTiF4woKYEUlsqE6Xu2CRtCcg2/IV0eWIM0Ir/QaWigVYNqwokK6 -n8ZObSQYu5SfScK29vbvygfUrl9gyYP9fs8ThZEPpgUoZIQkgIfrtSrYkj+7ctSH -38zQFDhGib6NP5lBsJPjYs5BAGGxQGHMsrYwaom/5+UPg6R8ThUThNSuKvoNP0W0 -GH4h30BQHEx3i+HeSDEz+gV7O8IRz9YxQf8A3HyyfVyxgRag2skK+T8UMet5GJMO -o5eArD0RITJktqyq2OB8atDV6OZaSLgvB6q1LP1gKEhdVOd0qgRmvRiyAl0dwtjw -A2HeYRtBnli1AxNZq/x3xe4fGNF82Asme0fMgXngTCPAOpHREr4ZpJ83jiGtTQNI -Ocdw3WEurlMRr19+byHAuaydT08faHMR0A2Bec7/VA6StwEjWCAzqW8qjP+1vTWh -w4JUHw0+MeMACvi5PbTXi/EkGICugdu3VkDdybAP1jFR/ZPagZqwYx9PFWRpYNwz -Q5SggswrgsXJFpLRHi2/d/3DZ7g32+jy9TDulTREprXuw+OJXCRoRp8i82vO+qCr -UzDvlaRY9SZa6+/gCreKlY2TKyPl0wRyOcDhEPHNEh2+3FoX+/QDu+l4xpW58PTd -i6FDTRv2AbEUbgOsc6tCZwVNfYIiEgneN+cWtqyFlvrj1Epwq756jj/aEjUxwc8l -PG9AghZ9y/B99zbt18N2afE8FnAySBWF144j+4UzMgQI1tUZflR7kwIzs81cqpN2 -rc0jQMLKnzTt0994GpGgA7mnhuHf3srB2Etad4doD2gA6jrWmd6j33hUBGEV4Lg3 -WZ5Ng6hWJQACGarasWe6QEKZo/F8XQQHsRaUy5Yot896TK0MsdF2cSZAP7lO0sMD -ZDg2MuvN6Er9gfnaR1uwDfo8sqn6gQR2DVwTdCzlaz3dvx8QIdST2zSgFYBTc573 -eJ+NCtjtLXa/phZsmUU32iTE2odX4FkviBu0K1xRa/lkfH0nIhf1U7QppcqcgRzf -cwk74BQhOjkTzGBOcFUWWcDeXyZKnvOeNNsN6oS3nKF+RHDfIGO1ecnpn4VzLHhS -Fp4RBLbp0x7vUgTbJzcHSTuFFimXjR1RyLqRPiWFjh03LfZ72LUmI/s49W35Jx9w -iIqMO+i6ql/c6bjho3FOHNPq6EmHs2j4TXXSZKdd62wID1skba58L7/Njp3u85wX -ArwT3DZHBS1S24P39RMk5hb6VeJiunEbQdff73G/+AB5qsZ89zHgMu7wKVDzuEdE -ljCN05CdSw3pzFcJW9U7E3YoN2tP4eBJQNC0wXcTzMsES5iArWMsZkvF6xeRCt4m -WVAGqqly0TVMP5BprKWJi1paN6GC7sSQb6xXfSeqhNWzfYn7/VC4231bql+Qv+ac -NMHt4OKtoTH4kw9RX8wbEyhVn+FJLIzEcr99QxMSA+9ZbsXCwAvcJGbwZQmGCfnl -hIXyUoJXAnvDHtgxwik3SX1qlH+G4tdaf7UcdJwpYUAtrqAFysSE0gpX1+gdSEsu -YHM/jPSrEAq0qO53Daxeu1nwQ7XGOTxCjESl9f4g283ZkH4HT8Olo80LRXzjHZC5 -i/FV8sQdZSzP9vyd9DzXfPVjK0q4Hvv/v6+8dsmxjgQzrlIDTtKtuuemI9KwB8M6 -oEZUbGeKNHAKpsV91IDmxElgylTPc4LwPzgRwfCW/KEwaNccMc8KwglfdFGccOLT -QlYFbiqnHxujD5/V98Vgk8b0Rf1ZQohAuXhqYdv4g0jh/wf7apFpTsaZiv766V32 -qBY0wnyJgSw6XFLV+BUyCu2z7NNN17k090p2Nhzbd4YA9PtYWeHeOfOz5mR0+Wir -Xnp6xFrwX86iaw+IpsWCOgiJz4g+McMQRRnWzmUWlmrLK26QIIP87U5b4GeA7Dff -ghn4Ub4/ce2U29Rk9/YSHeLih4mERk+ssaqJFHYTZbzCtAJI0ELIjDjHYRBpYl+4 -BGW+E2zlC0lZ6ofq4oyR7E4xKf7WyjBQrKsaZ0W9W3TJ+nIo9g6aC7PgxOaPVHHq -b0KOfQZtt5VdtjOYeBYqZYAWT9gj7yYvdSuU+RE4Fsyle76jA8rg5uavs7bseR+l -MUAWR5KF1oticEmrx2SF3T2ltU5pxsc4Qln6oy7c8i0p9u9IiW3h9KgmV4CcJ3v8 -/yOITs6TFZJni+FGRZM/3zXM32loouwTqmdwwUKo4Vt8dfKs0iYpSj+wK1B8UKB/ -ai55I30IyEqd/YRjNxt+0pQRz8DyQaZKVqVNS74KJwqdgjgkvEYCSId59NPL/RAv -7wLFxBHGeJ/vog5NAIkLIRKF/e8nwv9zpJzsdv253fUqnpyfX5fnLlbYVOSjDR9o -LW8hl1u8iWpWEAyrklQL8n6wlVGtqfDblg629yir+vuIPZzgf1x1R7DWfGF/VQFn -VJgXbyNWTIh5x6KdfYD+YwtFcQ5Lgnw+uWKc2MM1rTlHODPHpsTjgaJRR1Zx/br9 -U23LM/ls+ptsGeTPGEiS/2oh9FMZajHXXsit/DdTDcSu72HdyIklM0Guz7+wLxVN -jI9lAcwr6Be9HwFYAAs0UXjvbFIYii0d5O/gVLkkhRahJwNxmRz12MXPafncliKP -ChnVvZgoBxKPQgUH6VB3gIMHJ3lBtzdumXG+I+3UNrydnzb2+t5zRywGZ9XK/GcB -KP9zGYk9ClV12CZHDhD0t2uEVhL3CKuZOjiuLZ7pe46/rW7dqtxibGcLavWZmI89 -sdpNBqMSFM6oeQ4xh53uBVIg0CDAnfy33CD13YdwZ9t6ty1R1VHN3IOLv3MqnxRR -npsGTdLigr3dBQ7I/GnRVCQ/BE3FPfB/YjJkSSQF0pvLvgLdkoG3yTpKQUwc9HfN -gSgIWI30vUDWpYn0BzOKt/xF3qlPkD655Md3I0CVyqvVeEDIIaZePlME08gDnMYe -H7pg/hGKmdemempLSlCce4zfRAkB63yb92y/+/nShIBf7sfBX7Ng4KRqVc7PW7y/ -Bz3u8YMHz47PQbe2gxN5fliOAuT5bN++zpmI+cBJPbA2ZWWwXIu1ZiGaHSPk5lns -xrgYQM21/yNH0EvSCwK3uc3QXvhI3p1gLutEO28tpGnaM5uDKzjouqTzQSDnHa2p -S92Su5L0/iGAvSU/AgSwlgZZk7LFaa/zYzSOIsu+wrwBGimrqpO6+wCj/Pr+2Eet -WuTw4HtGnSCHF9C6bz8S2DEOf1ynU5ykUxA/jD5+WS6xOjqvylv9139qeO3htSSd -3mP1aGppnL+TjVdYPvkTyrx85k40Wf+kDC+PvDy2+b+vgBY6Mwd3nlE5L1WkN/IS -i9IxWV6ASTiYkME3jmGyG8B6OHre0tplygOCATs29AE8DPevzRG3AUSLjI6T6u8j -LZ2+v8lRYWnE1+buEhhsedoFE2PNKWVpeHvCytwAAAAAAAAAAAAAAAAAAAAAAAgO -FRoeJg== +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 -----END CERTIFICATE----- )"; @@ -700,239 +700,241 @@ FRoeJg== // NULL in the signature algorithm. static const char kDilithium3CertNull[] = R"( -----BEGIN CERTIFICATE----- -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 -----END CERTIFICATE----- + )"; // kDilithium3CertParam is an invalid self-signed Dilithium3 with an explicit // NULL in the AlgorithmIdentifier parameters. static const char kDilithium3CertParam[] = R"( -----BEGIN CERTIFICATE----- -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 +Gx8= -----END CERTIFICATE----- )"; @@ -2950,47 +2952,61 @@ TEST(X509Test, Ed25519Sign) { TEST(X509Test, Dilithium3SignVerifyCert) { // This test generates a Dilithium3 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_NISTDSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(), NID_MLDSA65)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *raw = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr)); bssl::UniquePtr leaf = - MakeTestCert("Intermediate", "Leaf", pkey, /*is_ca=*/false); + MakeTestCert("Intermediate", "Leaf", pkey.get(), 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)); ASSERT_TRUE(cert); - - bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); + //extract the asn1 bit string from the cert + ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); + // create a new PKEY and set the raw public key as the one from the cert + bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + nullptr, + key->data, + key->length)); ASSERT_TRUE(pkey); - + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey.get(), NID_MLDSA65); ASSERT_TRUE(X509_verify(cert.get(), pkey.get())); } -TEST(X509Test, TestBadSigAlgDilithium3) { - // This test generates a Dilithium3 certificate from the PEM encoding +TEST(X509Test, TestBadSigAlgMLDSA65) { + // This test generates a MLDSA65 certificate from the PEM encoding // kDilithium3CertNull that has an explicit NULL in the signature algorithm. // After extracting the public key, verification should fail. bssl::UniquePtr cert(CertFromPEM(kDilithium3CertNull)); ASSERT_TRUE(cert); - - bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); + // extract the asn1 bit string from the cert + ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); + // create a new PKEY and set the raw public key as the one from the cert + bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + nullptr, + key->data, + key->length)); ASSERT_TRUE(pkey); + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey.get(), NID_MLDSA65); ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); @@ -2999,20 +3015,26 @@ TEST(X509Test, TestBadSigAlgDilithium3) { ERR_clear_error(); } -TEST(X509Test, TestBadParamsDilithium3) { - // This test generates a Dilithium3 certificate from the PEM encoding +TEST(X509Test, TestBadParamsMLDSA65) { + // This test generates a MLDSA65 certificate from the PEM encoding // kDilithium3CertParam that has an explicit NULL in the signature algorithm. // After extracting the public key, verification should fail. bssl::UniquePtr cert(CertFromPEM(kDilithium3CertParam)); ASSERT_TRUE(cert); - - bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); + // extract the asn1 bit string from the cert + ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); + // create a new PKEY and set the raw public key as the one from the cert + bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + nullptr, + key->data, + key->length)); ASSERT_TRUE(pkey); + // set the correct params for the PKEY + EVP_PKEY_nistdsa_set_params(pkey.get(), NID_MLDSA65); ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); - ASSERT_EQ(ERR_LIB_X509, ERR_GET_LIB(err)); - ASSERT_EQ(X509_R_INVALID_PARAMETER, ERR_GET_REASON(err)); + ASSERT_EQ(ERR_LIB_ASN1, ERR_GET_LIB(err)); ERR_clear_error(); } diff --git a/include/openssl/base.h b/include/openssl/base.h index c20f6c576f..d9dfd0faee 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 nistdsa_st NISTDSA_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 93d631c7e5..a48cb645e0 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_NISTDSA NID_NISTDSA #endif #define EVP_PKEY_KEM NID_kem @@ -946,6 +946,16 @@ 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); +// Signature specific functions. + +// EVP_PKEY_nistdsa_set_params sets signature scheme parameters defined by |nid| +// in |pkey|. If |pkey| already has a public key set, the public key is preserved. +OPENSSL_EXPORT int EVP_PKEY_nistdsa_set_params(EVP_PKEY *pkey, int nid); + +// EVP_PKEY_CTX_nistdsa_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_nistdsa_set_params(EVP_PKEY_CTX *ctx, int nid); // Diffie-Hellman-specific control functions. diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 52cd599341..923387eeb8 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_NISTDSA "NISTDSA" +#define NID_NISTDSA 993 +#define OBJ_NISTDSA 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 c5d1fedcd5..1a8387dfd0 100644 --- a/tool/speed.cc +++ b/tool/speed.cc @@ -864,7 +864,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) { @@ -872,8 +872,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_NISTDSA + BM_NAMESPACE::UniquePtr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + + // Setup CTX for specific signature alg NID + EVP_PKEY_CTX_nistdsa_set_params(pkey_ctx.get(), nid); // Setup CTX for Keygen Operations if (!pkey_ctx || EVP_PKEY_keygen_init(pkey_ctx.get()) != 1) { @@ -927,7 +930,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 @@ -2855,7 +2858,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) || From 8542649ea28a3a1ca0e0ff9492f7d9d9d0a8e0fe Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 6 Nov 2024 11:39:52 -0800 Subject: [PATCH 02/28] renamed NISTDSA to PQDSA --- crypto/dilithium/internal.h | 26 ++--- crypto/dilithium/p_dilithium3.c | 156 +++++++++++++-------------- crypto/dilithium/p_dilithium3_asn1.c | 134 ++++++++++++----------- crypto/dilithium/p_dilithium_test.cc | 48 ++++----- crypto/evp_extra/internal.h | 4 +- crypto/evp_extra/p_methods.c | 4 +- crypto/evp_extra/print.c | 10 +- crypto/fipsmodule/evp/internal.h | 2 +- crypto/x509/x509_test.cc | 8 +- include/openssl/base.h | 2 +- include/openssl/evp.h | 8 +- tool/speed.cc | 2 +- 12 files changed, 201 insertions(+), 203 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index 0c1d36fc1d..4dd6065df1 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -10,7 +10,7 @@ extern "C" { #endif -// NISTDSA_METHOD structure and helper functions. +// PQDSA_METHOD structure and helper functions. typedef struct { int (*keygen)(uint8_t *public_key, uint8_t *secret_key); @@ -30,9 +30,9 @@ typedef struct { size_t ctx_len, const uint8_t *public_key); -} NISTDSA_METHOD; +} PQDSA_METHOD; -// NISTDSA structure and helper functions. +// PQDSA structure and helper functions. typedef struct { int nid; const uint8_t *oid; @@ -43,21 +43,21 @@ typedef struct { size_t signature_len; size_t keygen_seed_len; size_t sign_seed_len; - const NISTDSA_METHOD *method; -} NISTDSA; + const PQDSA_METHOD *method; +} PQDSA; -// NISTDSA_KEY structure and helper functions. -struct nistdsa_st { - const NISTDSA *nistdsa; +// PQDSA_KEY structure and helper functions. +struct pqdsa_key_st { + const PQDSA *pqdsa; uint8_t *public_key; uint8_t *secret_key; }; -int NISTDSA_KEY_init(NISTDSA_KEY *key, const NISTDSA *nistdsa); -const NISTDSA * SIG_find_dsa_by_nid(int nid); -const NISTDSA *NISTDSA_KEY_get0_sig(NISTDSA_KEY* key); -NISTDSA_KEY *NISTDSA_KEY_new(void); -void NISTDSA_KEY_free(NISTDSA_KEY *key); +int PQDSA_KEY_init(PQDSA_KEY *key, const PQDSA *pqdsa); +const PQDSA * PQDSA_find_dsa_by_nid(int nid); +const PQDSA *PQDSA_KEY_get0_sig(PQDSA_KEY* key); +PQDSA_KEY *PQDSA_KEY_new(void); +void PQDSA_KEY_free(PQDSA_KEY *key); #if defined(__cplusplus) } // extern C diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index 2b1f51c615..2e3d222686 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -17,16 +17,16 @@ //2.16.840.1.101.3.4.3.18 static const uint8_t kOIDMLDSA65[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12}; -// NISTDSA functions: these are init/new/clear/free/get_sig functions for NISTDSA_KEY +// PQDSA functions: these are init/new/clear/free/get_sig functions for PQDSA_KEY // These will be moved to a separate file location after CR for clearer review. // These are analagous to the ec_key functions in crypto/fipsmodule/ec/ec_key.c typedef struct { - const NISTDSA *nistdsa; -} NISTDSA_PKEY_CTX; + const PQDSA *pqdsa; +} PQDSA_PKEY_CTX; -NISTDSA_KEY *NISTDSA_KEY_new(void) { - NISTDSA_KEY *ret = OPENSSL_zalloc(sizeof(NISTDSA_KEY)); +PQDSA_KEY *PQDSA_KEY_new(void) { + PQDSA_KEY *ret = OPENSSL_zalloc(sizeof(PQDSA_KEY)); if (ret == NULL) { return NULL; } @@ -34,48 +34,48 @@ NISTDSA_KEY *NISTDSA_KEY_new(void) { return ret; } -static void NISTDSA_KEY_clear(NISTDSA_KEY *key) { - key->nistdsa = NULL; +static void PQDSA_KEY_clear(PQDSA_KEY *key) { + key->pqdsa = NULL; OPENSSL_free(key->public_key); OPENSSL_free(key->secret_key); key->public_key = NULL; key->secret_key = NULL; } -int NISTDSA_KEY_init(NISTDSA_KEY *key, const NISTDSA *nistdsa) { - if (key == NULL || nistdsa == 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. - NISTDSA_KEY_clear(key); + PQDSA_KEY_clear(key); - key->nistdsa = nistdsa; - key->public_key = OPENSSL_malloc(nistdsa->public_key_len); - key->secret_key = OPENSSL_malloc(nistdsa->secret_key_len); + key->pqdsa = pqdsa; + key->public_key = OPENSSL_malloc(pqdsa->public_key_len); + key->secret_key = OPENSSL_malloc(pqdsa->secret_key_len); if (key->public_key == NULL || key->secret_key == NULL) { - NISTDSA_KEY_clear(key); + PQDSA_KEY_clear(key); return 0; } return 1; } -void NISTDSA_KEY_free(NISTDSA_KEY *key) { +void PQDSA_KEY_free(PQDSA_KEY *key) { if (key == NULL) { return; } - NISTDSA_KEY_clear(key); + PQDSA_KEY_clear(key); OPENSSL_free(key); } -const NISTDSA *NISTDSA_KEY_get0_sig(NISTDSA_KEY* key) { - return key->nistdsa; +const PQDSA *PQDSA_KEY_get0_sig(PQDSA_KEY* key) { + return key->pqdsa; } -// NISTDSA PKEY functions +// PQDSA PKEY functions -static int pkey_nistdsa_init(EVP_PKEY_CTX *ctx) { - NISTDSA_PKEY_CTX *dctx; - dctx = OPENSSL_zalloc(sizeof(NISTDSA_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; } @@ -85,75 +85,75 @@ static int pkey_nistdsa_init(EVP_PKEY_CTX *ctx) { return 1; } -static void pkey_nistdsa_cleanup(EVP_PKEY_CTX *ctx) { +static void pkey_pqdsa_cleanup(EVP_PKEY_CTX *ctx) { OPENSSL_free(ctx->data); } -static int pkey_nistdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { +static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { GUARD_PTR(ctx); - NISTDSA_PKEY_CTX *dctx = ctx->data; + PQDSA_PKEY_CTX *dctx = ctx->data; GUARD_PTR(dctx); - const NISTDSA *nistdsa = dctx->nistdsa; - if (nistdsa == NULL) { + const PQDSA *pqdsa = dctx->pqdsa; + if (pqdsa == NULL) { if (ctx->pkey == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } - nistdsa = NISTDSA_KEY_get0_sig(ctx->pkey->pkey.nistdsa_key); + pqdsa = PQDSA_KEY_get0_sig(ctx->pkey->pkey.pqdsa_key); } - NISTDSA_KEY *key = NISTDSA_KEY_new(); + PQDSA_KEY *key = PQDSA_KEY_new(); if (key == NULL || - !NISTDSA_KEY_init(key, nistdsa) || - !nistdsa->method->keygen(key->public_key, key->secret_key) || + !PQDSA_KEY_init(key, pqdsa) || + !pqdsa->method->keygen(key->public_key, key->secret_key) || !EVP_PKEY_set_type(pkey, EVP_PKEY_NISTDSA)) { - NISTDSA_KEY_free(key); + PQDSA_KEY_free(key); return 0; } - pkey->pkey.nistdsa_key = key; + pkey->pkey.pqdsa_key = key; return 1; } -static int pkey_nistdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, +static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, const uint8_t *tbs, size_t tbslen) { - NISTDSA_PKEY_CTX *dctx = ctx->data; - const NISTDSA *nistdsa = dctx->nistdsa; - if (nistdsa == NULL) { + 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; } - nistdsa = NISTDSA_KEY_get0_sig(ctx->pkey->pkey.nistdsa_key); + pqdsa = PQDSA_KEY_get0_sig(ctx->pkey->pkey.pqdsa_key); } // Caller is getting parameter values. if (sig == NULL) { - *siglen = nistdsa->signature_len; + *siglen = pqdsa->signature_len; return 1; } - if (*siglen < nistdsa->signature_len) { + if (*siglen < 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.nistdsa_key == NULL || + ctx->pkey->pkey.pqdsa_key == NULL || ctx->pkey->type != EVP_PKEY_NISTDSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); return 0; } - NISTDSA_KEY *key = ctx->pkey->pkey.nistdsa_key; + PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; if (!key->secret_key) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; } - if (nistdsa->method->sign(sig, siglen, tbs, tbslen, NULL, + if (pqdsa->method->sign(sig, siglen, tbs, tbslen, NULL, 0, key->secret_key) != 0) { OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); return 0; @@ -161,32 +161,32 @@ static int pkey_nistdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, return 1; } -static int pkey_nistdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, +static int pkey_pqdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen, const uint8_t *tbs, size_t tbslen) { - NISTDSA_PKEY_CTX *dctx = ctx->data; - const NISTDSA *nistdsa = dctx->nistdsa; + PQDSA_PKEY_CTX *dctx = ctx->data; + const PQDSA *pqdsa = dctx->pqdsa; - if (nistdsa == NULL) { + if (pqdsa == NULL) { if (ctx->pkey == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } - nistdsa = NISTDSA_KEY_get0_sig(ctx->pkey->pkey.nistdsa_key); + pqdsa = PQDSA_KEY_get0_sig(ctx->pkey->pkey.pqdsa_key); } // Check that the context is properly configured. if (ctx->pkey == NULL || - ctx->pkey->pkey.nistdsa_key == NULL || + ctx->pkey->pkey.pqdsa_key == NULL || ctx->pkey->type != EVP_PKEY_NISTDSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); return 0; } - NISTDSA_KEY *key = ctx->pkey->pkey.nistdsa_key; + PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; - if (siglen != nistdsa->signature_len || - nistdsa->method->verify(tbs, tbslen, sig, siglen, + if (siglen != pqdsa->signature_len || + pqdsa->method->verify(tbs, tbslen, sig, siglen, NULL, 0, key->public_key) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); return 0; @@ -195,12 +195,12 @@ static int pkey_nistdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, return 1; } -// This function sets nistdsa parameters defined by |nid| in |pkey|. +// This function sets pqdsa parameters defined by |nid| in |pkey|. // If |pkey| already has a public key set, this public key is preserved. -int EVP_PKEY_nistdsa_set_params(EVP_PKEY *pkey, int nid) { - const NISTDSA *nistdsa = SIG_find_dsa_by_nid(nid); +int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid) { + const PQDSA *pqdsa = PQDSA_find_dsa_by_nid(nid); - if (nistdsa == NULL) { + if (pqdsa == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); return 0; } @@ -208,28 +208,28 @@ int EVP_PKEY_nistdsa_set_params(EVP_PKEY *pkey, int nid) { // if the public key has already been set either by EVP_parse_public_key or // some other method that returns a PKEY without setting params, then // we preserve that PKEY and just populate the params - if (pkey->pkey.nistdsa_key != NULL) { - pkey->pkey.nistdsa_key->nistdsa = nistdsa; + if (pkey->pkey.pqdsa_key != NULL) { + pkey->pkey.pqdsa_key->pqdsa = pqdsa; return 1; } - evp_pkey_set_method(pkey, &nistdsa_asn1_meth); + evp_pkey_set_method(pkey, &pqdsa_asn1_meth); - NISTDSA_KEY *key = NISTDSA_KEY_new(); + PQDSA_KEY *key = PQDSA_KEY_new(); if (key == NULL) { - // NISTDSA_KEY_new sets the appropriate error. + // PQDSA_KEY_new sets the appropriate error. return 0; } - key->nistdsa = nistdsa; - pkey->pkey.nistdsa_key = key; + key->pqdsa = pqdsa; + pkey->pkey.pqdsa_key = key; return 1; } -// Takes an EVP_PKEY_CTX object |ctx| and sets nistdsa parameters defined +// Takes an EVP_PKEY_CTX object |ctx| and sets pqdsa parameters defined // by |nid| -int EVP_PKEY_CTX_nistdsa_set_params(EVP_PKEY_CTX *ctx, int 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; @@ -242,30 +242,30 @@ int EVP_PKEY_CTX_nistdsa_set_params(EVP_PKEY_CTX *ctx, int nid) { return 0; } - const NISTDSA *nistdsa = SIG_find_dsa_by_nid(nid); - if (nistdsa == NULL) { + const PQDSA *pqdsa = PQDSA_find_dsa_by_nid(nid); + if (pqdsa == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); return 0; } - NISTDSA_PKEY_CTX *dctx = ctx->data; - dctx->nistdsa = nistdsa; + PQDSA_PKEY_CTX *dctx = ctx->data; + dctx->pqdsa = pqdsa; return 1; } -const EVP_PKEY_METHOD nistdsa_pkey_meth = { +const EVP_PKEY_METHOD pqdsa_pkey_meth = { EVP_PKEY_NISTDSA, - pkey_nistdsa_init /* init */, + pkey_pqdsa_init /* init */, NULL /* copy */, - pkey_nistdsa_cleanup /* cleanup */, - pkey_nistdsa_keygen, + pkey_pqdsa_cleanup /* cleanup */, + pkey_pqdsa_keygen, NULL /* sign_init */, NULL /* sign */, - pkey_nistdsa_sign_message, + pkey_pqdsa_sign_message, NULL /* verify_init */, NULL /* verify */, - pkey_nistdsa_verify_message, + pkey_pqdsa_verify_message, NULL /* verify_recover */, NULL /* encrypt */, NULL /* decrypt */, @@ -279,13 +279,13 @@ const EVP_PKEY_METHOD nistdsa_pkey_meth = { NULL /* decapsulate */, }; -DEFINE_LOCAL_DATA(NISTDSA_METHOD, sig_ml_dsa_65_method) { +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(NISTDSA, sig_ml_dsa_65) { +DEFINE_LOCAL_DATA(PQDSA, sig_ml_dsa_65) { out->nid = NID_MLDSA65; out->oid = kOIDMLDSA65; out->oid_len = sizeof(kOIDMLDSA65); @@ -298,7 +298,7 @@ DEFINE_LOCAL_DATA(NISTDSA, sig_ml_dsa_65) { out->method = sig_ml_dsa_65_method(); } -const NISTDSA *SIG_find_dsa_by_nid(int nid) { +const PQDSA *PQDSA_find_dsa_by_nid(int nid) { switch (nid) { case NID_MLDSA65: return sig_ml_dsa_65(); diff --git a/crypto/dilithium/p_dilithium3_asn1.c b/crypto/dilithium/p_dilithium3_asn1.c index 7fafbf16e4..f2a7cb5a1e 100644 --- a/crypto/dilithium/p_dilithium3_asn1.c +++ b/crypto/dilithium/p_dilithium3_asn1.c @@ -13,22 +13,20 @@ #include "sig_dilithium.h" #include "internal.h" - -static void nistdsa_free(EVP_PKEY *pkey) { - NISTDSA_KEY_free(pkey->pkey.nistdsa_key); - pkey->pkey.nistdsa_key = NULL; +static void pqdsa_free(EVP_PKEY *pkey) { + PQDSA_KEY_free(pkey->pkey.pqdsa_key); + pkey->pkey.pqdsa_key = NULL; } - -static int nistdsa_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, +static int pqdsa_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, size_t privkey_len, const uint8_t *pubkey, size_t pubkey_len) { - NISTDSA_KEY *key = OPENSSL_malloc(sizeof(NISTDSA_KEY)); + PQDSA_KEY *key = OPENSSL_malloc(sizeof(PQDSA_KEY)); if (key == NULL) { return 0; } - // At time of writing, all |set_priv_raw| and |nistdsa_set_priv_raw| + // At time of writing, all |set_priv_raw| and |pqdsa_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) { @@ -40,14 +38,14 @@ static int nistdsa_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, // that the pointers are valid and |in| has the correct size. key->public_key = NULL; key->secret_key = OPENSSL_memdup(privkey, privkey_len); - nistdsa_free(pkey); - pkey->pkey.nistdsa_key = key; + pqdsa_free(pkey); + pkey->pkey.pqdsa_key = key; return 1; } -static int nistdsa_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { - //generate a fresh nistdsa_key - NISTDSA_KEY *key = OPENSSL_malloc(sizeof(NISTDSA_KEY)); +static int pqdsa_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { + //generate a fresh pqdsa_key + PQDSA_KEY *key = OPENSSL_malloc(sizeof(PQDSA_KEY)); if (key == NULL) { return 0; @@ -58,57 +56,57 @@ static int nistdsa_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { key->public_key = OPENSSL_memdup(in, len); key->secret_key = NULL; - nistdsa_free(pkey); - pkey->pkey.nistdsa_key = key; + pqdsa_free(pkey); + pkey->pkey.pqdsa_key = key; return 1; } -static int nistdsa_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, +static int pqdsa_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, size_t *out_len) { - if (pkey->pkey.nistdsa_key == NULL) { + if (pkey->pkey.pqdsa_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } - NISTDSA_KEY *key = pkey->pkey.nistdsa_key; - const NISTDSA *nistdsa = key->nistdsa; + PQDSA_KEY *key = pkey->pkey.pqdsa_key; + const PQDSA *pqdsa = key->pqdsa; if (key->secret_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; } - if (nistdsa == NULL) { + if (pqdsa == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } if (out == NULL) { - *out_len = key->nistdsa->secret_key_len; + *out_len = key->pqdsa->secret_key_len; return 1; } - if (*out_len < key->nistdsa->secret_key_len) { + if (*out_len < key->pqdsa->secret_key_len) { OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); return 0; } - OPENSSL_memcpy(out, key->secret_key, nistdsa->secret_key_len); - *out_len = nistdsa->secret_key_len; + OPENSSL_memcpy(out, key->secret_key, pqdsa->secret_key_len); + *out_len = pqdsa->secret_key_len; return 1; } -static int nistdsa_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, +static int pqdsa_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, size_t *out_len) { - if (pkey->pkey.nistdsa_key == NULL) { + if (pkey->pkey.pqdsa_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } - NISTDSA_KEY *key = pkey->pkey.nistdsa_key; - const NISTDSA *nistdsa = key->nistdsa; + PQDSA_KEY *key = pkey->pkey.pqdsa_key; + const PQDSA *pqdsa = key->pqdsa; - if (nistdsa == NULL) { + if (pqdsa == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } @@ -119,33 +117,33 @@ static int nistdsa_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, } if (out == NULL) { - *out_len = nistdsa->public_key_len; + *out_len = pqdsa->public_key_len; return 1; } - if (*out_len < key->nistdsa->public_key_len) { + 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, nistdsa->public_key_len); - *out_len = nistdsa->public_key_len; + OPENSSL_memcpy(out, key->public_key, pqdsa->public_key_len); + *out_len = pqdsa->public_key_len; return 1; } -static int nistdsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { +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 parameters must be omitted. if (CBS_len(params) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return 0; } - return nistdsa_set_pub_raw(out, CBS_data(key), CBS_len(key)); + return pqdsa_set_pub_raw(out, CBS_data(key), CBS_len(key)); } -static int nistdsa_pub_encode(CBB *out, const EVP_PKEY *pkey) { - NISTDSA_KEY *key = pkey->pkey.nistdsa_key; - const NISTDSA *nistdsa = key->nistdsa; +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; @@ -160,7 +158,7 @@ static int nistdsa_pub_encode(CBB *out, const EVP_PKEY *pkey) { !CBB_add_bytes(&oid, pkey->ameth->oid, pkey->ameth->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, nistdsa->public_key_len) || + !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; @@ -169,16 +167,16 @@ static int nistdsa_pub_encode(CBB *out, const EVP_PKEY *pkey) { return 1; } -static int nistdsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { - NISTDSA_KEY *a_key = a->pkey.nistdsa_key; - NISTDSA_KEY *b_key = b->pkey.nistdsa_key; +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.nistdsa_key->nistdsa->public_key_len) == 0; + a->pkey.pqdsa_key->pqdsa->public_key_len) == 0; } -static int nistdsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey) { +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 parameters must be omitted. if (CBS_len(params) != 0 ) { @@ -186,12 +184,12 @@ static int nistdsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey return 0; } - return nistdsa_set_priv_raw(out, CBS_data(key), CBS_len(key), NULL, 0); + return pqdsa_set_priv_raw(out, CBS_data(key), CBS_len(key), NULL, 0); } -static int nistdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { - NISTDSA_KEY *key = pkey->pkey.nistdsa_key; - const NISTDSA *nistdsa = key->nistdsa; +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->secret_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; @@ -204,7 +202,7 @@ static int nistdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || !CBB_add_bytes(&oid, pkey->ameth->oid, pkey->ameth->oid_len) || !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || - !CBB_add_bytes(&private_key, key->secret_key, nistdsa->secret_key_len) || + !CBB_add_bytes(&private_key, key->secret_key, pqdsa->secret_key_len) || !CBB_flush(out)) { OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); return 0; @@ -213,23 +211,23 @@ static int nistdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { return 1; } -static int nistdsa_size(const EVP_PKEY *pkey) { - if (pkey->pkey.nistdsa_key == NULL) { +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.nistdsa_key->nistdsa->signature_len; + return pkey->pkey.pqdsa_key->pqdsa->signature_len; } -static int nistdsa_bits(const EVP_PKEY *pkey) { - if (pkey->pkey.nistdsa_key == NULL) { +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.nistdsa_key->nistdsa->public_key_len); + return 8 * (pkey->pkey.pqdsa_key->pqdsa->public_key_len); } -const EVP_PKEY_ASN1_METHOD nistdsa_asn1_meth = { +const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth = { //2.16.840.1.101.3.4.3 EVP_PKEY_NISTDSA, @@ -239,21 +237,21 @@ const EVP_PKEY_ASN1_METHOD nistdsa_asn1_meth = { "NIST DSA", "AWS-LC NIST DSA method", - nistdsa_pub_decode, - nistdsa_pub_encode, - nistdsa_pub_cmp, - nistdsa_priv_decode, - nistdsa_priv_encode, + pqdsa_pub_decode, + pqdsa_pub_encode, + pqdsa_pub_cmp, + pqdsa_priv_decode, + pqdsa_priv_encode, NULL /*priv_encode_v2*/, - nistdsa_set_priv_raw, - nistdsa_set_pub_raw, - nistdsa_get_priv_raw, - nistdsa_get_pub_raw, + pqdsa_set_priv_raw, + pqdsa_set_pub_raw, + pqdsa_get_priv_raw, + pqdsa_get_pub_raw, NULL /* pkey_opaque */, - nistdsa_size, - nistdsa_bits, + pqdsa_size, + pqdsa_bits, NULL /* param_missing */, NULL /* param_copy */, NULL /* param_cmp */, - nistdsa_free, + pqdsa_free, }; diff --git a/crypto/dilithium/p_dilithium_test.cc b/crypto/dilithium/p_dilithium_test.cc index 4a0a052e01..9fd4de08ca 100644 --- a/crypto/dilithium/p_dilithium_test.cc +++ b/crypto/dilithium/p_dilithium_test.cc @@ -47,10 +47,10 @@ EXPECT_EQ(Bytes(vec), Bytes(tmp)); \ } #define CMP_VEC_AND_PKEY_PUBLIC(vec, pkey, len) \ -CMP_VEC_AND_PTR(vec, pkey->pkey.nistdsa_key->public_key, 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.nistdsa_key->secret_key, len) +CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->secret_key, len) static const struct ML_DSA parameterSet[] = { {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt",mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1973}, @@ -105,7 +105,7 @@ TEST_P(MLDSAParameterTest, KAT) { // Generate our dilithium public and private key pair bssl::UniquePtr pctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(pctx); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(pctx.get(),GetParam().nid)); + 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)); @@ -140,7 +140,7 @@ TEST_P(MLDSAParameterTest, KeyGen) { bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(),nid)); + 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)); @@ -188,7 +188,7 @@ TEST_P(MLDSAParameterTest, KeyCmp) { // Generate first keypair bssl::UniquePtr ctx1(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx1); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx1.get(),nid)); + 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)); @@ -197,7 +197,7 @@ TEST_P(MLDSAParameterTest, KeyCmp) { // Generate second keypair bssl::UniquePtr ctx2(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx2); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx2.get(),nid)); + 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)); @@ -216,7 +216,7 @@ TEST_P(MLDSAParameterTest, KeySize) { // generate an MLDSA keypair bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(),nid)); + 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)); @@ -235,7 +235,7 @@ TEST_P(MLDSAParameterTest, NewKeyFromBytes) { // Source key bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(), nid)); + 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)); @@ -245,13 +245,13 @@ TEST_P(MLDSAParameterTest, NewKeyFromBytes) { // New raw pkey to store raw public key bssl::UniquePtr new_pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, nullptr, - pkey->pkey.nistdsa_key->public_key, + 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.nistdsa_key->public_key, nullptr); - EXPECT_EQ(new_pkey->pkey.nistdsa_key->secret_key, nullptr); + EXPECT_NE(new_pkey->pkey.pqdsa_key->public_key, nullptr); + EXPECT_EQ(new_pkey->pkey.pqdsa_key->secret_key, nullptr); // check that EVP_PKEY_get_raw_private_key fails correctly uint8_t *buf = nullptr; @@ -267,14 +267,14 @@ TEST_P(MLDSAParameterTest, NewKeyFromBytes) { // New raw pkey to store raw secret key bssl::UniquePtr private_pkey(EVP_PKEY_new_raw_private_key(EVP_PKEY_NISTDSA, nullptr, - pkey->pkey.nistdsa_key->secret_key, + pkey->pkey.pqdsa_key->secret_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.nistdsa_key->public_key, nullptr); - EXPECT_NE(private_pkey->pkey.nistdsa_key->secret_key, nullptr); - EXPECT_EQ(0, OPENSSL_memcmp(private_pkey->pkey.nistdsa_key->secret_key, pkey->pkey.nistdsa_key->secret_key, sk_len)); + EXPECT_EQ(private_pkey->pkey.pqdsa_key->public_key, nullptr); + EXPECT_NE(private_pkey->pkey.pqdsa_key->secret_key, nullptr); + EXPECT_EQ(0, OPENSSL_memcmp(private_pkey->pkey.pqdsa_key->secret_key, pkey->pkey.pqdsa_key->secret_key, sk_len)); } TEST_P(MLDSAParameterTest, RawFunctions) { @@ -291,7 +291,7 @@ TEST_P(MLDSAParameterTest, RawFunctions) { // Generate mldsa key bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(),nid)); + 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)); @@ -311,7 +311,7 @@ TEST_P(MLDSAParameterTest, RawFunctions) { pk_len)); ASSERT_TRUE(pkey_pk_new); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey_pk_new.get(), nid); + EVP_PKEY_pqdsa_set_params(pkey_pk_new.get(), nid); // The public key must encode properly. bssl::ScopedCBB cbb; @@ -343,7 +343,7 @@ TEST_P(MLDSAParameterTest, RawFunctions) { sk_len)); ASSERT_TRUE(pkey_sk_new); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey_sk_new.get(), nid); + EVP_PKEY_pqdsa_set_params(pkey_sk_new.get(), nid); // The private key must encode properly. @@ -358,10 +358,10 @@ TEST_P(MLDSAParameterTest, RawFunctions) { ASSERT_TRUE(pkey_priv_from_der); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey_priv_from_der.get(), nid); + EVP_PKEY_pqdsa_set_params(pkey_priv_from_der.get(), nid); // check that the private key from pkey_priv_from_der matches the original key - EXPECT_EQ(Bytes(pkey_priv_from_der->pkey.nistdsa_key->secret_key, - pkey_priv_from_der->pkey.nistdsa_key->nistdsa->secret_key_len), + EXPECT_EQ(Bytes(pkey_priv_from_der->pkey.pqdsa_key->secret_key, + pkey_priv_from_der->pkey.pqdsa_key->pqdsa->secret_key_len), Bytes(priv_buf.data(), sk_len)); } @@ -373,7 +373,7 @@ TEST_P(MLDSAParameterTest, SIGOperations) { // Generate a mldsa key bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(),nid)); + 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)); @@ -436,7 +436,7 @@ TEST_P(MLDSAParameterTest, MarshalParse) { pk_len)); ASSERT_TRUE(pkey_pk_new); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey_pk_new.get(), nid); + EVP_PKEY_pqdsa_set_params(pkey_pk_new.get(), nid); // Encode the public key as DER bssl::ScopedCBB cbb; @@ -457,7 +457,7 @@ TEST_P(MLDSAParameterTest, MarshalParse) { ASSERT_TRUE(pkey_from_der); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey_from_der.get(), nid); + EVP_PKEY_pqdsa_set_params(pkey_from_der.get(), nid); // Extract the public key and check it is equivalent to original key std::vector pub_buf(pk_len); diff --git a/crypto/evp_extra/internal.h b/crypto/evp_extra/internal.h index f9ed81a6ce..57f193dd7f 100644 --- a/crypto/evp_extra/internal.h +++ b/crypto/evp_extra/internal.h @@ -37,7 +37,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 nistdsa_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 +45,7 @@ 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 nistdsa_pkey_meth; +extern const EVP_PKEY_METHOD pqdsa_pkey_meth; extern const EVP_PKEY_METHOD hmac_pkey_meth; extern const EVP_PKEY_METHOD dh_pkey_meth; diff --git a/crypto/evp_extra/p_methods.c b/crypto/evp_extra/p_methods.c index f97711100e..f8fd4c364a 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 - &nistdsa_pkey_meth, + &pqdsa_pkey_meth, #endif &dh_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 - &nistdsa_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 900c3e3654..34cace7478 100644 --- a/crypto/evp_extra/print.c +++ b/crypto/evp_extra/print.c @@ -326,21 +326,21 @@ static int do_mldsa_65_print(BIO *bp, const EVP_PKEY *pkey, int off, int ptype) return 0; } - const NISTDSA *nistdsa = pkey->pkey.nistdsa_key->nistdsa; + const PQDSA *pqdsa = pkey->pkey.pqdsa_key->pqdsa; int bit_len = 0; if (ptype == 2) { - bit_len = nistdsa->secret_key_len; + bit_len = pqdsa->secret_key_len; if (BIO_printf(bp, "Private-Key: (%d bit)\n", bit_len) <= 0) { return 0; } - print_hex(bp, pkey->pkey.nistdsa_key->secret_key, bit_len, off); + print_hex(bp, pkey->pkey.pqdsa_key->secret_key, bit_len, off); } else { - bit_len = nistdsa->public_key_len; + 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, pkey->pkey.nistdsa_key->public_key, bit_len, off); + int ret = print_hex(bp, pkey->pkey.pqdsa_key->public_key, bit_len, off); if (!ret) { return 0; } diff --git a/crypto/fipsmodule/evp/internal.h b/crypto/fipsmodule/evp/internal.h index 48ad94097c..99479da154 100644 --- a/crypto/fipsmodule/evp/internal.h +++ b/crypto/fipsmodule/evp/internal.h @@ -150,7 +150,7 @@ struct evp_pkey_st { DH *dh; EC_KEY *ec; KEM_KEY *kem_key; - NISTDSA_KEY * nistdsa_key; + PQDSA_KEY * pqdsa_key; } pkey; // ameth contains a pointer to a method table that contains many ASN.1 diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index d99e7df34f..4ebff75a6d 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -2956,7 +2956,7 @@ TEST(X509Test, Dilithium3SignVerifyCert) { // Generate mldsa key bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); ASSERT_TRUE(ctx); - ASSERT_TRUE(EVP_PKEY_CTX_nistdsa_set_params(ctx.get(), NID_MLDSA65)); + ASSERT_TRUE(EVP_PKEY_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)); @@ -2987,7 +2987,7 @@ TEST(X509Test, TestMLDSA65) { key->length)); ASSERT_TRUE(pkey); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey.get(), NID_MLDSA65); + EVP_PKEY_pqdsa_set_params(pkey.get(), NID_MLDSA65); ASSERT_TRUE(X509_verify(cert.get(), pkey.get())); } @@ -3006,7 +3006,7 @@ TEST(X509Test, TestBadSigAlgMLDSA65) { key->length)); ASSERT_TRUE(pkey); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey.get(), NID_MLDSA65); + EVP_PKEY_pqdsa_set_params(pkey.get(), NID_MLDSA65); ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); @@ -3030,7 +3030,7 @@ TEST(X509Test, TestBadParamsMLDSA65) { key->length)); ASSERT_TRUE(pkey); // set the correct params for the PKEY - EVP_PKEY_nistdsa_set_params(pkey.get(), NID_MLDSA65); + EVP_PKEY_pqdsa_set_params(pkey.get(), NID_MLDSA65); ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); diff --git a/include/openssl/base.h b/include/openssl/base.h index d9dfd0faee..4bc14e1f11 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -348,7 +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 nistdsa_st NISTDSA_KEY; +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 a48cb645e0..62f66f7385 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -948,14 +948,14 @@ OPENSSL_EXPORT int EVP_PKEY_kem_check_key(EVP_PKEY *key); // Signature specific functions. -// EVP_PKEY_nistdsa_set_params sets signature scheme parameters defined by |nid| +// EVP_PKEY_pqdsa_set_params sets signature scheme parameters defined by |nid| // in |pkey|. If |pkey| already has a public key set, the public key is preserved. -OPENSSL_EXPORT int EVP_PKEY_nistdsa_set_params(EVP_PKEY *pkey, int nid); +OPENSSL_EXPORT int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid); -// EVP_PKEY_CTX_nistdsa_set_params sets in |ctx| the parameters associated with +// 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_nistdsa_set_params(EVP_PKEY_CTX *ctx, int nid); +OPENSSL_EXPORT int EVP_PKEY_CTX_pqdsa_set_params(EVP_PKEY_CTX *ctx, int nid); // Diffie-Hellman-specific control functions. diff --git a/tool/speed.cc b/tool/speed.cc index 1a8387dfd0..a2238b5248 100644 --- a/tool/speed.cc +++ b/tool/speed.cc @@ -876,7 +876,7 @@ static bool SpeedDigestSignNID(const std::string &name, int nid, BM_NAMESPACE::UniquePtr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); // Setup CTX for specific signature alg NID - EVP_PKEY_CTX_nistdsa_set_params(pkey_ctx.get(), 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) { From e2234e347025d64cd9f912fb78555585e03a6198 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 6 Nov 2024 13:35:35 -0800 Subject: [PATCH 03/28] CR fixes --- crypto/dilithium/internal.h | 2 +- crypto/dilithium/p_dilithium3.c | 67 +++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index 4dd6065df1..6109023138 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -55,7 +55,7 @@ struct pqdsa_key_st { int PQDSA_KEY_init(PQDSA_KEY *key, const PQDSA *pqdsa); const PQDSA * PQDSA_find_dsa_by_nid(int nid); -const PQDSA *PQDSA_KEY_get0_sig(PQDSA_KEY* key); +const PQDSA *PQDSA_KEY_get0_dsa(PQDSA_KEY* key); PQDSA_KEY *PQDSA_KEY_new(void); void PQDSA_KEY_free(PQDSA_KEY *key); diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index 2e3d222686..6f7cff6036 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -12,7 +12,7 @@ #include "internal.h" #include "../fipsmodule/delocate.h" -// ML-DSA OIDs from as defined within: +// 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}; @@ -67,7 +67,7 @@ void PQDSA_KEY_free(PQDSA_KEY *key) { OPENSSL_free(key); } -const PQDSA *PQDSA_KEY_get0_sig(PQDSA_KEY* key) { +const PQDSA *PQDSA_KEY_get0_dsa(PQDSA_KEY* key) { return key->pqdsa; } @@ -99,7 +99,7 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } - pqdsa = PQDSA_KEY_get0_sig(ctx->pkey->pkey.pqdsa_key); + pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key); } PQDSA_KEY *key = PQDSA_KEY_new(); @@ -115,9 +115,9 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { return 1; } -static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, - size_t *siglen, const uint8_t *tbs, - size_t tbslen) { +static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, + size_t *siglen, const uint8_t *tbs, + size_t tbslen) { PQDSA_PKEY_CTX *dctx = ctx->data; const PQDSA *pqdsa = dctx->pqdsa; if (pqdsa == NULL) { @@ -125,16 +125,18 @@ static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); return 0; } - pqdsa = PQDSA_KEY_get0_sig(ctx->pkey->pkey.pqdsa_key); + pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key); } // Caller is getting parameter values. if (sig == NULL) { - *siglen = pqdsa->signature_len; - return 1; + if (pqdsa != NULL) { + *siglen = pqdsa->signature_len; + return 1; + } } - if (*siglen < pqdsa->signature_len) { + if (*siglen != pqdsa->signature_len) { OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); return 0; } @@ -145,11 +147,11 @@ static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, ctx->pkey->type != EVP_PKEY_NISTDSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); return 0; - } + } PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; if (!key->secret_key) { - OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET); return 0; } @@ -161,9 +163,9 @@ static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, return 1; } -static int pkey_pqdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, - size_t siglen, const uint8_t *tbs, - size_t tbslen) { +static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t siglen, const uint8_t *tbs, + size_t tbslen) { PQDSA_PKEY_CTX *dctx = ctx->data; const PQDSA *pqdsa = dctx->pqdsa; @@ -173,7 +175,7 @@ static int pkey_pqdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, return 0; } - pqdsa = PQDSA_KEY_get0_sig(ctx->pkey->pkey.pqdsa_key); + pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key); } // Check that the context is properly configured. if (ctx->pkey == NULL || @@ -181,7 +183,7 @@ static int pkey_pqdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, ctx->pkey->type != EVP_PKEY_NISTDSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); return 0; - } + } PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; @@ -190,7 +192,7 @@ static int pkey_pqdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, NULL, 0, key->public_key) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); return 0; - } + } return 1; } @@ -262,10 +264,10 @@ const EVP_PKEY_METHOD pqdsa_pkey_meth = { pkey_pqdsa_keygen, NULL /* sign_init */, NULL /* sign */, - pkey_pqdsa_sign_message, + pkey_pqdsa_sign_signature, NULL /* verify_init */, NULL /* verify */, - pkey_pqdsa_verify_message, + pkey_pqdsa_verify_signature, NULL /* verify_recover */, NULL /* encrypt */, NULL /* decrypt */, @@ -279,6 +281,31 @@ const EVP_PKEY_METHOD pqdsa_pkey_meth = { NULL /* decapsulate */, }; +DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_kem_pkey_meth) { + out->pkey_id = EVP_PKEY_KEM; + out->init = pkey_kem_init; + out->copy = NULL; + out->cleanup = pkey_kem_cleanup; + out->keygen = pkey_kem_keygen; + out->sign_init = NULL; + out->sign = NULL; + out->sign_message = NULL; + out->verify_init = NULL; + out->verify = NULL; + out->verify_message = NULL; + out->verify_recover = NULL; + out->encrypt = NULL; + out->decrypt = NULL; + out->derive = pkey_hkdf_derive; + out->paramgen = NULL; + out->ctrl = NULL; + out->ctrl_str = NULL; + out->keygen_deterministic = pkey_kem_keygen_deterministic; + out->encapsulate_deterministic = pkey_kem_encapsulate_deterministic; + out->encapsulate = pkey_kem_encapsulate; + out->decapsulate = pkey_kem_decapsulate; +} + DEFINE_LOCAL_DATA(PQDSA_METHOD, sig_ml_dsa_65_method) { out->keygen = ml_dsa_65_keypair; out->sign = ml_dsa_65_sign; From 163b50dd5151ba91fd3e61f984698fb3097ac6b5 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 6 Nov 2024 13:36:48 -0800 Subject: [PATCH 04/28] removed accidental code --- crypto/dilithium/p_dilithium3.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index 6f7cff6036..998979be8f 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -281,31 +281,6 @@ const EVP_PKEY_METHOD pqdsa_pkey_meth = { NULL /* decapsulate */, }; -DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_kem_pkey_meth) { - out->pkey_id = EVP_PKEY_KEM; - out->init = pkey_kem_init; - out->copy = NULL; - out->cleanup = pkey_kem_cleanup; - out->keygen = pkey_kem_keygen; - out->sign_init = NULL; - out->sign = NULL; - out->sign_message = NULL; - out->verify_init = NULL; - out->verify = NULL; - out->verify_message = NULL; - out->verify_recover = NULL; - out->encrypt = NULL; - out->decrypt = NULL; - out->derive = pkey_hkdf_derive; - out->paramgen = NULL; - out->ctrl = NULL; - out->ctrl_str = NULL; - out->keygen_deterministic = pkey_kem_keygen_deterministic; - out->encapsulate_deterministic = pkey_kem_encapsulate_deterministic; - out->encapsulate = pkey_kem_encapsulate; - out->decapsulate = pkey_kem_decapsulate; -} - DEFINE_LOCAL_DATA(PQDSA_METHOD, sig_ml_dsa_65_method) { out->keygen = ml_dsa_65_keypair; out->sign = ml_dsa_65_sign; From 221c5335e77ba5ced8d33314cc9adaa646c0ac27 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 6 Nov 2024 14:02:35 -0800 Subject: [PATCH 05/28] api argument consistency --- crypto/dilithium/internal.h | 15 ++++----- crypto/dilithium/p_dilithium3.c | 6 ++-- crypto/dilithium/sig_dilithium.h | 51 ++++++++++++++++--------------- crypto/dilithium/sig_dilithium3.c | 30 +++++++++--------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index 6109023138..f13d5d0f5d 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -15,20 +15,21 @@ typedef struct { int (*keygen)(uint8_t *public_key, uint8_t *secret_key); - int (*sign)(uint8_t *sig, size_t *sig_len, + int (*sign)(const uint8_t *secret_key, + 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); + size_t ctx_len); - int (*verify)(const uint8_t *message, - size_t message_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, - size_t ctx_len, - const uint8_t *public_key); + size_t ctx_len); } PQDSA_METHOD; diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index 998979be8f..8a0adc5000 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -155,8 +155,7 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, return 0; } - if (pqdsa->method->sign(sig, siglen, tbs, tbslen, NULL, - 0, key->secret_key) != 0) { + if (pqdsa->method->sign(key->secret_key, sig, siglen, tbs, tbslen, NULL, 0) != 0) { OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); return 0; } @@ -188,8 +187,7 @@ static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; if (siglen != pqdsa->signature_len || - pqdsa->method->verify(tbs, tbslen, sig, siglen, - NULL, 0, key->public_key) != 0) { + pqdsa->method->verify(key->public_key, sig, siglen, tbs, tbslen, NULL, 0) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); return 0; } diff --git a/crypto/dilithium/sig_dilithium.h b/crypto/dilithium/sig_dilithium.h index e29aa9f701..491feb52f1 100644 --- a/crypto/dilithium/sig_dilithium.h +++ b/crypto/dilithium/sig_dilithium.h @@ -20,30 +20,31 @@ 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_sign generates an ML-DSA-65 signature. Where |secret_key| is a +// pointer to bit-packed secret key, |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, and |ctx_len| is the length of the context +// string (max length 255 bytes). It returns 0 upon success. +int ml_dsa_65_sign(const uint8_t *secret_key, + uint8_t *sig, + size_t *sig_len, + const uint8_t *message, + size_t message_len, + const uint8_t *ctx, + size_t ctx_len); -// 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); +// ml_dsa_65_verify generates an ML-DSA-65 signature. Where |public_key| is a +// pointer to bit-packed public key, |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, and |ctx_len| is the length of the context string (max length 255 +// bytes). Returns 0 if signature could be verified successfully and -1 otherwise. +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, + size_t ctx_len); #endif diff --git a/crypto/dilithium/sig_dilithium3.c b/crypto/dilithium/sig_dilithium3.c index 704c76b41f..37c66c3417 100644 --- a/crypto/dilithium/sig_dilithium3.c +++ b/crypto/dilithium/sig_dilithium3.c @@ -25,32 +25,32 @@ // depending on platform support. int ml_dsa_65_keypair(uint8_t *public_key /* OUT */, - uint8_t *secret_key /* OUT */) { + uint8_t *secret_key /* OUT */) { ml_dsa_params params; ml_dsa_65_params_init(¶ms); return (crypto_sign_keypair(¶ms, public_key, secret_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 *secret_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 /* IN */, + size_t ctx_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); } -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 /* IN */, + size_t ctx_len /* IN */) { ml_dsa_params params; ml_dsa_65_params_init(¶ms); return crypto_sign_verify(¶ms, sig, sig_len, message, message_len, From e47ef838c72641966a62cf59044e44fcae7f5009 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 6 Nov 2024 14:42:55 -0800 Subject: [PATCH 06/28] moved evp_pkey_pqdsa_set_params --- crypto/dilithium/internal.h | 1 + include/openssl/evp.h | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index f13d5d0f5d..65e0c3303e 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -59,6 +59,7 @@ const PQDSA * PQDSA_find_dsa_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); #if defined(__cplusplus) } // extern C diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 62f66f7385..7bc0e7071f 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -948,10 +948,6 @@ OPENSSL_EXPORT int EVP_PKEY_kem_check_key(EVP_PKEY *key); // Signature specific functions. -// EVP_PKEY_pqdsa_set_params sets signature scheme parameters defined by |nid| -// in |pkey|. If |pkey| already has a public key set, the public key is preserved. -OPENSSL_EXPORT int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid); - // 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. From c72e3e6d667a865c8828034cf8c72cd81fa24bd1 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 6 Nov 2024 15:11:53 -0800 Subject: [PATCH 07/28] fixed comment --- crypto/dilithium/p_dilithium3_asn1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/dilithium/p_dilithium3_asn1.c b/crypto/dilithium/p_dilithium3_asn1.c index f2a7cb5a1e..5c89d6b90e 100644 --- a/crypto/dilithium/p_dilithium3_asn1.c +++ b/crypto/dilithium/p_dilithium3_asn1.c @@ -35,7 +35,7 @@ static int pqdsa_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, } // NOTE: No checks are done in this function, the caller has to ensure - // that the pointers are valid and |in| has the correct size. + // that the pointers are valid and |privkey| has the correct size. key->public_key = NULL; key->secret_key = OPENSSL_memdup(privkey, privkey_len); pqdsa_free(pkey); From 7e524dfe45a483297a072dce8c58ff664df8040a Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 7 Nov 2024 08:22:13 -0800 Subject: [PATCH 08/28] CR fixes, name changes --- crypto/dilithium/p_dilithium3.c | 8 +- crypto/dilithium/p_dilithium3_asn1.c | 6 +- crypto/dilithium/p_dilithium_test.cc | 376 ++++++++++++++++++++++++--- crypto/evp_extra/evp_extra_test.cc | 2 +- crypto/evp_extra/print.c | 2 +- crypto/obj/obj_dat.h | 10 +- crypto/obj/obj_mac.num | 2 +- crypto/obj/obj_xref.c | 2 +- crypto/obj/objects.txt | 2 +- crypto/x509/algorithm.c | 6 +- crypto/x509/x509_test.cc | 32 +-- include/openssl/evp.h | 2 +- include/openssl/nid.h | 6 +- tool/speed.cc | 4 +- 14 files changed, 382 insertions(+), 78 deletions(-) diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index 8a0adc5000..16849ef72f 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -106,7 +106,7 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { if (key == NULL || !PQDSA_KEY_init(key, pqdsa) || !pqdsa->method->keygen(key->public_key, key->secret_key) || - !EVP_PKEY_set_type(pkey, EVP_PKEY_NISTDSA)) { + !EVP_PKEY_set_type(pkey, EVP_PKEY_PQDSA)) { PQDSA_KEY_free(key); return 0; } @@ -144,7 +144,7 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, // Check that the context is properly configured. if (ctx->pkey == NULL || ctx->pkey->pkey.pqdsa_key == NULL || - ctx->pkey->type != EVP_PKEY_NISTDSA) { + ctx->pkey->type != EVP_PKEY_PQDSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); return 0; } @@ -179,7 +179,7 @@ static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, // Check that the context is properly configured. if (ctx->pkey == NULL || ctx->pkey->pkey.pqdsa_key == NULL || - ctx->pkey->type != EVP_PKEY_NISTDSA) { + ctx->pkey->type != EVP_PKEY_PQDSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); return 0; } @@ -255,7 +255,7 @@ int EVP_PKEY_CTX_pqdsa_set_params(EVP_PKEY_CTX *ctx, int nid) { } const EVP_PKEY_METHOD pqdsa_pkey_meth = { - EVP_PKEY_NISTDSA, + EVP_PKEY_PQDSA, pkey_pqdsa_init /* init */, NULL /* copy */, pkey_pqdsa_cleanup /* cleanup */, diff --git a/crypto/dilithium/p_dilithium3_asn1.c b/crypto/dilithium/p_dilithium3_asn1.c index 5c89d6b90e..1efe7ed4d2 100644 --- a/crypto/dilithium/p_dilithium3_asn1.c +++ b/crypto/dilithium/p_dilithium3_asn1.c @@ -229,13 +229,13 @@ static int pqdsa_bits(const EVP_PKEY *pkey) { const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth = { //2.16.840.1.101.3.4.3 - EVP_PKEY_NISTDSA, + EVP_PKEY_PQDSA, {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03}, 8, - "NIST DSA", - "AWS-LC NIST DSA method", + "PQ DSA", + "AWS-LC PQ DSA method", pqdsa_pub_decode, pqdsa_pub_encode, diff --git a/crypto/dilithium/p_dilithium_test.cc b/crypto/dilithium/p_dilithium_test.cc index 9fd4de08ca..ef866a4318 100644 --- a/crypto/dilithium/p_dilithium_test.cc +++ b/crypto/dilithium/p_dilithium_test.cc @@ -22,12 +22,316 @@ #include "../rand_extra/pq_custom_randombytes.h" #include "sig_dilithium.h" -static const uint8_t mldsa65kPublicKey[] = {0x9B, 0x77, 0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x02, 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, 0x03, 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, 0x06, 0xBA, 0xD5, 0xF8, 0x9E, 0x0A, 0x2D, 0xA2, 0xC7, 0x96, 0x4B, 0x79, 0xE9, 0xA9, 0xA6, 0x73, 0x69, 0xF8, 0x8C, 0x01, 0x69, 0xF2, 0x66, 0x05, 0x37, 0x31, 0x65, 0xA9, 0x09, 0x3E, 0x0E, 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, 0x06, 0x23, 0xE6, 0x1C, 0x44, 0x63, 0x02, 0x9E, 0x09, 0x76, 0x6C, 0x72, 0xBD, 0x0D, 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, 0x0F, 0x6B, 0x32, 0x78, 0xD2, 0x24, 0xB7, 0x8C, 0xE8, 0x84, 0xE3, 0xB8, 0xF6, 0x04, 0xF3, 0x30, 0xE9, 0x5B, 0xA5, 0xD8, 0x94, 0xA7, 0xA3, 0xF0, 0xE8, 0xAC, 0x70, 0x32, 0x42, 0xB5, 0x08, 0xEE, 0x2A, 0x77, 0xFA, 0x04, 0x49, 0xE9, 0x7A, 0xB7, 0x0A, 0x95, 0x05, 0x86, 0x33, 0xA5, 0xE4, 0x5A, 0xC6, 0xE1, 0xE7, 0x48, 0xBD, 0xBA, 0x80, 0xE7, 0x21, 0x61, 0x45, 0x24, 0x5E, 0xA9, 0x7F, 0x2D, 0x75, 0x0F, 0xE9, 0xEE, 0x79, 0x88, 0x64, 0xF3, 0xE7, 0x0C, 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, 0x08, 0x58, 0x3F, 0x20, 0x96, 0x52, 0xD2, 0x61, 0xDA, 0xED, 0x5F, 0x7F, 0xAD, 0x40, 0x93, 0x21, 0xEB, 0xC4, 0x37, 0x5C, 0xD1, 0x72, 0xE6, 0x06, 0x37, 0xD9, 0xF6, 0x09, 0xD4, 0xC9, 0x6D, 0xED, 0x07, 0xF6, 0xD2, 0x15, 0x94, 0xFD, 0xF6, 0xC3, 0x09, 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, 0x0E, 0x6A, 0x9E, 0x6D, 0xAC, 0xF1, 0x0F, 0x90, 0x25, 0xED, 0xC5, 0x94, 0x9E, 0x10, 0x29, 0x97, 0x47, 0x05, 0x3D, 0x03, 0x6F, 0x69, 0xAE, 0x84, 0x08, 0x9B, 0x33, 0x0C, 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, 0x01, 0x5F, 0x39, 0xD1, 0xBC, 0x07, 0x8E, 0xAC, 0xC9, 0x28, 0x0C, 0x7B, 0xD8, 0x02, 0xFE, 0x46, 0x12, 0xA8, 0xBD, 0x0E, 0x6B, 0x23, 0x65, 0x5B, 0xAA, 0xFC, 0x32, 0x20, 0xF7, 0xCC, 0xC7, 0x06, 0x80, 0x09, 0x0A, 0x95, 0xD9, 0x69, 0xED, 0x3C, 0x6C, 0xEB, 0x62, 0x28, 0xE6, 0x4E, 0xF4, 0xFA, 0x9B, 0x5C, 0x36, 0x07, 0xE0, 0x25, 0x20, 0xB8, 0xF4, 0x1F, 0x2E, 0x78, 0x21, 0xEE, 0xFA, 0x9E, 0x80, 0x14, 0xAD, 0xAD, 0x83, 0x39, 0x2E, 0xD0, 0xE9, 0x56, 0xE3, 0x88, 0x0C, 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, 0x0A, 0x07, 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, 0x08, 0x40, 0x25, 0x7B, 0x03, 0x75, 0x47, 0xAD, 0x19, 0x02, 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, 0x0E, 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, 0x0D, 0x17, 0x90, 0x66, 0x70, 0xB2, 0x98, 0x24, 0x1B, 0x58, 0x79, 0xAC, 0x3E, 0x61, 0x9C, 0x67, 0xB4, 0xEE, 0x09, 0x06, 0x20, 0xCE, 0x39, 0x03, 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, 0x06, 0x51, 0x74, 0x72, 0x71, 0x9D, 0xA1, 0x3F, 0x3C, 0x73, 0xCF, 0x07, 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, 0x04, 0x67, 0x20, 0x5D, 0x2B, 0x79, 0x42, 0x07, 0x03, 0x5C, 0x36, 0xD7, 0xBE, 0x72, 0xCA, 0x13, 0xCF, 0x93, 0x2D, 0xD8, 0xA9, 0xEE, 0x06, 0x0B, 0xCF, 0x5A, 0x46, 0x88, 0x57, 0x9E, 0x18, 0x92, 0x3B, 0x5F, 0x2F, 0x86, 0xCD, 0x3D, 0x49, 0xF6, 0xA3, 0x05, 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, 0x03, 0xDF, 0xF8, 0xD5, 0x7F, 0x7B, 0x09, 0x62, 0xBF, 0x28, 0xBD, 0xC6, 0x3E, 0xC3, 0x6C, 0x91, 0x01, 0x45, 0x3F, 0xE2, 0x1F, 0xEF, 0x2A, 0x8F, 0xB2, 0x1B, 0x72, 0x35, 0x4D, 0x18, 0x6F, 0x4D, 0x57, 0xBF, 0x6A, 0x69, 0x02, 0x69, 0x4A, 0xE5, 0x5F, 0x74, 0xF7, 0x69, 0x5B, 0x89, 0x08, 0xCE, 0xCE, 0x15, 0x56, 0x3F, 0x21, 0x1A, 0xB8, 0xEC, 0x4D, 0xB0, 0x7E, 0x0F, 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, 0x0C, 0x61, 0xEA, 0x59, 0x33, 0x25, 0x39, 0xAF, 0xF0, 0x12, 0x81, 0x55, 0x4A, 0x9D, 0x0C, 0x3E, 0x5E, 0x34, 0x9F, 0xA7, 0xD8, 0xC5, 0xB5, 0x0A, 0xC3, 0xA2, 0x00, 0x3F, 0x59, 0x3D, 0x07, 0x5F, 0x2B, 0xC1, 0x6F, 0x6A, 0xE3, 0x94, 0x90, 0xAF, 0x81, 0x11, 0x82, 0x89, 0xF4, 0x9D, 0x8B, 0x05, 0xE2, 0x7C, 0x22, 0x02, 0xEC, 0x00, 0x38, 0x39, 0xED, 0x04, 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, 0x0F, 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, 0x06, 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, 0x0B, 0x09, 0x44, 0x9C, 0x20, 0x34, 0xF6, 0xEE, 0x6F, 0x26, 0xB9, 0x4C, 0x76, 0xCC, 0xE1, 0x6F, 0x09, 0x91, 0xAF, 0x48, 0x8C, 0xC4, 0x31, 0xA2, 0xF9, 0x44, 0x77, 0x19, 0xA7, 0x00, 0x33, 0x77, 0x31, 0xF2, 0xF5, 0xF7, 0x30, 0xDF, 0xAB, 0xFE, 0x7E, 0xE6, 0x83, 0xE1, 0xC9, 0x2A, 0xC8, 0xE0, 0xA6, 0xAC, 0x5A, 0x28, 0x7F, 0xC4, 0x0B, 0xEB, 0x55, 0xD9, 0x5D, 0xBD, 0xB5, 0xD2, 0xF6, 0xB4, 0xA9, 0x76, 0x2B, 0x35, 0x10, 0x36, 0x3B, 0xCC, 0x61, 0x6C, 0x79, 0xCE, 0xC3, 0x9A, 0x02, 0x9A, 0x00, 0xBA, 0x43, 0x20, 0x3F, 0x26, 0x36, 0x66, 0x07, 0x11, 0x68, 0x51, 0x47, 0xBE, 0x78, 0xED, 0x4A, 0xFA, 0xBC, 0xDA, 0xCD, 0xFD, 0x02, 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, 0x0B, 0x73, 0x03, 0xFB, 0xFE, 0xC0, 0x50, 0x38, 0x70, 0xDF, 0x81, 0x5D, 0x22, 0x4C, 0x5B, 0xCB, 0x27, 0x5D, 0xD2, 0x94, 0x64, 0x0A, 0x88, 0x67, 0x31, 0xE9, 0x08, 0xF0, 0x88, 0x20, 0xF2, 0x86, 0xCA, 0xBD, 0x18, 0x5F, 0x34, 0xD0, 0x96, 0x0D, 0x4A, 0x62, 0x4D, 0xBE, 0xE8, 0xA6, 0x04, 0xA6, 0x69, 0xCE, 0xCD, 0xE9, 0x5A, 0x1D, 0xD2, 0xF8, 0xCF, 0x19, 0x06, 0x17, 0x05, 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, 0x0D, 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, 0x01, 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, 0x01, 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, 0x0C, 0x87, 0x03, 0x61, 0xB4, 0x3B, 0x60, 0x6D, 0x07, 0x56, 0xB8, 0x1F, 0x89, 0xAD, 0x00, 0x25, 0x10, 0x4A, 0x34, 0x4C, 0x9A, 0x26, 0xDA, 0x06, 0x25, 0x9C, 0x91, 0xA6, 0xA5, 0xAD, 0x4D, 0x6E, 0xE9, 0x2F, 0x18, 0xC4, 0x1D, 0x09, 0xE1, 0xAA, 0x66, 0x01, 0x31, 0x6D, 0x12, 0x30, 0xED, 0x97, 0x3F, 0x67, 0xCE, 0x4E, 0x26, 0x0B, 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, 0x0E, 0x51, 0x63, 0x90, 0x05, 0x68, 0x7A, 0x45, 0x86, 0x68, 0x2A, 0x0E, 0x81, 0x5F, 0xDD, 0x12, 0xAD, 0x48, 0xF6, 0x87, 0x2E, 0x8D, 0xF6, 0x86, 0xC3, 0x6D, 0x69, 0xD5, 0x4E, 0x52, 0x8A, 0x8E, 0xE8, 0x01, 0x56, 0x11, 0xCC, 0x2E, 0x3F, 0xB5, 0x46, 0x1D, 0xF6, 0x6E, 0x4A, 0xEE, 0x1C, 0x60, 0x15, 0x85, 0xF6, 0x40, 0xFD, 0x56, 0xDC, 0x10, 0x01, 0xC3, 0xBD, 0xAE, 0x5A, 0x13, 0x1F, 0x15, 0x16, 0x10, 0x92, 0xC5, 0x02, 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, 0x0E, -}; -static const uint8_t mldsa65kPublicKeySPKI[] = { 0x30, 0x82, 0x07, 0xB1, 0x30, 0x0A, 0x06, 0x08, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x03, 0x82, 0x07, 0xA1, 0x00, 0x9B, 0x77, 0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x02, 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, 0x03, 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, 0x06, 0xBA, 0xD5, 0xF8, 0x9E, 0x0A, 0x2D, 0xA2, 0xC7, 0x96, 0x4B, 0x79, 0xE9, 0xA9, 0xA6, 0x73, 0x69, 0xF8, 0x8C, 0x01, 0x69, 0xF2, 0x66, 0x05, 0x37, 0x31, 0x65, 0xA9, 0x09, 0x3E, 0x0E, 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, 0x06, 0x23, 0xE6, 0x1C, 0x44, 0x63, 0x02, 0x9E, 0x09, 0x76, 0x6C, 0x72, 0xBD, 0x0D, 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, 0x0F, 0x6B, 0x32, 0x78, 0xD2, 0x24, 0xB7, 0x8C, 0xE8, 0x84, 0xE3, 0xB8, 0xF6, 0x04, 0xF3, 0x30, 0xE9, 0x5B, 0xA5, 0xD8, 0x94, 0xA7, 0xA3, 0xF0, 0xE8, 0xAC, 0x70, 0x32, 0x42, 0xB5, 0x08, 0xEE, 0x2A, 0x77, 0xFA, 0x04, 0x49, 0xE9, 0x7A, 0xB7, 0x0A, 0x95, 0x05, 0x86, 0x33, 0xA5, 0xE4, 0x5A, 0xC6, 0xE1, 0xE7, 0x48, 0xBD, 0xBA, 0x80, 0xE7, 0x21, 0x61, 0x45, 0x24, 0x5E, 0xA9, 0x7F, 0x2D, 0x75, 0x0F, 0xE9, 0xEE, 0x79, 0x88, 0x64, 0xF3, 0xE7, 0x0C, 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, 0x08, 0x58, 0x3F, 0x20, 0x96, 0x52, 0xD2, 0x61, 0xDA, 0xED, 0x5F, 0x7F, 0xAD, 0x40, 0x93, 0x21, 0xEB, 0xC4, 0x37, 0x5C, 0xD1, 0x72, 0xE6, 0x06, 0x37, 0xD9, 0xF6, 0x09, 0xD4, 0xC9, 0x6D, 0xED, 0x07, 0xF6, 0xD2, 0x15, 0x94, 0xFD, 0xF6, 0xC3, 0x09, 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, 0x0E, 0x6A, 0x9E, 0x6D, 0xAC, 0xF1, 0x0F, 0x90, 0x25, 0xED, 0xC5, 0x94, 0x9E, 0x10, 0x29, 0x97, 0x47, 0x05, 0x3D, 0x03, 0x6F, 0x69, 0xAE, 0x84, 0x08, 0x9B, 0x33, 0x0C, 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, 0x01, 0x5F, 0x39, 0xD1, 0xBC, 0x07, 0x8E, 0xAC, 0xC9, 0x28, 0x0C, 0x7B, 0xD8, 0x02, 0xFE, 0x46, 0x12, 0xA8, 0xBD, 0x0E, 0x6B, 0x23, 0x65, 0x5B, 0xAA, 0xFC, 0x32, 0x20, 0xF7, 0xCC, 0xC7, 0x06, 0x80, 0x09, 0x0A, 0x95, 0xD9, 0x69, 0xED, 0x3C, 0x6C, 0xEB, 0x62, 0x28, 0xE6, 0x4E, 0xF4, 0xFA, 0x9B, 0x5C, 0x36, 0x07, 0xE0, 0x25, 0x20, 0xB8, 0xF4, 0x1F, 0x2E, 0x78, 0x21, 0xEE, 0xFA, 0x9E, 0x80, 0x14, 0xAD, 0xAD, 0x83, 0x39, 0x2E, 0xD0, 0xE9, 0x56, 0xE3, 0x88, 0x0C, 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, 0x0A, 0x07, 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, 0x08, 0x40, 0x25, 0x7B, 0x03, 0x75, 0x47, 0xAD, 0x19, 0x02, 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, 0x0E, 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, 0x0D, 0x17, 0x90, 0x66, 0x70, 0xB2, 0x98, 0x24, 0x1B, 0x58, 0x79, 0xAC, 0x3E, 0x61, 0x9C, 0x67, 0xB4, 0xEE, 0x09, 0x06, 0x20, 0xCE, 0x39, 0x03, 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, 0x06, 0x51, 0x74, 0x72, 0x71, 0x9D, 0xA1, 0x3F, 0x3C, 0x73, 0xCF, 0x07, 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, 0x04, 0x67, 0x20, 0x5D, 0x2B, 0x79, 0x42, 0x07, 0x03, 0x5C, 0x36, 0xD7, 0xBE, 0x72, 0xCA, 0x13, 0xCF, 0x93, 0x2D, 0xD8, 0xA9, 0xEE, 0x06, 0x0B, 0xCF, 0x5A, 0x46, 0x88, 0x57, 0x9E, 0x18, 0x92, 0x3B, 0x5F, 0x2F, 0x86, 0xCD, 0x3D, 0x49, 0xF6, 0xA3, 0x05, 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, 0x03, 0xDF, 0xF8, 0xD5, 0x7F, 0x7B, 0x09, 0x62, 0xBF, 0x28, 0xBD, 0xC6, 0x3E, 0xC3, 0x6C, 0x91, 0x01, 0x45, 0x3F, 0xE2, 0x1F, 0xEF, 0x2A, 0x8F, 0xB2, 0x1B, 0x72, 0x35, 0x4D, 0x18, 0x6F, 0x4D, 0x57, 0xBF, 0x6A, 0x69, 0x02, 0x69, 0x4A, 0xE5, 0x5F, 0x74, 0xF7, 0x69, 0x5B, 0x89, 0x08, 0xCE, 0xCE, 0x15, 0x56, 0x3F, 0x21, 0x1A, 0xB8, 0xEC, 0x4D, 0xB0, 0x7E, 0x0F, 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, 0x0C, 0x61, 0xEA, 0x59, 0x33, 0x25, 0x39, 0xAF, 0xF0, 0x12, 0x81, 0x55, 0x4A, 0x9D, 0x0C, 0x3E, 0x5E, 0x34, 0x9F, 0xA7, 0xD8, 0xC5, 0xB5, 0x0A, 0xC3, 0xA2, 0x00, 0x3F, 0x59, 0x3D, 0x07, 0x5F, 0x2B, 0xC1, 0x6F, 0x6A, 0xE3, 0x94, 0x90, 0xAF, 0x81, 0x11, 0x82, 0x89, 0xF4, 0x9D, 0x8B, 0x05, 0xE2, 0x7C, 0x22, 0x02, 0xEC, 0x00, 0x38, 0x39, 0xED, 0x04, 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, 0x0F, 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, 0x06, 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, 0x0B, 0x09, 0x44, 0x9C, 0x20, 0x34, 0xF6, 0xEE, 0x6F, 0x26, 0xB9, 0x4C, 0x76, 0xCC, 0xE1, 0x6F, 0x09, 0x91, 0xAF, 0x48, 0x8C, 0xC4, 0x31, 0xA2, 0xF9, 0x44, 0x77, 0x19, 0xA7, 0x00, 0x33, 0x77, 0x31, 0xF2, 0xF5, 0xF7, 0x30, 0xDF, 0xAB, 0xFE, 0x7E, 0xE6, 0x83, 0xE1, 0xC9, 0x2A, 0xC8, 0xE0, 0xA6, 0xAC, 0x5A, 0x28, 0x7F, 0xC4, 0x0B, 0xEB, 0x55, 0xD9, 0x5D, 0xBD, 0xB5, 0xD2, 0xF6, 0xB4, 0xA9, 0x76, 0x2B, 0x35, 0x10, 0x36, 0x3B, 0xCC, 0x61, 0x6C, 0x79, 0xCE, 0xC3, 0x9A, 0x02, 0x9A, 0x00, 0xBA, 0x43, 0x20, 0x3F, 0x26, 0x36, 0x66, 0x07, 0x11, 0x68, 0x51, 0x47, 0xBE, 0x78, 0xED, 0x4A, 0xFA, 0xBC, 0xDA, 0xCD, 0xFD, 0x02, 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, 0x0B, 0x73, 0x03, 0xFB, 0xFE, 0xC0, 0x50, 0x38, 0x70, 0xDF, 0x81, 0x5D, 0x22, 0x4C, 0x5B, 0xCB, 0x27, 0x5D, 0xD2, 0x94, 0x64, 0x0A, 0x88, 0x67, 0x31, 0xE9, 0x08, 0xF0, 0x88, 0x20, 0xF2, 0x86, 0xCA, 0xBD, 0x18, 0x5F, 0x34, 0xD0, 0x96, 0x0D, 0x4A, 0x62, 0x4D, 0xBE, 0xE8, 0xA6, 0x04, 0xA6, 0x69, 0xCE, 0xCD, 0xE9, 0x5A, 0x1D, 0xD2, 0xF8, 0xCF, 0x19, 0x06, 0x17, 0x05, 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, 0x0D, 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, 0x01, 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, 0x01, 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, 0x0C, 0x87, 0x03, 0x61, 0xB4, 0x3B, 0x60, 0x6D, 0x07, 0x56, 0xB8, 0x1F, 0x89, 0xAD, 0x00, 0x25, 0x10, 0x4A, 0x34, 0x4C, 0x9A, 0x26, 0xDA, 0x06, 0x25, 0x9C, 0x91, 0xA6, 0xA5, 0xAD, 0x4D, 0x6E, 0xE9, 0x2F, 0x18, 0xC4, 0x1D, 0x09, 0xE1, 0xAA, 0x66, 0x01, 0x31, 0x6D, 0x12, 0x30, 0xED, 0x97, 0x3F, 0x67, 0xCE, 0x4E, 0x26, 0x0B, 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, 0x0E, 0x51, 0x63, 0x90, 0x05, 0x68, 0x7A, 0x45, 0x86, 0x68, 0x2A, 0x0E, 0x81, 0x5F, 0xDD, 0x12, 0xAD, 0x48, 0xF6, 0x87, 0x2E, 0x8D, 0xF6, 0x86, 0xC3, 0x6D, 0x69, 0xD5, 0x4E, 0x52, 0x8A, 0x8E, 0xE8, 0x01, 0x56, 0x11, 0xCC, 0x2E, 0x3F, 0xB5, 0x46, 0x1D, 0xF6, 0x6E, 0x4A, 0xEE, 0x1C, 0x60, 0x15, 0x85, 0xF6, 0x40, 0xFD, 0x56, 0xDC, 0x10, 0x01, 0xC3, 0xBD, 0xAE, 0x5A, 0x13, 0x1F, 0x15, 0x16, 0x10, 0x92, 0xC5, 0x02, 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, 0x0E, -}; - -struct ML_DSA { +// 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, 0xB1, 0x30, 0xA, 0x6, 0x8, 0x60, 0x86, 0x48, 0x1, 0x65, +0x3, 0x4, 0x3, 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 PQ_DSA { const char name[20]; const int nid; const size_t public_key_len; @@ -40,11 +344,11 @@ struct ML_DSA { }; #define CMP_VEC_AND_PTR(vec, ptr, len) \ -{ \ -std::vector tmp(len); \ -tmp.assign(ptr, ptr+len); \ -EXPECT_EQ(Bytes(vec), Bytes(tmp)); \ -} + { \ + 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) @@ -52,18 +356,18 @@ 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->secret_key, len) -static const struct ML_DSA parameterSet[] = { +static const struct PQ_DSA parameterSet[] = { {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt",mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1973}, }; -class MLDSAParameterTest : public testing::TestWithParam {}; +class PQDSAParameterTest : public testing::TestWithParam {}; -INSTANTIATE_TEST_SUITE_P(All, MLDSAParameterTest, testing::ValuesIn(parameterSet), - [](const testing::TestParamInfo ¶ms) +INSTANTIATE_TEST_SUITE_P(All, PQDSAParameterTest, testing::ValuesIn(parameterSet), + [](const testing::TestParamInfo ¶ms) -> std::string { return params.param.name; }); -TEST_P(MLDSAParameterTest, KAT) { +TEST_P(PQDSAParameterTest, KAT) { std::string kat_filepath = "crypto/"; kat_filepath += GetParam().kat_filename; @@ -103,7 +407,7 @@ TEST_P(MLDSAParameterTest, KAT) { 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_NISTDSA, nullptr)); + 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())); @@ -131,14 +435,14 @@ TEST_P(MLDSAParameterTest, KAT) { }); } -TEST_P(MLDSAParameterTest, KeyGen) { +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().secret_key_len; - bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + 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())); @@ -181,12 +485,12 @@ TEST_P(MLDSAParameterTest, KeyGen) { OPENSSL_free(buf); } -TEST_P(MLDSAParameterTest, KeyCmp) { +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_NISTDSA, nullptr)); + 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())); @@ -195,7 +499,7 @@ TEST_P(MLDSAParameterTest, KeyCmp) { bssl::UniquePtr pkey1(raw1); // Generate second keypair - bssl::UniquePtr ctx2(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + 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())); @@ -207,14 +511,14 @@ TEST_P(MLDSAParameterTest, KeyCmp) { EXPECT_EQ(0, EVP_PKEY_cmp(pkey1.get(), pkey2.get())); } -TEST_P(MLDSAParameterTest, KeySize) { +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_NISTDSA, nullptr)); + 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())); @@ -226,14 +530,14 @@ TEST_P(MLDSAParameterTest, KeySize) { EXPECT_EQ(8*(pk_len), EVP_PKEY_bits(pkey.get())); } -TEST_P(MLDSAParameterTest, NewKeyFromBytes) { +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().secret_key_len; // Source key - bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + 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())); @@ -243,7 +547,7 @@ TEST_P(MLDSAParameterTest, NewKeyFromBytes) { // New raw pkey to store raw public key - bssl::UniquePtr new_pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr new_pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, nullptr, pkey->pkey.pqdsa_key->public_key, pk_len)); @@ -265,7 +569,7 @@ TEST_P(MLDSAParameterTest, NewKeyFromBytes) { 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_new_raw_private_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr private_pkey(EVP_PKEY_new_raw_private_key(EVP_PKEY_PQDSA, nullptr, pkey->pkey.pqdsa_key->secret_key, sk_len)); @@ -277,7 +581,7 @@ TEST_P(MLDSAParameterTest, NewKeyFromBytes) { EXPECT_EQ(0, OPENSSL_memcmp(private_pkey->pkey.pqdsa_key->secret_key, pkey->pkey.pqdsa_key->secret_key, sk_len)); } -TEST_P(MLDSAParameterTest, RawFunctions) { +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_new_raw_public_key for generating a new PKEY from raw pub @@ -289,7 +593,7 @@ TEST_P(MLDSAParameterTest, RawFunctions) { size_t sk_len = GetParam().secret_key_len; // Generate mldsa key - bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + 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())); @@ -305,7 +609,7 @@ TEST_P(MLDSAParameterTest, RawFunctions) { ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pub_buf.data(), &pub_len)); // Generate a new pkey with only public key set from the extracted public key - bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, nullptr, pub_buf.data(), pk_len)); @@ -337,7 +641,7 @@ TEST_P(MLDSAParameterTest, RawFunctions) { ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), priv_buf.data(), &priv_len)); // Generate a new pkey with only secret key set from the extracted secret key - bssl::UniquePtr pkey_sk_new(EVP_PKEY_new_raw_private_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr pkey_sk_new(EVP_PKEY_new_raw_private_key(EVP_PKEY_PQDSA, nullptr, priv_buf.data(), sk_len)); @@ -365,13 +669,13 @@ TEST_P(MLDSAParameterTest, RawFunctions) { Bytes(priv_buf.data(), sk_len)); } -TEST_P(MLDSAParameterTest, SIGOperations) { +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_NISTDSA, nullptr)); + 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())); @@ -418,7 +722,7 @@ TEST_P(MLDSAParameterTest, SIGOperations) { md_ctx.Reset(); } -TEST_P(MLDSAParameterTest, MarshalParse) { +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 // Test that extacting the public key from the PKEY is the same as the original key @@ -430,7 +734,7 @@ TEST_P(MLDSAParameterTest, MarshalParse) { size_t kPublicKeySPKI_len = GetParam().kPublicKeySPKI_len; // Generate a new pkey with only public key set from the extracted public key - bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, nullptr, kPublicKey, pk_len)); diff --git a/crypto/evp_extra/evp_extra_test.cc b/crypto/evp_extra/evp_extra_test.cc index 473a145f47..9ac067c55b 100644 --- a/crypto/evp_extra/evp_extra_test.cc +++ b/crypto/evp_extra/evp_extra_test.cc @@ -1179,7 +1179,7 @@ TEST(EVPExtraTest, d2i_PrivateKey) { ParsePrivateKey(EVP_PKEY_EC, kExampleECKeyDER, sizeof(kExampleECKeyDER))); #ifdef ENABLE_DILITHIUM - EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_NISTDSA, kExampleMLDSA65KeyDER, + EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_PQDSA, kExampleMLDSA65KeyDER, sizeof(kExampleMLDSA65KeyDER))); #endif diff --git a/crypto/evp_extra/print.c b/crypto/evp_extra/print.c index 34cace7478..a53fa6f04f 100644 --- a/crypto/evp_extra/print.c +++ b/crypto/evp_extra/print.c @@ -387,7 +387,7 @@ static EVP_PKEY_PRINT_METHOD kPrintMethods[] = { }, #ifdef ENABLE_DILITHIUM { - EVP_PKEY_NISTDSA, + EVP_PKEY_PQDSA, mldsa_65_pub_print, mldsa_65_priv_print, NULL /* param_print */, diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h index f544d4356c..eb284bb0d0 100644 --- a/crypto/obj/obj_dat.h +++ b/crypto/obj/obj_dat.h @@ -7281,7 +7281,7 @@ static const uint8_t kObjectData[] = { 0x0f, 0x63, 0x37, - /* NID_NISTDSA */ + /* NID_PQDSA */ 0x60, 0x86, 0x48, @@ -9000,7 +9000,7 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { &kObjectData[6315], 0}, {"SecP256r1MLKEM768", "SecP256r1MLKEM768", NID_SecP256r1MLKEM768, 5, &kObjectData[6320], 0}, - {"NISTDSA", "NISTDSA", NID_NISTDSA, 8, &kObjectData[6325], 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}, @@ -9144,7 +9144,6 @@ static const uint16_t kNIDsInShortNameOrder[] = { 989 /* MLKEM768 */, 986 /* MLKEM768IPD */, 388 /* Mail */, - 993 /* NISTDSA */, 57 /* Netscape */, 366 /* Nonce */, 17 /* O */, @@ -9170,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 */, @@ -10074,7 +10074,6 @@ static const uint16_t kNIDsInLongNameOrder[] = { 648 /* Microsoft Smartcardlogin */, 136 /* Microsoft Trust List Signing */, 649 /* Microsoft Universal Principal Name */, - 993 /* NISTDSA */, 72 /* Netscape Base Url */, 76 /* Netscape CA Policy Url */, 74 /* Netscape CA Revocation Url */, @@ -10099,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 */, @@ -11570,7 +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_NISTDSA) */, + 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) */, diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num index 176315c53a..72782a89e7 100644 --- a/crypto/obj/obj_mac.num +++ b/crypto/obj/obj_mac.num @@ -980,7 +980,7 @@ MLKEM768 989 MLKEM1024 990 X25519MLKEM768 991 SecP256r1MLKEM768 992 -NISTDSA 993 +PQDSA 993 MLDSA44 994 MLDSA65 995 MLDSA87 996 diff --git a/crypto/obj/obj_xref.c b/crypto/obj/obj_xref.c index 6a58328e39..c649c31b80 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_NISTDSA, NID_undef, NID_NISTDSA}, + {NID_PQDSA, NID_undef, NID_PQDSA}, }; 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 87f6017a25..791704d5a3 100644 --- a/crypto/obj/objects.txt +++ b/crypto/obj/objects.txt @@ -1405,7 +1405,7 @@ nist_kem 3 : MLKEM1024 # 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 : NISTDSA +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 cd90e532df..5ec35af856 100644 --- a/crypto/x509/algorithm.c +++ b/crypto/x509/algorithm.c @@ -97,8 +97,8 @@ int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { } #ifdef ENABLE_DILITHIUM - if (EVP_PKEY_id(pkey) == EVP_PKEY_NISTDSA) { - return X509_ALGOR_set0(algor, OBJ_nid2obj(EVP_PKEY_NISTDSA), V_ASN1_UNDEF, NULL); + if (EVP_PKEY_id(pkey) == EVP_PKEY_PQDSA) { + return X509_ALGOR_set0(algor, OBJ_nid2obj(EVP_PKEY_PQDSA), V_ASN1_UNDEF, NULL); } #endif @@ -158,7 +158,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_NISTDSA) { + if (sigalg_nid == NID_ED25519 || sigalg_nid == NID_PQDSA) { #else if (sigalg_nid == NID_ED25519) { #endif diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 4ebff75a6d..be3e630758 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -578,7 +578,7 @@ w1AH9efZBw== #ifdef ENABLE_DILITHIUM -static const char kDilithium3Cert[] = R"( +static const char kMLDSA65Cert[] = R"( -----BEGIN CERTIFICATE----- MIIVKDCCCCagAwIBAgIBADAKBghghkgBZQMEAzAXMRUwEwYDVQQDDAxJbnRlcm1l ZGlhdGUwHhcNMTYwOTI2MDAwMDAwWhcNMTYwOTI4MDAwMDAwWjAPMQ0wCwYDVQQD @@ -696,9 +696,9 @@ gpSap7z7DhchKkdnb3eAtw8eZmrXfb0AAAAAAAAAAAAAAAAAAAAHCxchJig= -----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----- MIIVLDCCCCegAwIBAgIBADALBglghkgBZQMEAxIwFzEVMBMGA1UEAwwMSW50ZXJt ZWRpYXRlMB4XDTE2MDkyNjAwMDAwMFoXDTE2MDkyODAwMDAwMFowDzENMAsGA1UE @@ -817,9 +817,9 @@ mKm80BAolbXG4fX4d6cpVZbBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw8RGRsf )"; -// 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----- MIIVLjCCCCmgAwIBAgIBADANBglghkgBZQMEAxIFADAXMRUwEwYDVQQDDAxJbnRl cm1lZGlhdGUwHhcNMTYwOTI2MDAwMDAwWhcNMTYwOTI4MDAwMDAwWjAPMQ0wCwYD @@ -2949,12 +2949,12 @@ 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. // Generate mldsa key - bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, nullptr)); + 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())); @@ -2976,12 +2976,12 @@ TEST(X509Test, Dilithium3SignVerifyCert) { 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); //extract the asn1 bit string from the cert ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, nullptr, key->data, key->length)); @@ -2993,14 +2993,14 @@ TEST(X509Test, TestMLDSA65) { TEST(X509Test, TestBadSigAlgMLDSA65) { // This test generates a MLDSA65 certificate from the PEM encoding - // kDilithium3CertNull that has an explicit NULL in the signature algorithm. + // 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); // extract the asn1 bit string from the cert ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, nullptr, key->data, key->length)); @@ -3017,14 +3017,14 @@ TEST(X509Test, TestBadSigAlgMLDSA65) { TEST(X509Test, TestBadParamsMLDSA65) { // This test generates a MLDSA65 certificate from the PEM encoding - // kDilithium3CertParam that has an explicit NULL in the signature algorithm. + // kMLDSA65CertParam that has an explicit NULL in the signature algorithm. // After extracting the public key, verification should fail. - bssl::UniquePtr cert(CertFromPEM(kDilithium3CertParam)); + bssl::UniquePtr cert(CertFromPEM(kMLDSA65CertParam)); ASSERT_TRUE(cert); // extract the asn1 bit string from the cert ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_NISTDSA, + bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, nullptr, key->data, key->length)); diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 7bc0e7071f..100f1f7d0b 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_NISTDSA NID_NISTDSA +#define EVP_PKEY_PQDSA NID_PQDSA #endif #define EVP_PKEY_KEM NID_kem diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 923387eeb8..2ec2a9105b 100644 --- a/include/openssl/nid.h +++ b/include/openssl/nid.h @@ -4363,9 +4363,9 @@ extern "C" { #define NID_SecP256r1MLKEM768 992 #define OBJ_SecP256r1MLKEM768 1L, 3L, 9999L, 99L, 55L -#define SN_NISTDSA "NISTDSA" -#define NID_NISTDSA 993 -#define OBJ_NISTDSA 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L +#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 diff --git a/tool/speed.cc b/tool/speed.cc index a2238b5248..39c59b88f8 100644 --- a/tool/speed.cc +++ b/tool/speed.cc @@ -872,8 +872,8 @@ static bool SpeedDigestSignNID(const std::string &name, int nid, return true; } - // Setup CTX for Sign/Verify Operations of type EVP_PKEY_NISTDSA - BM_NAMESPACE::UniquePtr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_NISTDSA, 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); From 8d6ff48bbe5888bab04acccadf12eca319fb45ba Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 7 Nov 2024 08:51:37 -0800 Subject: [PATCH 09/28] added PQDSA assign --- crypto/dilithium/p_dilithium3.c | 4 +--- crypto/evp_extra/internal.h | 9 --------- crypto/fipsmodule/evp/evp.c | 15 +++++++++++++++ include/openssl/evp.h | 2 ++ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index 16849ef72f..0c247ab8db 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -106,12 +106,10 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { if (key == NULL || !PQDSA_KEY_init(key, pqdsa) || !pqdsa->method->keygen(key->public_key, key->secret_key) || - !EVP_PKEY_set_type(pkey, EVP_PKEY_PQDSA)) { + !EVP_PKEY_assign_PQDSA_KEY(pkey, key)) { PQDSA_KEY_free(key); return 0; } - - pkey->pkey.pqdsa_key = key; return 1; } diff --git a/crypto/evp_extra/internal.h b/crypto/evp_extra/internal.h index 57f193dd7f..5ed7d5be2b 100644 --- a/crypto/evp_extra/internal.h +++ b/crypto/evp_extra/internal.h @@ -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; diff --git a/crypto/fipsmodule/evp/evp.c b/crypto/fipsmodule/evp/evp.c index 7bfc79ea91..227b510a38 100644 --- a/crypto/fipsmodule/evp/evp.c +++ b/crypto/fipsmodule/evp/evp.c @@ -422,6 +422,17 @@ EC_KEY *EVP_PKEY_get1_EC_KEY(const EVP_PKEY *pkey) { return ec_key; } +#ifdef ENABLE_DILITHIUM +int EVP_PKEY_assign_PQDSA_KEY(EVP_PKEY *pkey, PQDSA_KEY *key) { + SET_DIT_AUTO_RESET; + const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_PQDSA); + assert(meth != NULL); + evp_pkey_set_method(pkey, meth); + pkey->pkey.ptr = key; + return key != NULL; +} +#endif + int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { // This function can only be used to assign RSA, DSA, EC, and DH keys. Other // key types have internal representations which are not exposed through the @@ -436,6 +447,10 @@ int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { return EVP_PKEY_assign_EC_KEY(pkey, key); case EVP_PKEY_DH: return EVP_PKEY_assign_DH(pkey, key); +#ifdef ENABLE_DILITHIUM + case EVP_PKEY_PQDSA: + return EVP_PKEY_assign_PQDSA_KEY(pkey, key); +#endif default: if (!EVP_PKEY_set_type(pkey, type)) { return 0; diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 100f1f7d0b..2c0c836a0d 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -181,6 +181,8 @@ OPENSSL_EXPORT int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key); OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey); OPENSSL_EXPORT DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey); +OPENSSL_EXPORT int EVP_PKEY_assign_PQDSA_KEY(EVP_PKEY *pkey, PQDSA_KEY *key); + // EVP_PKEY_CTX_set_dh_paramgen_prime_len sets the length of the DH prime // parameter p for DH parameter generation. If this function is not called, // the default length of 2048 is used. |pbits| must be greater than or equal From 91056cb9c81f7900894a59af2d2ac4a216e4da6a Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 7 Nov 2024 10:49:16 -0800 Subject: [PATCH 10/28] file structure change --- crypto/CMakeLists.txt | 9 +- .../dilithium/{sig_dilithium3.c => ml_dsa.c} | 3 +- .../dilithium/{sig_dilithium.h => ml_dsa.h} | 0 .../dilithium/{p_dilithium3.c => p_pqdsa.c} | 88 +----------------- .../{p_dilithium3_asn1.c => p_pqdsa_asn1.c} | 2 +- .../{p_dilithium_test.cc => p_pqdsa_test.cc} | 2 +- crypto/dilithium/pqdsa.c | 90 +++++++++++++++++++ crypto/evp_extra/internal.h | 2 +- crypto/evp_extra/print.c | 2 +- 9 files changed, 103 insertions(+), 95 deletions(-) rename crypto/dilithium/{sig_dilithium3.c => ml_dsa.c} (99%) rename crypto/dilithium/{sig_dilithium.h => ml_dsa.h} (100%) rename crypto/dilithium/{p_dilithium3.c => p_pqdsa.c} (71%) rename crypto/dilithium/{p_dilithium3_asn1.c => p_pqdsa_asn1.c} (99%) rename crypto/dilithium/{p_dilithium_test.cc => p_pqdsa_test.cc} (99%) create mode 100644 crypto/dilithium/pqdsa.c diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index b1a3310174..cba2cbc880 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() @@ -774,7 +775,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/sig_dilithium3.c b/crypto/dilithium/ml_dsa.c similarity index 99% rename from crypto/dilithium/sig_dilithium3.c rename to crypto/dilithium/ml_dsa.c index 37c66c3417..ba4a2495cc 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" diff --git a/crypto/dilithium/sig_dilithium.h b/crypto/dilithium/ml_dsa.h similarity index 100% rename from crypto/dilithium/sig_dilithium.h rename to crypto/dilithium/ml_dsa.h diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_pqdsa.c similarity index 71% rename from crypto/dilithium/p_dilithium3.c rename to crypto/dilithium/p_pqdsa.c index 0c247ab8db..64517783e8 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_pqdsa.c @@ -8,71 +8,15 @@ #include "../crypto/internal.h" #include "../fipsmodule/evp/internal.h" #include "../evp_extra/internal.h" -#include "sig_dilithium.h" +#include "ml_dsa.h" #include "internal.h" -#include "../fipsmodule/delocate.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 will be moved to a separate file location after CR for clearer review. -// These are analagous to the ec_key functions in crypto/fipsmodule/ec/ec_key.c +// PQDSA PKEY functions typedef struct { const PQDSA *pqdsa; } PQDSA_PKEY_CTX; -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->secret_key); - key->public_key = NULL; - key->secret_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->secret_key = OPENSSL_malloc(pqdsa->secret_key_len); - if (key->public_key == NULL || key->secret_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; -} - -// PQDSA PKEY functions - static int pkey_pqdsa_init(EVP_PKEY_CTX *ctx) { PQDSA_PKEY_CTX *dctx; dctx = OPENSSL_zalloc(sizeof(PQDSA_PKEY_CTX)); @@ -276,31 +220,3 @@ const EVP_PKEY_METHOD pqdsa_pkey_meth = { NULL /* encapsulate */, NULL /* decapsulate */, }; - -DEFINE_LOCAL_DATA(PQDSA_METHOD, sig_ml_dsa_65_method) { - out->keygen = ml_dsa_65_keypair; - out->sign = ml_dsa_65_sign; - out->verify = ml_dsa_65_verify; -} - -DEFINE_LOCAL_DATA(PQDSA, sig_ml_dsa_65) { - out->nid = NID_MLDSA65; - out->oid = kOIDMLDSA65; - out->oid_len = sizeof(kOIDMLDSA65); - out->comment = "MLDSA65 "; - out->public_key_len = MLDSA65_PUBLIC_KEY_BYTES; - out->secret_key_len = MLDSA65_PRIVATE_KEY_BYTES; - out->signature_len = MLDSA65_SIGNATURE_BYTES; - out->keygen_seed_len = MLDSA65_KEYGEN_SEED_BYTES; - out->sign_seed_len = MLDSA65_SIGNATURE_SEED_BYTES; - out->method = sig_ml_dsa_65_method(); -} - -const PQDSA *PQDSA_find_dsa_by_nid(int nid) { - switch (nid) { - case NID_MLDSA65: - return sig_ml_dsa_65(); - default: - return NULL; - } -} diff --git a/crypto/dilithium/p_dilithium3_asn1.c b/crypto/dilithium/p_pqdsa_asn1.c similarity index 99% rename from crypto/dilithium/p_dilithium3_asn1.c rename to crypto/dilithium/p_pqdsa_asn1.c index 1efe7ed4d2..763a92e5b7 100644 --- a/crypto/dilithium/p_dilithium3_asn1.c +++ b/crypto/dilithium/p_pqdsa_asn1.c @@ -10,7 +10,7 @@ #include "../evp_extra/internal.h" #include "../fipsmodule/evp/internal.h" #include "../internal.h" -#include "sig_dilithium.h" +#include "ml_dsa.h" #include "internal.h" static void pqdsa_free(EVP_PKEY *pkey) { diff --git a/crypto/dilithium/p_dilithium_test.cc b/crypto/dilithium/p_pqdsa_test.cc similarity index 99% rename from crypto/dilithium/p_dilithium_test.cc rename to crypto/dilithium/p_pqdsa_test.cc index ef866a4318..1e408c3025 100644 --- a/crypto/dilithium/p_dilithium_test.cc +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -20,7 +20,7 @@ #include "../test/file_test.h" #include "../test/test_util.h" #include "../rand_extra/pq_custom_randombytes.h" -#include "sig_dilithium.h" +#include "ml_dsa.h" // mldsa65kPublicKey is an example ML-DSA-65 public key static const uint8_t mldsa65kPublicKey[] = { diff --git a/crypto/dilithium/pqdsa.c b/crypto/dilithium/pqdsa.c new file mode 100644 index 0000000000..f371683e3a --- /dev/null +++ b/crypto/dilithium/pqdsa.c @@ -0,0 +1,90 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC +#include +#include + +#include +#include "internal.h" +#include "../fipsmodule/delocate.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->secret_key); + key->public_key = NULL; + key->secret_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->secret_key = OPENSSL_malloc(pqdsa->secret_key_len); + if (key->public_key == NULL || key->secret_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; +} +DEFINE_LOCAL_DATA(PQDSA_METHOD, sig_ml_dsa_65_method) { + out->keygen = ml_dsa_65_keypair; + out->sign = ml_dsa_65_sign; + out->verify = ml_dsa_65_verify; +} + +DEFINE_LOCAL_DATA(PQDSA, sig_ml_dsa_65) { + out->nid = NID_MLDSA65; + out->oid = kOIDMLDSA65; + out->oid_len = sizeof(kOIDMLDSA65); + out->comment = "MLDSA65 "; + out->public_key_len = MLDSA65_PUBLIC_KEY_BYTES; + out->secret_key_len = MLDSA65_PRIVATE_KEY_BYTES; + out->signature_len = MLDSA65_SIGNATURE_BYTES; + out->keygen_seed_len = MLDSA65_KEYGEN_SEED_BYTES; + out->sign_seed_len = MLDSA65_SIGNATURE_SEED_BYTES; + out->method = sig_ml_dsa_65_method(); +} + +const PQDSA *PQDSA_find_dsa_by_nid(int nid) { + switch (nid) { + case NID_MLDSA65: + return sig_ml_dsa_65(); + default: + return NULL; + } +} diff --git a/crypto/evp_extra/internal.h b/crypto/evp_extra/internal.h index 5ed7d5be2b..de956cba9e 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 diff --git a/crypto/evp_extra/print.c b/crypto/evp_extra/print.c index a53fa6f04f..98fbe04232 100644 --- a/crypto/evp_extra/print.c +++ b/crypto/evp_extra/print.c @@ -66,7 +66,7 @@ #include "../fipsmodule/rsa/internal.h" #ifdef ENABLE_DILITHIUM -#include "../dilithium/sig_dilithium.h" +#include "../dilithium/ml_dsa.h" #include "../dilithium/internal.h" #endif From c0d4e651b5accb0d1a05fc260635ce1d8968b3e8 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 7 Nov 2024 14:24:01 -0800 Subject: [PATCH 11/28] removed EVP_PKEY_nistdsa_set_params, implemented differently --- crypto/dilithium/internal.h | 2 + crypto/dilithium/p_pqdsa.c | 83 ++++++++++++++++++++++++++++---- crypto/dilithium/p_pqdsa_test.cc | 47 +++--------------- crypto/dilithium/pqdsa.c | 19 ++++++++ crypto/x509/x509_test.cc | 29 ++++------- include/openssl/evp.h | 18 ++++++- 6 files changed, 127 insertions(+), 71 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index 65e0c3303e..2ecc550c62 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -61,6 +61,8 @@ 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_secret_key(PQDSA_KEY *key, const uint8_t *in); #if defined(__cplusplus) } // extern C #endif diff --git a/crypto/dilithium/p_pqdsa.c b/crypto/dilithium/p_pqdsa.c index 64517783e8..a679866832 100644 --- a/crypto/dilithium/p_pqdsa.c +++ b/crypto/dilithium/p_pqdsa.c @@ -137,8 +137,9 @@ static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, return 1; } +// Additional PQDSA specific EVP functions. + // This function sets pqdsa parameters defined by |nid| in |pkey|. -// If |pkey| already has a public key set, this public key is preserved. int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid) { const PQDSA *pqdsa = PQDSA_find_dsa_by_nid(nid); @@ -147,14 +148,6 @@ int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid) { return 0; } - // if the public key has already been set either by EVP_parse_public_key or - // some other method that returns a PKEY without setting params, then - // we preserve that PKEY and just populate the params - if (pkey->pkey.pqdsa_key != NULL) { - pkey->pkey.pqdsa_key->pqdsa = pqdsa; - return 1; - } - evp_pkey_set_method(pkey, &pqdsa_asn1_meth); PQDSA_KEY *key = PQDSA_KEY_new(); @@ -196,6 +189,78 @@ int EVP_PKEY_CTX_pqdsa_set_params(EVP_PKEY_CTX *ctx, int nid) { 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_secret_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->secret_key_len != len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); + goto err; + } + + if (!PQDSA_KEY_set_raw_secret_key(ret->pkey.pqdsa_key, in)) { + // PQDSA_KEY_set_raw_secret_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 */, diff --git a/crypto/dilithium/p_pqdsa_test.cc b/crypto/dilithium/p_pqdsa_test.cc index 1e408c3025..5b14f2dec2 100644 --- a/crypto/dilithium/p_pqdsa_test.cc +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -584,9 +584,9 @@ TEST_P(PQDSAParameterTest, NewKeyFromBytes) { 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_new_raw_public_key for generating a new PKEY from raw pub + // 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_new_raw_private_key for generating a new PKEY from raw priv + // Test EVP_PKEY_pqdsa_new_raw_secret_key for generating a new PKEY from raw priv int nid = GetParam().nid; size_t pk_len = GetParam().public_key_len; @@ -608,14 +608,8 @@ TEST_P(PQDSAParameterTest, RawFunctions) { EXPECT_EQ(pub_len, pk_len); ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pub_buf.data(), &pub_len)); - // Generate a new pkey with only public key set from the extracted public key - bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, - nullptr, - pub_buf.data(), - pk_len)); + bssl::UniquePtr pkey_pk_new(EVP_PKEY_pqdsa_new_raw_public_key(nid, pub_buf.data(), pk_len)); ASSERT_TRUE(pkey_pk_new); - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey_pk_new.get(), nid); // The public key must encode properly. bssl::ScopedCBB cbb; @@ -640,15 +634,8 @@ TEST_P(PQDSAParameterTest, RawFunctions) { EXPECT_EQ(priv_len, sk_len); ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), priv_buf.data(), &priv_len)); - // Generate a new pkey with only secret key set from the extracted secret key - bssl::UniquePtr pkey_sk_new(EVP_PKEY_new_raw_private_key(EVP_PKEY_PQDSA, - nullptr, - priv_buf.data(), - sk_len)); + bssl::UniquePtr pkey_sk_new(EVP_PKEY_pqdsa_new_raw_secret_key(nid, priv_buf.data(), sk_len)); ASSERT_TRUE(pkey_sk_new); - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey_sk_new.get(), nid); - // The private key must encode properly. ASSERT_TRUE(CBB_init(cbb.get(), 0)); @@ -661,11 +648,7 @@ TEST_P(PQDSAParameterTest, RawFunctions) { bssl::UniquePtr pkey_priv_from_der(EVP_parse_private_key(&cbs)); ASSERT_TRUE(pkey_priv_from_der); - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey_priv_from_der.get(), nid); - // check that the private key from pkey_priv_from_der matches the original key - EXPECT_EQ(Bytes(pkey_priv_from_der->pkey.pqdsa_key->secret_key, - pkey_priv_from_der->pkey.pqdsa_key->pqdsa->secret_key_len), + EXPECT_EQ(Bytes(pkey_priv_from_der->pkey.pqdsa_key->secret_key, priv_len), Bytes(priv_buf.data(), sk_len)); } @@ -725,7 +708,6 @@ TEST_P(PQDSAParameterTest, SIGOperations) { 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 - // Test that extacting the public key from the PKEY is the same as the original key int nid = GetParam().nid; size_t pk_len = GetParam().public_key_len; @@ -733,14 +715,8 @@ TEST_P(PQDSAParameterTest, MarshalParse) { const uint8_t * kPublicKeySPKI = GetParam().kPublicKeySPKI; size_t kPublicKeySPKI_len = GetParam().kPublicKeySPKI_len; - // Generate a new pkey with only public key set from the extracted public key - bssl::UniquePtr pkey_pk_new(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, - nullptr, - kPublicKey, - pk_len)); + bssl::UniquePtr pkey_pk_new(EVP_PKEY_pqdsa_new_raw_public_key(nid, kPublicKey, pk_len)); ASSERT_TRUE(pkey_pk_new); - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey_pk_new.get(), nid); // Encode the public key as DER bssl::ScopedCBB cbb; @@ -759,17 +735,6 @@ TEST_P(PQDSAParameterTest, MarshalParse) { CBS_init(&cbs, der, der_len); bssl::UniquePtr pkey_from_der(EVP_parse_public_key(&cbs)); ASSERT_TRUE(pkey_from_der); - - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey_from_der.get(), nid); - - // Extract the public key and check it is equivalent to original key - std::vector pub_buf(pk_len); - size_t pub_len; - ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey_from_der.get(), nullptr, &pub_len)); - EXPECT_EQ(pub_len, pk_len); - ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey_from_der.get(), pub_buf.data(), &pub_len)); - EXPECT_EQ(Bytes(kPublicKey, pk_len), Bytes(pub_buf.data(), pub_len)); } #else diff --git a/crypto/dilithium/pqdsa.c b/crypto/dilithium/pqdsa.c index f371683e3a..9404e0858a 100644 --- a/crypto/dilithium/pqdsa.c +++ b/crypto/dilithium/pqdsa.c @@ -61,6 +61,25 @@ void PQDSA_KEY_free(PQDSA_KEY *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_secret_key(PQDSA_KEY *key, const uint8_t *in) { + key->secret_key = OPENSSL_memdup(in, key->pqdsa->secret_key_len); + if (key->secret_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; diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index be3e630758..0d69dc7ac0 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -2981,13 +2981,10 @@ TEST(X509Test, TestMLDSA65) { //extract the asn1 bit string from the cert ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, - nullptr, - key->data, - key->length)); + bssl::UniquePtr pkey(EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, + key->data, + key->length)); ASSERT_TRUE(pkey); - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey.get(), NID_MLDSA65); ASSERT_TRUE(X509_verify(cert.get(), pkey.get())); } @@ -3000,14 +2997,10 @@ TEST(X509Test, TestBadSigAlgMLDSA65) { // extract the asn1 bit string from the cert ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, - nullptr, - key->data, - key->length)); + bssl::UniquePtr pkey(EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, + key->data, + key->length)); ASSERT_TRUE(pkey); - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey.get(), NID_MLDSA65); - ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); ASSERT_EQ(ERR_LIB_X509, ERR_GET_LIB(err)); @@ -3024,14 +3017,10 @@ TEST(X509Test, TestBadParamsMLDSA65) { // extract the asn1 bit string from the cert ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_PQDSA, - nullptr, - key->data, - key->length)); + bssl::UniquePtr pkey(EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, + key->data, + key->length)); ASSERT_TRUE(pkey); - // set the correct params for the PKEY - EVP_PKEY_pqdsa_set_params(pkey.get(), NID_MLDSA65); - ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); ASSERT_EQ(ERR_LIB_ASN1, ERR_GET_LIB(err)); diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 2c0c836a0d..4a93fcd1e2 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -181,7 +181,9 @@ OPENSSL_EXPORT int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key); OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey); OPENSSL_EXPORT DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey); +#ifdef ENABLE_DILITHIUM OPENSSL_EXPORT int EVP_PKEY_assign_PQDSA_KEY(EVP_PKEY *pkey, PQDSA_KEY *key); +#endif // EVP_PKEY_CTX_set_dh_paramgen_prime_len sets the length of the DH prime // parameter p for DH parameter generation. If this function is not called, @@ -948,13 +950,27 @@ 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); -// Signature specific functions. +// 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_secret_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_secret_key(int nid, const uint8_t *in, size_t len); +#endif + // Diffie-Hellman-specific control functions. // EVP_PKEY_CTX_set_dh_pad configures configures whether |ctx|, which must be an From bcbb8322f367532268ad01c5a940a5518b349562 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Fri, 8 Nov 2024 07:33:01 -0800 Subject: [PATCH 12/28] CR fixes --- crypto/dilithium/internal.h | 8 ++++---- crypto/dilithium/ml_dsa.c | 12 ++++++------ crypto/dilithium/ml_dsa.h | 18 ++---------------- crypto/dilithium/p_pqdsa.c | 16 ++++++++-------- crypto/fipsmodule/evp/evp.c | 15 --------------- include/openssl/evp.h | 4 ---- 6 files changed, 20 insertions(+), 53 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index 2ecc550c62..964797f165 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -20,16 +20,16 @@ typedef struct { size_t *sig_len, const uint8_t *message, size_t message_len, - const uint8_t *ctx, - size_t ctx_len); + const uint8_t *pre, + size_t pre_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, - size_t ctx_len); + const uint8_t *pre, + size_t pre_len); } PQDSA_METHOD; diff --git a/crypto/dilithium/ml_dsa.c b/crypto/dilithium/ml_dsa.c index ba4a2495cc..994b403737 100644 --- a/crypto/dilithium/ml_dsa.c +++ b/crypto/dilithium/ml_dsa.c @@ -37,12 +37,12 @@ int ml_dsa_65_sign(const uint8_t *secret_key /* IN */, 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 *pre /* IN */, + size_t pre_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); + pre, pre_len, secret_key); } int ml_dsa_65_verify(const uint8_t *public_key /* IN */, @@ -50,10 +50,10 @@ int ml_dsa_65_verify(const uint8_t *public_key /* IN */, size_t sig_len /* IN */, const uint8_t *message /* IN */, size_t message_len /* IN */, - const uint8_t *ctx /* IN */, - size_t ctx_len /* IN */) { + const uint8_t *pre /* IN */, + size_t pre_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); + pre, pre_len, public_key); } diff --git a/crypto/dilithium/ml_dsa.h b/crypto/dilithium/ml_dsa.h index 491feb52f1..3a1f786b6c 100644 --- a/crypto/dilithium/ml_dsa.h +++ b/crypto/dilithium/ml_dsa.h @@ -1,8 +1,8 @@ // 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 +#ifndef ML_DSA_H +#define ML_DSA_H #include #include @@ -15,17 +15,9 @@ #define MLDSA65_KEYGEN_SEED_BYTES 32 #define MLDSA65_SIGNATURE_SEED_BYTES 32 -// 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 |secret_key| is a -// pointer to bit-packed secret key, |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, and |ctx_len| is the length of the context -// string (max length 255 bytes). It returns 0 upon success. int ml_dsa_65_sign(const uint8_t *secret_key, uint8_t *sig, size_t *sig_len, @@ -34,12 +26,6 @@ int ml_dsa_65_sign(const uint8_t *secret_key, const uint8_t *ctx, size_t ctx_len); -// ml_dsa_65_verify generates an ML-DSA-65 signature. Where |public_key| is a -// pointer to bit-packed public key, |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, and |ctx_len| is the length of the context string (max length 255 -// bytes). Returns 0 if signature could be verified successfully and -1 otherwise. int ml_dsa_65_verify(const uint8_t *public_key, const uint8_t *sig, size_t sig_len, diff --git a/crypto/dilithium/p_pqdsa.c b/crypto/dilithium/p_pqdsa.c index a679866832..5d5831e36e 100644 --- a/crypto/dilithium/p_pqdsa.c +++ b/crypto/dilithium/p_pqdsa.c @@ -50,7 +50,7 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { if (key == NULL || !PQDSA_KEY_init(key, pqdsa) || !pqdsa->method->keygen(key->public_key, key->secret_key) || - !EVP_PKEY_assign_PQDSA_KEY(pkey, key)) { + !EVP_PKEY_assign(pkey, EVP_PKEY_PQDSA, key)) { PQDSA_KEY_free(key); return 0; } @@ -58,8 +58,8 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { } static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, - size_t *siglen, const uint8_t *tbs, - size_t tbslen) { + size_t *siglen, const uint8_t *message, + size_t message_len) { PQDSA_PKEY_CTX *dctx = ctx->data; const PQDSA *pqdsa = dctx->pqdsa; if (pqdsa == NULL) { @@ -72,7 +72,7 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, // Caller is getting parameter values. if (sig == NULL) { - if (pqdsa != NULL) { + if (siglen != NULL) { *siglen = pqdsa->signature_len; return 1; } @@ -97,7 +97,7 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, return 0; } - if (pqdsa->method->sign(key->secret_key, sig, siglen, tbs, tbslen, NULL, 0) != 0) { + if (pqdsa->method->sign(key->secret_key, sig, siglen, message, message_len, NULL, 0) != 0) { OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); return 0; } @@ -105,8 +105,8 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, } static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, - size_t siglen, const uint8_t *tbs, - size_t tbslen) { + size_t siglen, const uint8_t *message, + size_t message_len) { PQDSA_PKEY_CTX *dctx = ctx->data; const PQDSA *pqdsa = dctx->pqdsa; @@ -129,7 +129,7 @@ static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; if (siglen != pqdsa->signature_len || - pqdsa->method->verify(key->public_key, sig, siglen, tbs, tbslen, NULL, 0) != 0) { + pqdsa->method->verify(key->public_key, sig, siglen, message, message_len, NULL, 0) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); return 0; } diff --git a/crypto/fipsmodule/evp/evp.c b/crypto/fipsmodule/evp/evp.c index 227b510a38..7bfc79ea91 100644 --- a/crypto/fipsmodule/evp/evp.c +++ b/crypto/fipsmodule/evp/evp.c @@ -422,17 +422,6 @@ EC_KEY *EVP_PKEY_get1_EC_KEY(const EVP_PKEY *pkey) { return ec_key; } -#ifdef ENABLE_DILITHIUM -int EVP_PKEY_assign_PQDSA_KEY(EVP_PKEY *pkey, PQDSA_KEY *key) { - SET_DIT_AUTO_RESET; - const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_PQDSA); - assert(meth != NULL); - evp_pkey_set_method(pkey, meth); - pkey->pkey.ptr = key; - return key != NULL; -} -#endif - int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { // This function can only be used to assign RSA, DSA, EC, and DH keys. Other // key types have internal representations which are not exposed through the @@ -447,10 +436,6 @@ int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { return EVP_PKEY_assign_EC_KEY(pkey, key); case EVP_PKEY_DH: return EVP_PKEY_assign_DH(pkey, key); -#ifdef ENABLE_DILITHIUM - case EVP_PKEY_PQDSA: - return EVP_PKEY_assign_PQDSA_KEY(pkey, key); -#endif default: if (!EVP_PKEY_set_type(pkey, type)) { return 0; diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 4a93fcd1e2..5c6cf05672 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -181,10 +181,6 @@ OPENSSL_EXPORT int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key); OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey); OPENSSL_EXPORT DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey); -#ifdef ENABLE_DILITHIUM -OPENSSL_EXPORT int EVP_PKEY_assign_PQDSA_KEY(EVP_PKEY *pkey, PQDSA_KEY *key); -#endif - // EVP_PKEY_CTX_set_dh_paramgen_prime_len sets the length of the DH prime // parameter p for DH parameter generation. If this function is not called, // the default length of 2048 is used. |pbits| must be greater than or equal From 7435f9b2920753efc71a6461c55be213dc24da65 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Tue, 12 Nov 2024 11:28:18 -0800 Subject: [PATCH 13/28] CR fixes --- crypto/CMakeLists.txt | 8 +- crypto/dilithium/internal.h | 4 +- crypto/dilithium/ml_dsa.c | 12 +- crypto/dilithium/ml_dsa.h | 8 +- crypto/dilithium/p_pqdsa.c | 20 +- crypto/evp_extra/evp_extra_test.cc | 314 ++++++++++++++++++++++++++++- 6 files changed, 338 insertions(+), 28 deletions(-) diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index cba2cbc880..6db5ac00b6 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -324,9 +324,9 @@ if(ENABLE_DILITHIUM) DILITHIUM_SOURCES dilithium/pqdsa.c - dilithium/p_pqdsa.c - dilithium/p_pqdsa_asn1.c - dilithium/ml_dsa.c + dilithium/p_pqdsa.c + dilithium/p_pqdsa_asn1.c + dilithium/ml_dsa.c ) endif() @@ -775,7 +775,7 @@ if(BUILD_TESTING) ecdh_extra/ecdh_test.cc dh_extra/dh_test.cc digest_extra/digest_test.cc - dilithium/p_pqdsa_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 index 964797f165..f4edf212e7 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -1,8 +1,8 @@ // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR ISC -#ifndef AWSLC_HEADER_SIG_INTERNAL_H -#define AWSLC_HEADER_SIG_INTERNAL_H +#ifndef AWSLC_HEADER_PQDSA_INTERNAL_H +#define AWSLC_HEADER_PQDSA_INTERNAL_H #include diff --git a/crypto/dilithium/ml_dsa.c b/crypto/dilithium/ml_dsa.c index 994b403737..6727c569c2 100644 --- a/crypto/dilithium/ml_dsa.c +++ b/crypto/dilithium/ml_dsa.c @@ -37,12 +37,12 @@ int ml_dsa_65_sign(const uint8_t *secret_key /* IN */, size_t *sig_len /* OUT */, const uint8_t *message /* IN */, size_t message_len /* IN */, - const uint8_t *pre /* IN */, - size_t pre_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, - pre, pre_len, secret_key); + ctx_string, ctx_string_len, secret_key) == 0; } int ml_dsa_65_verify(const uint8_t *public_key /* IN */, @@ -50,10 +50,10 @@ int ml_dsa_65_verify(const uint8_t *public_key /* IN */, size_t sig_len /* IN */, const uint8_t *message /* IN */, size_t message_len /* IN */, - const uint8_t *pre /* IN */, - size_t pre_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, - pre, pre_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 index 3a1f786b6c..a6563d50ce 100644 --- a/crypto/dilithium/ml_dsa.h +++ b/crypto/dilithium/ml_dsa.h @@ -23,14 +23,14 @@ int ml_dsa_65_sign(const uint8_t *secret_key, size_t *sig_len, const uint8_t *message, size_t message_len, - const uint8_t *ctx, - size_t ctx_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, - size_t ctx_len); + const uint8_t *ctx_string, + size_t ctx_string_len); #endif diff --git a/crypto/dilithium/p_pqdsa.c b/crypto/dilithium/p_pqdsa.c index 5d5831e36e..2e73236267 100644 --- a/crypto/dilithium/p_pqdsa.c +++ b/crypto/dilithium/p_pqdsa.c @@ -57,8 +57,8 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { return 1; } -static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, - size_t *siglen, const uint8_t *message, +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; @@ -72,13 +72,13 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, // Caller is getting parameter values. if (sig == NULL) { - if (siglen != NULL) { - *siglen = pqdsa->signature_len; + if (sig_len != NULL) { + *sig_len = pqdsa->signature_len; return 1; } } - if (*siglen != pqdsa->signature_len) { + if (*sig_len != pqdsa->signature_len) { OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); return 0; } @@ -97,7 +97,7 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, return 0; } - if (pqdsa->method->sign(key->secret_key, sig, siglen, message, message_len, NULL, 0) != 0) { + if (!pqdsa->method->sign(key->secret_key, sig, sig_len, message, message_len, NULL, 0)) { OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); return 0; } @@ -105,7 +105,7 @@ static int pkey_pqdsa_sign_signature(EVP_PKEY_CTX *ctx, uint8_t *sig, } static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, - size_t siglen, const uint8_t *message, + size_t sig_len, const uint8_t *message, size_t message_len) { PQDSA_PKEY_CTX *dctx = ctx->data; const PQDSA *pqdsa = dctx->pqdsa; @@ -128,8 +128,8 @@ static int pkey_pqdsa_verify_signature(EVP_PKEY_CTX *ctx, const uint8_t *sig, PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; - if (siglen != pqdsa->signature_len || - pqdsa->method->verify(key->public_key, sig, siglen, message, message_len, NULL, 0) != 0) { + 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; } @@ -269,7 +269,7 @@ const EVP_PKEY_METHOD pqdsa_pkey_meth = { pkey_pqdsa_keygen, NULL /* sign_init */, NULL /* sign */, - pkey_pqdsa_sign_signature, + pkey_pqdsa_sign_message, NULL /* verify_init */, NULL /* verify */, pkey_pqdsa_verify_signature, diff --git a/crypto/evp_extra/evp_extra_test.cc b/crypto/evp_extra/evp_extra_test.cc index 9ac067c55b..3bec8ea4a1 100644 --- a/crypto/evp_extra/evp_extra_test.cc +++ b/crypto/evp_extra/evp_extra_test.cc @@ -701,8 +701,318 @@ static const uint8_t kInvalidPrivateKey[] = { // 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 kExampleMLDSA65KeyDER[] = { - 0x30, 0x82, 0x0F, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x0A, 0x06, 0x08, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x04, 0x82, 0x0F, 0xC0, 0x9B, 0x77, 0xAB, 0x96, 0x9D, 0x65, 0xA2, 0xC1, 0x55, 0x65, 0x02, 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, 0x04, 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, 0x09, 0x2C, 0xBB, 0x6A, 0x54, 0x6D, 0x9D, 0x5D, 0x97, 0xD3, 0xCC, 0x20, 0x31, 0x9C, 0x7E, 0x2B, 0x5C, 0x42, 0x9E, 0x2E, 0xCB, 0x41, 0x38, 0x84, 0x02, 0x03, 0x24, 0x75, 0x37, 0x23, 0x73, 0x38, 0x85, 0x00, 0x62, 0x42, 0x24, 0x76, 0x38, 0x88, 0x21, 0x31, 0x76, 0x74, 0x55, 0x51, 0x28, 0x34, 0x08, 0x41, 0x32, 0x67, 0x40, 0x11, 0x81, 0x62, 0x48, 0x27, 0x51, 0x85, 0x33, 0x61, 0x12, 0x22, 0x24, 0x30, 0x28, 0x75, 0x20, 0x03, 0x63, 0x11, 0x71, 0x88, 0x38, 0x88, 0x58, 0x84, 0x16, 0x66, 0x14, 0x22, 0x27, 0x28, 0x11, 0x44, 0x37, 0x76, 0x15, 0x24, 0x08, 0x56, 0x40, 0x13, 0x71, 0x74, 0x46, 0x88, 0x14, 0x37, 0x13, 0x00, 0x01, 0x48, 0x44, 0x04, 0x83, 0x67, 0x88, 0x16, 0x00, 0x13, 0x17, 0x06, 0x38, 0x18, 0x76, 0x15, 0x14, 0x67, 0x16, 0x76, 0x57, 0x24, 0x53, 0x86, 0x31, 0x34, 0x16, 0x34, 0x03, 0x08, 0x68, 0x65, 0x77, 0x36, 0x86, 0x37, 0x30, 0x76, 0x20, 0x51, 0x33, 0x82, 0x28, 0x72, 0x45, 0x35, 0x83, 0x06, 0x58, 0x58, 0x37, 0x71, 0x86, 0x00, 0x84, 0x18, 0x11, 0x54, 0x87, 0x12, 0x78, 0x75, 0x23, 0x45, 0x81, 0x17, 0x42, 0x01, 0x00, 0x34, 0x32, 0x55, 0x38, 0x88, 0x25, 0x52, 0x62, 0x05, 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, 0x04, 0x87, 0x22, 0x00, 0x66, 0x74, 0x52, 0x18, 0x32, 0x07, 0x61, 0x27, 0x68, 0x70, 0x65, 0x78, 0x85, 0x66, 0x60, 0x05, 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, 0x01, 0x78, 0x70, 0x16, 0x11, 0x35, 0x58, 0x58, 0x08, 0x82, 0x55, 0x61, 0x85, 0x17, 0x46, 0x70, 0x77, 0x77, 0x37, 0x42, 0x35, 0x56, 0x53, 0x85, 0x07, 0x64, 0x13, 0x34, 0x51, 0x25, 0x78, 0x12, 0x21, 0x14, 0x74, 0x81, 0x32, 0x41, 0x00, 0x60, 0x78, 0x71, 0x22, 0x22, 0x56, 0x48, 0x57, 0x24, 0x65, 0x40, 0x36, 0x03, 0x03, 0x17, 0x86, 0x31, 0x44, 0x48, 0x55, 0x60, 0x55, 0x84, 0x68, 0x76, 0x16, 0x15, 0x40, 0x82, 0x64, 0x88, 0x47, 0x88, 0x44, 0x58, 0x46, 0x05, 0x02, 0x47, 0x27, 0x64, 0x20, 0x74, 0x14, 0x74, 0x02, 0x18, 0x21, 0x50, 0x42, 0x43, 0x14, 0x63, 0x05, 0x36, 0x08, 0x38, 0x80, 0x86, 0x80, 0x61, 0x15, 0x80, 0x56, 0x53, 0x13, 0x70, 0x64, 0x66, 0x20, 0x17, 0x21, 0x50, 0x68, 0x07, 0x53, 0x34, 0x73, 0x17, 0x50, 0x68, 0x72, 0x43, 0x02, 0x00, 0x80, 0x07, 0x37, 0x85, 0x72, 0x12, 0x87, 0x73, 0x46, 0x45, 0x56, 0x66, 0x02, 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, 0x05, 0x07, 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, 0x01, 0x75, 0x57, 0x42, 0x88, 0x21, 0x22, 0x77, 0x68, 0x22, 0x43, 0x84, 0x14, 0x51, 0x73, 0x68, 0x54, 0x62, 0x08, 0x83, 0x75, 0x41, 0x10, 0x15, 0x14, 0x57, 0x73, 0x42, 0x13, 0x20, 0x52, 0x76, 0x72, 0x34, 0x18, 0x10, 0x00, 0x18, 0x17, 0x55, 0x30, 0x88, 0x47, 0x23, 0x00, 0x76, 0x44, 0x85, 0x25, 0x04, 0x03, 0x88, 0x00, 0x70, 0x10, 0x70, 0x01, 0x80, 0x12, 0x04, 0x73, 0x20, 0x72, 0x21, 0x24, 0x37, 0x04, 0x01, 0x63, 0x76, 0x04, 0x71, 0x30, 0x31, 0x17, 0x20, 0x18, 0x37, 0x23, 0x44, 0x03, 0x08, 0x77, 0x63, 0x73, 0x61, 0x43, 0x70, 0x11, 0x06, 0x84, 0x73, 0x26, 0x38, 0x78, 0x23, 0x61, 0x12, 0x45, 0x84, 0x76, 0x31, 0x23, 0x67, 0x37, 0x07, 0x73, 0x13, 0x46, 0x42, 0x51, 0x13, 0x12, 0x05, 0x15, 0x28, 0x57, 0x64, 0x62, 0x82, 0x42, 0x06, 0x83, 0x25, 0x12, 0x20, 0x40, 0x48, 0x21, 0x47, 0x73, 0x38, 0x13, 0x32, 0x10, 0x73, 0x36, 0x57, 0x03, 0x00, 0x31, 0x54, 0x78, 0x40, 0x23, 0x21, 0x14, 0x35, 0x13, 0x62, 0x83, 0x56, 0x35, 0x87, 0x44, 0x65, 0x74, 0x05, 0x66, 0x76, 0x26, 0x35, 0x17, 0x18, 0x67, 0x12, 0x06, 0x00, 0x42, 0x85, 0x71, 0x20, 0x62, 0x81, 0x22, 0x05, 0x76, 0x32, 0x77, 0x60, 0x65, 0x84, 0x64, 0x14, 0x60, 0x08, 0x55, 0x65, 0x21, 0x18, 0x08, 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, 0x05, 0x81, 0x84, 0x34, 0x78, 0x70, 0x65, 0x34, 0x10, 0x76, 0x76, 0x20, 0x76, 0x33, 0x33, 0x22, 0x76, 0x75, 0x28, 0x03, 0x04, 0x21, 0x28, 0x73, 0x03, 0x57, 0x72, 0x03, 0x35, 0x37, 0x66, 0x88, 0x23, 0x88, 0x27, 0x43, 0x32, 0x26, 0x05, 0x20, 0x36, 0x32, 0x78, 0x54, 0x83, 0x38, 0x86, 0x81, 0x78, 0x01, 0x63, 0x21, 0x75, 0x82, 0x01, 0x73, 0x18, 0x00, 0x42, 0x54, 0x67, 0x26, 0x52, 0x38, 0x18, 0x65, 0x87, 0x36, 0x86, 0x53, 0x84, 0x20, 0x06, 0x23, 0x62, 0x73, 0x04, 0x14, 0x83, 0x77, 0x00, 0x57, 0x86, 0x84, 0x70, 0x48, 0x02, 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, 0x02, 0x56, 0x62, 0x67, 0x05, 0x34, 0x54, 0x64, 0x68, 0x25, 0x15, 0x55, 0x88, 0x43, 0x58, 0x73, 0x77, 0x65, 0x46, 0x48, 0x36, 0x06, 0x86, 0x32, 0x80, 0x80, 0x18, 0x72, 0x02, 0x54, 0x54, 0x72, 0x10, 0x65, 0x70, 0x41, 0x63, 0x47, 0x35, 0x40, 0x75, 0x02, 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, 0x06, 0x42, 0x75, 0x16, 0x17, 0x58, 0x04, 0x81, 0x05, 0x48, 0x54, 0x78, 0x53, 0x71, 0x06, 0x28, 0x41, 0x63, 0x81, 0x67, 0x00, 0x18, 0x25, 0x24, 0x14, 0x70, 0x85, 0x70, 0x80, 0x72, 0x48, 0x23, 0x21, 0x47, 0x13, 0x74, 0x72, 0x04, 0x27, 0x20, 0x75, 0x06, 0x80, 0x12, 0x24, 0x18, 0x57, 0x75, 0x45, 0x33, 0x80, 0x47, 0x28, 0x25, 0x80, 0x86, 0x06, 0x67, 0x23, 0x51, 0x80, 0x06, 0x72, 0x34, 0x30, 0x16, 0x25, 0x15, 0x52, 0x16, 0x57, 0x77, 0x45, 0x01, 0x48, 0x83, 0x35, 0x58, 0x68, 0x77, 0x03, 0x20, 0x34, 0x70, 0x23, 0x66, 0x14, 0x85, 0x00, 0x05, 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, 0x02, 0x62, 0x75, 0x86, 0x57, 0x82, 0x38, 0x34, 0x85, 0x21, 0x74, 0x15, 0x55, 0x26, 0x53, 0x16, 0x70, 0x82, 0x87, 0x17, 0x04, 0x63, 0x28, 0x21, 0x41, 0x61, 0x66, 0x16, 0x78, 0x37, 0x05, 0x81, 0x13, 0x26, 0x16, 0x56, 0x56, 0x85, 0x04, 0x72, 0x40, 0x64, 0x74, 0x13, 0x85, 0x20, 0x27, 0x14, 0x62, 0x72, 0x67, 0x70, 0x33, 0x25, 0x78, 0x48, 0x01, 0x17, 0x77, 0x14, 0x33, 0x41, 0x65, 0x05, 0x08, 0x00, 0x71, 0x44, 0x88, 0x08, 0x48, 0x02, 0x60, 0x12, 0x88, 0x05, 0x74, 0x56, 0x04, 0x77, 0x04, 0x52, 0x04, 0x31, 0x11, 0x81, 0x78, 0x88, 0x21, 0x11, 0x26, 0x51, 0x60, 0x67, 0x20, 0x37, 0x52, 0x01, 0x63, 0x85, 0x16, 0x68, 0x47, 0x65, 0x25, 0x02, 0x01, 0x18, 0x32, 0x00, 0x57, 0x33, 0x37, 0x38, 0x25, 0x27, 0x36, 0x21, 0x06, 0x40, 0x03, 0x74, 0x43, 0x24, 0x35, 0x86, 0x53, 0x88, 0x53, 0x16, 0x16, 0x02, 0x88, 0x44, 0x22, 0x25, 0x72, 0x63, 0x85, 0x17, 0x81, 0x56, 0x47, 0x16, 0x65, 0x02, 0x24, 0x05, 0x58, 0x55, 0x86, 0x72, 0x18, 0x21, 0x71, 0x86, 0x65, 0x61, 0x88, 0x85, 0x84, 0x70, 0x47, 0x27, 0x63, 0x73, 0x01, 0x26, 0x27, 0x85, 0x54, 0x85, 0x55, 0x45, 0x73, 0x30, 0x36, 0x44, 0x36, 0x45, 0x52, 0x43, 0x08, 0x14, 0x22, 0x64, 0x77, 0x36, 0x43, 0x14, 0x33, 0x66, 0x10, 0x56, 0x84, 0x42, 0x18, 0x77, 0x71, 0x27, 0x86, 0x84, 0x21, 0x26, 0x03, 0x22, 0x14, 0x47, 0x00, 0x51, 0x84, 0x28, 0x52, 0x66, 0x40, 0x66, 0x55, 0x85, 0x67, 0x02, 0x74, 0x06, 0x15, 0x72, 0x87, 0x40, 0x24, 0x71, 0x43, 0x74, 0x10, 0x27, 0x53, 0x42, 0x10, 0x03, 0x77, 0x01, 0x84, 0x08, 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, 0x04, 0x03, 0x14, 0x87, 0x31, 0x38, 0x22, 0x65, 0x68, 0x68, 0x88, 0x10, 0x32, 0x71, 0x77, 0x05, 0x51, 0x76, 0x68, 0x40, 0x52, 0x36, 0x63, 0x02, 0x76, 0x84, 0x50, 0x76, 0x27, 0x06, 0x77, 0x58, 0x52, 0x52, 0x74, 0x78, 0x77, 0x77, 0x50, 0x30, 0x84, 0x54, 0x28, 0x53, 0x70, 0x82, 0x07, 0x21, 0x06, 0x64, 0x35, 0x62, 0x80, 0x55, 0x10, 0x71, 0x82, 0x02, 0x66, 0x81, 0x40, 0x57, 0x61, 0x07, 0x16, 0x02, 0x72, 0x67, 0x06, 0x24, 0x88, 0x23, 0x88, 0x63, 0x83, 0x81, 0x14, 0x40, 0x07, 0x17, 0x15, 0x20, 0x63, 0x76, 0x22, 0x75, 0x81, 0x70, 0x43, 0x81, 0x80, 0x43, 0x04, 0x51, 0x78, 0x40, 0x63, 0x36, 0x00, 0x77, 0x40, 0x24, 0x53, 0x11, 0x44, 0x65, 0x62, 0x56, 0x77, 0x20, 0x21, 0x25, 0x08, 0x25, 0x63, 0x34, 0x54, 0x76, 0x53, 0x06, 0x13, 0x01, 0x80, 0x25, 0x77, 0x44, 0x38, 0x17, 0x32, 0x36, 0x13, 0x32, 0x27, 0x00, 0x37, 0x60, 0x63, 0x74, 0x06, 0x52, 0x05, 0x72, 0x83, 0x83, 0x84, 0x28, 0x71, 0x15, 0x38, 0x17, 0x47, 0x08, 0x37, 0x42, 0x67, 0x86, 0x38, 0x62, 0x65, 0x26, 0x23, 0x84, 0x22, 0x38, 0x66, 0x06, 0xD9, 0x77, 0xF8, 0x41, 0xCB, 0x87, 0xD3, 0x3F, 0x76, 0xEB, 0x57, 0x71, 0xFF, 0xBF, 0x14, 0x3B, 0x4C, 0x53, 0x01, 0xA8, 0x24, 0xAC, 0xB4, 0x71, 0x4A, 0xD8, 0xAF, 0xCB, 0x45, 0x70, 0x6E, 0xF8, 0x89, 0xB6, 0x31, 0xA7, 0x8B, 0x4A, 0xCF, 0x6C, 0x42, 0x8E, 0x08, 0xCE, 0x55, 0x7D, 0x00, 0x1B, 0xA3, 0x3B, 0x9D, 0x2D, 0xC0, 0xF9, 0x85, 0x66, 0xA6, 0x3F, 0x5C, 0x77, 0xC0, 0xE1, 0x12, 0xF3, 0xEE, 0xBD, 0x4F, 0x9C, 0xB1, 0xD5, 0x01, 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, 0x09, 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, 0x05, 0xA1, 0x00, 0x6C, 0x0F, 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, 0x09, 0xA5, 0x9C, 0xBD, 0x69, 0x1C, 0xA5, 0xB9, 0x8F, 0x68, 0x96, 0x1F, 0xA1, 0xDA, 0xFD, 0xF4, 0xED, 0xA2, 0xA6, 0xA7, 0xD2, 0x81, 0x9D, 0x91, 0x56, 0x09, 0xF4, 0x29, 0x24, 0x24, 0xA2, 0x8F, 0xC2, 0xB0, 0xEE, 0x02, 0xD9, 0x96, 0x8B, 0x9D, 0x9E, 0x1A, 0x48, 0xA7, 0x7A, 0x2D, 0x1D, 0x5A, 0xBF, 0x21, 0x60, 0x57, 0xB2, 0x28, 0x03, 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, 0x06, 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, 0x08, 0xA5, 0xA5, 0xE9, 0xC6, 0xBD, 0xB6, 0xC2, 0x4F, 0xFF, 0xD1, 0xA5, 0x89, 0x30, 0xBF, 0x82, 0xE5, 0xEF, 0x1C, 0x47, 0x4B, 0x0C, 0x3C, 0xFB, 0x46, 0x9D, 0xDA, 0x30, 0x35, 0xF8, 0x04, 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, 0x00, 0x70, 0x9B, 0xE9, 0xDC, 0xB3, 0xC7, 0x72, 0x62, 0xB7, 0xAD, 0x01, 0x4F, 0x6D, 0x23, 0x19, 0x67, 0xD8, 0xE8, 0x78, 0x84, 0x2E, 0xF1, 0xF8, 0x7A, 0x88, 0x13, 0xF2, 0xAA, 0x56, 0x08, 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, 0x00, 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, 0x04, 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, 0x0E, 0x24, 0x3D, 0xA2, 0x9D, 0x95, 0x44, 0x09, 0x7A, 0x42, 0x2B, 0x00, 0x23, 0x1C, 0x3D, 0xBC, 0x3E, 0x2B, 0x67, 0x6F, 0xB4, 0xC2, 0x49, 0xEB, 0x0D, 0xFF, 0x6D, 0x19, 0x34, 0xBF, 0xDE, 0x2A, 0x09, 0x6C, 0x2F, 0x2B, 0x7D, 0xDE, 0x17, 0x54, 0x16, 0xEF, 0x04, 0x86, 0x89, 0xCA, 0x67, 0xA4, 0xE7, 0xBA, 0xF9, 0x7E, 0x8A, 0x42, 0xB2, 0xEB, 0x4F, 0xE8, 0x7B, 0xAD, 0x71, 0xBC, 0x1C, 0x0F, 0x1D, 0x40, 0xB1, 0x84, 0xB2, 0x46, 0x46, 0xFB, 0x6A, 0xA7, 0x67, 0x30, 0x9B, 0xD0, 0x1A, 0x7A, 0xC1, 0xE9, 0xE7, 0x01, 0xA4, 0x1B, 0xC9, 0x0E, 0x79, 0x6C, 0xE8, 0x46, 0x47, 0xCF, 0x0A, 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, 0x04, 0xD0, 0xB6, 0x36, 0xF8, 0xF9, 0xB2, 0xD9, 0xDE, 0xD6, 0x29, 0xCD, 0x15, 0x90, 0x47, 0x8F, 0xCA, 0x5C, 0x1D, 0x42, 0x8D, 0x47, 0xF0, 0x72, 0xD5, 0x09, 0x92, 0x72, 0xE5, 0xB4, 0x2A, 0xAB, 0xD9, 0x06, 0x40, 0xDD, 0x3E, 0x7D, 0x85, 0x08, 0x7E, 0x12, 0x7E, 0x6A, 0x0D, 0xB7, 0x9F, 0x98, 0xC7, 0x47, 0x63, 0xBB, 0xC6, 0x3C, 0x07, 0x68, 0x5F, 0xC3, 0x82, 0xAC, 0x6A, 0xD6, 0x4D, 0x29, 0x68, 0xFF, 0xD5, 0x46, 0xD4, 0x87, 0xE6, 0x4A, 0xFF, 0x22, 0x93, 0x2A, 0x04, 0x08, 0xA7, 0x9B, 0xF3, 0xA1, 0x7E, 0x4C, 0x2C, 0xFF, 0xEA, 0x7D, 0x97, 0x4B, 0x5B, 0x8F, 0xDE, 0x6F, 0x00, 0x80, 0xAB, 0x62, 0x96, 0x5E, 0x3A, 0x25, 0x39, 0xD3, 0x65, 0x9B, 0x07, 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, 0x0F, 0xB9, 0x3C, 0x99, 0xB0, 0x49, 0x65, 0x37, 0x28, 0xE7, 0x11, 0x0C, 0xB8, 0xB9, 0x6B, 0xDC, 0x3C, 0x28, 0xF9, 0xFA, 0x96, 0x1A, 0x84, 0xDF, 0x20, 0x1E, 0x0C, 0x8C, 0x5B, 0xA2, 0x22, 0x3E, 0x5B, 0x74, 0x38, 0x72, 0x45, 0x8D, 0xFA, 0x7D, 0x9F, 0xC3, 0x1F, 0x49, 0x0A, 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, 0x07, 0x6C, 0xCE, 0xAE, 0x25, 0x82, 0xB6, 0xE1, 0x30, 0x91, 0xE8, 0xB3, 0xD2, 0x24, 0x11, 0x31, 0xC6, 0x58, 0xC5, 0xB3, 0xBC, 0x45, 0xA8, 0x41, 0x06, 0x31, 0x89, 0xC9, 0x43, 0x02, 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, 0x01, 0x98, 0xC5, 0xA6, 0x3D, 0x1E, 0xE8, 0x78, 0x85, 0x19, 0xDD, 0xAC, 0x8C, 0xBF, 0x01, 0xEE, 0x44, 0xA1, 0xD1, 0x0A, 0xAB, 0x13, 0x99, 0x9D, 0x45, 0x73, 0x07, 0xF9, 0xD7, 0x09, 0x97, 0x93, 0x00, 0x94, 0x02, 0x68, 0xF9, 0xE8, 0x88, 0xC4, 0x9E, 0x53, 0xD6, 0x74, 0xF7, 0x9A, 0xAD, 0xC7, 0xE2, 0x1E, 0xBE, 0x57, 0x7B, 0x0D, 0x5D, 0xE6, 0x7D, 0x3C, 0xF5, 0xF0, 0xE6, 0x01, 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, 0x09, 0x2F, 0xB9, 0x00, 0xEB, 0xB0, 0x34, 0xD7, 0x5F, 0x3E, 0x3E, 0x76, 0xC1, 0x5D, 0x11, 0xCC, 0xB2, 0x4A, 0xBB, 0x07, 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, 0x09, 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, 0x01, 0x46, 0x53, 0x84, 0xBC, 0xEE, 0x78, 0x38, 0x25, 0x99, 0x2D, 0xA7, 0x7B, 0xAA, 0x06, 0xB8, 0x28, 0xE9, 0x01, 0xD2, 0xDE, 0x84, 0x56, 0x02, 0xBA, 0x49, 0xFB, 0xA2, 0xAD, 0x8E, 0xEC, 0x73, 0x0A, 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, 0x04, 0x3D, 0x97, 0x70, 0x8F, 0x2D, 0xCA, 0x6D, 0xAD, 0x2C, 0x9A, 0x53, 0x45, 0x51, 0xA1, 0xE3, 0x47, 0x2C, 0x80, 0x7D, 0x02, 0x7B, 0x8A, 0xD4, 0x7A, 0x8B, 0x58, 0x11, 0x81, 0x60, 0x2A, 0xC4, 0x4D, 0x26, 0x0E, 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, 0x02, 0xE5, 0xD8, 0x15, 0x8C, 0xEC, 0xA6, 0x03, 0x9A, 0x11, 0xF9, 0x95, 0x31, 0xED, 0xF2, 0x8C, 0xF1, 0xEF, 0x6B, 0xA5, 0x39, 0xAD, 0xF7, 0x08, 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, 0x0E, 0xDE, 0x37, 0x1D, 0x4C, 0xFA, 0x71, 0xCA, 0xAA, 0x96, 0x05, 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, 0x04, 0xEE, 0xCF, 0x8C, 0xE2, 0x5D, 0x36, 0xE8, 0xAA, 0x4E, 0x4B, 0x7B, 0xD0, 0x4D, 0xB4, 0x24, 0xA8, 0x42, 0x12, 0x0D, 0xDC, 0x0A, 0xAF, 0xBB, 0x52, 0xE6, 0xF2, 0xD1, 0x07, 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, 0x07, 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, 0x08, 0xD6, 0x45, 0xAB, 0xCF, 0x7C, 0x0B, 0x94, 0xB7, 0x56, 0x63, 0x43, 0x1A, 0x46, 0x3C, 0xF3, 0x3D, 0x07, 0x19, 0x27, 0x9D, 0x03, 0x3E, 0x48, 0x85, 0xF7, 0xF5, 0x1D, 0x5F, 0xD8, 0x14, 0xEE, 0x3A, 0x9D, 0xDD, 0xF6, 0x1D, 0x7B, 0x03, 0x45, 0x30, 0x84, 0x51, 0xE2, 0x54, 0xBB, 0x96, 0x21, 0xD6, 0x93, 0x94, 0x46, 0x08, 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, 0x04, 0x6E, 0xA9, 0x46, 0x96, 0x5E, 0xA1, 0x5E, 0xEB, 0x02, 0xCB, 0x02, 0x1B, 0x21, 0xF7, 0x78, 0xB0, 0x10, 0x8F, 0x29, 0x9C, 0xFB, 0xAC, 0xFE, 0xC8, 0x8A, 0x79, 0x04, 0xC6, 0xED, 0x0D, 0x9D, 0x27, 0xE5, 0x11, 0x65, 0x66, 0x14, 0xCD, 0x0D, 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, 0x02, 0x72, 0xDC, 0x8A, 0xA6, 0x86, 0x85, 0xBE, 0xC6, 0x78, 0xFC, 0xDD, 0x0C, 0xB0, 0x4B, 0x4D, 0xD4, 0xBE, 0x24, 0xB9, 0x03, 0x03, 0x54, 0x9F, 0xAB, 0x06, 0x05, 0x91, 0x4E, 0x41, 0xE9, 0x7E, 0x99, 0x18, 0x3C, 0xB1, 0x96, 0xF0, 0x99, 0x6A, 0xEC, 0xF6, 0x60, 0x7E, 0xE2, 0xD3, 0x6E, 0xED, 0xA8, 0xFC, 0x5F, 0x07, 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, 0x02, 0x48, 0x01, 0x3D, 0xFC, 0xA1, 0x75, 0x95, 0xF9, 0x90, 0x0D, 0x3A, 0xF5, 0x6B, 0xBB, 0xDC, 0xC6, 0x2C, 0x82, 0x2B, 0xE4, 0x4C, 0x02, 0xDC, 0xD0, 0x80, 0x4F, 0x93, 0x22, 0x8D, 0xED, 0xE3, 0x92, 0x26, 0xC7, 0x64, 0x47, 0xDC, 0x85, 0x65, 0x09, 0x3D, 0x5B, 0x82, 0x34, 0x2F, 0x52, 0x93, 0x42, 0xD8, 0x68, 0x35, 0xF8, 0xA9, 0xCC, 0x87, 0x42, 0x09, 0x99, 0xFE, 0x5F, 0x70, 0xBB, 0x16, 0xD5, 0xFC, 0x60, 0x5D, 0x17, 0x92, 0x63, 0xBA, 0x1B, 0x69, 0xD5, 0xDC, 0x62, 0x2A, 0x66, 0x06, 0xD7, 0xD0, 0x46, 0x29, 0xC5, 0x00, 0x01, 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, 0x0B, 0xC6, 0x7C, 0x10, 0x08, 0xF5, 0x8E, 0xD5, 0xF2, 0x38, 0x78, 0x09, 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, 0x0B, 0x33, 0x9E, 0xAD, 0x66, 0x85, 0x3F, 0xD0, 0x61, 0x9A, 0x44, 0xA6, 0xDF, 0x96, 0x0A, 0x1D, 0x78, 0xC2, 0x8D, 0x64, 0x86, 0xD9, 0x0C, 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, 0x08, 0x8F, 0xDA, 0x20, 0xBF, 0x85, 0x97, 0x74, 0x79, 0x0B, 0x00, 0x0B, 0x1E, 0xF1, 0x1A, 0x83, 0x40, 0xC7, 0x51, 0xFD, 0xDD, 0x3D, 0xB7, 0x0C, 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, 0x0B, 0x07, 0x65, 0x30, 0xAB, 0xFC, 0xC0, 0xB7, 0x90, 0x8F, 0xA9, 0x3F, 0xC8, 0x09, 0x9A, 0xF7, 0x8F, 0x33, 0x8A, 0xB3, 0xEE, 0xFC, 0xA3, 0x6E, 0x50, 0x0A, 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, 0x0B, 0x86, 0x9E, 0x19, 0x14, 0xC0, 0x49, 0xB5, 0x74, 0xEB, 0x79, 0xF7, 0xC2, 0x34, 0xF2, 0xEF, 0x10, 0x3A, 0xB0, 0x17, 0x8D, 0x16, 0x71, 0x02, 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, 0x03, 0xE8, 0x4B, 0x45, 0x9B, 0x5B, 0xD9, 0x9F, 0x03, 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, 0x0A, 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, 0x0E, 0xC9, 0x75, 0x1E, 0x39, 0x2E, 0xD2, 0x43, 0x01, 0x76, 0x3B, 0xF7, 0x88, 0xAF, 0xC0, 0x3C, 0x96, 0x0D, 0xF3, 0x0E, 0x42, 0xFC, 0x80, 0x0A, 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, 0x09, 0x3C, 0x6C, 0x15, 0xE3, 0x1D, 0xF6, 0xF7, 0xEE, 0x9F, 0x0A, 0xC5, 0x91, 0x14, 0x33, 0x4B, 0xDB, 0xC4, 0xEE, 0x0C, 0xFB, 0xE4, 0xD1, 0x43, 0xC2, 0x1B, 0xC3, 0x02, 0x9B, 0x6B, -}; +0x30, 0x82, 0xF, 0xD3, 0x2, 0x1, 0x0, 0x30, 0xA, 0x6, 0x8, 0x60, 0x86, +0x48, 0x1, 0x65, 0x3, 0x4, 0x3, 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 From 297f76b3eeb7ba855e1d52860153531f021f41b8 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 13 Nov 2024 15:50:46 -0800 Subject: [PATCH 14/28] removed pqdsa_set_pub/priv_raw --- crypto/dilithium/ml_dsa.h | 2 +- crypto/dilithium/p_pqdsa_asn1.c | 60 +-- crypto/dilithium/p_pqdsa_test.cc | 323 ++++++++------- crypto/evp_extra/evp_asn1.c | 45 ++- crypto/evp_extra/evp_extra_test.cc | 624 ++++++++++++++--------------- 5 files changed, 527 insertions(+), 527 deletions(-) diff --git a/crypto/dilithium/ml_dsa.h b/crypto/dilithium/ml_dsa.h index a6563d50ce..dc10980695 100644 --- a/crypto/dilithium/ml_dsa.h +++ b/crypto/dilithium/ml_dsa.h @@ -16,7 +16,7 @@ #define MLDSA65_SIGNATURE_SEED_BYTES 32 int ml_dsa_65_keypair(uint8_t *public_key, - uint8_t *secret_key); + uint8_t *secret_key); int ml_dsa_65_sign(const uint8_t *secret_key, uint8_t *sig, diff --git a/crypto/dilithium/p_pqdsa_asn1.c b/crypto/dilithium/p_pqdsa_asn1.c index 763a92e5b7..bb716d8798 100644 --- a/crypto/dilithium/p_pqdsa_asn1.c +++ b/crypto/dilithium/p_pqdsa_asn1.c @@ -18,49 +18,6 @@ static void pqdsa_free(EVP_PKEY *pkey) { pkey->pkey.pqdsa_key = NULL; } -static int pqdsa_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, - size_t privkey_len, const uint8_t *pubkey, size_t pubkey_len) { - - PQDSA_KEY *key = OPENSSL_malloc(sizeof(PQDSA_KEY)); - if (key == NULL) { - return 0; - } - - // At time of writing, all |set_priv_raw| and |pqdsa_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; - } - - // NOTE: No checks are done in this function, the caller has to ensure - // that the pointers are valid and |privkey| has the correct size. - key->public_key = NULL; - key->secret_key = OPENSSL_memdup(privkey, privkey_len); - pqdsa_free(pkey); - pkey->pkey.pqdsa_key = key; - return 1; -} - -static int pqdsa_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { - //generate a fresh pqdsa_key - PQDSA_KEY *key = OPENSSL_malloc(sizeof(PQDSA_KEY)); - - if (key == NULL) { - return 0; - } - - // NOTE: No checks are done in this function, the caller has to ensure - // that the pointers are valid and |in| has the correct size. - key->public_key = OPENSSL_memdup(in, len); - key->secret_key = NULL; - - pqdsa_free(pkey); - pkey->pkey.pqdsa_key = key; - return 1; -} - static int pqdsa_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, size_t *out_len) { if (pkey->pkey.pqdsa_key == NULL) { @@ -138,7 +95,9 @@ static int pqdsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return 0; } - return pqdsa_set_pub_raw(out, CBS_data(key), CBS_len(key)); + // set the pqdsa params on the fresh pkey + EVP_PKEY_pqdsa_set_params(out, out->type); + 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) { @@ -155,7 +114,7 @@ static int pqdsa_pub_encode(CBB *out, const EVP_PKEY *pkey) { 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, pkey->ameth->oid, pkey->ameth->oid_len) || + !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) || @@ -183,8 +142,9 @@ static int pqdsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey) OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return 0; } - - return pqdsa_set_priv_raw(out, CBS_data(key), CBS_len(key), NULL, 0); + // set the pqdsa params on the fresh pkey + EVP_PKEY_pqdsa_set_params(out, out->type); + return PQDSA_KEY_set_raw_secret_key(out->pkey.pqdsa_key,CBS_data(key)); } static int pqdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { @@ -200,7 +160,7 @@ static int pqdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { !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, pkey->ameth->oid, pkey->ameth->oid_len) || + !CBB_add_bytes(&oid, pqdsa->oid, pqdsa->oid_len) || !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&private_key, key->secret_key, pqdsa->secret_key_len) || !CBB_flush(out)) { @@ -243,8 +203,8 @@ const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth = { pqdsa_priv_decode, pqdsa_priv_encode, NULL /*priv_encode_v2*/, - pqdsa_set_priv_raw, - pqdsa_set_pub_raw, + NULL /* pqdsa_set_priv_raw */, + NULL /*pqdsa_set_pub_raw */ , pqdsa_get_priv_raw, pqdsa_get_pub_raw, NULL /* pkey_opaque */, diff --git a/crypto/dilithium/p_pqdsa_test.cc b/crypto/dilithium/p_pqdsa_test.cc index 5b14f2dec2..682893c46f 100644 --- a/crypto/dilithium/p_pqdsa_test.cc +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -176,160 +176,166 @@ static const uint8_t mldsa65kPublicKey[] = { 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, 0xB1, 0x30, 0xA, 0x6, 0x8, 0x60, 0x86, 0x48, 0x1, 0x65, -0x3, 0x4, 0x3, 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 }; +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 PQ_DSA { const char name[20]; @@ -357,7 +363,7 @@ CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->public_key, len) CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->secret_key, len) static const struct PQ_DSA parameterSet[] = { - {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt",mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1973}, + {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt",mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1974}, }; class PQDSAParameterTest : public testing::TestWithParam {}; @@ -545,12 +551,8 @@ TEST_P(PQDSAParameterTest, NewKeyFromBytes) { 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_new_raw_public_key(EVP_PKEY_PQDSA, - nullptr, - pkey->pkey.pqdsa_key->public_key, - pk_len)); + 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); @@ -569,10 +571,7 @@ TEST_P(PQDSAParameterTest, NewKeyFromBytes) { 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_new_raw_private_key(EVP_PKEY_PQDSA, - nullptr, - pkey->pkey.pqdsa_key->secret_key, - sk_len)); + bssl::UniquePtr private_pkey(EVP_PKEY_pqdsa_new_raw_secret_key(nid, pkey->pkey.pqdsa_key->secret_key, sk_len)); // check that secret key is present and public key is not present ASSERT_NE(private_pkey, nullptr); diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index a486459f63..119d47799f 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -90,13 +90,22 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { if (OBJ_cbs2nid(&oid) == NID_rsa) { return &rsa_asn1_meth; } + // 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. + + //TODO find a way to search through the OIDs of known PQDSA methods and return + // the ans1 meth + if (OBJ_cbs2nid(&oid) == NID_MLDSA65) { + return &pqdsa_asn1_meth; + } return NULL; } EVP_PKEY *EVP_parse_public_key(CBS *cbs) { // Parse the SubjectPublicKeyInfo. - CBS spki, algorithm, key; + CBS spki, algorithm, algorithm_cpy, oid, key; uint8_t padding; if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || @@ -105,6 +114,13 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return NULL; } + + // when calling parse_key_type on |algorithm| for PKEYs of the type PQDSA + // we get the method pqdsa_asn1_meth, howvever, this method pkey_id is + // EVP_PKEY_PQDSA and not the specific algorithm OID from the asn.1. To + // prevent the actual OID from being lost, we make a copy of it. + OPENSSL_memcpy(&algorithm_cpy, &algorithm, sizeof(algorithm)); + const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); @@ -125,6 +141,15 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { } evp_pkey_set_method(ret, method); + // if we are parsing a public key of the type EVP_PKEY_PQDSA then we include + // the specific algorithm OID as the pkey_type for |ret|. + if (method == &pqdsa_asn1_meth) { + if (!CBS_get_asn1(&algorithm_cpy, &oid, CBS_ASN1_OBJECT)) { + return NULL; + } + ret->type = OBJ_cbs2nid(&oid); + } + // Call into the type-specific SPKI decoding function. if (ret->ameth->pub_decode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); @@ -160,7 +185,7 @@ static const unsigned kPublicKeyTag = EVP_PKEY *EVP_parse_private_key(CBS *cbs) { // Parse the PrivateKeyInfo (RFC 5208) or OneAsymmetricKey (RFC 5958). - CBS pkcs8, algorithm, key, public_key; + CBS pkcs8, algorithm, algorithm_cpy, key, public_key, oid; uint64_t version; if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) || !CBS_get_asn1_uint64(&pkcs8, &version) || @@ -170,6 +195,13 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return NULL; } + + // when calling parse_key_type on |algorithm| for PKEYs of the type PQDSA + // we get the method pqdsa_asn1_meth, howvever, this method pkey_id is + // EVP_PKEY_PQDSA and not the specific algorithm OID from the asn.1. To + // prevent the actual OID from being lost, we make a copy of it. + OPENSSL_memcpy(&algorithm_cpy, &algorithm, sizeof(algorithm)); + const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); @@ -205,6 +237,15 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { } evp_pkey_set_method(ret, method); + // if we are parsing a public key of the type EVP_PKEY_PQDSA then we include + // the specific algorithm OID as the pkey_type for |ret|. + if (method == &pqdsa_asn1_meth) { + if (!CBS_get_asn1(&algorithm_cpy, &oid, CBS_ASN1_OBJECT)) { + return NULL; + } + ret->type = OBJ_cbs2nid(&oid); + } + // Call into the type-specific PrivateKeyInfo decoding function. if (ret->ameth->priv_decode == 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 3bec8ea4a1..fbe8fd41d7 100644 --- a/crypto/evp_extra/evp_extra_test.cc +++ b/crypto/evp_extra/evp_extra_test.cc @@ -701,318 +701,318 @@ static const uint8_t kInvalidPrivateKey[] = { // 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 kExampleMLDSA65KeyDER[] = { -0x30, 0x82, 0xF, 0xD3, 0x2, 0x1, 0x0, 0x30, 0xA, 0x6, 0x8, 0x60, 0x86, -0x48, 0x1, 0x65, 0x3, 0x4, 0x3, 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 }; +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 From 5a744cf240b3c5170ee9249a60ffb77ac01de2ca Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 13 Nov 2024 15:57:08 -0800 Subject: [PATCH 15/28] added dilithium ifdef --- crypto/evp_extra/evp_asn1.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index 119d47799f..4c17794937 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -96,16 +96,17 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { //TODO find a way to search through the OIDs of known PQDSA methods and return // the ans1 meth +#ifdef ENABLE_DILITHIUM if (OBJ_cbs2nid(&oid) == NID_MLDSA65) { return &pqdsa_asn1_meth; } - +#endif return NULL; } EVP_PKEY *EVP_parse_public_key(CBS *cbs) { // Parse the SubjectPublicKeyInfo. - CBS spki, algorithm, algorithm_cpy, oid, key; + CBS spki, algorithm, algorithm_cpy, key; uint8_t padding; if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || @@ -141,6 +142,8 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { } evp_pkey_set_method(ret, method); +#ifdef ENABLE_DILITHIUM + CBS oid; // if we are parsing a public key of the type EVP_PKEY_PQDSA then we include // the specific algorithm OID as the pkey_type for |ret|. if (method == &pqdsa_asn1_meth) { @@ -149,6 +152,7 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { } ret->type = OBJ_cbs2nid(&oid); } +#endif // Call into the type-specific SPKI decoding function. if (ret->ameth->pub_decode == NULL) { @@ -185,7 +189,7 @@ static const unsigned kPublicKeyTag = EVP_PKEY *EVP_parse_private_key(CBS *cbs) { // Parse the PrivateKeyInfo (RFC 5208) or OneAsymmetricKey (RFC 5958). - CBS pkcs8, algorithm, algorithm_cpy, key, public_key, oid; + CBS pkcs8, algorithm, algorithm_cpy, key, public_key; uint64_t version; if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) || !CBS_get_asn1_uint64(&pkcs8, &version) || @@ -237,6 +241,8 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { } evp_pkey_set_method(ret, method); +#ifdef ENABLE_DILITHIUM + CBS oid; // if we are parsing a public key of the type EVP_PKEY_PQDSA then we include // the specific algorithm OID as the pkey_type for |ret|. if (method == &pqdsa_asn1_meth) { @@ -245,7 +251,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { } ret->type = OBJ_cbs2nid(&oid); } - +#endif // Call into the type-specific PrivateKeyInfo decoding function. if (ret->ameth->priv_decode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); From 2e5d891ef9321bb41e729ec0237e2ed97d2c567a Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 13 Nov 2024 16:11:45 -0800 Subject: [PATCH 16/28] CR fixes --- crypto/dilithium/p_pqdsa_test.cc | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/crypto/dilithium/p_pqdsa_test.cc b/crypto/dilithium/p_pqdsa_test.cc index 682893c46f..e5c8d620e0 100644 --- a/crypto/dilithium/p_pqdsa_test.cc +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -176,12 +176,6 @@ static const uint8_t mldsa65kPublicKey[] = { 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, @@ -669,38 +663,39 @@ TEST_P(PQDSAParameterTest, SIGOperations) { bssl::ScopedEVP_MD_CTX md_ctx; std::vector signature(sig_len); - std::vector msg = { + // 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 badmsg = { + 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(), signature.data(), &sig_len, - msg.data(), msg.size())); + msg1.data(), msg1.size())); // Verify the correct signed message ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), signature.data(), sig_len, - msg.data(), msg.size())); + msg1.data(), msg1.size())); - // Verify the signed message fails upon a bad message + // Verify the signed message fails upon a different message ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature.data(), sig_len, - badmsg.data(), badmsg.size())); + msg2.data(), msg2.size())); - // Sign the bad message + // Sign the different message std::vector signature1(sig_len); ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature1.data(), &sig_len, - badmsg.data(), badmsg.size())); + msg2.data(), msg2.size())); // Check that the two signatures are not equal EXPECT_NE(0, OPENSSL_memcmp(signature.data(), signature1.data(), sig_len)); - // Verify the signed message fails upon a bad signature + // Verify the signed message fails upon a different signature ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature1.data(), sig_len, - msg.data(), msg.size())); + msg1.data(), msg1.size())); md_ctx.Reset(); } @@ -738,7 +733,7 @@ TEST_P(PQDSAParameterTest, MarshalParse) { #else -TEST(Dilithium3Test, EvpDisabled) { +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)); From ad0a24c2de9fbf3c9e1e0266fdf1ca9da04aa901 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 13 Nov 2024 16:17:11 -0800 Subject: [PATCH 17/28] CR fixes --- crypto/x509/x509_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 0d69dc7ac0..e6df1e13a0 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -2964,7 +2964,7 @@ TEST(X509Test, MLDSA65SignVerifyCert) { ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr)); bssl::UniquePtr leaf = - MakeTestCert("Intermediate", "Leaf", pkey.get(), false); + MakeTestCert("Intermediate", "Leaf", pkey.get(), /*is_ca=*/false); ASSERT_TRUE(leaf); bssl::ScopedEVP_MD_CTX md_ctx; @@ -3010,7 +3010,7 @@ TEST(X509Test, TestBadSigAlgMLDSA65) { TEST(X509Test, TestBadParamsMLDSA65) { // This test generates a MLDSA65 certificate from the PEM encoding - // kMLDSA65CertParam that has an explicit NULL in the signature algorithm. + // kMLDSA65CertParam that has an explicit NULL in the parameters field. // After extracting the public key, verification should fail. bssl::UniquePtr cert(CertFromPEM(kMLDSA65CertParam)); ASSERT_TRUE(cert); From 739a3be97c4f8ffcb6192064a90b33c4e118b529 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 14 Nov 2024 08:50:49 -0800 Subject: [PATCH 18/28] CR fixes --- crypto/dilithium/internal.h | 10 +++--- crypto/dilithium/ml_dsa.c | 8 ++--- crypto/dilithium/ml_dsa.h | 4 +-- crypto/dilithium/p_pqdsa.c | 14 ++++----- crypto/dilithium/p_pqdsa_asn1.c | 16 +++++----- crypto/dilithium/p_pqdsa_test.cc | 54 +++++++++++++++++--------------- crypto/dilithium/pqdsa.c | 16 +++++----- crypto/evp_extra/print.c | 4 +-- crypto/x509/x509_test.cc | 28 ++++++----------- include/openssl/evp.h | 4 +-- 10 files changed, 77 insertions(+), 81 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index f4edf212e7..8c919e6d2d 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -13,9 +13,9 @@ extern "C" { // PQDSA_METHOD structure and helper functions. typedef struct { int (*keygen)(uint8_t *public_key, - uint8_t *secret_key); + uint8_t *private_key); - int (*sign)(const uint8_t *secret_key, + int (*sign)(const uint8_t *private_key, uint8_t *sig, size_t *sig_len, const uint8_t *message, @@ -40,7 +40,7 @@ typedef struct { uint8_t oid_len; const char *comment; size_t public_key_len; - size_t secret_key_len; + size_t private_key_len; size_t signature_len; size_t keygen_seed_len; size_t sign_seed_len; @@ -51,7 +51,7 @@ typedef struct { struct pqdsa_key_st { const PQDSA *pqdsa; uint8_t *public_key; - uint8_t *secret_key; + uint8_t *private_key; }; int PQDSA_KEY_init(PQDSA_KEY *key, const PQDSA *pqdsa); @@ -62,7 +62,7 @@ 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_secret_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 diff --git a/crypto/dilithium/ml_dsa.c b/crypto/dilithium/ml_dsa.c index 6727c569c2..286b7edd4e 100644 --- a/crypto/dilithium/ml_dsa.c +++ b/crypto/dilithium/ml_dsa.c @@ -26,13 +26,13 @@ // depending on platform support. int ml_dsa_65_keypair(uint8_t *public_key /* OUT */, - uint8_t *secret_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) == 0); + return (crypto_sign_keypair(¶ms, public_key, private_key) == 0); } -int ml_dsa_65_sign(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 */, @@ -42,7 +42,7 @@ int ml_dsa_65_sign(const uint8_t *secret_key /* IN */, ml_dsa_params params; ml_dsa_65_params_init(¶ms); return crypto_sign_signature(¶ms, sig, sig_len, message, message_len, - ctx_string, ctx_string_len, secret_key) == 0; + ctx_string, ctx_string_len, private_key) == 0; } int ml_dsa_65_verify(const uint8_t *public_key /* IN */, diff --git a/crypto/dilithium/ml_dsa.h b/crypto/dilithium/ml_dsa.h index dc10980695..9716d260a6 100644 --- a/crypto/dilithium/ml_dsa.h +++ b/crypto/dilithium/ml_dsa.h @@ -16,9 +16,9 @@ #define MLDSA65_SIGNATURE_SEED_BYTES 32 int ml_dsa_65_keypair(uint8_t *public_key, - uint8_t *secret_key); + uint8_t *private_key); -int ml_dsa_65_sign(const uint8_t *secret_key, +int ml_dsa_65_sign(const uint8_t *private_key, uint8_t *sig, size_t *sig_len, const uint8_t *message, diff --git a/crypto/dilithium/p_pqdsa.c b/crypto/dilithium/p_pqdsa.c index 2e73236267..c44cd6d692 100644 --- a/crypto/dilithium/p_pqdsa.c +++ b/crypto/dilithium/p_pqdsa.c @@ -49,7 +49,7 @@ static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { PQDSA_KEY *key = PQDSA_KEY_new(); if (key == NULL || !PQDSA_KEY_init(key, pqdsa) || - !pqdsa->method->keygen(key->public_key, key->secret_key) || + !pqdsa->method->keygen(key->public_key, key->private_key) || !EVP_PKEY_assign(pkey, EVP_PKEY_PQDSA, key)) { PQDSA_KEY_free(key); return 0; @@ -92,12 +92,12 @@ static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, } PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key; - if (!key->secret_key) { + if (!key->private_key) { OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET); return 0; } - if (!pqdsa->method->sign(key->secret_key, sig, sig_len, message, message_len, NULL, 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; } @@ -231,7 +231,7 @@ EVP_PKEY *EVP_PKEY_pqdsa_new_raw_public_key(int nid, const uint8_t *in, size_t l return NULL; } -EVP_PKEY *EVP_PKEY_pqdsa_new_raw_secret_key(int nid, const uint8_t *in, size_t len) { +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; @@ -244,13 +244,13 @@ EVP_PKEY *EVP_PKEY_pqdsa_new_raw_secret_key(int nid, const uint8_t *in, size_t l } const PQDSA *pqdsa = PQDSA_KEY_get0_dsa(ret->pkey.pqdsa_key); - if (pqdsa->secret_key_len != len) { + if (pqdsa->private_key_len != len) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); goto err; } - if (!PQDSA_KEY_set_raw_secret_key(ret->pkey.pqdsa_key, in)) { - // PQDSA_KEY_set_raw_secret_key sets the appropriate error. + if (!PQDSA_KEY_set_raw_private_key(ret->pkey.pqdsa_key, in)) { + // PQDSA_KEY_set_raw_private_key sets the appropriate error. goto err; } diff --git a/crypto/dilithium/p_pqdsa_asn1.c b/crypto/dilithium/p_pqdsa_asn1.c index bb716d8798..5897a36032 100644 --- a/crypto/dilithium/p_pqdsa_asn1.c +++ b/crypto/dilithium/p_pqdsa_asn1.c @@ -28,7 +28,7 @@ static int pqdsa_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, PQDSA_KEY *key = pkey->pkey.pqdsa_key; const PQDSA *pqdsa = key->pqdsa; - if (key->secret_key == NULL) { + if (key->private_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; } @@ -39,17 +39,17 @@ static int pqdsa_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, } if (out == NULL) { - *out_len = key->pqdsa->secret_key_len; + *out_len = key->pqdsa->private_key_len; return 1; } - if (*out_len < key->pqdsa->secret_key_len) { + if (*out_len < key->pqdsa->private_key_len) { OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); return 0; } - OPENSSL_memcpy(out, key->secret_key, pqdsa->secret_key_len); - *out_len = pqdsa->secret_key_len; + OPENSSL_memcpy(out, key->private_key, pqdsa->private_key_len); + *out_len = pqdsa->private_key_len; return 1; } @@ -144,13 +144,13 @@ static int pqdsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey) } // set the pqdsa params on the fresh pkey EVP_PKEY_pqdsa_set_params(out, out->type); - return PQDSA_KEY_set_raw_secret_key(out->pkey.pqdsa_key,CBS_data(key)); + 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->secret_key == NULL) { + if (key->private_key == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); return 0; } @@ -162,7 +162,7 @@ static int pqdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) { !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->secret_key, pqdsa->secret_key_len) || + !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; diff --git a/crypto/dilithium/p_pqdsa_test.cc b/crypto/dilithium/p_pqdsa_test.cc index e5c8d620e0..afd7b2c546 100644 --- a/crypto/dilithium/p_pqdsa_test.cc +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -335,7 +335,7 @@ struct PQ_DSA { const char name[20]; const int nid; const size_t public_key_len; - const size_t secret_key_len; + const size_t private_key_len; const size_t signature_len; const char *kat_filename; const uint8_t *kPublicKey; @@ -346,7 +346,7 @@ struct PQ_DSA { #define CMP_VEC_AND_PTR(vec, ptr, len) \ { \ std::vector tmp(len); \ - tmp.assign(ptr, ptr+len); \ + tmp.assign(ptr, ptr + len); \ EXPECT_EQ(Bytes(vec), Bytes(tmp)); \ } @@ -354,10 +354,10 @@ struct PQ_DSA { 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->secret_key, len) +CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->private_key, len) static const struct PQ_DSA parameterSet[] = { - {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt",mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1974}, + {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt", mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1974}, }; class PQDSAParameterTest : public testing::TestWithParam {}; @@ -385,15 +385,15 @@ TEST_P(PQDSAParameterTest, KAT) { ASSERT_TRUE(t->GetBytes(&sm, "sm")); size_t pk_len = GetParam().public_key_len; - size_t sk_len = GetParam().secret_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 signed message down to a - // constant DILITHIUM3_SIGNATURE_BYTES. + // 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); @@ -440,7 +440,7 @@ TEST_P(PQDSAParameterTest, KeyGen) { // Generate a MLDSA key int nid = GetParam().nid; size_t pk_len = GetParam().public_key_len; - size_t sk_len = GetParam().secret_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); @@ -534,7 +534,7 @@ 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().secret_key_len; + size_t sk_len = GetParam().private_key_len; // Source key bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr)); @@ -551,7 +551,7 @@ TEST_P(PQDSAParameterTest, NewKeyFromBytes) { // 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->secret_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; @@ -565,13 +565,13 @@ TEST_P(PQDSAParameterTest, NewKeyFromBytes) { 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_secret_key(nid, pkey->pkey.pqdsa_key->secret_key, sk_len)); + 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->secret_key, nullptr); - EXPECT_EQ(0, OPENSSL_memcmp(private_pkey->pkey.pqdsa_key->secret_key, pkey->pkey.pqdsa_key->secret_key, sk_len)); + 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) { @@ -579,11 +579,11 @@ TEST_P(PQDSAParameterTest, RawFunctions) { // 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_secret_key for generating a new PKEY from raw priv + // 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().secret_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)); @@ -627,7 +627,7 @@ TEST_P(PQDSAParameterTest, RawFunctions) { 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_secret_key(nid, priv_buf.data(), sk_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. @@ -641,7 +641,7 @@ TEST_P(PQDSAParameterTest, RawFunctions) { 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->secret_key, priv_len), + EXPECT_EQ(Bytes(pkey_priv_from_der->pkey.pqdsa_key->private_key, priv_len), Bytes(priv_buf.data(), sk_len)); } @@ -661,7 +661,7 @@ TEST_P(PQDSAParameterTest, SIGOperations) { // Sign a message bssl::ScopedEVP_MD_CTX md_ctx; - std::vector signature(sig_len); + std::vector signature1(sig_len); // msg2 differs from msg1 by one byte std::vector msg1 = { @@ -673,28 +673,32 @@ TEST_P(PQDSAParameterTest, SIGOperations) { ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey.get())); - ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature.data(), &sig_len, + 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(), signature.data(), sig_len, + 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(), signature.data(), sig_len, + ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature1.data(), sig_len, msg2.data(), msg2.size())); // Sign the different message - std::vector signature1(sig_len); - ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature1.data(), &sig_len, + 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(signature.data(), signature1.data(), sig_len)); + 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(), signature1.data(), sig_len, + ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), signature2.data(), sig_len, msg1.data(), msg1.size())); md_ctx.Reset(); } diff --git a/crypto/dilithium/pqdsa.c b/crypto/dilithium/pqdsa.c index 9404e0858a..5bc5ceb235 100644 --- a/crypto/dilithium/pqdsa.c +++ b/crypto/dilithium/pqdsa.c @@ -28,9 +28,9 @@ PQDSA_KEY *PQDSA_KEY_new(void) { static void PQDSA_KEY_clear(PQDSA_KEY *key) { key->pqdsa = NULL; OPENSSL_free(key->public_key); - OPENSSL_free(key->secret_key); + OPENSSL_free(key->private_key); key->public_key = NULL; - key->secret_key = NULL; + key->private_key = NULL; } int PQDSA_KEY_init(PQDSA_KEY *key, const PQDSA *pqdsa) { @@ -42,8 +42,8 @@ int PQDSA_KEY_init(PQDSA_KEY *key, const PQDSA *pqdsa) { key->pqdsa = pqdsa; key->public_key = OPENSSL_malloc(pqdsa->public_key_len); - key->secret_key = OPENSSL_malloc(pqdsa->secret_key_len); - if (key->public_key == NULL || key->secret_key == NULL) { + key->private_key = OPENSSL_malloc(pqdsa->private_key_len); + if (key->public_key == NULL || key->private_key == NULL) { PQDSA_KEY_clear(key); return 0; } @@ -71,9 +71,9 @@ int PQDSA_KEY_set_raw_public_key(PQDSA_KEY *key, const uint8_t *in) { return 1; } -int PQDSA_KEY_set_raw_secret_key(PQDSA_KEY *key, const uint8_t *in) { - key->secret_key = OPENSSL_memdup(in, key->pqdsa->secret_key_len); - if (key->secret_key == NULL) { +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; } @@ -92,7 +92,7 @@ DEFINE_LOCAL_DATA(PQDSA, sig_ml_dsa_65) { out->oid_len = sizeof(kOIDMLDSA65); out->comment = "MLDSA65 "; out->public_key_len = MLDSA65_PUBLIC_KEY_BYTES; - out->secret_key_len = MLDSA65_PRIVATE_KEY_BYTES; + out->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; diff --git a/crypto/evp_extra/print.c b/crypto/evp_extra/print.c index 98fbe04232..02f9a9f870 100644 --- a/crypto/evp_extra/print.c +++ b/crypto/evp_extra/print.c @@ -330,11 +330,11 @@ static int do_mldsa_65_print(BIO *bp, const EVP_PKEY *pkey, int off, int ptype) int bit_len = 0; if (ptype == 2) { - bit_len = pqdsa->secret_key_len; + bit_len = pqdsa->private_key_len; if (BIO_printf(bp, "Private-Key: (%d bit)\n", bit_len) <= 0) { return 0; } - print_hex(bp, pkey->pkey.pqdsa_key->secret_key, bit_len, off); + print_hex(bp, pkey->pkey.pqdsa_key->private_key, bit_len, off); } else { bit_len = pqdsa->public_key_len; if (BIO_printf(bp, "Public-Key: (%d bit)\n", bit_len) <= 0) { diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index e6df1e13a0..fb43a81615 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -2978,13 +2978,10 @@ TEST(X509Test, TestMLDSA65) { // extracts the public key, and then verifies the certificate. bssl::UniquePtr cert(CertFromPEM(kMLDSA65Cert)); ASSERT_TRUE(cert); - //extract the asn1 bit string from the cert - ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); - // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, - key->data, - key->length)); + + bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); ASSERT_TRUE(pkey); + ASSERT_TRUE(X509_verify(cert.get(), pkey.get())); } @@ -2994,13 +2991,10 @@ TEST(X509Test, TestBadSigAlgMLDSA65) { // After extracting the public key, verification should fail. bssl::UniquePtr cert(CertFromPEM(kMLDSA65CertNull)); ASSERT_TRUE(cert); - // extract the asn1 bit string from the cert - ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); - // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, - key->data, - key->length)); + + bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); ASSERT_TRUE(pkey); + ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); ASSERT_EQ(ERR_LIB_X509, ERR_GET_LIB(err)); @@ -3014,16 +3008,14 @@ TEST(X509Test, TestBadParamsMLDSA65) { // After extracting the public key, verification should fail. bssl::UniquePtr cert(CertFromPEM(kMLDSA65CertParam)); ASSERT_TRUE(cert); - // extract the asn1 bit string from the cert - ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert.get()); - // create a new PKEY and set the raw public key as the one from the cert - bssl::UniquePtr pkey(EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, - key->data, - key->length)); + + bssl::UniquePtr pkey(X509_get_pubkey(cert.get())); ASSERT_TRUE(pkey); + ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); ASSERT_EQ(ERR_LIB_ASN1, ERR_GET_LIB(err)); + ASSERT_EQ(ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM, ERR_GET_REASON(err)); ERR_clear_error(); } diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 5c6cf05672..8574eb0eb3 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -960,11 +960,11 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_pqdsa_set_params(EVP_PKEY_CTX *ctx, int nid); // 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_secret_key generates a new EVP_PKEY object of type +// 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_secret_key(int nid, const uint8_t *in, size_t len); +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. From a1a15febbcbff8f08910dca931a719b58e34dccd Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 14 Nov 2024 09:00:11 -0800 Subject: [PATCH 19/28] CR fixes --- crypto/dilithium/p_pqdsa_test.cc | 8 ++++---- crypto/evp_extra/internal.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crypto/dilithium/p_pqdsa_test.cc b/crypto/dilithium/p_pqdsa_test.cc index afd7b2c546..6db8985fd4 100644 --- a/crypto/dilithium/p_pqdsa_test.cc +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -331,7 +331,7 @@ static const uint8_t mldsa65kPublicKeySPKI[] = { 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 PQ_DSA { +struct PQDSATestVector { const char name[20]; const int nid; const size_t public_key_len; @@ -356,14 +356,14 @@ 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 PQ_DSA parameterSet[] = { +static const struct PQDSATestVector parameterSet[] = { {"MLDSA65", NID_MLDSA65, 1952, 4032, 3309, "dilithium/kat/mldsa65.txt", mldsa65kPublicKey, mldsa65kPublicKeySPKI, 1974}, }; -class PQDSAParameterTest : public testing::TestWithParam {}; +class PQDSAParameterTest : public testing::TestWithParam {}; INSTANTIATE_TEST_SUITE_P(All, PQDSAParameterTest, testing::ValuesIn(parameterSet), - [](const testing::TestParamInfo ¶ms) + [](const testing::TestParamInfo ¶ms) -> std::string { return params.param.name; }); diff --git a/crypto/evp_extra/internal.h b/crypto/evp_extra/internal.h index de956cba9e..24012218e9 100644 --- a/crypto/evp_extra/internal.h +++ b/crypto/evp_extra/internal.h @@ -36,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; +#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; From c4afe506ebcf8cb04c5c0e3c5d0423e3fb9ccbfc Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 14 Nov 2024 09:30:40 -0800 Subject: [PATCH 20/28] documentation and names --- crypto/dilithium/internal.h | 8 ++++---- crypto/dilithium/p_pqdsa_test.cc | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index 8c919e6d2d..ccb28066cf 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -20,16 +20,16 @@ typedef struct { size_t *sig_len, const uint8_t *message, size_t message_len, - const uint8_t *pre, - size_t pre_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 *pre, - size_t pre_len); + const uint8_t *ctx_string, + size_t ctx_string_len); } PQDSA_METHOD; diff --git a/crypto/dilithium/p_pqdsa_test.cc b/crypto/dilithium/p_pqdsa_test.cc index 6db8985fd4..a343d2969b 100644 --- a/crypto/dilithium/p_pqdsa_test.cc +++ b/crypto/dilithium/p_pqdsa_test.cc @@ -561,7 +561,7 @@ TEST_P(PQDSAParameterTest, NewKeyFromBytes) { EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); EXPECT_EQ(EVP_R_NOT_A_PRIVATE_KEY, ERR_GET_REASON(err)); - // EVP_PKEY_cmp compares the public keys so this should return 1 + // 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 From 2622a60b2857702883a2bcb7fca812de6abf8db8 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 14 Nov 2024 11:37:35 -0800 Subject: [PATCH 21/28] cleaned up search for asn1 method by nid --- crypto/dilithium/internal.h | 1 + crypto/dilithium/pqdsa.c | 12 +++++++++++- crypto/evp_extra/evp_asn1.c | 8 ++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/crypto/dilithium/internal.h b/crypto/dilithium/internal.h index ccb28066cf..be19b0d561 100644 --- a/crypto/dilithium/internal.h +++ b/crypto/dilithium/internal.h @@ -56,6 +56,7 @@ struct pqdsa_key_st { 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); diff --git a/crypto/dilithium/pqdsa.c b/crypto/dilithium/pqdsa.c index 5bc5ceb235..708b3e9c9d 100644 --- a/crypto/dilithium/pqdsa.c +++ b/crypto/dilithium/pqdsa.c @@ -4,8 +4,9 @@ #include #include -#include "internal.h" +#include "../evp_extra/internal.h" #include "../fipsmodule/delocate.h" +#include "internal.h" #include "ml_dsa.h" // ML-DSA OIDs as defined within: @@ -107,3 +108,12 @@ const PQDSA *PQDSA_find_dsa_by_nid(int nid) { 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/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index 4c17794937..7009a12d0b 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -68,6 +68,7 @@ #include "../bytestring/internal.h" #include "../internal.h" #include "internal.h" +#include "../dilithium/internal.h" static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { CBS oid; @@ -93,13 +94,8 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { // 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. - - //TODO find a way to search through the OIDs of known PQDSA methods and return - // the ans1 meth #ifdef ENABLE_DILITHIUM - if (OBJ_cbs2nid(&oid) == NID_MLDSA65) { - return &pqdsa_asn1_meth; - } + return PQDSA_find_asn1_by_nid(OBJ_cbs2nid(&oid)); #endif return NULL; } From 2c0d95a803de8f7b1203ebe7642bcf5186380f23 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Thu, 14 Nov 2024 15:59:48 -0800 Subject: [PATCH 22/28] edits to evp_asn1.c --- crypto/dilithium/p_pqdsa_asn1.c | 12 +++++--- crypto/evp_extra/evp_asn1.c | 50 ++++++++------------------------- 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/crypto/dilithium/p_pqdsa_asn1.c b/crypto/dilithium/p_pqdsa_asn1.c index 5897a36032..b535dea4e5 100644 --- a/crypto/dilithium/p_pqdsa_asn1.c +++ b/crypto/dilithium/p_pqdsa_asn1.c @@ -91,12 +91,14 @@ static int pqdsa_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, 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 parameters must be omitted. - if (CBS_len(params) != 0) { + + // 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 - EVP_PKEY_pqdsa_set_params(out, out->type); + EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(params)); return PQDSA_KEY_set_raw_public_key(out->pkey.pqdsa_key,CBS_data(key)); } @@ -138,12 +140,14 @@ static int pqdsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { 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 parameters must be omitted. - if (CBS_len(params) != 0 ) { + + // 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 - EVP_PKEY_pqdsa_set_params(out, out->type); + EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(params)); return PQDSA_KEY_set_raw_private_key(out->pkey.pqdsa_key,CBS_data(key)); } diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index 7009a12d0b..ce89331fff 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -91,10 +91,19 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { if (OBJ_cbs2nid(&oid) == NID_rsa) { return &rsa_asn1_meth; } + +#ifdef ENABLE_DILITHIUM + // if |cbs| is empty we overwrite the contents with |oid| so that we can + // call pub_decode(ret, &algorithm, &key) with the |algorithm| populated as |oid|. + // We could probably use CBS_peek_asn1_tag for this, to conditionally set |algorithm| + // based on if peeking at the next tag to see if there is params. + if (CBS_len(cbs) == 0) { + OPENSSL_memcpy(cbs, &oid, sizeof(oid)); + } + // 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. -#ifdef ENABLE_DILITHIUM return PQDSA_find_asn1_by_nid(OBJ_cbs2nid(&oid)); #endif return NULL; @@ -102,7 +111,7 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { EVP_PKEY *EVP_parse_public_key(CBS *cbs) { // Parse the SubjectPublicKeyInfo. - CBS spki, algorithm, algorithm_cpy, key; + CBS spki, algorithm, key; uint8_t padding; if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || @@ -112,12 +121,6 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { return NULL; } - // when calling parse_key_type on |algorithm| for PKEYs of the type PQDSA - // we get the method pqdsa_asn1_meth, howvever, this method pkey_id is - // EVP_PKEY_PQDSA and not the specific algorithm OID from the asn.1. To - // prevent the actual OID from being lost, we make a copy of it. - OPENSSL_memcpy(&algorithm_cpy, &algorithm, sizeof(algorithm)); - const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); @@ -138,18 +141,6 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { } evp_pkey_set_method(ret, method); -#ifdef ENABLE_DILITHIUM - CBS oid; - // if we are parsing a public key of the type EVP_PKEY_PQDSA then we include - // the specific algorithm OID as the pkey_type for |ret|. - if (method == &pqdsa_asn1_meth) { - if (!CBS_get_asn1(&algorithm_cpy, &oid, CBS_ASN1_OBJECT)) { - return NULL; - } - ret->type = OBJ_cbs2nid(&oid); - } -#endif - // Call into the type-specific SPKI decoding function. if (ret->ameth->pub_decode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); @@ -185,7 +176,7 @@ static const unsigned kPublicKeyTag = EVP_PKEY *EVP_parse_private_key(CBS *cbs) { // Parse the PrivateKeyInfo (RFC 5208) or OneAsymmetricKey (RFC 5958). - CBS pkcs8, algorithm, algorithm_cpy, key, public_key; + CBS pkcs8, algorithm, key, public_key; uint64_t version; if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) || !CBS_get_asn1_uint64(&pkcs8, &version) || @@ -196,12 +187,6 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { return NULL; } - // when calling parse_key_type on |algorithm| for PKEYs of the type PQDSA - // we get the method pqdsa_asn1_meth, howvever, this method pkey_id is - // EVP_PKEY_PQDSA and not the specific algorithm OID from the asn.1. To - // prevent the actual OID from being lost, we make a copy of it. - OPENSSL_memcpy(&algorithm_cpy, &algorithm, sizeof(algorithm)); - const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); @@ -237,17 +222,6 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { } evp_pkey_set_method(ret, method); -#ifdef ENABLE_DILITHIUM - CBS oid; - // if we are parsing a public key of the type EVP_PKEY_PQDSA then we include - // the specific algorithm OID as the pkey_type for |ret|. - if (method == &pqdsa_asn1_meth) { - if (!CBS_get_asn1(&algorithm_cpy, &oid, CBS_ASN1_OBJECT)) { - return NULL; - } - ret->type = OBJ_cbs2nid(&oid); - } -#endif // Call into the type-specific PrivateKeyInfo decoding function. if (ret->ameth->priv_decode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); From c71bbac49160038ba8262b9f1996b43e197410ba Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Fri, 15 Nov 2024 10:26:05 -0800 Subject: [PATCH 23/28] added external certificate from standard --- crypto/evp_extra/evp_asn1.c | 15 +- crypto/obj/obj_xref.c | 2 +- crypto/x509/algorithm.c | 11 +- crypto/x509/x509_test.cc | 696 ++++++++++++++++++------------------ 4 files changed, 372 insertions(+), 352 deletions(-) diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index ce89331fff..af99690521 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -70,6 +70,14 @@ #include "internal.h" #include "../dilithium/internal.h" +// The function 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 to +// 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)) { @@ -93,10 +101,9 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { } #ifdef ENABLE_DILITHIUM - // if |cbs| is empty we overwrite the contents with |oid| so that we can - // call pub_decode(ret, &algorithm, &key) with the |algorithm| populated as |oid|. - // We could probably use CBS_peek_asn1_tag for this, to conditionally set |algorithm| - // based on if peeking at the next tag to see if there is params. + // 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)); } diff --git a/crypto/obj/obj_xref.c b/crypto/obj/obj_xref.c index c649c31b80..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_PQDSA, NID_undef, NID_PQDSA}, + {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/x509/algorithm.c b/crypto/x509/algorithm.c index 5ec35af856..ef5645d7f3 100644 --- a/crypto/x509/algorithm.c +++ b/crypto/x509/algorithm.c @@ -98,7 +98,7 @@ int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { #ifdef ENABLE_DILITHIUM if (EVP_PKEY_id(pkey) == EVP_PKEY_PQDSA) { - return X509_ALGOR_set0(algor, OBJ_nid2obj(EVP_PKEY_PQDSA), V_ASN1_UNDEF, NULL); + return X509_ALGOR_set0(algor, OBJ_nid2obj(NID_MLDSA65), V_ASN1_UNDEF, NULL); } #endif @@ -141,7 +141,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 +163,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_PQDSA) { + 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 fb43a81615..48dcbba70b 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -577,122 +577,126 @@ w1AH9efZBw== )"; #ifdef ENABLE_DILITHIUM - +// 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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 +Lw== -----END CERTIFICATE----- )"; @@ -700,241 +704,245 @@ gpSap7z7DhchKkdnb3eAtw8eZmrXfb0AAAAAAAAAAAAAAAAAAAAHCxchJig= // NULL in the signature algorithm. static const char kMLDSA65CertNull[] = R"( -----BEGIN CERTIFICATE----- -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 +HCIv -----END CERTIFICATE----- - )"; // kMLDSA65CertParam is an invalid self-signed MLDSA65 with an explicit // NULL in the AlgorithmIdentifier parameters. static const char kMLDSA65CertParam[] = R"( -----BEGIN CERTIFICATE----- -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 -Gx8= +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 +DhQcIi8= -----END CERTIFICATE----- )"; @@ -3014,8 +3022,8 @@ TEST(X509Test, TestBadParamsMLDSA65) { ASSERT_FALSE(X509_verify(cert.get(), pkey.get())); uint32_t err = ERR_get_error(); - ASSERT_EQ(ERR_LIB_ASN1, ERR_GET_LIB(err)); - ASSERT_EQ(ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM, ERR_GET_REASON(err)); + ASSERT_EQ(ERR_LIB_X509, ERR_GET_LIB(err)); + ASSERT_EQ(X509_R_INVALID_PARAMETER, ERR_GET_REASON(err)); ERR_clear_error(); } From 13b5886280e214f4dc2f795c75ba64d7b191c034 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Fri, 15 Nov 2024 11:19:05 -0800 Subject: [PATCH 24/28] documentation nit --- crypto/dilithium/ml_dsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/dilithium/ml_dsa.c b/crypto/dilithium/ml_dsa.c index 286b7edd4e..a96d7d9562 100644 --- a/crypto/dilithium/ml_dsa.c +++ b/crypto/dilithium/ml_dsa.c @@ -21,7 +21,7 @@ #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. From e419b9944904e8e30496d5a250b696997bc7e3f0 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Fri, 15 Nov 2024 11:19:29 -0800 Subject: [PATCH 25/28] documentation fix --- crypto/evp_extra/evp_asn1.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index af99690521..15b1247d97 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -70,14 +70,14 @@ #include "internal.h" #include "../dilithium/internal.h" -// The function 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. +// 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 to -// type specific decoding functions within the algorithm parameter. +// 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)) { @@ -101,7 +101,7 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { } #ifdef ENABLE_DILITHIUM - // if |cbs| is empty after parsing |oid| from it), we overwrite the contents + // 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) { From 53522b6872a79fe37f304dfa646bb4bbba529c6f Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Fri, 15 Nov 2024 13:49:16 -0800 Subject: [PATCH 26/28] alignment fix, re-run ci --- crypto/dilithium/ml_dsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/dilithium/ml_dsa.c b/crypto/dilithium/ml_dsa.c index a96d7d9562..267ef0381f 100644 --- a/crypto/dilithium/ml_dsa.c +++ b/crypto/dilithium/ml_dsa.c @@ -25,14 +25,14 @@ // 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 */, +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, private_key) == 0); } -int ml_dsa_65_sign(const uint8_t *private_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 */, From 369080b5a595f1880b4edc75a12eb8dcbe643c02 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Fri, 15 Nov 2024 15:52:56 -0800 Subject: [PATCH 27/28] check values, documentation, x509 oid --- crypto/dilithium/p_pqdsa_asn1.c | 10 +++++----- crypto/evp_extra/evp_asn1.c | 19 ++++++++++--------- crypto/x509/algorithm.c | 4 +++- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/crypto/dilithium/p_pqdsa_asn1.c b/crypto/dilithium/p_pqdsa_asn1.c index b535dea4e5..9f3e134f58 100644 --- a/crypto/dilithium/p_pqdsa_asn1.c +++ b/crypto/dilithium/p_pqdsa_asn1.c @@ -90,8 +90,6 @@ static int pqdsa_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, 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 parameters must be omitted. - // 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); @@ -139,15 +137,17 @@ static int pqdsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { 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 parameters must be omitted. - // 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 - EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(params)); + 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)); } diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index 15b1247d97..20c660895c 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -99,19 +99,20 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { if (OBJ_cbs2nid(&oid) == NID_rsa) { return &rsa_asn1_meth; } - #ifdef ENABLE_DILITHIUM - // 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)); - } - // 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. - return PQDSA_find_asn1_by_nid(OBJ_cbs2nid(&oid)); + 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; } diff --git a/crypto/x509/algorithm.c b/crypto/x509/algorithm.c index ef5645d7f3..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 @@ -98,7 +100,7 @@ int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { #ifdef ENABLE_DILITHIUM if (EVP_PKEY_id(pkey) == EVP_PKEY_PQDSA) { - return X509_ALGOR_set0(algor, OBJ_nid2obj(NID_MLDSA65), V_ASN1_UNDEF, NULL); + return X509_ALGOR_set0(algor, OBJ_nid2obj(pkey->pkey.pqdsa_key->pqdsa->nid), V_ASN1_UNDEF, NULL); } #endif From fb8631e132f89e65bda5372f7e76c157202d7341 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Fri, 15 Nov 2024 15:59:22 -0800 Subject: [PATCH 28/28] check return value --- crypto/dilithium/p_pqdsa_asn1.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crypto/dilithium/p_pqdsa_asn1.c b/crypto/dilithium/p_pqdsa_asn1.c index 9f3e134f58..ffb0a5a764 100644 --- a/crypto/dilithium/p_pqdsa_asn1.c +++ b/crypto/dilithium/p_pqdsa_asn1.c @@ -96,7 +96,10 @@ static int pqdsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { return 0; } // set the pqdsa params on the fresh pkey - EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(params)); + 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)); } @@ -147,7 +150,6 @@ static int pqdsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key, CBS *pubkey) OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return 0; } - return PQDSA_KEY_set_raw_private_key(out->pkey.pqdsa_key,CBS_data(key)); }