// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#include <gtest/gtest.h>
#include <openssl/base.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/pem.h>
#include "../test/test_util.h"

#include <vector>
#include "../fipsmodule/evp/internal.h"
#include "../internal.h"
#include "../fipsmodule/ml_dsa/ml_dsa.h"
#include "../fipsmodule/pqdsa/internal.h"
#include "../test/file_test.h"
#include "../test/test_util.h"
#include "../test/wycheproof_util.h"

// mldsa44kPublicKey is an example ML-DSA-44 public key
static const uint8_t mldsa44kPublicKey[] = {
0x88, 0x96, 0x9F, 0xBD, 0x4C, 0xC9, 0x27, 0x00, 0x57, 0xA5, 0xBF, 0xB2, 0x28,
0x9B, 0xB8, 0xB6, 0x66, 0x58, 0xB9, 0x65, 0x9A, 0x37, 0xA8, 0x2E, 0x5B, 0x5D,
0xE4, 0x85, 0xA8, 0x7F, 0x98, 0x3B, 0x57, 0x2D, 0xDB, 0xDD, 0x11, 0x7E, 0x74,
0x34, 0xCF, 0xFE, 0x78, 0x3F, 0x04, 0xBB, 0x9E, 0x7C, 0x74, 0x46, 0x00, 0xCF,
0x46, 0xA8, 0x9F, 0x53, 0x11, 0x4C, 0xBB, 0x33, 0x49, 0x50, 0x5A, 0xA5, 0x6D,
0xEA, 0x2A, 0x79, 0xF4, 0x83, 0x0E, 0x19, 0x8A, 0xCB, 0x0B, 0xDA, 0xBC, 0xFE,
0xD3, 0x0D, 0x12, 0x0B, 0x34, 0x35, 0xDB, 0x3D, 0xF7, 0x95, 0x89, 0xBF, 0x87,
0x82, 0x0A, 0x5B, 0x5E, 0x5C, 0xF1, 0x96, 0x7A, 0x46, 0xA3, 0xB5, 0x80, 0x60,
0xB4, 0xB5, 0xD1, 0x72, 0xB7, 0x2C, 0x7A, 0x99, 0x94, 0x48, 0x93, 0x0E, 0xFC,
0xEB, 0x02, 0x2F, 0x15, 0xC3, 0x5C, 0xC5, 0x4A, 0xDE, 0x84, 0xEC, 0x45, 0xBA,
0xEA, 0x1D, 0x8F, 0xD2, 0x01, 0x6F, 0xC0, 0x85, 0xDF, 0x7B, 0xBA, 0x1F, 0x52,
0xEE, 0xD1, 0xB8, 0x50, 0xBE, 0x93, 0x42, 0x87, 0x39, 0x46, 0x1C, 0xCA, 0x63,
0x4D, 0xAD, 0x5F, 0xBD, 0xEF, 0x0C, 0x9D, 0x11, 0x6E, 0xBA, 0xC2, 0x8E, 0xB7,
0x59, 0x4B, 0x1C, 0x22, 0xC0, 0x4D, 0x05, 0x37, 0x93, 0x10, 0xE6, 0xFD, 0x7A,
0xEC, 0x6C, 0x80, 0x32, 0xF9, 0x64, 0x60, 0xC7, 0x35, 0x81, 0x98, 0x42, 0xDD,
0x70, 0x0E, 0xFD, 0x13, 0x2D, 0x36, 0xF7, 0xDA, 0x3D, 0x00, 0x1B, 0x4C, 0x7D,
0xAB, 0x13, 0xAA, 0xED, 0x3B, 0xC2, 0x01, 0xB1, 0x54, 0xA7, 0x99, 0xAB, 0x7D,
0x6F, 0xA9, 0x29, 0xCF, 0xCA, 0x45, 0xBE, 0x0C, 0x2C, 0xFB, 0x04, 0xF9, 0x64,
0x60, 0xF4, 0x3A, 0x60, 0xDC, 0x62, 0x49, 0x9E, 0xBF, 0x0B, 0xE3, 0x73, 0xFC,
0xC4, 0xC2, 0x44, 0xC4, 0x6D, 0xD0, 0x3F, 0xD2, 0xC5, 0x7D, 0x0E, 0x87, 0xE5,
0x68, 0xC9, 0xEF, 0x93, 0x42, 0xCD, 0xA3, 0x2E, 0x6D, 0xA4, 0x5B, 0xD6, 0x66,
0x7B, 0x94, 0xA0, 0xA7, 0xB8, 0x7E, 0x30, 0xEE, 0x15, 0x3A, 0xB8, 0xB3, 0x68,
0x66, 0x14, 0x09, 0x22, 0xB1, 0x10, 0x52, 0x47, 0x7A, 0xDD, 0x43, 0x29, 0x77,
0x50, 0xDA, 0x60, 0xF9, 0x17, 0x43, 0xA3, 0xA8, 0x6E, 0x73, 0x47, 0x75, 0xCD,
0xEB, 0x00, 0xDC, 0xAB, 0xEE, 0xCD, 0x77, 0x3A, 0xA5, 0x0D, 0xA7, 0xDB, 0xD3,
0xAA, 0xD2, 0x21, 0xB4, 0x8F, 0xC8, 0x6F, 0x56, 0x9C, 0x20, 0xB2, 0xC6, 0x53,
0x28, 0xA6, 0x63, 0x48, 0x45, 0x78, 0x57, 0xB3, 0xF3, 0xCC, 0xED, 0xAD, 0x30,
0x38, 0x45, 0x02, 0x3E, 0xF8, 0x86, 0x29, 0xA9, 0x56, 0xAA, 0x8C, 0x83, 0xC8,
0x7C, 0xF3, 0x04, 0x64, 0x57, 0xE5, 0x62, 0xFB, 0x53, 0x3B, 0x9E, 0xF9, 0x44,
0xB2, 0x47, 0xFF, 0x0A, 0x60, 0x06, 0x34, 0xD4, 0x85, 0x9B, 0xF4, 0x2E, 0x13,
0xB8, 0x99, 0x6F, 0xC6, 0x9A, 0x9B, 0x69, 0x10, 0x46, 0x78, 0xB0, 0x63, 0x26,
0x18, 0x73, 0xEB, 0x0A, 0x64, 0xA8, 0x10, 0x5B, 0xA3, 0xBD, 0x7B, 0x67, 0xF0,
0x8E, 0x49, 0x7E, 0xB5, 0x7D, 0xCF, 0xA8, 0xD3, 0x88, 0xAD, 0x01, 0xC2, 0x12,
0x89, 0x31, 0xCD, 0x9C, 0xC9, 0x57, 0x97, 0x70, 0x79, 0x0E, 0x16, 0x71, 0x85,
0x79, 0x39, 0x41, 0x63, 0xF8, 0x2E, 0x4D, 0x53, 0x88, 0xBE, 0xED, 0xC9, 0x82,
0xBD, 0x0F, 0x81, 0x22, 0x40, 0x14, 0xAF, 0xA4, 0x07, 0x10, 0x7C, 0x07, 0xAA,
0xF3, 0x27, 0x11, 0x19, 0x2F, 0xFF, 0xFE, 0xBB, 0x0A, 0xF5, 0xC1, 0xBF, 0x2C,
0x93, 0x00, 0xCE, 0xF1, 0xF7, 0x7F, 0xEA, 0x68, 0x39, 0x04, 0x48, 0xBF, 0x42,
0x01, 0xBB, 0x51, 0x82, 0x36, 0x3C, 0x93, 0x55, 0x43, 0x7C, 0x2C, 0xFF, 0xE1,
0xD8, 0x51, 0x5B, 0xC3, 0xB4, 0x57, 0x72, 0x24, 0xAB, 0xDD, 0xDA, 0x14, 0x71,
0x0C, 0xC0, 0x9B, 0x73, 0x46, 0xF7, 0xE4, 0x12, 0x15, 0x8B, 0x26, 0x44, 0xD7,
0xD3, 0xF1, 0x86, 0xD5, 0xA4, 0x90, 0xA9, 0x0C, 0x89, 0x26, 0x8A, 0x67, 0xCB,
0xA0, 0xFF, 0x45, 0x8D, 0xB0, 0xF4, 0x5D, 0x78, 0x77, 0x38, 0x34, 0x7E, 0xDE,
0x65, 0x8A, 0x68, 0x69, 0x26, 0xD3, 0x2D, 0xD8, 0x95, 0xD9, 0x3A, 0x88, 0x4E,
0x8E, 0x9B, 0x9C, 0x83, 0x21, 0x18, 0x6B, 0xE1, 0x4A, 0xEC, 0x43, 0x39, 0xF8,
0xD7, 0xC4, 0x77, 0x32, 0xDD, 0x20, 0x51, 0x2B, 0x90, 0x08, 0x5B, 0x51, 0xF1,
0x3C, 0x73, 0x68, 0x89, 0x18, 0x8E, 0xD2, 0x9C, 0x9A, 0x32, 0xAE, 0x49, 0xA5,
0x19, 0xED, 0xE4, 0x1E, 0x6B, 0x78, 0x7D, 0x4A, 0x92, 0x07, 0x07, 0x75, 0x19,
0x7A, 0x0B, 0xC1, 0x79, 0xFF, 0xB4, 0xCF, 0x26, 0x28, 0x3B, 0xF8, 0xC6, 0xE4,
0x89, 0x8C, 0x92, 0x39, 0xC3, 0x81, 0x63, 0xC4, 0xAA, 0xE3, 0xE2, 0x00, 0x7F,
0xB0, 0x77, 0xE9, 0x07, 0xE4, 0x38, 0xA4, 0xFC, 0x2F, 0x67, 0xD1, 0xED, 0x22,
0xA3, 0xCB, 0x31, 0x79, 0xB9, 0x38, 0xDB, 0x12, 0x50, 0x1A, 0x0F, 0xE6, 0x53,
0x09, 0xD1, 0x06, 0xD1, 0xE4, 0x35, 0x2F, 0x93, 0x5B, 0x5A, 0x6C, 0x27, 0x06,
0xC4, 0x77, 0xED, 0x6F, 0xB5, 0x41, 0x87, 0xF6, 0x26, 0xAA, 0x96, 0xC1, 0x76,
0xE1, 0x1C, 0x0F, 0x13, 0x2D, 0x05, 0xBA, 0x38, 0x52, 0x7B, 0xD2, 0x71, 0xDF,
0xF0, 0xF9, 0x5E, 0x85, 0x45, 0x52, 0xDC, 0x2A, 0x8A, 0x20, 0x05, 0x8F, 0x11,
0xDE, 0x0C, 0x9E, 0x6B, 0xC9, 0x36, 0xDE, 0x05, 0xE9, 0xC9, 0xFD, 0xED, 0x80,
0xA8, 0x63, 0xFC, 0xE5, 0x3B, 0x29, 0x81, 0x4F, 0x25, 0xF3, 0x59, 0xCC, 0x8F,
0x40, 0xA9, 0x6B, 0x67, 0x1E, 0x67, 0x29, 0x19, 0x27, 0x14, 0xF2, 0xDC, 0x2C,
0x9D, 0xFF, 0x73, 0x60, 0x29, 0x22, 0xF6, 0x10, 0x12, 0x39, 0xE8, 0xB8, 0xB9,
0xD0, 0x90, 0xC7, 0xE1, 0x10, 0x0D, 0x30, 0xC5, 0x11, 0x85, 0x7C, 0x0B, 0x0C,
0x29, 0xD9, 0x4A, 0xBA, 0xBB, 0xE9, 0xF6, 0x4E, 0xEC, 0x1B, 0x62, 0x48, 0x0C,
0x7A, 0xFA, 0x9A, 0xF9, 0x12, 0xA5, 0xC3, 0x3E, 0x67, 0x0B, 0x7A, 0x27, 0x2B,
0x20, 0xB2, 0x82, 0x5C, 0x86, 0xEA, 0x31, 0x8A, 0x90, 0xE6, 0xFA, 0x45, 0x36,
0x41, 0x53, 0x78, 0x57, 0x88, 0x76, 0x97, 0x3D, 0xB0, 0x8A, 0x43, 0x2B, 0x67,
0x79, 0x96, 0x35, 0x7D, 0xEF, 0x9C, 0x93, 0xBA, 0xD2, 0x91, 0x86, 0xCF, 0x52,
0xD5, 0x96, 0xAA, 0xD0, 0x45, 0xD8, 0x3C, 0x93, 0xC4, 0xC2, 0xC3, 0x5F, 0x4A,
0x23, 0xD4, 0xC7, 0xE4, 0x1D, 0x3B, 0xD1, 0x8F, 0x91, 0x36, 0xFA, 0x64, 0x15,
0xA8, 0xA8, 0xD1, 0x95, 0xCD, 0x2C, 0x99, 0x8A, 0x34, 0x0A, 0x5E, 0x0E, 0xB0,
0x6A, 0x8E, 0xF2, 0xE8, 0xE9, 0xF9, 0x67, 0xF6, 0xD6, 0x33, 0xBE, 0xD3, 0xB7,
0x94, 0x8B, 0x27, 0xB2, 0x33, 0xE2, 0x41, 0xE3, 0x9E, 0x12, 0xE4, 0x21, 0x35,
0x58, 0xD6, 0xDE, 0xB5, 0xAC, 0xF2, 0x72, 0xC4, 0x32, 0x72, 0xB8, 0x2E, 0x7D,
0xD0, 0xF3, 0xE3, 0x56, 0x86, 0xFD, 0x5F, 0xD0, 0x66, 0x64, 0xB4, 0x92, 0x27,
0xCA, 0x36, 0xE1, 0x57, 0x9F, 0xC0, 0x0D, 0x0E, 0xBE, 0xA6, 0x42, 0xAD, 0xD9,
0x7D, 0x9A, 0x7D, 0x1F, 0x87, 0x17, 0x46, 0x3B, 0xA5, 0x40, 0x9C, 0xD2, 0x9F,
0xD6, 0x73, 0xC6, 0xFA, 0xD3, 0x03, 0x27, 0x01, 0x59, 0x8D, 0x5F, 0xB8, 0xAF,
0x2D, 0xCE, 0x06, 0xA2, 0x73, 0xE2, 0xE4, 0xC9, 0xE2, 0x14, 0x58, 0xA8, 0x2C,
0xC6, 0xBF, 0x72, 0x8E, 0x87, 0x84, 0x81, 0x7B, 0x62, 0x5A, 0x13, 0x7D, 0xFF,
0x38, 0x9E, 0x97, 0xEF, 0x91, 0x45, 0xB6, 0xC6, 0xCF, 0x0E, 0xC0, 0xBA, 0x2A,
0xAE, 0x41, 0x44, 0x48, 0xE5, 0x52, 0x45, 0x15, 0x01, 0xE0, 0xF7, 0x98, 0xAB,
0x45, 0x26, 0x25, 0xCA, 0x95, 0x6D, 0xB2, 0x04, 0xB7, 0x93, 0x06, 0xE2, 0x8F,
0xF5, 0x59, 0xA7, 0xD6, 0x69, 0x4D, 0x03, 0x07, 0x45, 0xE7, 0xE6, 0xA4, 0x8A,
0x8B, 0xBD, 0xB8, 0x09, 0x9F, 0x33, 0xD5, 0x58, 0x88, 0xC3, 0xD8, 0x55, 0x26,
0xCE, 0x94, 0x21, 0x08, 0x43, 0x36, 0x57, 0xE8, 0x6A, 0x5D, 0x4D, 0x5B, 0x00,
0x4D, 0x58, 0xB3, 0x29, 0xE4, 0x23, 0xF5, 0x3B, 0x78, 0xD4, 0x3D, 0x08, 0xE3,
0xC2, 0x26, 0x16, 0x86, 0x4A, 0xD2, 0x5B, 0x08, 0x3D, 0xE4, 0x31, 0x5A, 0x77,
0x40, 0xFA, 0xC4, 0x4B, 0x78, 0xB1, 0x16, 0xEA, 0x57, 0xA5, 0x63, 0x2A, 0x7C,
0x4C, 0x0D, 0xF5, 0xD4, 0xD4, 0x1C, 0x7A, 0x28, 0x96, 0xAF, 0xEB, 0x23, 0x32,
0x2F, 0x84, 0x68, 0x33, 0x94, 0x60, 0xDD, 0x65, 0xBA, 0x4F, 0x88, 0x25, 0x5F,
0x42, 0x86, 0xD7, 0xF8, 0x3D, 0x6D, 0xDF, 0xA1, 0x08, 0x67, 0xCA, 0xFB, 0xB0,
0x0B, 0x3C, 0x0F, 0xB0, 0x69, 0xD5, 0x44, 0x56, 0x6D, 0xB7, 0xCF, 0x1D, 0xA2,
0x38, 0x3C, 0x72, 0xC7, 0x6C, 0x9D, 0x08, 0xCF, 0xDE, 0x2D, 0x99, 0x85, 0x8A,
0xD3, 0xC9, 0xCE, 0x59, 0x86, 0x63, 0x9A, 0x20, 0xD8, 0x54, 0xA6, 0x30, 0xF7,
0x6D, 0xFC, 0x99, 0xDF, 0xF3, 0x85, 0xD7, 0xCE, 0xEC, 0x83, 0x9B, 0x45, 0x3C,
0xA9, 0x7B, 0x52, 0xBB, 0xB6, 0x31, 0xCF, 0x1F, 0xD2, 0x99, 0x1D, 0x5A, 0x30,
0xB5, 0x63, 0x3E, 0x28, 0x0B, 0xA4, 0x61, 0xD9, 0xE9, 0xBD, 0x04, 0x70, 0x76,
0x83, 0x4C, 0x35, 0x60, 0x7A, 0x0A, 0x55, 0x6C, 0x9C, 0x9F, 0x6A, 0x42, 0xBE,
0x1F, 0xDD, 0x89, 0x55, 0x87, 0x48, 0xF3, 0xBB, 0x64, 0x17, 0xFA, 0x17, 0x60,
0xC4, 0xDC, 0xB6, 0xBF, 0xB7, 0x56, 0x64, 0x6E, 0x0A, 0xC3, 0x6B, 0x33, 0x8A,
0xAC, 0x6C, 0x97, 0x86, 0xB4, 0x27, 0x0D, 0xB0, 0x36, 0x3F, 0x3C, 0x6D, 0x7C,
0x66, 0x13, 0x94, 0xFB, 0x0E, 0x8E, 0xE8, 0x0E, 0x49, 0xEF, 0xD0, 0x0E};

// mldsa44kPublicKeySPKI is the above example ML-DSA-44 public key encoded
static const uint8_t mldsa44kPublicKeySPKI[] = {
0x30, 0x82, 0x05, 0x32, 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
0x03, 0x04, 0x03, 0x11, 0x03, 0x82, 0x05, 0x21, 0x00, 0x88, 0x96, 0x9F, 0xBD,
0x4C, 0xC9, 0x27, 0x00, 0x57, 0xA5, 0xBF, 0xB2, 0x28, 0x9B, 0xB8, 0xB6, 0x66,
0x58, 0xB9, 0x65, 0x9A, 0x37, 0xA8, 0x2E, 0x5B, 0x5D, 0xE4, 0x85, 0xA8, 0x7F,
0x98, 0x3B, 0x57, 0x2D, 0xDB, 0xDD, 0x11, 0x7E, 0x74, 0x34, 0xCF, 0xFE, 0x78,
0x3F, 0x04, 0xBB, 0x9E, 0x7C, 0x74, 0x46, 0x00, 0xCF, 0x46, 0xA8, 0x9F, 0x53,
0x11, 0x4C, 0xBB, 0x33, 0x49, 0x50, 0x5A, 0xA5, 0x6D, 0xEA, 0x2A, 0x79, 0xF4,
0x83, 0x0E, 0x19, 0x8A, 0xCB, 0x0B, 0xDA, 0xBC, 0xFE, 0xD3, 0x0D, 0x12, 0x0B,
0x34, 0x35, 0xDB, 0x3D, 0xF7, 0x95, 0x89, 0xBF, 0x87, 0x82, 0x0A, 0x5B, 0x5E,
0x5C, 0xF1, 0x96, 0x7A, 0x46, 0xA3, 0xB5, 0x80, 0x60, 0xB4, 0xB5, 0xD1, 0x72,
0xB7, 0x2C, 0x7A, 0x99, 0x94, 0x48, 0x93, 0x0E, 0xFC, 0xEB, 0x02, 0x2F, 0x15,
0xC3, 0x5C, 0xC5, 0x4A, 0xDE, 0x84, 0xEC, 0x45, 0xBA, 0xEA, 0x1D, 0x8F, 0xD2,
0x01, 0x6F, 0xC0, 0x85, 0xDF, 0x7B, 0xBA, 0x1F, 0x52, 0xEE, 0xD1, 0xB8, 0x50,
0xBE, 0x93, 0x42, 0x87, 0x39, 0x46, 0x1C, 0xCA, 0x63, 0x4D, 0xAD, 0x5F, 0xBD,
0xEF, 0x0C, 0x9D, 0x11, 0x6E, 0xBA, 0xC2, 0x8E, 0xB7, 0x59, 0x4B, 0x1C, 0x22,
0xC0, 0x4D, 0x05, 0x37, 0x93, 0x10, 0xE6, 0xFD, 0x7A, 0xEC, 0x6C, 0x80, 0x32,
0xF9, 0x64, 0x60, 0xC7, 0x35, 0x81, 0x98, 0x42, 0xDD, 0x70, 0x0E, 0xFD, 0x13,
0x2D, 0x36, 0xF7, 0xDA, 0x3D, 0x00, 0x1B, 0x4C, 0x7D, 0xAB, 0x13, 0xAA, 0xED,
0x3B, 0xC2, 0x01, 0xB1, 0x54, 0xA7, 0x99, 0xAB, 0x7D, 0x6F, 0xA9, 0x29, 0xCF,
0xCA, 0x45, 0xBE, 0x0C, 0x2C, 0xFB, 0x04, 0xF9, 0x64, 0x60, 0xF4, 0x3A, 0x60,
0xDC, 0x62, 0x49, 0x9E, 0xBF, 0x0B, 0xE3, 0x73, 0xFC, 0xC4, 0xC2, 0x44, 0xC4,
0x6D, 0xD0, 0x3F, 0xD2, 0xC5, 0x7D, 0x0E, 0x87, 0xE5, 0x68, 0xC9, 0xEF, 0x93,
0x42, 0xCD, 0xA3, 0x2E, 0x6D, 0xA4, 0x5B, 0xD6, 0x66, 0x7B, 0x94, 0xA0, 0xA7,
0xB8, 0x7E, 0x30, 0xEE, 0x15, 0x3A, 0xB8, 0xB3, 0x68, 0x66, 0x14, 0x09, 0x22,
0xB1, 0x10, 0x52, 0x47, 0x7A, 0xDD, 0x43, 0x29, 0x77, 0x50, 0xDA, 0x60, 0xF9,
0x17, 0x43, 0xA3, 0xA8, 0x6E, 0x73, 0x47, 0x75, 0xCD, 0xEB, 0x00, 0xDC, 0xAB,
0xEE, 0xCD, 0x77, 0x3A, 0xA5, 0x0D, 0xA7, 0xDB, 0xD3, 0xAA, 0xD2, 0x21, 0xB4,
0x8F, 0xC8, 0x6F, 0x56, 0x9C, 0x20, 0xB2, 0xC6, 0x53, 0x28, 0xA6, 0x63, 0x48,
0x45, 0x78, 0x57, 0xB3, 0xF3, 0xCC, 0xED, 0xAD, 0x30, 0x38, 0x45, 0x02, 0x3E,
0xF8, 0x86, 0x29, 0xA9, 0x56, 0xAA, 0x8C, 0x83, 0xC8, 0x7C, 0xF3, 0x04, 0x64,
0x57, 0xE5, 0x62, 0xFB, 0x53, 0x3B, 0x9E, 0xF9, 0x44, 0xB2, 0x47, 0xFF, 0x0A,
0x60, 0x06, 0x34, 0xD4, 0x85, 0x9B, 0xF4, 0x2E, 0x13, 0xB8, 0x99, 0x6F, 0xC6,
0x9A, 0x9B, 0x69, 0x10, 0x46, 0x78, 0xB0, 0x63, 0x26, 0x18, 0x73, 0xEB, 0x0A,
0x64, 0xA8, 0x10, 0x5B, 0xA3, 0xBD, 0x7B, 0x67, 0xF0, 0x8E, 0x49, 0x7E, 0xB5,
0x7D, 0xCF, 0xA8, 0xD3, 0x88, 0xAD, 0x01, 0xC2, 0x12, 0x89, 0x31, 0xCD, 0x9C,
0xC9, 0x57, 0x97, 0x70, 0x79, 0x0E, 0x16, 0x71, 0x85, 0x79, 0x39, 0x41, 0x63,
0xF8, 0x2E, 0x4D, 0x53, 0x88, 0xBE, 0xED, 0xC9, 0x82, 0xBD, 0x0F, 0x81, 0x22,
0x40, 0x14, 0xAF, 0xA4, 0x07, 0x10, 0x7C, 0x07, 0xAA, 0xF3, 0x27, 0x11, 0x19,
0x2F, 0xFF, 0xFE, 0xBB, 0x0A, 0xF5, 0xC1, 0xBF, 0x2C, 0x93, 0x00, 0xCE, 0xF1,
0xF7, 0x7F, 0xEA, 0x68, 0x39, 0x04, 0x48, 0xBF, 0x42, 0x01, 0xBB, 0x51, 0x82,
0x36, 0x3C, 0x93, 0x55, 0x43, 0x7C, 0x2C, 0xFF, 0xE1, 0xD8, 0x51, 0x5B, 0xC3,
0xB4, 0x57, 0x72, 0x24, 0xAB, 0xDD, 0xDA, 0x14, 0x71, 0x0C, 0xC0, 0x9B, 0x73,
0x46, 0xF7, 0xE4, 0x12, 0x15, 0x8B, 0x26, 0x44, 0xD7, 0xD3, 0xF1, 0x86, 0xD5,
0xA4, 0x90, 0xA9, 0x0C, 0x89, 0x26, 0x8A, 0x67, 0xCB, 0xA0, 0xFF, 0x45, 0x8D,
0xB0, 0xF4, 0x5D, 0x78, 0x77, 0x38, 0x34, 0x7E, 0xDE, 0x65, 0x8A, 0x68, 0x69,
0x26, 0xD3, 0x2D, 0xD8, 0x95, 0xD9, 0x3A, 0x88, 0x4E, 0x8E, 0x9B, 0x9C, 0x83,
0x21, 0x18, 0x6B, 0xE1, 0x4A, 0xEC, 0x43, 0x39, 0xF8, 0xD7, 0xC4, 0x77, 0x32,
0xDD, 0x20, 0x51, 0x2B, 0x90, 0x08, 0x5B, 0x51, 0xF1, 0x3C, 0x73, 0x68, 0x89,
0x18, 0x8E, 0xD2, 0x9C, 0x9A, 0x32, 0xAE, 0x49, 0xA5, 0x19, 0xED, 0xE4, 0x1E,
0x6B, 0x78, 0x7D, 0x4A, 0x92, 0x07, 0x07, 0x75, 0x19, 0x7A, 0x0B, 0xC1, 0x79,
0xFF, 0xB4, 0xCF, 0x26, 0x28, 0x3B, 0xF8, 0xC6, 0xE4, 0x89, 0x8C, 0x92, 0x39,
0xC3, 0x81, 0x63, 0xC4, 0xAA, 0xE3, 0xE2, 0x00, 0x7F, 0xB0, 0x77, 0xE9, 0x07,
0xE4, 0x38, 0xA4, 0xFC, 0x2F, 0x67, 0xD1, 0xED, 0x22, 0xA3, 0xCB, 0x31, 0x79,
0xB9, 0x38, 0xDB, 0x12, 0x50, 0x1A, 0x0F, 0xE6, 0x53, 0x09, 0xD1, 0x06, 0xD1,
0xE4, 0x35, 0x2F, 0x93, 0x5B, 0x5A, 0x6C, 0x27, 0x06, 0xC4, 0x77, 0xED, 0x6F,
0xB5, 0x41, 0x87, 0xF6, 0x26, 0xAA, 0x96, 0xC1, 0x76, 0xE1, 0x1C, 0x0F, 0x13,
0x2D, 0x05, 0xBA, 0x38, 0x52, 0x7B, 0xD2, 0x71, 0xDF, 0xF0, 0xF9, 0x5E, 0x85,
0x45, 0x52, 0xDC, 0x2A, 0x8A, 0x20, 0x05, 0x8F, 0x11, 0xDE, 0x0C, 0x9E, 0x6B,
0xC9, 0x36, 0xDE, 0x05, 0xE9, 0xC9, 0xFD, 0xED, 0x80, 0xA8, 0x63, 0xFC, 0xE5,
0x3B, 0x29, 0x81, 0x4F, 0x25, 0xF3, 0x59, 0xCC, 0x8F, 0x40, 0xA9, 0x6B, 0x67,
0x1E, 0x67, 0x29, 0x19, 0x27, 0x14, 0xF2, 0xDC, 0x2C, 0x9D, 0xFF, 0x73, 0x60,
0x29, 0x22, 0xF6, 0x10, 0x12, 0x39, 0xE8, 0xB8, 0xB9, 0xD0, 0x90, 0xC7, 0xE1,
0x10, 0x0D, 0x30, 0xC5, 0x11, 0x85, 0x7C, 0x0B, 0x0C, 0x29, 0xD9, 0x4A, 0xBA,
0xBB, 0xE9, 0xF6, 0x4E, 0xEC, 0x1B, 0x62, 0x48, 0x0C, 0x7A, 0xFA, 0x9A, 0xF9,
0x12, 0xA5, 0xC3, 0x3E, 0x67, 0x0B, 0x7A, 0x27, 0x2B, 0x20, 0xB2, 0x82, 0x5C,
0x86, 0xEA, 0x31, 0x8A, 0x90, 0xE6, 0xFA, 0x45, 0x36, 0x41, 0x53, 0x78, 0x57,
0x88, 0x76, 0x97, 0x3D, 0xB0, 0x8A, 0x43, 0x2B, 0x67, 0x79, 0x96, 0x35, 0x7D,
0xEF, 0x9C, 0x93, 0xBA, 0xD2, 0x91, 0x86, 0xCF, 0x52, 0xD5, 0x96, 0xAA, 0xD0,
0x45, 0xD8, 0x3C, 0x93, 0xC4, 0xC2, 0xC3, 0x5F, 0x4A, 0x23, 0xD4, 0xC7, 0xE4,
0x1D, 0x3B, 0xD1, 0x8F, 0x91, 0x36, 0xFA, 0x64, 0x15, 0xA8, 0xA8, 0xD1, 0x95,
0xCD, 0x2C, 0x99, 0x8A, 0x34, 0x0A, 0x5E, 0x0E, 0xB0, 0x6A, 0x8E, 0xF2, 0xE8,
0xE9, 0xF9, 0x67, 0xF6, 0xD6, 0x33, 0xBE, 0xD3, 0xB7, 0x94, 0x8B, 0x27, 0xB2,
0x33, 0xE2, 0x41, 0xE3, 0x9E, 0x12, 0xE4, 0x21, 0x35, 0x58, 0xD6, 0xDE, 0xB5,
0xAC, 0xF2, 0x72, 0xC4, 0x32, 0x72, 0xB8, 0x2E, 0x7D, 0xD0, 0xF3, 0xE3, 0x56,
0x86, 0xFD, 0x5F, 0xD0, 0x66, 0x64, 0xB4, 0x92, 0x27, 0xCA, 0x36, 0xE1, 0x57,
0x9F, 0xC0, 0x0D, 0x0E, 0xBE, 0xA6, 0x42, 0xAD, 0xD9, 0x7D, 0x9A, 0x7D, 0x1F,
0x87, 0x17, 0x46, 0x3B, 0xA5, 0x40, 0x9C, 0xD2, 0x9F, 0xD6, 0x73, 0xC6, 0xFA,
0xD3, 0x03, 0x27, 0x01, 0x59, 0x8D, 0x5F, 0xB8, 0xAF, 0x2D, 0xCE, 0x06, 0xA2,
0x73, 0xE2, 0xE4, 0xC9, 0xE2, 0x14, 0x58, 0xA8, 0x2C, 0xC6, 0xBF, 0x72, 0x8E,
0x87, 0x84, 0x81, 0x7B, 0x62, 0x5A, 0x13, 0x7D, 0xFF, 0x38, 0x9E, 0x97, 0xEF,
0x91, 0x45, 0xB6, 0xC6, 0xCF, 0x0E, 0xC0, 0xBA, 0x2A, 0xAE, 0x41, 0x44, 0x48,
0xE5, 0x52, 0x45, 0x15, 0x01, 0xE0, 0xF7, 0x98, 0xAB, 0x45, 0x26, 0x25, 0xCA,
0x95, 0x6D, 0xB2, 0x04, 0xB7, 0x93, 0x06, 0xE2, 0x8F, 0xF5, 0x59, 0xA7, 0xD6,
0x69, 0x4D, 0x03, 0x07, 0x45, 0xE7, 0xE6, 0xA4, 0x8A, 0x8B, 0xBD, 0xB8, 0x09,
0x9F, 0x33, 0xD5, 0x58, 0x88, 0xC3, 0xD8, 0x55, 0x26, 0xCE, 0x94, 0x21, 0x08,
0x43, 0x36, 0x57, 0xE8, 0x6A, 0x5D, 0x4D, 0x5B, 0x00, 0x4D, 0x58, 0xB3, 0x29,
0xE4, 0x23, 0xF5, 0x3B, 0x78, 0xD4, 0x3D, 0x08, 0xE3, 0xC2, 0x26, 0x16, 0x86,
0x4A, 0xD2, 0x5B, 0x08, 0x3D, 0xE4, 0x31, 0x5A, 0x77, 0x40, 0xFA, 0xC4, 0x4B,
0x78, 0xB1, 0x16, 0xEA, 0x57, 0xA5, 0x63, 0x2A, 0x7C, 0x4C, 0x0D, 0xF5, 0xD4,
0xD4, 0x1C, 0x7A, 0x28, 0x96, 0xAF, 0xEB, 0x23, 0x32, 0x2F, 0x84, 0x68, 0x33,
0x94, 0x60, 0xDD, 0x65, 0xBA, 0x4F, 0x88, 0x25, 0x5F, 0x42, 0x86, 0xD7, 0xF8,
0x3D, 0x6D, 0xDF, 0xA1, 0x08, 0x67, 0xCA, 0xFB, 0xB0, 0x0B, 0x3C, 0x0F, 0xB0,
0x69, 0xD5, 0x44, 0x56, 0x6D, 0xB7, 0xCF, 0x1D, 0xA2, 0x38, 0x3C, 0x72, 0xC7,
0x6C, 0x9D, 0x08, 0xCF, 0xDE, 0x2D, 0x99, 0x85, 0x8A, 0xD3, 0xC9, 0xCE, 0x59,
0x86, 0x63, 0x9A, 0x20, 0xD8, 0x54, 0xA6, 0x30, 0xF7, 0x6D, 0xFC, 0x99, 0xDF,
0xF3, 0x85, 0xD7, 0xCE, 0xEC, 0x83, 0x9B, 0x45, 0x3C, 0xA9, 0x7B, 0x52, 0xBB,
0xB6, 0x31, 0xCF, 0x1F, 0xD2, 0x99, 0x1D, 0x5A, 0x30, 0xB5, 0x63, 0x3E, 0x28,
0x0B, 0xA4, 0x61, 0xD9, 0xE9, 0xBD, 0x04, 0x70, 0x76, 0x83, 0x4C, 0x35, 0x60,
0x7A, 0x0A, 0x55, 0x6C, 0x9C, 0x9F, 0x6A, 0x42, 0xBE, 0x1F, 0xDD, 0x89, 0x55,
0x87, 0x48, 0xF3, 0xBB, 0x64, 0x17, 0xFA, 0x17, 0x60, 0xC4, 0xDC, 0xB6, 0xBF,
0xB7, 0x56, 0x64, 0x6E, 0x0A, 0xC3, 0x6B, 0x33, 0x8A, 0xAC, 0x6C, 0x97, 0x86,
0xB4, 0x27, 0x0D, 0xB0, 0x36, 0x3F, 0x3C, 0x6D, 0x7C, 0x66, 0x13, 0x94, 0xFB,
0x0E, 0x8E, 0xE8, 0x0E, 0x49, 0xEF, 0xD0, 0x0E};

// mldsa65kPublicKey is an example ML-DSA-65 public key
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};

// mldsa65kPublicKeySPKI is the above example ML-DSA-65 public key encoded
static const uint8_t mldsa65kPublicKeySPKI[] = {
0x30, 0x82, 0x07, 0xB2, 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
0x03, 0x04, 0x03, 0x12, 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 };

// mldsa87kPublicKey is an example ML-DSA-87 public key
static const uint8_t mldsa87kPublicKey[] = {
0xE4, 0x36, 0x63, 0x53, 0xA7, 0xE7, 0xDF, 0x51, 0x06, 0x19, 0x34, 0x9F, 0xB5,
0x95, 0x53, 0x9D, 0xC0, 0x59, 0x21, 0x38, 0x0F, 0x8E, 0x2A, 0xEC, 0x43, 0x5C,
0x9B, 0x4B, 0xD0, 0xDC, 0x7E, 0xE1, 0x89, 0x77, 0x51, 0xD4, 0x26, 0x46, 0x8F,
0x25, 0x76, 0xAB, 0x5E, 0x68, 0xFE, 0x45, 0xC6, 0x35, 0xF5, 0xF0, 0xD0, 0x2D,
0xD2, 0x11, 0xCB, 0x2D, 0x3B, 0x6B, 0xF3, 0x2F, 0x68, 0xD1, 0xF2, 0xCC, 0x51,
0x9E, 0xE0, 0xC5, 0x1D, 0xFA, 0x2C, 0x55, 0x02, 0xE5, 0xAB, 0xC6, 0xA2, 0xA9,
0x2C, 0x35, 0xC1, 0x22, 0xDC, 0xFB, 0x9D, 0xDC, 0x9E, 0x17, 0xCB, 0x7C, 0xEC,
0xB4, 0x7D, 0x1C, 0x40, 0xA6, 0x40, 0x3C, 0x2B, 0x1C, 0x5B, 0x85, 0x97, 0x31,
0x5D, 0x9E, 0xAD, 0x7C, 0xC9, 0xF1, 0xBC, 0x99, 0x59, 0x2B, 0xE0, 0x10, 0x30,
0x58, 0xC6, 0x63, 0xBD, 0xD7, 0xF1, 0x27, 0x2B, 0x1E, 0xB2, 0xA8, 0x31, 0xD7,
0xD3, 0x2B, 0x85, 0xA7, 0x59, 0xAF, 0x70, 0x15, 0x66, 0x9E, 0xD2, 0x13, 0xB0,
0x50, 0xBF, 0x59, 0x08, 0x92, 0x32, 0x07, 0x9C, 0x81, 0xD7, 0x06, 0x55, 0x76,
0xEE, 0x15, 0x8A, 0xFE, 0xCB, 0x62, 0x58, 0xF7, 0xDF, 0x0F, 0xEB, 0x0A, 0x11,
0x98, 0xF8, 0x93, 0xD8, 0x96, 0xF5, 0x14, 0x87, 0x40, 0x4F, 0xEC, 0x9A, 0x45,
0xE2, 0x7A, 0x54, 0x91, 0x0B, 0xDB, 0x39, 0x90, 0x48, 0x5D, 0x1B, 0xE6, 0x63,
0x2C, 0x47, 0xC2, 0x2C, 0x45, 0x91, 0xDA, 0x52, 0x65, 0x15, 0x54, 0x35, 0x1A,
0xFF, 0x3E, 0xC9, 0x64, 0xED, 0x48, 0xE6, 0x7C, 0xDB, 0x2C, 0x72, 0x7B, 0x14,
0xC0, 0x35, 0x5C, 0x14, 0xE8, 0xBB, 0x92, 0xEA, 0xB6, 0x29, 0x29, 0x8B, 0x8A,
0x4D, 0x95, 0x1F, 0xAE, 0x54, 0x64, 0x07, 0x2D, 0xAD, 0x3D, 0xA4, 0x20, 0x20,
0xA0, 0x7A, 0x7C, 0xAE, 0x9E, 0xFE, 0x5C, 0xE8, 0x88, 0x63, 0x41, 0x2C, 0x3A,
0xCB, 0xF0, 0xA0, 0x33, 0x5B, 0x34, 0xE1, 0xD2, 0x85, 0x31, 0xB7, 0xB9, 0x4A,
0xD3, 0x29, 0x8A, 0x9B, 0x7E, 0x2E, 0x8E, 0x32, 0x72, 0xEB, 0x85, 0x8C, 0xA6,
0x61, 0x86, 0x36, 0x4A, 0x23, 0x22, 0xE2, 0xB4, 0x21, 0xF6, 0xD7, 0xCD, 0x40,
0xDB, 0xE1, 0x6E, 0x37, 0x0B, 0xB7, 0x08, 0x01, 0x17, 0x12, 0xB2, 0x56, 0x9E,
0x6B, 0x17, 0x2C, 0x31, 0x69, 0x14, 0x33, 0x0D, 0x49, 0x96, 0x44, 0x86, 0x42,
0x0B, 0xA7, 0x51, 0x67, 0x53, 0x2C, 0x86, 0x39, 0x49, 0xC2, 0x5F, 0x3C, 0xE9,
0xDF, 0x5F, 0x9C, 0x1F, 0x93, 0xC8, 0x28, 0x5F, 0x41, 0x83, 0xD9, 0x34, 0x80,
0x77, 0xE3, 0x6C, 0xE9, 0x81, 0xBE, 0x16, 0xC2, 0x6F, 0x85, 0x75, 0x93, 0x28,
0x15, 0xDB, 0xE1, 0x67, 0xC1, 0x75, 0xDA, 0x9C, 0x80, 0xE2, 0x8D, 0xA2, 0x29,
0x62, 0x9A, 0xA6, 0x0C, 0x6F, 0xC8, 0xE2, 0xB8, 0x35, 0x26, 0x7F, 0x27, 0x35,
0xCE, 0xEF, 0x21, 0x43, 0xED, 0xF2, 0x8F, 0x34, 0x22, 0x0E, 0x2A, 0x0D, 0x63,
0x2B, 0x01, 0x75, 0xB0, 0x95, 0xD2, 0x74, 0x3F, 0x21, 0x84, 0xE5, 0x23, 0x06,
0x62, 0x47, 0x8E, 0x0B, 0x40, 0xEA, 0xB8, 0x2F, 0x9C, 0x07, 0xF4, 0xCC, 0xA2,
0xA7, 0x8D, 0x78, 0x17, 0x40, 0x38, 0x0E, 0xA6, 0x1F, 0x81, 0xB1, 0x21, 0xF6,
0x10, 0x18, 0x4A, 0xD3, 0x7B, 0x46, 0x8F, 0x69, 0xE2, 0x78, 0x1B, 0x2E, 0xCF,
0x96, 0xBF, 0x56, 0xA9, 0x17, 0x8D, 0x97, 0xB5, 0x69, 0x1D, 0xFE, 0xD4, 0x7E,
0xB6, 0x0D, 0xC1, 0xEA, 0xAC, 0x12, 0xB3, 0xAD, 0xE0, 0xC6, 0xB5, 0xF2, 0x96,
0xE0, 0x12, 0xD6, 0xF5, 0xB8, 0xF4, 0x86, 0xCC, 0xE4, 0x55, 0xA7, 0x05, 0x6F,
0xF9, 0x88, 0xD5, 0x36, 0x8D, 0xD6, 0x75, 0x18, 0xCA, 0xD5, 0x28, 0x21, 0x64,
0x41, 0x1D, 0xC6, 0x38, 0x56, 0x50, 0x96, 0x8E, 0x1A, 0x32, 0xD8, 0x4A, 0x47,
0x82, 0xFC, 0x67, 0xB2, 0xB5, 0xED, 0xC2, 0x54, 0x46, 0x87, 0xE3, 0x1F, 0xBB,
0x18, 0xCD, 0xB0, 0x59, 0xA0, 0xBE, 0xA6, 0x4D, 0x4E, 0x1E, 0x7A, 0x46, 0xE5,
0x77, 0xB2, 0x59, 0xCE, 0x61, 0xEF, 0xA2, 0x0A, 0xEC, 0x55, 0x8E, 0xB0, 0xD4,
0x3E, 0x1B, 0x25, 0x37, 0x8E, 0xA7, 0xB2, 0x27, 0xED, 0x00, 0x8C, 0x38, 0x26,
0x5E, 0x9D, 0x20, 0x38, 0x6A, 0xAF, 0xD2, 0x24, 0x94, 0x31, 0xF5, 0x6E, 0x66,
0x41, 0x2C, 0xFD, 0x77, 0x9C, 0x2D, 0x73, 0xE5, 0x8E, 0x64, 0xF7, 0x3D, 0xDF,
0x42, 0x37, 0xFE, 0x07, 0xB6, 0xBC, 0x29, 0x02, 0xD4, 0x90, 0xDA, 0x3F, 0x5E,
0x7F, 0xEC, 0x39, 0xC7, 0x4D, 0x11, 0x09, 0xBE, 0xA6, 0xF4, 0xBE, 0x4F, 0x14,
0x2C, 0x59, 0xD5, 0x07, 0xD3, 0x49, 0x81, 0x5D, 0x3B, 0xF9, 0x90, 0xD1, 0x8E,
0xB1, 0x83, 0xE3, 0x39, 0xDF, 0x04, 0x62, 0x56, 0x44, 0x12, 0xA2, 0x36, 0x28,
0xAA, 0xBC, 0x46, 0xDF, 0x78, 0xFF, 0x27, 0xC5, 0x3A, 0x16, 0xA5, 0x59, 0x63,
0xBF, 0x25, 0x0C, 0x31, 0xAD, 0x90, 0xF5, 0xBB, 0xAA, 0x9C, 0x56, 0x7D, 0x4A,
0xA5, 0x8C, 0x25, 0xAA, 0x9D, 0xB3, 0x44, 0xDB, 0x82, 0xCF, 0x46, 0x10, 0x1F,
0x4E, 0x24, 0xC1, 0x85, 0x6B, 0x6E, 0xD0, 0xC0, 0x66, 0x79, 0x58, 0xB1, 0x86,
0x86, 0xD0, 0xEF, 0xDA, 0xE0, 0xE0, 0x40, 0x61, 0x53, 0xFB, 0x02, 0xB4, 0x57,
0xFD, 0x47, 0xC0, 0xE0, 0x01, 0x9F, 0x4B, 0x51, 0xB1, 0x0B, 0x8C, 0x58, 0x7F,
0x92, 0xA9, 0xFA, 0x9D, 0x74, 0x12, 0x1B, 0xCC, 0x23, 0xF1, 0x21, 0xAE, 0x21,
0x16, 0xEF, 0xE1, 0xF9, 0x78, 0x67, 0xED, 0xDD, 0x31, 0xC1, 0xE0, 0xE6, 0x53,
0xD8, 0x55, 0xCE, 0x04, 0x99, 0x50, 0xB9, 0x11, 0x05, 0xDE, 0xD1, 0xD3, 0x2B,
0x9E, 0xF4, 0xB9, 0x8A, 0x95, 0x20, 0x69, 0x5A, 0x96, 0xD2, 0x82, 0x9C, 0x26,
0x60, 0xE0, 0x51, 0x95, 0xA3, 0x74, 0x4F, 0x22, 0x7F, 0x01, 0xCC, 0x80, 0xAB,
0xD5, 0x92, 0xB3, 0xF0, 0x3F, 0xE8, 0x0F, 0xD8, 0x7C, 0x4D, 0xB0, 0x37, 0x55,
0xE7, 0xE2, 0x9A, 0xDC, 0x09, 0x80, 0x01, 0x43, 0x54, 0xDF, 0x57, 0x6D, 0x92,
0x21, 0x81, 0x92, 0xA4, 0x33, 0xEF, 0xDD, 0x59, 0xC6, 0xD3, 0x17, 0x3A, 0xBD,
0x75, 0x7A, 0x91, 0x50, 0xCF, 0x69, 0x97, 0x07, 0x38, 0xFB, 0x9E, 0xCE, 0x3A,
0x78, 0x25, 0xCF, 0x11, 0x5C, 0xD6, 0xC8, 0x53, 0xCF, 0xA6, 0x0E, 0x06, 0xF5,
0xD5, 0x5C, 0x16, 0x26, 0x4F, 0x0E, 0x12, 0x37, 0xEF, 0xD8, 0x7A, 0xFF, 0xCE,
0xA8, 0x8D, 0x44, 0x05, 0x4F, 0x35, 0xC1, 0x87, 0xBB, 0xF1, 0xF8, 0x91, 0x8B,
0x91, 0xD4, 0x96, 0x70, 0x7C, 0x4B, 0x89, 0xA8, 0x07, 0x66, 0x63, 0x7C, 0xD0,
0x1D, 0xBE, 0x4D, 0x03, 0x41, 0x19, 0x8B, 0x67, 0x66, 0xFD, 0xCE, 0xF5, 0xD8,
0x46, 0x13, 0x45, 0x72, 0xA7, 0x47, 0xF0, 0x67, 0xB4, 0x30, 0x58, 0xCE, 0x5B,
0xEA, 0x02, 0x7C, 0xF3, 0xC2, 0xF7, 0xAE, 0x3A, 0x4C, 0x5C, 0x11, 0xAF, 0xC3,
0xB2, 0xA8, 0x1F, 0x2F, 0xD2, 0x1E, 0x8F, 0xF1, 0x70, 0x1B, 0x9D, 0xF0, 0x61,
0x28, 0xF0, 0xBB, 0x64, 0x9C, 0x07, 0x2E, 0xD6, 0xFB, 0xA0, 0xD3, 0x14, 0x16,
0x7E, 0x73, 0x00, 0xD0, 0x28, 0xF5, 0x96, 0x83, 0x18, 0x2F, 0xBC, 0x7E, 0x4D,
0xE1, 0xA4, 0xC2, 0x91, 0x6C, 0xDA, 0xAB, 0xDD, 0xE0, 0xC1, 0x89, 0xD3, 0xE3,
0x5D, 0x17, 0x64, 0x48, 0x23, 0x4F, 0x8C, 0xB4, 0x17, 0x38, 0x6C, 0x25, 0xCF,
0x89, 0x84, 0x56, 0x3E, 0x92, 0x6F, 0xCA, 0xCB, 0xD7, 0xC0, 0x89, 0x05, 0xB0,
0x39, 0x66, 0x16, 0x98, 0x6C, 0xD5, 0xD2, 0x14, 0x7D, 0x85, 0xF5, 0xD0, 0x3A,
0x02, 0x42, 0x25, 0x6B, 0xDB, 0x40, 0xF3, 0xA5, 0x5C, 0x03, 0x6F, 0xA9, 0x6A,
0x98, 0x4F, 0xC4, 0x77, 0x83, 0xED, 0x40, 0x4E, 0x32, 0xB6, 0xE4, 0x6F, 0x5B,
0x13, 0x88, 0x04, 0x3B, 0x0D, 0x6E, 0xC1, 0x67, 0x20, 0xEA, 0x3B, 0x3C, 0xC4,
0x4A, 0xA9, 0x23, 0xE0, 0x41, 0x8A, 0xA8, 0x13, 0x00, 0xB5, 0x8C, 0x37, 0x71,
0x57, 0xD3, 0xED, 0x9F, 0x9A, 0x6C, 0xB7, 0x6C, 0x5B, 0x46, 0xBD, 0x8A, 0x98,
0x30, 0xA3, 0x34, 0x1F, 0xCA, 0x19, 0x81, 0xE0, 0xFF, 0x4C, 0x08, 0x09, 0x82,
0xBC, 0x0D, 0xDF, 0xB2, 0x57, 0x68, 0x0B, 0x0A, 0xE7, 0xE2, 0x83, 0xD4, 0xD1,
0xA4, 0x62, 0x8F, 0x88, 0xCF, 0x04, 0xDC, 0x11, 0xE9, 0x9B, 0xCD, 0xEC, 0x0B,
0x88, 0x2B, 0x57, 0x9A, 0xF9, 0x71, 0xB8, 0xC3, 0x05, 0x59, 0x35, 0xF2, 0xA9,
0x80, 0xE0, 0x16, 0x22, 0xCA, 0xE0, 0xAE, 0x1B, 0xB5, 0x54, 0x76, 0xC1, 0xBA,
0x32, 0x9B, 0x67, 0x18, 0x86, 0x7C, 0x15, 0xD6, 0x81, 0x1A, 0xDF, 0x83, 0xD0,
0xDD, 0x6B, 0x2F, 0x98, 0x56, 0xB2, 0xBA, 0xFC, 0xA7, 0xD3, 0xE7, 0xAA, 0xE7,
0x3A, 0xC2, 0x50, 0x74, 0x63, 0xE6, 0x72, 0xC3, 0x40, 0x00, 0xF2, 0xDC, 0x06,
0x86, 0x1F, 0xF5, 0xE2, 0xD5, 0x77, 0xF5, 0xFF, 0x87, 0x32, 0x30, 0x61, 0x94,
0xE7, 0x04, 0x68, 0x0E, 0xC4, 0xF9, 0xDA, 0x54, 0x93, 0x32, 0xCE, 0x7D, 0x82,
0x05, 0x9A, 0x25, 0xF2, 0x88, 0x32, 0x64, 0x1A, 0x71, 0x94, 0x50, 0xBC, 0xD0,
0x31, 0xE2, 0x53, 0x61, 0x4A, 0xFF, 0xD4, 0x2E, 0xCE, 0xE0, 0x5B, 0xC4, 0x24,
0xCA, 0x95, 0xE2, 0x75, 0x54, 0xB6, 0xCF, 0x5C, 0xD6, 0x96, 0x0F, 0x1F, 0x60,
0xA2, 0x20, 0x1F, 0x00, 0x3C, 0x2D, 0x0D, 0x89, 0x90, 0xBD, 0x3A, 0xD3, 0xDC,
0x64, 0xB1, 0x61, 0xFB, 0xAA, 0x67, 0x15, 0xB0, 0xCE, 0x18, 0x1B, 0x09, 0xA2,
0x38, 0x31, 0x95, 0x0F, 0x2C, 0x25, 0x80, 0x4B, 0x13, 0xCB, 0xA0, 0xC7, 0xC7,
0xFA, 0xCC, 0x2C, 0x98, 0x66, 0xBE, 0xDC, 0x7B, 0xBB, 0x53, 0x12, 0x33, 0xDF,
0x92, 0x0C, 0x5F, 0x9E, 0xCC, 0x8E, 0x18, 0x23, 0x03, 0x2D, 0x7A, 0x2B, 0x90,
0x71, 0x07, 0x24, 0x95, 0xFE, 0x50, 0x95, 0x6E, 0x95, 0xFF, 0x29, 0x85, 0x7B,
0x44, 0x1C, 0x0A, 0x86, 0x48, 0x9B, 0x6B, 0xEA, 0xA7, 0xF9, 0xBF, 0xE8, 0x84,
0x10, 0xDC, 0x45, 0xC7, 0xFB, 0x2A, 0x39, 0x99, 0x0D, 0xCF, 0x23, 0x88, 0x35,
0x9C, 0x3D, 0xBA, 0x77, 0x7E, 0x8D, 0x4C, 0xA7, 0xB6, 0x41, 0x25, 0x46, 0x9A,
0x8E, 0xFF, 0x74, 0x5E, 0x9E, 0xDB, 0x8F, 0x20, 0xE9, 0xE3, 0x83, 0x84, 0x28,
0x0E, 0x14, 0xFC, 0x52, 0x1A, 0x69, 0xEC, 0x95, 0x5E, 0xBD, 0xFA, 0x05, 0xE4,
0xE5, 0xC7, 0xEB, 0x5F, 0x90, 0x21, 0x9C, 0xD5, 0x6B, 0xF7, 0x31, 0x35, 0xDA,
0x30, 0x41, 0xB2, 0x7E, 0xAB, 0x43, 0x36, 0x4E, 0x0B, 0x84, 0xDE, 0x43, 0x62,
0x96, 0x81, 0xF8, 0x9B, 0x81, 0x20, 0x06, 0x3B, 0xCA, 0x8E, 0x09, 0xE7, 0x2A,
0x6B, 0x41, 0x0C, 0x42, 0x02, 0x27, 0x41, 0x95, 0x8C, 0x86, 0x91, 0x40, 0xB1,
0xE8, 0x0C, 0x65, 0x6F, 0x23, 0xA5, 0x4A, 0xA9, 0x14, 0x8F, 0x32, 0x36, 0x3A,
0xDC, 0xAE, 0x54, 0x29, 0x13, 0x6B, 0xC0, 0x0D, 0x76, 0x6F, 0x79, 0xC4, 0x0A,
0x87, 0x89, 0xF2, 0xDD, 0xB0, 0xE3, 0xC0, 0x65, 0xC7, 0xE3, 0xBD, 0x17, 0xC4,
0x66, 0x3F, 0x84, 0x0B, 0x3F, 0x7A, 0x50, 0x08, 0x5F, 0x68, 0xE6, 0xC6, 0x37,
0xA7, 0x73, 0xF4, 0x4F, 0x37, 0x05, 0x28, 0x64, 0x0E, 0x36, 0xF8, 0xC2, 0x2F,
0xEA, 0x1D, 0x98, 0xBB, 0xB2, 0xFB, 0xE5, 0x98, 0xAE, 0x5D, 0xF8, 0xE8, 0xDA,
0xA1, 0xB6, 0x43, 0x0C, 0x6D, 0x1C, 0x39, 0x59, 0xE1, 0xBF, 0xEB, 0xA6, 0x4D,
0xBF, 0x12, 0x0E, 0x6E, 0xC4, 0x93, 0x8B, 0x72, 0x54, 0x47, 0xBE, 0xFC, 0x3A,
0x00, 0x7F, 0xD3, 0x57, 0x32, 0xE7, 0x86, 0xF0, 0x96, 0xCC, 0x06, 0x8F, 0x73,
0x9C, 0xE6, 0x8D, 0xD8, 0xB8, 0x24, 0xF9, 0xC0, 0x51, 0x99, 0xB8, 0x35, 0x98,
0x37, 0x32, 0x35, 0x03, 0x5C, 0xDA, 0x91, 0xC9, 0x6A, 0x50, 0xE5, 0xE1, 0xF0,
0xEF, 0xBB, 0x66, 0x27, 0x91, 0x51, 0x57, 0x09, 0xBB, 0x5B, 0xE9, 0x26, 0x8E,
0xB9, 0x75, 0xD9, 0x2E, 0x80, 0xE2, 0xDD, 0x27, 0xDD, 0x5A, 0x1B, 0x4E, 0xCF,
0x17, 0x11, 0x2B, 0x7B, 0xCB, 0xF9, 0xB3, 0xED, 0x07, 0xF3, 0x5A, 0xEE, 0xBF,
0x4B, 0x07, 0x43, 0x73, 0xF8, 0x24, 0x16, 0x67, 0x41, 0xE9, 0x64, 0xB4, 0xE7,
0x05, 0x72, 0x91, 0xF7, 0xCE, 0x38, 0x7D, 0x38, 0xA5, 0x60, 0x95, 0xC1, 0xC7,
0x64, 0x1B, 0xCC, 0xC4, 0x12, 0x32, 0xC3, 0x49, 0x7E, 0xAB, 0x96, 0x1D, 0x2A,
0x3C, 0x60, 0x51, 0xAA, 0x62, 0x86, 0xF3, 0x9F, 0xC6, 0x7F, 0xAB, 0x0F, 0xBB,
0x15, 0x7B, 0xBA, 0x43, 0x26, 0xAE, 0x37, 0x45, 0x5F, 0x39, 0x70, 0xB7, 0x19,
0x2F, 0x02, 0x33, 0xF1, 0x11, 0x4E, 0x78, 0x7D, 0x17, 0x8F, 0xBF, 0xEB, 0x92,
0xCC, 0x2F, 0xCA, 0x87, 0x01, 0xA8, 0xE3, 0xAD, 0x7B, 0x4A, 0x44, 0x0C, 0x75,
0x5A, 0x31, 0xCA, 0xE1, 0xE6, 0x18, 0xD7, 0xC4, 0xA3, 0xBA, 0x7F, 0xB5, 0xBC,
0xFD, 0xA6, 0x9C, 0xDC, 0x2A, 0xEB, 0x18, 0xDC, 0x88, 0x08, 0x6E, 0x7D, 0x6A,
0x97, 0xB6, 0xCD, 0x53, 0x41, 0x1D, 0xB4, 0xA8, 0xBD, 0xE3, 0x85, 0x29, 0x5F,
0x12, 0x03, 0xB8, 0x09, 0x13, 0x20, 0x6D, 0x68, 0x4F, 0x80, 0x1E, 0xBB, 0x6C,
0xD6, 0x51, 0x8C, 0x46, 0x19, 0x00, 0xBB, 0x90, 0xF9, 0xEA, 0xB0, 0x33, 0xF4,
0x52, 0xCA, 0x19, 0xD6, 0x68, 0xAE, 0x79, 0xE2, 0xC1, 0x39, 0xA9, 0x18, 0xF2,
0x26, 0x71, 0x69, 0xFF, 0xBA, 0x97, 0x28, 0x34, 0x4D, 0x10, 0x01, 0xFB, 0xD7,
0xBA, 0x37, 0x0F, 0xC8, 0xFC, 0x07, 0x7A, 0xCD, 0x1A, 0xDD, 0x92, 0x0D, 0x45,
0x8A, 0x7B, 0x6F, 0x94, 0x00, 0x53, 0x7E, 0xAF, 0xA5, 0x99, 0xB9, 0x7F, 0x00,
0xCD, 0xC7, 0x7C, 0x35, 0xCE, 0x53, 0x64, 0x15, 0xC2, 0x47, 0x7C, 0xD1, 0x12,
0x40, 0xBD, 0xF9, 0x8B, 0xBA, 0x3B, 0x5A, 0x3D, 0xFF, 0x5C, 0x48, 0x3A, 0x7F,
0xEF, 0x5B, 0xA8, 0xFC, 0xD6, 0xEA, 0xFB, 0x49, 0x0B, 0x29, 0x98, 0x5F, 0xCA,
0xBC, 0xC1, 0xD5, 0xA8, 0x15, 0x5B, 0x09, 0xEF, 0xB3, 0x0E, 0x41, 0xDC, 0x4D,
0x22, 0x30, 0xEE, 0xAA, 0xD9, 0xBA, 0x37, 0x43, 0xDE, 0x34, 0xF8, 0xB9, 0x42,
0xE7, 0x65, 0xEC, 0xE6, 0xA3, 0xE1, 0xED, 0x46, 0x46, 0xB4, 0x9F, 0x1C, 0xA0,
0x61, 0x50, 0x8E, 0x8A, 0x61, 0xBC, 0xF1, 0x3A, 0x55, 0xF8, 0xAB, 0xBA, 0x09,
0x5A, 0x4F, 0xB1, 0x38, 0x99, 0x77, 0x0A, 0xF5, 0x5D, 0xF7, 0xA0, 0x29, 0xA5,
0x00, 0x1D, 0x92, 0xC1, 0xA8, 0x4A, 0x73, 0x13, 0xCB, 0x1F, 0x14, 0xB0, 0xDB,
0x64, 0x53, 0xA8, 0x77, 0xB1, 0x80, 0xDF, 0xA7, 0x20, 0x9A, 0xA3, 0xD1, 0x79,
0x4B, 0x75, 0x45, 0x6D, 0xB0, 0xF5, 0xD8, 0x09, 0xE3, 0xB7, 0x7C, 0xC8, 0x1B,
0x56, 0xA2, 0x04, 0x11, 0xFB, 0xAC, 0x2D, 0x55, 0xF3, 0x95, 0x36, 0xF2, 0xAE,
0x6E, 0x9F, 0x10, 0xFE, 0xC0, 0xD5, 0x62, 0x36, 0xA7, 0xA0, 0xC5, 0x05, 0x2F,
0x55, 0x79, 0x59, 0x1B, 0xF4, 0xF6, 0xC3, 0xD2, 0x77, 0x96, 0x35, 0xBF, 0x89,
0x33, 0x45, 0xE9, 0xAB, 0x0A, 0x4B, 0xE1, 0x42, 0x31, 0xAF, 0x38, 0xA2, 0xA9,
0x45, 0xCF, 0x7D, 0x02, 0x88, 0x77, 0x4B, 0xD0, 0x2D, 0x9B, 0x56, 0x6E, 0xC3,
0xB3, 0x61, 0xA8, 0x1F, 0x8B, 0x9C, 0x3F, 0x63, 0xD4, 0x3C, 0x88, 0xA0, 0x7B,
0x90, 0xDB, 0x02, 0x30, 0xC5, 0xE8, 0x68, 0x82, 0x28, 0x58, 0x40, 0x31, 0xA3,
0x5C, 0xE9, 0xFB, 0x2A, 0xE6, 0x6E, 0x8F, 0x49, 0x5B, 0xF6, 0xAC, 0xB5, 0xBF,
0x30, 0xA8, 0x68, 0x83, 0x5E, 0xB4, 0x26, 0xBF, 0x6D, 0x1F, 0xEC, 0xEB, 0x00,
0xBD, 0x12, 0x0D, 0xB9, 0x80, 0xF1, 0xE7, 0x13, 0x3B, 0xCA, 0x81, 0x98, 0x5C,
0xE8, 0xA1, 0x98, 0xA1, 0x82, 0x26, 0x5F, 0xDD, 0xE0, 0xAE, 0xF8, 0x0C, 0x63,
0x78, 0xA8, 0xC1, 0xF7, 0x20, 0x62, 0x0B, 0xC8, 0xF9, 0xE5, 0x89, 0x43, 0x44,
0x05, 0x56, 0x98, 0xDE, 0xFD, 0x99, 0x25, 0xC0, 0x33, 0xCA, 0x1C, 0xDD, 0xAE,
0x2F, 0xDF, 0x14, 0x7E, 0xE2, 0x75, 0x75, 0xBC, 0x1C, 0x81, 0xF7, 0x21, 0x07,
0x0E, 0x21, 0x4A, 0x41, 0x4F, 0x33, 0xBD, 0x00, 0x5D, 0xBD, 0xF1, 0x79, 0x0C,
0x15, 0x8C, 0x98, 0x06, 0x72, 0xB8, 0xC2, 0xC1, 0x29, 0xFB, 0x7E, 0xE5, 0xF4,
0x04, 0x49, 0x17, 0xFD, 0x4B, 0xE5, 0xC7, 0x03, 0xFA, 0x88, 0x81, 0xBF, 0xDB,
0x10, 0xE2, 0x37, 0x12, 0x9E, 0x63, 0x7D, 0xFA, 0xBC, 0xF6, 0x98, 0x12, 0x23,
0x99, 0x59, 0xE3, 0x30, 0xD0, 0xA8, 0x21, 0x6D, 0x80, 0x2A, 0xF4, 0xB9, 0x6D,
0x71, 0x62, 0x0B, 0xA7, 0x99, 0xB2, 0xA1, 0x60, 0x34, 0xC5, 0x7F, 0xC3, 0x59,
0x78, 0xED, 0xB4, 0xA6, 0x5E, 0xF8, 0xC8, 0x5E, 0xF6, 0x69, 0xCE, 0xA0, 0x98,
0x87, 0x79, 0xDB, 0xB8, 0xA2, 0x3C, 0x94, 0xAC, 0xD1, 0x4C, 0x6C, 0x72, 0x39,
0x17, 0x32, 0x78, 0xA1, 0xDC, 0x1D, 0x03, 0xB2, 0xA1, 0x57, 0x0D, 0x2F, 0xA7,
0xF4, 0x8D, 0xE8, 0x4C, 0x67, 0x95, 0x19, 0x95, 0x55, 0xB9, 0xDE, 0x38, 0xD0,
0x85, 0xDB, 0x15, 0xB8, 0x8C, 0x0F, 0x6A, 0x69, 0x38, 0xF6, 0x8B, 0x75, 0x81,
0x89, 0x7E, 0xF8, 0x3A, 0xF3, 0x27, 0x08, 0xC0, 0x7B, 0x78, 0x3A, 0x73, 0xA5,
0xCB, 0xB0, 0x67, 0xD7, 0xDF, 0x88, 0x84, 0x4A, 0x52, 0xBD, 0x91, 0x74, 0x2C,
0xD1, 0x16, 0x3A, 0xCB, 0x0D, 0x3D, 0x08, 0x3D, 0x4F, 0x58, 0xE6, 0xCB, 0x32,
0x8A, 0x52, 0x86, 0x82, 0x61, 0x00, 0xDE, 0xCA, 0xF3, 0xDE, 0x05, 0xAB, 0x15,
0xAE, 0x13, 0x35, 0x4A, 0xE2, 0x45, 0xD5, 0xC1, 0xB0, 0x1B, 0xFA, 0xD8, 0xAD,
0xF7, 0xD2, 0x9A, 0x53, 0x06, 0x79, 0x15, 0xA6, 0x95, 0xE0, 0x6C, 0xC7, 0xFA,
0x94, 0x81, 0xB4, 0x91, 0x9D, 0x53, 0x89, 0x2D, 0x59, 0x74, 0x9F, 0x0F, 0xD5,
0x4E, 0xE6, 0xF6, 0x07, 0x62, 0x3B, 0x2C, 0x59, 0xA0, 0x47, 0x52, 0xDF, 0xF4,
0x10, 0xC2, 0xEB, 0x38, 0x86, 0x2F, 0x42, 0x01, 0xC2, 0x8A, 0xCB, 0x20, 0x7B,
0xFC, 0xB8, 0xEA, 0x20, 0x14, 0x69, 0x8B, 0x63, 0x52, 0xA8, 0x13, 0x1D, 0xD4,
0x60, 0x32, 0xF6, 0xDE, 0x75, 0x4D, 0x41, 0xC2, 0xC7, 0xA2, 0x62, 0x6F, 0x04,
0xAF, 0xF9, 0x9E, 0x3D, 0x1C, 0xCB, 0xBB, 0xEC, 0x7A, 0xFD, 0x9C, 0x97, 0x87,
0x40, 0xF1, 0xE7, 0x91, 0xCD, 0x36, 0xD2, 0x64, 0xB1, 0x2B, 0x43, 0xBA, 0x6E,
0xBD, 0x0E, 0x7D, 0xB1, 0x45, 0xA4, 0x0B, 0x84, 0xEB, 0x18, 0x5C, 0x25, 0x8B,
0x9B, 0x62, 0xB3, 0x8C, 0x95, 0xEF, 0x6F, 0x09, 0xE9, 0xF8, 0xE8, 0x18, 0x1A,
0x8A, 0xE2, 0xCC, 0x48, 0xDC, 0xC6, 0xDC, 0x94, 0xB1, 0x24, 0x55, 0x13, 0xB6,
0xD8, 0x16, 0xAB, 0x5F, 0x20, 0x7F, 0x5E, 0x35, 0x1F, 0x5A, 0x56, 0x2C, 0xFF,
0x02, 0x9C, 0xAF, 0x18, 0xF8, 0xBB, 0x60, 0xE1, 0xD4, 0xEF, 0x5E, 0x03, 0x08,
0x07, 0xCD, 0x29, 0x35, 0x7B, 0x9F, 0xEC, 0x35, 0xDB, 0x1D, 0xE1, 0xFD, 0x85,
0xC3, 0xDB, 0xE0, 0x58, 0x1F, 0x39, 0xE9, 0x38, 0xAE, 0x37, 0x18, 0xAF, 0x9C,
0x11, 0x97, 0x97, 0x6B, 0x67, 0x46, 0xC8, 0x68, 0xB7, 0x65, 0x05, 0x20, 0x02,
0x70, 0xDA, 0x6B, 0xC7, 0x34};

// mldsa87kPublicKeySPKI is the above example ML-DSA-87 public key encoded
static const uint8_t mldsa87kPublicKeySPKI[] = {
0x30, 0x82, 0x0A, 0x32, 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
0x03, 0x04, 0x03, 0x13, 0x03, 0x82, 0x0A, 0x21, 0x00, 0xE4, 0x36, 0x63, 0x53,
0xA7, 0xE7, 0xDF, 0x51, 0x06, 0x19, 0x34, 0x9F, 0xB5, 0x95, 0x53, 0x9D, 0xC0,
0x59, 0x21, 0x38, 0x0F, 0x8E, 0x2A, 0xEC, 0x43, 0x5C, 0x9B, 0x4B, 0xD0, 0xDC,
0x7E, 0xE1, 0x89, 0x77, 0x51, 0xD4, 0x26, 0x46, 0x8F, 0x25, 0x76, 0xAB, 0x5E,
0x68, 0xFE, 0x45, 0xC6, 0x35, 0xF5, 0xF0, 0xD0, 0x2D, 0xD2, 0x11, 0xCB, 0x2D,
0x3B, 0x6B, 0xF3, 0x2F, 0x68, 0xD1, 0xF2, 0xCC, 0x51, 0x9E, 0xE0, 0xC5, 0x1D,
0xFA, 0x2C, 0x55, 0x02, 0xE5, 0xAB, 0xC6, 0xA2, 0xA9, 0x2C, 0x35, 0xC1, 0x22,
0xDC, 0xFB, 0x9D, 0xDC, 0x9E, 0x17, 0xCB, 0x7C, 0xEC, 0xB4, 0x7D, 0x1C, 0x40,
0xA6, 0x40, 0x3C, 0x2B, 0x1C, 0x5B, 0x85, 0x97, 0x31, 0x5D, 0x9E, 0xAD, 0x7C,
0xC9, 0xF1, 0xBC, 0x99, 0x59, 0x2B, 0xE0, 0x10, 0x30, 0x58, 0xC6, 0x63, 0xBD,
0xD7, 0xF1, 0x27, 0x2B, 0x1E, 0xB2, 0xA8, 0x31, 0xD7, 0xD3, 0x2B, 0x85, 0xA7,
0x59, 0xAF, 0x70, 0x15, 0x66, 0x9E, 0xD2, 0x13, 0xB0, 0x50, 0xBF, 0x59, 0x08,
0x92, 0x32, 0x07, 0x9C, 0x81, 0xD7, 0x06, 0x55, 0x76, 0xEE, 0x15, 0x8A, 0xFE,
0xCB, 0x62, 0x58, 0xF7, 0xDF, 0x0F, 0xEB, 0x0A, 0x11, 0x98, 0xF8, 0x93, 0xD8,
0x96, 0xF5, 0x14, 0x87, 0x40, 0x4F, 0xEC, 0x9A, 0x45, 0xE2, 0x7A, 0x54, 0x91,
0x0B, 0xDB, 0x39, 0x90, 0x48, 0x5D, 0x1B, 0xE6, 0x63, 0x2C, 0x47, 0xC2, 0x2C,
0x45, 0x91, 0xDA, 0x52, 0x65, 0x15, 0x54, 0x35, 0x1A, 0xFF, 0x3E, 0xC9, 0x64,
0xED, 0x48, 0xE6, 0x7C, 0xDB, 0x2C, 0x72, 0x7B, 0x14, 0xC0, 0x35, 0x5C, 0x14,
0xE8, 0xBB, 0x92, 0xEA, 0xB6, 0x29, 0x29, 0x8B, 0x8A, 0x4D, 0x95, 0x1F, 0xAE,
0x54, 0x64, 0x07, 0x2D, 0xAD, 0x3D, 0xA4, 0x20, 0x20, 0xA0, 0x7A, 0x7C, 0xAE,
0x9E, 0xFE, 0x5C, 0xE8, 0x88, 0x63, 0x41, 0x2C, 0x3A, 0xCB, 0xF0, 0xA0, 0x33,
0x5B, 0x34, 0xE1, 0xD2, 0x85, 0x31, 0xB7, 0xB9, 0x4A, 0xD3, 0x29, 0x8A, 0x9B,
0x7E, 0x2E, 0x8E, 0x32, 0x72, 0xEB, 0x85, 0x8C, 0xA6, 0x61, 0x86, 0x36, 0x4A,
0x23, 0x22, 0xE2, 0xB4, 0x21, 0xF6, 0xD7, 0xCD, 0x40, 0xDB, 0xE1, 0x6E, 0x37,
0x0B, 0xB7, 0x08, 0x01, 0x17, 0x12, 0xB2, 0x56, 0x9E, 0x6B, 0x17, 0x2C, 0x31,
0x69, 0x14, 0x33, 0x0D, 0x49, 0x96, 0x44, 0x86, 0x42, 0x0B, 0xA7, 0x51, 0x67,
0x53, 0x2C, 0x86, 0x39, 0x49, 0xC2, 0x5F, 0x3C, 0xE9, 0xDF, 0x5F, 0x9C, 0x1F,
0x93, 0xC8, 0x28, 0x5F, 0x41, 0x83, 0xD9, 0x34, 0x80, 0x77, 0xE3, 0x6C, 0xE9,
0x81, 0xBE, 0x16, 0xC2, 0x6F, 0x85, 0x75, 0x93, 0x28, 0x15, 0xDB, 0xE1, 0x67,
0xC1, 0x75, 0xDA, 0x9C, 0x80, 0xE2, 0x8D, 0xA2, 0x29, 0x62, 0x9A, 0xA6, 0x0C,
0x6F, 0xC8, 0xE2, 0xB8, 0x35, 0x26, 0x7F, 0x27, 0x35, 0xCE, 0xEF, 0x21, 0x43,
0xED, 0xF2, 0x8F, 0x34, 0x22, 0x0E, 0x2A, 0x0D, 0x63, 0x2B, 0x01, 0x75, 0xB0,
0x95, 0xD2, 0x74, 0x3F, 0x21, 0x84, 0xE5, 0x23, 0x06, 0x62, 0x47, 0x8E, 0x0B,
0x40, 0xEA, 0xB8, 0x2F, 0x9C, 0x07, 0xF4, 0xCC, 0xA2, 0xA7, 0x8D, 0x78, 0x17,
0x40, 0x38, 0x0E, 0xA6, 0x1F, 0x81, 0xB1, 0x21, 0xF6, 0x10, 0x18, 0x4A, 0xD3,
0x7B, 0x46, 0x8F, 0x69, 0xE2, 0x78, 0x1B, 0x2E, 0xCF, 0x96, 0xBF, 0x56, 0xA9,
0x17, 0x8D, 0x97, 0xB5, 0x69, 0x1D, 0xFE, 0xD4, 0x7E, 0xB6, 0x0D, 0xC1, 0xEA,
0xAC, 0x12, 0xB3, 0xAD, 0xE0, 0xC6, 0xB5, 0xF2, 0x96, 0xE0, 0x12, 0xD6, 0xF5,
0xB8, 0xF4, 0x86, 0xCC, 0xE4, 0x55, 0xA7, 0x05, 0x6F, 0xF9, 0x88, 0xD5, 0x36,
0x8D, 0xD6, 0x75, 0x18, 0xCA, 0xD5, 0x28, 0x21, 0x64, 0x41, 0x1D, 0xC6, 0x38,
0x56, 0x50, 0x96, 0x8E, 0x1A, 0x32, 0xD8, 0x4A, 0x47, 0x82, 0xFC, 0x67, 0xB2,
0xB5, 0xED, 0xC2, 0x54, 0x46, 0x87, 0xE3, 0x1F, 0xBB, 0x18, 0xCD, 0xB0, 0x59,
0xA0, 0xBE, 0xA6, 0x4D, 0x4E, 0x1E, 0x7A, 0x46, 0xE5, 0x77, 0xB2, 0x59, 0xCE,
0x61, 0xEF, 0xA2, 0x0A, 0xEC, 0x55, 0x8E, 0xB0, 0xD4, 0x3E, 0x1B, 0x25, 0x37,
0x8E, 0xA7, 0xB2, 0x27, 0xED, 0x00, 0x8C, 0x38, 0x26, 0x5E, 0x9D, 0x20, 0x38,
0x6A, 0xAF, 0xD2, 0x24, 0x94, 0x31, 0xF5, 0x6E, 0x66, 0x41, 0x2C, 0xFD, 0x77,
0x9C, 0x2D, 0x73, 0xE5, 0x8E, 0x64, 0xF7, 0x3D, 0xDF, 0x42, 0x37, 0xFE, 0x07,
0xB6, 0xBC, 0x29, 0x02, 0xD4, 0x90, 0xDA, 0x3F, 0x5E, 0x7F, 0xEC, 0x39, 0xC7,
0x4D, 0x11, 0x09, 0xBE, 0xA6, 0xF4, 0xBE, 0x4F, 0x14, 0x2C, 0x59, 0xD5, 0x07,
0xD3, 0x49, 0x81, 0x5D, 0x3B, 0xF9, 0x90, 0xD1, 0x8E, 0xB1, 0x83, 0xE3, 0x39,
0xDF, 0x04, 0x62, 0x56, 0x44, 0x12, 0xA2, 0x36, 0x28, 0xAA, 0xBC, 0x46, 0xDF,
0x78, 0xFF, 0x27, 0xC5, 0x3A, 0x16, 0xA5, 0x59, 0x63, 0xBF, 0x25, 0x0C, 0x31,
0xAD, 0x90, 0xF5, 0xBB, 0xAA, 0x9C, 0x56, 0x7D, 0x4A, 0xA5, 0x8C, 0x25, 0xAA,
0x9D, 0xB3, 0x44, 0xDB, 0x82, 0xCF, 0x46, 0x10, 0x1F, 0x4E, 0x24, 0xC1, 0x85,
0x6B, 0x6E, 0xD0, 0xC0, 0x66, 0x79, 0x58, 0xB1, 0x86, 0x86, 0xD0, 0xEF, 0xDA,
0xE0, 0xE0, 0x40, 0x61, 0x53, 0xFB, 0x02, 0xB4, 0x57, 0xFD, 0x47, 0xC0, 0xE0,
0x01, 0x9F, 0x4B, 0x51, 0xB1, 0x0B, 0x8C, 0x58, 0x7F, 0x92, 0xA9, 0xFA, 0x9D,
0x74, 0x12, 0x1B, 0xCC, 0x23, 0xF1, 0x21, 0xAE, 0x21, 0x16, 0xEF, 0xE1, 0xF9,
0x78, 0x67, 0xED, 0xDD, 0x31, 0xC1, 0xE0, 0xE6, 0x53, 0xD8, 0x55, 0xCE, 0x04,
0x99, 0x50, 0xB9, 0x11, 0x05, 0xDE, 0xD1, 0xD3, 0x2B, 0x9E, 0xF4, 0xB9, 0x8A,
0x95, 0x20, 0x69, 0x5A, 0x96, 0xD2, 0x82, 0x9C, 0x26, 0x60, 0xE0, 0x51, 0x95,
0xA3, 0x74, 0x4F, 0x22, 0x7F, 0x01, 0xCC, 0x80, 0xAB, 0xD5, 0x92, 0xB3, 0xF0,
0x3F, 0xE8, 0x0F, 0xD8, 0x7C, 0x4D, 0xB0, 0x37, 0x55, 0xE7, 0xE2, 0x9A, 0xDC,
0x09, 0x80, 0x01, 0x43, 0x54, 0xDF, 0x57, 0x6D, 0x92, 0x21, 0x81, 0x92, 0xA4,
0x33, 0xEF, 0xDD, 0x59, 0xC6, 0xD3, 0x17, 0x3A, 0xBD, 0x75, 0x7A, 0x91, 0x50,
0xCF, 0x69, 0x97, 0x07, 0x38, 0xFB, 0x9E, 0xCE, 0x3A, 0x78, 0x25, 0xCF, 0x11,
0x5C, 0xD6, 0xC8, 0x53, 0xCF, 0xA6, 0x0E, 0x06, 0xF5, 0xD5, 0x5C, 0x16, 0x26,
0x4F, 0x0E, 0x12, 0x37, 0xEF, 0xD8, 0x7A, 0xFF, 0xCE, 0xA8, 0x8D, 0x44, 0x05,
0x4F, 0x35, 0xC1, 0x87, 0xBB, 0xF1, 0xF8, 0x91, 0x8B, 0x91, 0xD4, 0x96, 0x70,
0x7C, 0x4B, 0x89, 0xA8, 0x07, 0x66, 0x63, 0x7C, 0xD0, 0x1D, 0xBE, 0x4D, 0x03,
0x41, 0x19, 0x8B, 0x67, 0x66, 0xFD, 0xCE, 0xF5, 0xD8, 0x46, 0x13, 0x45, 0x72,
0xA7, 0x47, 0xF0, 0x67, 0xB4, 0x30, 0x58, 0xCE, 0x5B, 0xEA, 0x02, 0x7C, 0xF3,
0xC2, 0xF7, 0xAE, 0x3A, 0x4C, 0x5C, 0x11, 0xAF, 0xC3, 0xB2, 0xA8, 0x1F, 0x2F,
0xD2, 0x1E, 0x8F, 0xF1, 0x70, 0x1B, 0x9D, 0xF0, 0x61, 0x28, 0xF0, 0xBB, 0x64,
0x9C, 0x07, 0x2E, 0xD6, 0xFB, 0xA0, 0xD3, 0x14, 0x16, 0x7E, 0x73, 0x00, 0xD0,
0x28, 0xF5, 0x96, 0x83, 0x18, 0x2F, 0xBC, 0x7E, 0x4D, 0xE1, 0xA4, 0xC2, 0x91,
0x6C, 0xDA, 0xAB, 0xDD, 0xE0, 0xC1, 0x89, 0xD3, 0xE3, 0x5D, 0x17, 0x64, 0x48,
0x23, 0x4F, 0x8C, 0xB4, 0x17, 0x38, 0x6C, 0x25, 0xCF, 0x89, 0x84, 0x56, 0x3E,
0x92, 0x6F, 0xCA, 0xCB, 0xD7, 0xC0, 0x89, 0x05, 0xB0, 0x39, 0x66, 0x16, 0x98,
0x6C, 0xD5, 0xD2, 0x14, 0x7D, 0x85, 0xF5, 0xD0, 0x3A, 0x02, 0x42, 0x25, 0x6B,
0xDB, 0x40, 0xF3, 0xA5, 0x5C, 0x03, 0x6F, 0xA9, 0x6A, 0x98, 0x4F, 0xC4, 0x77,
0x83, 0xED, 0x40, 0x4E, 0x32, 0xB6, 0xE4, 0x6F, 0x5B, 0x13, 0x88, 0x04, 0x3B,
0x0D, 0x6E, 0xC1, 0x67, 0x20, 0xEA, 0x3B, 0x3C, 0xC4, 0x4A, 0xA9, 0x23, 0xE0,
0x41, 0x8A, 0xA8, 0x13, 0x00, 0xB5, 0x8C, 0x37, 0x71, 0x57, 0xD3, 0xED, 0x9F,
0x9A, 0x6C, 0xB7, 0x6C, 0x5B, 0x46, 0xBD, 0x8A, 0x98, 0x30, 0xA3, 0x34, 0x1F,
0xCA, 0x19, 0x81, 0xE0, 0xFF, 0x4C, 0x08, 0x09, 0x82, 0xBC, 0x0D, 0xDF, 0xB2,
0x57, 0x68, 0x0B, 0x0A, 0xE7, 0xE2, 0x83, 0xD4, 0xD1, 0xA4, 0x62, 0x8F, 0x88,
0xCF, 0x04, 0xDC, 0x11, 0xE9, 0x9B, 0xCD, 0xEC, 0x0B, 0x88, 0x2B, 0x57, 0x9A,
0xF9, 0x71, 0xB8, 0xC3, 0x05, 0x59, 0x35, 0xF2, 0xA9, 0x80, 0xE0, 0x16, 0x22,
0xCA, 0xE0, 0xAE, 0x1B, 0xB5, 0x54, 0x76, 0xC1, 0xBA, 0x32, 0x9B, 0x67, 0x18,
0x86, 0x7C, 0x15, 0xD6, 0x81, 0x1A, 0xDF, 0x83, 0xD0, 0xDD, 0x6B, 0x2F, 0x98,
0x56, 0xB2, 0xBA, 0xFC, 0xA7, 0xD3, 0xE7, 0xAA, 0xE7, 0x3A, 0xC2, 0x50, 0x74,
0x63, 0xE6, 0x72, 0xC3, 0x40, 0x00, 0xF2, 0xDC, 0x06, 0x86, 0x1F, 0xF5, 0xE2,
0xD5, 0x77, 0xF5, 0xFF, 0x87, 0x32, 0x30, 0x61, 0x94, 0xE7, 0x04, 0x68, 0x0E,
0xC4, 0xF9, 0xDA, 0x54, 0x93, 0x32, 0xCE, 0x7D, 0x82, 0x05, 0x9A, 0x25, 0xF2,
0x88, 0x32, 0x64, 0x1A, 0x71, 0x94, 0x50, 0xBC, 0xD0, 0x31, 0xE2, 0x53, 0x61,
0x4A, 0xFF, 0xD4, 0x2E, 0xCE, 0xE0, 0x5B, 0xC4, 0x24, 0xCA, 0x95, 0xE2, 0x75,
0x54, 0xB6, 0xCF, 0x5C, 0xD6, 0x96, 0x0F, 0x1F, 0x60, 0xA2, 0x20, 0x1F, 0x00,
0x3C, 0x2D, 0x0D, 0x89, 0x90, 0xBD, 0x3A, 0xD3, 0xDC, 0x64, 0xB1, 0x61, 0xFB,
0xAA, 0x67, 0x15, 0xB0, 0xCE, 0x18, 0x1B, 0x09, 0xA2, 0x38, 0x31, 0x95, 0x0F,
0x2C, 0x25, 0x80, 0x4B, 0x13, 0xCB, 0xA0, 0xC7, 0xC7, 0xFA, 0xCC, 0x2C, 0x98,
0x66, 0xBE, 0xDC, 0x7B, 0xBB, 0x53, 0x12, 0x33, 0xDF, 0x92, 0x0C, 0x5F, 0x9E,
0xCC, 0x8E, 0x18, 0x23, 0x03, 0x2D, 0x7A, 0x2B, 0x90, 0x71, 0x07, 0x24, 0x95,
0xFE, 0x50, 0x95, 0x6E, 0x95, 0xFF, 0x29, 0x85, 0x7B, 0x44, 0x1C, 0x0A, 0x86,
0x48, 0x9B, 0x6B, 0xEA, 0xA7, 0xF9, 0xBF, 0xE8, 0x84, 0x10, 0xDC, 0x45, 0xC7,
0xFB, 0x2A, 0x39, 0x99, 0x0D, 0xCF, 0x23, 0x88, 0x35, 0x9C, 0x3D, 0xBA, 0x77,
0x7E, 0x8D, 0x4C, 0xA7, 0xB6, 0x41, 0x25, 0x46, 0x9A, 0x8E, 0xFF, 0x74, 0x5E,
0x9E, 0xDB, 0x8F, 0x20, 0xE9, 0xE3, 0x83, 0x84, 0x28, 0x0E, 0x14, 0xFC, 0x52,
0x1A, 0x69, 0xEC, 0x95, 0x5E, 0xBD, 0xFA, 0x05, 0xE4, 0xE5, 0xC7, 0xEB, 0x5F,
0x90, 0x21, 0x9C, 0xD5, 0x6B, 0xF7, 0x31, 0x35, 0xDA, 0x30, 0x41, 0xB2, 0x7E,
0xAB, 0x43, 0x36, 0x4E, 0x0B, 0x84, 0xDE, 0x43, 0x62, 0x96, 0x81, 0xF8, 0x9B,
0x81, 0x20, 0x06, 0x3B, 0xCA, 0x8E, 0x09, 0xE7, 0x2A, 0x6B, 0x41, 0x0C, 0x42,
0x02, 0x27, 0x41, 0x95, 0x8C, 0x86, 0x91, 0x40, 0xB1, 0xE8, 0x0C, 0x65, 0x6F,
0x23, 0xA5, 0x4A, 0xA9, 0x14, 0x8F, 0x32, 0x36, 0x3A, 0xDC, 0xAE, 0x54, 0x29,
0x13, 0x6B, 0xC0, 0x0D, 0x76, 0x6F, 0x79, 0xC4, 0x0A, 0x87, 0x89, 0xF2, 0xDD,
0xB0, 0xE3, 0xC0, 0x65, 0xC7, 0xE3, 0xBD, 0x17, 0xC4, 0x66, 0x3F, 0x84, 0x0B,
0x3F, 0x7A, 0x50, 0x08, 0x5F, 0x68, 0xE6, 0xC6, 0x37, 0xA7, 0x73, 0xF4, 0x4F,
0x37, 0x05, 0x28, 0x64, 0x0E, 0x36, 0xF8, 0xC2, 0x2F, 0xEA, 0x1D, 0x98, 0xBB,
0xB2, 0xFB, 0xE5, 0x98, 0xAE, 0x5D, 0xF8, 0xE8, 0xDA, 0xA1, 0xB6, 0x43, 0x0C,
0x6D, 0x1C, 0x39, 0x59, 0xE1, 0xBF, 0xEB, 0xA6, 0x4D, 0xBF, 0x12, 0x0E, 0x6E,
0xC4, 0x93, 0x8B, 0x72, 0x54, 0x47, 0xBE, 0xFC, 0x3A, 0x00, 0x7F, 0xD3, 0x57,
0x32, 0xE7, 0x86, 0xF0, 0x96, 0xCC, 0x06, 0x8F, 0x73, 0x9C, 0xE6, 0x8D, 0xD8,
0xB8, 0x24, 0xF9, 0xC0, 0x51, 0x99, 0xB8, 0x35, 0x98, 0x37, 0x32, 0x35, 0x03,
0x5C, 0xDA, 0x91, 0xC9, 0x6A, 0x50, 0xE5, 0xE1, 0xF0, 0xEF, 0xBB, 0x66, 0x27,
0x91, 0x51, 0x57, 0x09, 0xBB, 0x5B, 0xE9, 0x26, 0x8E, 0xB9, 0x75, 0xD9, 0x2E,
0x80, 0xE2, 0xDD, 0x27, 0xDD, 0x5A, 0x1B, 0x4E, 0xCF, 0x17, 0x11, 0x2B, 0x7B,
0xCB, 0xF9, 0xB3, 0xED, 0x07, 0xF3, 0x5A, 0xEE, 0xBF, 0x4B, 0x07, 0x43, 0x73,
0xF8, 0x24, 0x16, 0x67, 0x41, 0xE9, 0x64, 0xB4, 0xE7, 0x05, 0x72, 0x91, 0xF7,
0xCE, 0x38, 0x7D, 0x38, 0xA5, 0x60, 0x95, 0xC1, 0xC7, 0x64, 0x1B, 0xCC, 0xC4,
0x12, 0x32, 0xC3, 0x49, 0x7E, 0xAB, 0x96, 0x1D, 0x2A, 0x3C, 0x60, 0x51, 0xAA,
0x62, 0x86, 0xF3, 0x9F, 0xC6, 0x7F, 0xAB, 0x0F, 0xBB, 0x15, 0x7B, 0xBA, 0x43,
0x26, 0xAE, 0x37, 0x45, 0x5F, 0x39, 0x70, 0xB7, 0x19, 0x2F, 0x02, 0x33, 0xF1,
0x11, 0x4E, 0x78, 0x7D, 0x17, 0x8F, 0xBF, 0xEB, 0x92, 0xCC, 0x2F, 0xCA, 0x87,
0x01, 0xA8, 0xE3, 0xAD, 0x7B, 0x4A, 0x44, 0x0C, 0x75, 0x5A, 0x31, 0xCA, 0xE1,
0xE6, 0x18, 0xD7, 0xC4, 0xA3, 0xBA, 0x7F, 0xB5, 0xBC, 0xFD, 0xA6, 0x9C, 0xDC,
0x2A, 0xEB, 0x18, 0xDC, 0x88, 0x08, 0x6E, 0x7D, 0x6A, 0x97, 0xB6, 0xCD, 0x53,
0x41, 0x1D, 0xB4, 0xA8, 0xBD, 0xE3, 0x85, 0x29, 0x5F, 0x12, 0x03, 0xB8, 0x09,
0x13, 0x20, 0x6D, 0x68, 0x4F, 0x80, 0x1E, 0xBB, 0x6C, 0xD6, 0x51, 0x8C, 0x46,
0x19, 0x00, 0xBB, 0x90, 0xF9, 0xEA, 0xB0, 0x33, 0xF4, 0x52, 0xCA, 0x19, 0xD6,
0x68, 0xAE, 0x79, 0xE2, 0xC1, 0x39, 0xA9, 0x18, 0xF2, 0x26, 0x71, 0x69, 0xFF,
0xBA, 0x97, 0x28, 0x34, 0x4D, 0x10, 0x01, 0xFB, 0xD7, 0xBA, 0x37, 0x0F, 0xC8,
0xFC, 0x07, 0x7A, 0xCD, 0x1A, 0xDD, 0x92, 0x0D, 0x45, 0x8A, 0x7B, 0x6F, 0x94,
0x00, 0x53, 0x7E, 0xAF, 0xA5, 0x99, 0xB9, 0x7F, 0x00, 0xCD, 0xC7, 0x7C, 0x35,
0xCE, 0x53, 0x64, 0x15, 0xC2, 0x47, 0x7C, 0xD1, 0x12, 0x40, 0xBD, 0xF9, 0x8B,
0xBA, 0x3B, 0x5A, 0x3D, 0xFF, 0x5C, 0x48, 0x3A, 0x7F, 0xEF, 0x5B, 0xA8, 0xFC,
0xD6, 0xEA, 0xFB, 0x49, 0x0B, 0x29, 0x98, 0x5F, 0xCA, 0xBC, 0xC1, 0xD5, 0xA8,
0x15, 0x5B, 0x09, 0xEF, 0xB3, 0x0E, 0x41, 0xDC, 0x4D, 0x22, 0x30, 0xEE, 0xAA,
0xD9, 0xBA, 0x37, 0x43, 0xDE, 0x34, 0xF8, 0xB9, 0x42, 0xE7, 0x65, 0xEC, 0xE6,
0xA3, 0xE1, 0xED, 0x46, 0x46, 0xB4, 0x9F, 0x1C, 0xA0, 0x61, 0x50, 0x8E, 0x8A,
0x61, 0xBC, 0xF1, 0x3A, 0x55, 0xF8, 0xAB, 0xBA, 0x09, 0x5A, 0x4F, 0xB1, 0x38,
0x99, 0x77, 0x0A, 0xF5, 0x5D, 0xF7, 0xA0, 0x29, 0xA5, 0x00, 0x1D, 0x92, 0xC1,
0xA8, 0x4A, 0x73, 0x13, 0xCB, 0x1F, 0x14, 0xB0, 0xDB, 0x64, 0x53, 0xA8, 0x77,
0xB1, 0x80, 0xDF, 0xA7, 0x20, 0x9A, 0xA3, 0xD1, 0x79, 0x4B, 0x75, 0x45, 0x6D,
0xB0, 0xF5, 0xD8, 0x09, 0xE3, 0xB7, 0x7C, 0xC8, 0x1B, 0x56, 0xA2, 0x04, 0x11,
0xFB, 0xAC, 0x2D, 0x55, 0xF3, 0x95, 0x36, 0xF2, 0xAE, 0x6E, 0x9F, 0x10, 0xFE,
0xC0, 0xD5, 0x62, 0x36, 0xA7, 0xA0, 0xC5, 0x05, 0x2F, 0x55, 0x79, 0x59, 0x1B,
0xF4, 0xF6, 0xC3, 0xD2, 0x77, 0x96, 0x35, 0xBF, 0x89, 0x33, 0x45, 0xE9, 0xAB,
0x0A, 0x4B, 0xE1, 0x42, 0x31, 0xAF, 0x38, 0xA2, 0xA9, 0x45, 0xCF, 0x7D, 0x02,
0x88, 0x77, 0x4B, 0xD0, 0x2D, 0x9B, 0x56, 0x6E, 0xC3, 0xB3, 0x61, 0xA8, 0x1F,
0x8B, 0x9C, 0x3F, 0x63, 0xD4, 0x3C, 0x88, 0xA0, 0x7B, 0x90, 0xDB, 0x02, 0x30,
0xC5, 0xE8, 0x68, 0x82, 0x28, 0x58, 0x40, 0x31, 0xA3, 0x5C, 0xE9, 0xFB, 0x2A,
0xE6, 0x6E, 0x8F, 0x49, 0x5B, 0xF6, 0xAC, 0xB5, 0xBF, 0x30, 0xA8, 0x68, 0x83,
0x5E, 0xB4, 0x26, 0xBF, 0x6D, 0x1F, 0xEC, 0xEB, 0x00, 0xBD, 0x12, 0x0D, 0xB9,
0x80, 0xF1, 0xE7, 0x13, 0x3B, 0xCA, 0x81, 0x98, 0x5C, 0xE8, 0xA1, 0x98, 0xA1,
0x82, 0x26, 0x5F, 0xDD, 0xE0, 0xAE, 0xF8, 0x0C, 0x63, 0x78, 0xA8, 0xC1, 0xF7,
0x20, 0x62, 0x0B, 0xC8, 0xF9, 0xE5, 0x89, 0x43, 0x44, 0x05, 0x56, 0x98, 0xDE,
0xFD, 0x99, 0x25, 0xC0, 0x33, 0xCA, 0x1C, 0xDD, 0xAE, 0x2F, 0xDF, 0x14, 0x7E,
0xE2, 0x75, 0x75, 0xBC, 0x1C, 0x81, 0xF7, 0x21, 0x07, 0x0E, 0x21, 0x4A, 0x41,
0x4F, 0x33, 0xBD, 0x00, 0x5D, 0xBD, 0xF1, 0x79, 0x0C, 0x15, 0x8C, 0x98, 0x06,
0x72, 0xB8, 0xC2, 0xC1, 0x29, 0xFB, 0x7E, 0xE5, 0xF4, 0x04, 0x49, 0x17, 0xFD,
0x4B, 0xE5, 0xC7, 0x03, 0xFA, 0x88, 0x81, 0xBF, 0xDB, 0x10, 0xE2, 0x37, 0x12,
0x9E, 0x63, 0x7D, 0xFA, 0xBC, 0xF6, 0x98, 0x12, 0x23, 0x99, 0x59, 0xE3, 0x30,
0xD0, 0xA8, 0x21, 0x6D, 0x80, 0x2A, 0xF4, 0xB9, 0x6D, 0x71, 0x62, 0x0B, 0xA7,
0x99, 0xB2, 0xA1, 0x60, 0x34, 0xC5, 0x7F, 0xC3, 0x59, 0x78, 0xED, 0xB4, 0xA6,
0x5E, 0xF8, 0xC8, 0x5E, 0xF6, 0x69, 0xCE, 0xA0, 0x98, 0x87, 0x79, 0xDB, 0xB8,
0xA2, 0x3C, 0x94, 0xAC, 0xD1, 0x4C, 0x6C, 0x72, 0x39, 0x17, 0x32, 0x78, 0xA1,
0xDC, 0x1D, 0x03, 0xB2, 0xA1, 0x57, 0x0D, 0x2F, 0xA7, 0xF4, 0x8D, 0xE8, 0x4C,
0x67, 0x95, 0x19, 0x95, 0x55, 0xB9, 0xDE, 0x38, 0xD0, 0x85, 0xDB, 0x15, 0xB8,
0x8C, 0x0F, 0x6A, 0x69, 0x38, 0xF6, 0x8B, 0x75, 0x81, 0x89, 0x7E, 0xF8, 0x3A,
0xF3, 0x27, 0x08, 0xC0, 0x7B, 0x78, 0x3A, 0x73, 0xA5, 0xCB, 0xB0, 0x67, 0xD7,
0xDF, 0x88, 0x84, 0x4A, 0x52, 0xBD, 0x91, 0x74, 0x2C, 0xD1, 0x16, 0x3A, 0xCB,
0x0D, 0x3D, 0x08, 0x3D, 0x4F, 0x58, 0xE6, 0xCB, 0x32, 0x8A, 0x52, 0x86, 0x82,
0x61, 0x00, 0xDE, 0xCA, 0xF3, 0xDE, 0x05, 0xAB, 0x15, 0xAE, 0x13, 0x35, 0x4A,
0xE2, 0x45, 0xD5, 0xC1, 0xB0, 0x1B, 0xFA, 0xD8, 0xAD, 0xF7, 0xD2, 0x9A, 0x53,
0x06, 0x79, 0x15, 0xA6, 0x95, 0xE0, 0x6C, 0xC7, 0xFA, 0x94, 0x81, 0xB4, 0x91,
0x9D, 0x53, 0x89, 0x2D, 0x59, 0x74, 0x9F, 0x0F, 0xD5, 0x4E, 0xE6, 0xF6, 0x07,
0x62, 0x3B, 0x2C, 0x59, 0xA0, 0x47, 0x52, 0xDF, 0xF4, 0x10, 0xC2, 0xEB, 0x38,
0x86, 0x2F, 0x42, 0x01, 0xC2, 0x8A, 0xCB, 0x20, 0x7B, 0xFC, 0xB8, 0xEA, 0x20,
0x14, 0x69, 0x8B, 0x63, 0x52, 0xA8, 0x13, 0x1D, 0xD4, 0x60, 0x32, 0xF6, 0xDE,
0x75, 0x4D, 0x41, 0xC2, 0xC7, 0xA2, 0x62, 0x6F, 0x04, 0xAF, 0xF9, 0x9E, 0x3D,
0x1C, 0xCB, 0xBB, 0xEC, 0x7A, 0xFD, 0x9C, 0x97, 0x87, 0x40, 0xF1, 0xE7, 0x91,
0xCD, 0x36, 0xD2, 0x64, 0xB1, 0x2B, 0x43, 0xBA, 0x6E, 0xBD, 0x0E, 0x7D, 0xB1,
0x45, 0xA4, 0x0B, 0x84, 0xEB, 0x18, 0x5C, 0x25, 0x8B, 0x9B, 0x62, 0xB3, 0x8C,
0x95, 0xEF, 0x6F, 0x09, 0xE9, 0xF8, 0xE8, 0x18, 0x1A, 0x8A, 0xE2, 0xCC, 0x48,
0xDC, 0xC6, 0xDC, 0x94, 0xB1, 0x24, 0x55, 0x13, 0xB6, 0xD8, 0x16, 0xAB, 0x5F,
0x20, 0x7F, 0x5E, 0x35, 0x1F, 0x5A, 0x56, 0x2C, 0xFF, 0x02, 0x9C, 0xAF, 0x18,
0xF8, 0xBB, 0x60, 0xE1, 0xD4, 0xEF, 0x5E, 0x03, 0x08, 0x07, 0xCD, 0x29, 0x35,
0x7B, 0x9F, 0xEC, 0x35, 0xDB, 0x1D, 0xE1, 0xFD, 0x85, 0xC3, 0xDB, 0xE0, 0x58,
0x1F, 0x39, 0xE9, 0x38, 0xAE, 0x37, 0x18, 0xAF, 0x9C, 0x11, 0x97, 0x97, 0x6B,
0x67, 0x46, 0xC8, 0x68, 0xB7, 0x65, 0x05, 0x20, 0x02, 0x70, 0xDA, 0x6B, 0xC7,
0x34};

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.2.  Example Public Key
const char *mldsa_44_pub_pem_str =
"-----BEGIN PUBLIC KEY-----\n"
"MIIFMjALBglghkgBZQMEAxEDggUhANeytHJUquDbReeTDUqY0sl9jxOX0Xidr6Fw\n"
"JLMW6b7JT8mUbULxm3mnQTu6oz5xSctC7VEVaTrAQfrLmIretf4OHYYxGEmVtZLD\n"
"l9IpTi4U+QqkFLo4JomaxD9MzKy8JumoMrlRGNXLQzy++WYLABOOCBf2HnYsonTD\n"
"atVU6yKqwRYuSrAay6HjjE79j4C2WzM9D3LlXf5xzpweu5iJ58VhBsD9c4A6Kuz+\n"
"r97XqjyyztpU0SvYzTanjPl1lDtHq9JeiArEUuV0LtHo0agq+oblkMdYwVrk0oQN\n"
"kryhpQkPQElll/yn2LlRPxob2m6VCqqY3kZ1B9Sk9aTwWZIWWCw1cvYu2okFqzWB\n"
"ZwxKAnd6M+DKcpX9j0/20aCjp2g9ZfX19/xg2gI+gmxfkhRMAvfRuhB1mHVT6pNn\n"
"/NdtmQt/qZzUWv24g21D5Fn1GH3wWEeXCaAepoNZNfpwRgmQzT3BukAbqUurHd5B\n"
"rGerMxncrKBgSNTE7vJ+4TqcF9BTj0MPLWQtwkFWYN54h32NirxyUjl4wELkKF9D\n"
"GYRsRBJiQpdoRMEOVWuiFbWnGeWdDGsqltOYWQcf3MLN51JKe+2uVOhbMY6FTo/i\n"
"svPt+slxkSgnCq/R5QRMOk/a/Z/zH5B4S46ORZYUSg2vWGUR09mWK56pWvGXtOX8\n"
"YPKx7RXeOlvvX4m9x52RBR2bKBbnT6VFMe/cHL501EiFf0drzVjyHAtlOzt2pOB2\n"
"plWaMCcYVVzGP3SFmqurkl8COGHKjND3utsocfZ9VTJtdFETWtRfShumkRj7ssij\n"
"DuyTku8/l3Bmya3VxxDMZHsVFNIX2VjHAXw+kP0gwE5nS5BIbpNwoxoAHTL0c5ee\n"
"SQZ0nn5Hf6C3RQj4pfI3gxK4PCW9OIygsP/3R4uvQrcWZ+2qyXxGsSlkPlhuWwVa\n"
"DCEZRtTzbmdb7Vhg+gQqMV2YJhZNapI3w1pfv0lUkKW9TfJIuVxKrneEtgVnMWas\n"
"QkW1tLCCoJ6TI+YvIHjFt2eDRG3v1zatOjcC1JsImESQCmGDM5e8RBmzDXqXoLOH\n"
"wZEUdMTUG1PjKpd6y28Op122W7OeWecB52lX3vby1EVZwxp3EitSBOO1whnxaIsU\n"
"7QvAuAGz5ugtzUPpwOn0F0TNmBW9G8iCDYuxI/BPrNGxtoXdWisbjbvz7ZM2cPCV\n"
"oYC08ZLQixC4+rvfzCskUY4y7qCl4MkEyoRHgAg/OwzS0Li2r2e8NVuUlAJdx7Cn\n"
"j6gOOi2/61EyiFHWB4GY6Uk2Ua54fsAlH5Irow6fUd9iptcnhM890gU5MXbfoySl\n"
"Er2Ulwo23TSlFKhnkfDrNvAUWwmrZGUbSgMTsplhGiocSIkWJ1mHaKMRQGC6RENI\n"
"bfUVIqHOiLMJhcIW+ObtF43VZ7MEoNTK+6iCooNC8XqaomrljbYwCD0sNY/fVmw/\n"
"XWKkKFZ7yeqM6VyqDzVHSwv6jzOaJQq0388gg76O77wQVeGP4VNw7ssmBWbYP/Br\n"
"IRquxDyim1TM0A+IFaJGXvC0ZRXMfkHzEk8J7/9zkwmrWLKaFFmgC85QOOk4yWeP\n"
"cusOTuX9quZtn4Vz/Jf8QrSVn0v4th14Qz6GsDNdbpGRxNi/SHs5BcEIz9asJLDO\n"
"t9y3z1H4TQ7Wh7lerrHFM8BvDZcCPZKnCCWDe1m6bLfU5WsKh8IDhiro8xW6WSXo\n"
"7e+meTaaIgJ2YVHxapZfn4Hs52zAcLVYaeTbl4TPBcgwsyQsgxI=\n"
"-----END PUBLIC KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.2.  Example Public Key
const char *mldsa_65_pub_pem_str =
"-----BEGIN PUBLIC KEY-----\n"
"MIIHsjALBglghkgBZQMEAxIDggehAEhoPZGXjjHrPd24sEc0gtK4il9iWUn9j1il\n"
"YeaWvUwn0Fs427Lt8B5mTv2Bvh6ok2iM5oqi1RxZWPi7xutOie5n0sAyCVTVchLK\n"
"xyKf8dbq8DkovVFRH42I2EdzbH3icw1ZeOVBBxMWCXiGdxG/VTmgv8TDUMK+Vyuv\n"
"DuLi+xbM/qCAKNmaxJrrt1k33c4RHNq2L/886ouiIz0eVvvFxaHnJt5j+t0q8Bax\n"
"GRd/o9lxotkncXP85VtndFrwt8IdWX2+uT5qMvNBxJpai+noJQiNHyqkUVXWyK4V\n"
"Nn5OsAO4/feFEHGUlzn5//CQI+r0UQTSqEpFkG7tRnGkTcKNJ5h7tV32np6FYfYa\n"
"gKcmmVA4Zf7Zt+5yqOF6GcQIFE9LKa/vcDHDpthXFhC0LJ9CEkWojxl+FoErAxFZ\n"
"tluWh+Wz6TTFIlrpinm6c9Kzmdc1EO/60Z5TuEUPC6j84QEv2Y0mCnSqqhP64kmg\n"
"BrHDT1uguILyY3giL7NvIoPCQ/D/618btBSgpw1V49QKVrbLyIrh8Dt7KILZje6i\n"
"jhRcne39jq8c7y7ZSosFD4lk9G0eoNDCpD4N2mGCrb9PbtF1tnQiV4Wb8i86QX7P\n"
"H52JMXteU51YevFrnhMT4EUU/6ZLqLP/K4Mh+IEcs/sCLI9kTnCkuAovv+5gSrtz\n"
"eQkeqObFx038AoNma0DAeThwAoIEoTa/XalWjreY00kDi9sMEeA0ReeEfLUGnHXP\n"
"KKxgHHeZ2VghDdvLIm5Rr++fHeR7Bzhz1tP5dFa+3ghQgudKKYss1I9LMJMVXzZs\n"
"j6YBxq+FjfoywISRsqKYh/kDNZSaXW7apnmIKjqV1r9tlwoiH0udPYy/OEr4GqyV\n"
"4rMpTgR4msg3J6XcBFWflq9B2KBTUW/u7rxSdG62qygZ4JEIcQ2DXwEfpjBlhyrT\n"
"NNXN/7KyMQUH6S/Jk64xfal/TzCc2vD2ftmdkCFVdgg4SflTskbX/ts/22dnmFCl\n"
"rUBOZBR/t89Pau3dBa+0uDSWjR/ogBSWDc5dlCI2Um4SpHjWnl++aXAxCzCMBoRQ\n"
"GM/HsqtDChOmsax7sCzMuz2RGsLxEGhhP74Cm/3OAs9c04lQ7XLIOUTt+8dWFa+H\n"
"+GTAUfPFVFbFQShjpAwG0dq1Yr3/BXG408ORe70wCIC7pemYI5uV+pG31kFtTzmL\n"
"OtvNMJg+01krTZ731CNv0A9Q2YqlOiNaxBcnIPd9lhcmcpgM/o/3pacCeD7cK6Mb\n"
"IlkBWhEvx/RoqcL5RkA5AC0w72eLTLeYvBFiFr96mnwYugO3tY/QdRXTEVBJ02FL\n"
"56B+dEMAdQ3x0sWHUziQWer8PXhczdMcB2SL7cA6XDuK1G0GTVnBPVc3Ryn8TilT\n"
"YuKlGRIEUwQovBUir6KP9f4WVeMEylvIwnrQ4MajndTfKJVsFLOMyTaCzv5AK71e\n"
"gtKcRk5E6103tI/FaN/gzG6OFrrqBeUTVZDxkpTnPoNnsCFtu4FQMLneVZE/CAOc\n"
"QjUcWeVRXdWvjgiaFeYl6Pbe5jk4bEZJfXomMoh3TeWBp96WKbQbRCQUH5ePuDMS\n"
"CO/ew8bg3jm8VwY/Pc1sRwNzwIiR6inLx8xtZIO4iJCDrOhqp7UbHCz+birRjZfO\n"
"NvvFbqQvrpfmp6wRSGRHjDZt8eux57EakJhQT9WXW98fSdxwACtjwXOanSY/utQH\n"
"P2qfbCuK9LTDMqEDoM/6Xe6y0GLKPCFf02ACa+fFFk9KRCTvdJSIBNZvRkh3Msgg\n"
"LHlUeGR7TqcdYnwIYCTMo1SkHwh3s48Zs3dK0glcjaU7Bp4hx2ri0gB+FnGe1ACA\n"
"0zT32lLp9aWZBDnK8IOpW4M/Aq0QoIwabQ8mDAByhb1KL0dwOlrvRlKH0lOxisIl\n"
"FDFiEP9WaBSxD4eik9bxmdPDlZmQ0MEmi09Q1fn877vyN70MKLgBgtZll0HxTxC/\n"
"uyG7oSq2IKojlvVsBoa06pAXmQIkIWsv6K12xKkUju+ahqNjWmqne8Hc+2+6Wad9\n"
"/am3Uw3AyoZIyNlzc44Burjwi0kF6EqkZBvWAkEM2XUgJl8vIx8rNeFesvoE0r2U\n"
"1ad6uvHg4WEBCpkAh/W0bqmIsrwFEv2g+pI9rdbEXFMB0JSDZzJltasuEPS6Ug9r\n"
"utVkpcPV4nvbCA99IOEylqMYGVTDnGSclD6+F99cH3quCo/hJsR3WFpdTWSKDQCL\n"
"avXozTG+aakpbU8/0l7YbyIeS5P2X1kplnUzYkuSNXUMMHB1ULWFNtEJpxMcWlu+\n"
"SlcVVnwSU0rsdmB2Huu5+uKJHHdFibgOVmrVV93vc2cZa3In6phw7wnd/seda5MZ\n"
"poebUgXXa/erpazzOvtZ0X/FTmg4PWvloI6bZtpT3N4Ai7KUuFgr0TLNzEmVn9vC\n"
"HlJyGIDIrQNSx58DpDu9hMTN/cbFKQBeHnzZo0mnFoo1Vpul3qgYlo1akUZr1uZO\n"
"IL9iQXGYr8ToHCjdd+1AKCMjmLUvvehryE9HW5AWcQziqrwRoGtNuskB7BbPNlyj\n"
"8tU4E5SKaToPk+ecRspdWm3KPSjKUK0YvRP8pVBZ3ZsYX3n5xHGWpOgbIQS8RgoF\n"
"HgLy6ERP\n"
"-----END PUBLIC KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.2.  Example Public Key
const char *mldsa_87_pub_pem_str =
"-----BEGIN PUBLIC KEY-----\n"
"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\n"
"5VvgYiIvi6kKl0BzMmsxISrs4KNKYA==\n"
"-----END PUBLIC KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.1.1.1. Example Private Key
const char *mldsa_44_priv_seed_pem_str =
"-----BEGIN PRIVATE KEY-----\n"
"MDQCAQAwCwYJYIZIAWUDBAMRBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ\n"
"GhscHR4f\n"
"-----END PRIVATE KEY-----\n";

// C.1.2.1. Example Private Key
const char *mldsa_65_priv_seed_pem_str =
"-----BEGIN PRIVATE KEY-----\n"
"MDQCAQAwCwYJYIZIAWUDBAMSBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ\n"
"GhscHR4f\n"
"-----END PRIVATE KEY-----\n";

// C.1.3.1. Example Private Key
const char *mldsa_87_priv_seed_pem_str =
"-----BEGIN PRIVATE KEY-----\n"
"MDQCAQAwCwYJYIZIAWUDBAMTBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ\n"
"GhscHR4f\n"
"-----END PRIVATE KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.1.1.3.  Example Private Key
const char *mldsa_44_priv_both_pem_str =
"-----BEGIN PRIVATE KEY-----\n"
"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\n"
"-----END PRIVATE KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.1.2.3.  Example Private Key
const char *mldsa_65_priv_both_pem_str =
"-----BEGIN PRIVATE KEY-----\n"
"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\n"
"1siS/I7yI6s/Q/kkwvRmCX7o\n"
"-----END PRIVATE KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.1.3.3.  Example Private Key
const char *mldsa_87_priv_both_pem_str =
"-----BEGIN PRIVATE KEY-----\n"
"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\n"
"WWVn6UNk36ptnVpuuZrk3fQk\n"
"-----END PRIVATE KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.4.  Example (1) Inconsistent Seed and Expanded Private Keys
const char *mldsa_44_priv_both_pem_str_inconsistent =
"-----BEGIN PRIVATE KEY-----\n"
"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\n"
"-----END PRIVATE KEY-----\n";

// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// C.4.  Example (2) Inconsistent Seed and Expanded Private Keys
const char *mldsa_44_priv_both_pem_str_inconsistent_tr =
"-----BEGIN PRIVATE KEY-----\n"
"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\n"
"-----END PRIVATE KEY-----\n";

struct PQDSATestVector {
  const char name[20];
  const int nid;
  const size_t public_key_len;
  const size_t private_key_len;
  const size_t signature_len;
  const char *kat_filename;
  const uint8_t *kPublicKey;
  const uint8_t *kPublicKeySPKI;
  const size_t kPublicKeySPKI_len;
  const char *public_pem_str;
  const char *private_pem_seed_str;
  const char *private_pem_both_str;

  int (*keygen)(uint8_t *public_key, uint8_t *private_key, const uint8_t *seed);

  int (*sign)(const uint8_t *private_key,
              uint8_t *sig, size_t *sig_len,
              const uint8_t *message, size_t message_len,
              const uint8_t *pre, size_t pre_len,
              const uint8_t *rnd);

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

  int (*pack_key)(uint8_t *public_key, const uint8_t *private_key);
};


#define CMP_VEC_AND_PTR(vec, ptr, len)         \
          {                                    \
            std::vector<uint8_t> tmp(len);     \
            tmp.assign(ptr, ptr + len);        \
            EXPECT_EQ(Bytes(vec), Bytes(tmp)); \
          }

#define CMP_VEC_AND_PKEY_PUBLIC(vec, pkey, len) \
CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->public_key, len)

#define CMP_VEC_AND_PKEY_SECRET(vec, pkey, len) \
CMP_VEC_AND_PTR(vec, pkey->pkey.pqdsa_key->private_key, len)

#define GET_ERR_AND_CHECK_REASON(reason)              \
          {                                           \
            uint32_t err = ERR_get_error();           \
            EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); \
            EXPECT_EQ(reason, ERR_GET_REASON(err));   \
          }


static const struct PQDSATestVector parameterSet[] = {
  {
    "MLDSA44",
    NID_MLDSA44,
    1312,
    2560,
    2420,
    "ml_dsa/kat/MLDSA_44_hedged_pure.txt",
    mldsa44kPublicKey,
    mldsa44kPublicKeySPKI,
    1334,
    mldsa_44_pub_pem_str,
    mldsa_44_priv_seed_pem_str,
    mldsa_44_priv_both_pem_str,
    ml_dsa_44_keypair_internal,
    ml_dsa_44_sign_internal,
    ml_dsa_44_verify_internal,
    ml_dsa_44_pack_pk_from_sk,
  },
  {
    "MLDSA65",
    NID_MLDSA65,
    1952,
    4032,
    3309,
    "ml_dsa/kat/MLDSA_65_hedged_pure.txt",
    mldsa65kPublicKey,
    mldsa65kPublicKeySPKI,
    1974,
    mldsa_65_pub_pem_str,
    mldsa_65_priv_seed_pem_str,
    mldsa_65_priv_both_pem_str,
    ml_dsa_65_keypair_internal,
    ml_dsa_65_sign_internal,
    ml_dsa_65_verify_internal,
    ml_dsa_65_pack_pk_from_sk
  },
  {
    "MLDSA87",
    NID_MLDSA87,
    2592,
    4896,
    4627,
    "ml_dsa/kat/MLDSA_87_hedged_pure.txt",
    mldsa87kPublicKey,
    mldsa87kPublicKeySPKI,
    2614,
    mldsa_87_pub_pem_str,
    mldsa_87_priv_seed_pem_str,
    mldsa_87_priv_both_pem_str,
    ml_dsa_87_keypair_internal,
    ml_dsa_87_sign_internal,
    ml_dsa_87_verify_internal,
    ml_dsa_87_pack_pk_from_sk
  },
};

class PQDSAParameterTest : public testing::TestWithParam<PQDSATestVector> {};

INSTANTIATE_TEST_SUITE_P(All, PQDSAParameterTest, testing::ValuesIn(parameterSet),
                         [](const testing::TestParamInfo<PQDSATestVector> &params)
                             -> std::string { return params.param.name; });

TEST_P(PQDSAParameterTest, KAT) {
  std::string kat_filepath = "crypto/fipsmodule/";
  kat_filepath += GetParam().kat_filename;

  FileTestGTest(kat_filepath.c_str(), [&](FileTest *t) {
    std::string count, mlen, smlen;
    std::vector<uint8_t> xi, rng, seed, msg, pk, sk, sm, ctxstr;

    ASSERT_TRUE(t->GetAttribute(&count, "count"));
    ASSERT_TRUE(t->GetBytes(&xi, "xi"));
    ASSERT_TRUE(t->GetBytes(&rng, "rng"));
    ASSERT_TRUE(t->GetBytes(&seed, "seed"));
    ASSERT_TRUE(t->GetBytes(&pk, "pk"));
    ASSERT_TRUE(t->GetBytes(&sk, "sk"));
    ASSERT_TRUE(t->GetBytes(&msg, "msg"));
    ASSERT_TRUE(t->GetAttribute(&mlen, "mlen"));
    ASSERT_TRUE(t->GetBytes(&sm, "sm"));
    ASSERT_TRUE(t->GetAttribute(&smlen, "smlen"));
    ASSERT_TRUE(t->GetBytes(&ctxstr, "ctx"));

    size_t pk_len = GetParam().public_key_len;
    size_t sk_len = GetParam().private_key_len;
    size_t sig_len = GetParam().signature_len;

    std::vector<uint8_t> pub(pk_len);
    std::vector<uint8_t> priv(sk_len);
    std::vector<uint8_t> signature(sig_len);

    std::string name = GetParam().name;
    size_t mlen_int = std::stoi(mlen);

    // The KATs provide the signed message, which is the signature appended with
    // the message that was signed. We use the ML-DSA APIs for sign_signature
    // and not sign_message, which return the signature without the appended
    // message, so we truncate the signed messaged to |sig_len|.
    sm.resize(sig_len);

    // Generate key pair from seed xi and assert that public and private keys
    // are equal to expected values from KAT
    ASSERT_TRUE(GetParam().keygen(pub.data(), priv.data(), xi.data()));
    EXPECT_EQ(Bytes(pub), Bytes(pk));
    EXPECT_EQ(Bytes(priv), Bytes(sk));

    // Prepare m_prime = (0 || ctxlen || ctx)
    // See both FIPS 204: Algorithm 2 line 10 and FIPS 205: Algorithm 22 line 8
    uint8_t m_prime[257];
    size_t m_prime_len = ctxstr.size() + 2;
    m_prime[0] = 0;
    m_prime[1] = ctxstr.size();
    ASSERT_TRUE(ctxstr.size() <= 255);
    OPENSSL_memcpy(m_prime + 2 , ctxstr.data(), ctxstr.size());

    // Generate signature by signing |msg|.
    ASSERT_TRUE(GetParam().sign(priv.data(),
                                signature.data(), &sig_len,
                                msg.data(), mlen_int,
                                m_prime, m_prime_len,
                                rng.data()));

    // Assert that signature is equal to expected signature
    ASSERT_EQ(Bytes(signature), Bytes(sm));

    // Assert that the signature verifies correctly.
    ASSERT_TRUE(GetParam().verify(pub.data(),
                                  signature.data(), sig_len,
                                  msg.data(), mlen_int,
                                  m_prime, m_prime_len));
  });
}

TEST_P(PQDSAParameterTest, KeyGen) {
  // ---- 1. Test basic key generation flow ----
  // Create context of PQDSA type and a key pair
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr));
  ASSERT_TRUE(ctx);

  // Setup the context with specific PQDSA parameters.
  int nid = GetParam().nid;
  ASSERT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(),nid));

  // Generate a key pair.
  EVP_PKEY *raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
  ASSERT_TRUE(raw);
  ASSERT_EQ(EVP_PKEY_pqdsa_get_type(raw), nid);
  bssl::UniquePtr<EVP_PKEY> pkey(raw);

  // ---- 2. Test key generation with PKEY as a template ----
  ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(ctx);

  // Generate a key pair.
  raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
  ASSERT_TRUE(raw);
  pkey.reset(raw);

  // ---- 3. Test getting raw keys and their size ----
  size_t pk_len, sk_len;

  // First getting the sizes only.
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().private_key_len);

  // Then getting the keys and the sizes.
  std::vector<uint8_t> pk_raw(pk_len);
  std::vector<uint8_t> sk_raw(sk_len);
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pk_raw.data(), &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), sk_raw.data(), &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().private_key_len);

  // ---- 4. Test failure modes for EVP_PKEY_CTX_pqdsa_set_params. ----
  // ctx is NULL.
  ASSERT_FALSE(EVP_PKEY_CTX_pqdsa_set_params(nullptr, nid));
  GET_ERR_AND_CHECK_REASON(ERR_R_PASSED_NULL_PARAMETER);

  // ctx->data is NULL
  void *tmp = ctx.get()->data;
  ctx.get()->data = nullptr;
  ASSERT_FALSE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(), nid));
  GET_ERR_AND_CHECK_REASON(ERR_R_PASSED_NULL_PARAMETER);
  ctx.get()->data = tmp;

  // ctx->pkey is not NULL.
  ASSERT_FALSE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(), nid));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_OPERATION);

  // nid is not a PQDSA.
  tmp = (void*) ctx.get()->pkey;
  ctx.get()->pkey = nullptr;
  ASSERT_FALSE(EVP_PKEY_CTX_pqdsa_set_params(ctx.get(), NID_MLKEM768));
  GET_ERR_AND_CHECK_REASON(EVP_R_UNSUPPORTED_ALGORITHM);
  ctx.get()->pkey = (EVP_PKEY*) tmp;
}

// Helper function that:
// 1. Creates a |EVP_PKEY_CTX| object of type: EVP_PKEY_PQDSA.
// 2. Sets the specific PQDSA parameters according to the |pqdsa_nid| provided.
// 3. Generates a key pair.
// 4. Creates an EVP_PKEY object from the generated key (as a bssl::UniquePtr).
// 5. returns the PKEY.
static bssl::UniquePtr<EVP_PKEY> generate_key_pair(int pqdsa_nid) {

  EVP_PKEY_CTX *ctx = nullptr;
  EVP_PKEY *raw = nullptr;

  // Create the PQDSA contex.
  ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, nullptr);
  EXPECT_TRUE(ctx);

  // Set specific PQDSA params for this NID
  EXPECT_TRUE(EVP_PKEY_CTX_pqdsa_set_params(ctx, pqdsa_nid));

  // Generate a keypair
  EXPECT_TRUE(EVP_PKEY_keygen_init(ctx));
  EXPECT_TRUE(EVP_PKEY_keygen(ctx, &raw));

  // Create a new PKEY from the generated raw key
  bssl::UniquePtr<EVP_PKEY> pkey(raw);
  EVP_PKEY_CTX_free(ctx);
  return pkey;
}

TEST_P(PQDSAParameterTest, KeyCmp) {
  // Generate two PQDSA keys and check that they are not equal.
  const int nid = GetParam().nid;

  // Generate first keypair
  bssl::UniquePtr<EVP_PKEY> pkey1(generate_key_pair(nid));

  // Generate second keypair
  bssl::UniquePtr<EVP_PKEY> pkey2(generate_key_pair(nid));

  // Compare keys
  EXPECT_EQ(0, EVP_PKEY_cmp(pkey1.get(), pkey2.get()));
}

TEST_P(PQDSAParameterTest, KeySize) {
  // Test the key size of PQDSA key is as expected
  int nid = GetParam().nid;
  int pk_len = GetParam().public_key_len;
  int sig_len = GetParam().signature_len;

  bssl::UniquePtr<EVP_PKEY> pkey(generate_key_pair(nid));
  EXPECT_EQ(sig_len, EVP_PKEY_size(pkey.get()));
  EXPECT_EQ(8*(pk_len), EVP_PKEY_bits(pkey.get()));
}

TEST_P(PQDSAParameterTest, RawFunctions) {
  // ---- 1. Setup phase: generate PQDSA EVP KEY ----
  int nid = GetParam().nid;
  bssl::UniquePtr<EVP_PKEY> pkey(generate_key_pair(GetParam().nid));

  // ---- 2. Test the extraction of public and private key from a PKEY ----
  size_t pk_len = GetParam().public_key_len;
  size_t sk_len = GetParam().private_key_len;
  std::vector<uint8_t> pk(pk_len);
  std::vector<uint8_t> sk(sk_len);

  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().private_key_len);
  CMP_VEC_AND_PKEY_PUBLIC(pk, pkey, pk_len);
  CMP_VEC_AND_PKEY_SECRET(sk, pkey, sk_len);

  // Passing too large of a buffer is okay. The function will still only read
  // the correct number of bytes (defined by pqdsa->public_key_len and
  // pqdsa->private_key_len)
  pk_len = GetParam().public_key_len + 1;
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  CMP_VEC_AND_PKEY_PUBLIC(pk, pkey, pk_len);

  sk_len = GetParam().private_key_len + 1;
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len));
  CMP_VEC_AND_PKEY_SECRET(sk, pkey, sk_len);

  // ---- 3. Test getting public/private key sizes ----
  pk_len = 0;
  sk_len = 0;
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().private_key_len);

  // ---- 4. Test creating PKEYs from raw data ----
  bssl::UniquePtr<EVP_PKEY>public_pkey(
    EVP_PKEY_pqdsa_new_raw_public_key(nid, pkey->pkey.pqdsa_key->public_key, pk_len));
  bssl::UniquePtr<EVP_PKEY> private_pkey(
    EVP_PKEY_pqdsa_new_raw_private_key(nid, pkey->pkey.pqdsa_key->private_key, sk_len));

  // check that public key is present and private key is not present in public_key
  ASSERT_NE(public_pkey, nullptr);
  EXPECT_NE(public_pkey->pkey.pqdsa_key->public_key, nullptr);
  EXPECT_EQ(public_pkey->pkey.pqdsa_key->private_key, nullptr);

  // check that calling EVP_PKEY_pqdsa_new_raw_private_key populates both the
  // public and private key
  ASSERT_NE(private_pkey, nullptr);
  EXPECT_NE(private_pkey->pkey.pqdsa_key->public_key, nullptr);
  EXPECT_NE(private_pkey->pkey.pqdsa_key->private_key, nullptr);

  // ---- 5. Test get_raw public/private failure modes ----
  std::vector<uint8_t> get_sk(sk_len);

  // Attempting to get a private key that is not present must fail correctly
  EXPECT_FALSE(EVP_PKEY_get_raw_private_key(public_pkey.get(), get_sk.data(), &sk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_NOT_A_PRIVATE_KEY);

  // Null PKEY must fail correctly.
  ASSERT_FALSE(EVP_PKEY_get_raw_public_key(nullptr, pk.data(), &pk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);

  ASSERT_FALSE(EVP_PKEY_get_raw_private_key(nullptr, sk.data(), &sk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);

  // Invalid PKEY (missing ameth) must fail correctly.
  void *tmp = (void*) pkey.get()->ameth;
  pkey.get()->ameth = nullptr;
  ASSERT_FALSE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);

  ASSERT_FALSE(EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
  pkey.get()->ameth = (const EVP_PKEY_ASN1_METHOD*)(tmp);

  // Invalid lengths
  pk_len = GetParam().public_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_BUFFER_TOO_SMALL);

  sk_len = GetParam().private_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_BUFFER_TOO_SMALL);

  // ---- 6. Test new_raw public/private failure modes  ----
  // Invalid lengths
  pk_len = GetParam().public_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_public_key(nid, pk.data(), pk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_BUFFER_SIZE);

  pk_len = GetParam().public_key_len + 1;
  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_public_key(nid, pk.data(), pk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_BUFFER_SIZE);

  sk_len = GetParam().private_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_private_key(nid, sk.data(), sk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_BUFFER_SIZE);

  sk_len = GetParam().private_key_len + 1;
  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_private_key(nid, sk.data(), sk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_BUFFER_SIZE);

  // Invalid nid
  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_public_key(0, pk.data(), pk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_UNSUPPORTED_ALGORITHM);

  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_private_key(0, pk.data(), pk_len));
  GET_ERR_AND_CHECK_REASON(EVP_R_UNSUPPORTED_ALGORITHM);

  // Invalid input buffer
  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_public_key(nid, nullptr, pk_len));
  GET_ERR_AND_CHECK_REASON(ERR_R_PASSED_NULL_PARAMETER);

  ASSERT_FALSE(EVP_PKEY_pqdsa_new_raw_private_key(nid, nullptr, sk_len));
  GET_ERR_AND_CHECK_REASON(ERR_R_PASSED_NULL_PARAMETER);
}

TEST_P(PQDSAParameterTest, MarshalParse) {
  // ---- 1. Setup phase: generate a key ----
  int nid = GetParam().nid;
  bssl::UniquePtr<EVP_PKEY> pkey(generate_key_pair(nid));

  // ---- 2. Test encode (marshal) and decode (parse) of public key ----
  // The public key must encode properly.
  bssl::ScopedCBB cbb;
  uint8_t *der;
  size_t der_len;
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pkey.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
  bssl::UniquePtr<uint8_t> free_der(der);

  // The public key must parse properly.
  CBS cbs;
  CBS_init(&cbs, der, der_len);
  bssl::UniquePtr<EVP_PKEY> pub_pkey_from_der(EVP_parse_public_key(&cbs));
  ASSERT_TRUE(pub_pkey_from_der.get());
  EXPECT_EQ(1, EVP_PKEY_cmp(pkey.get(), pub_pkey_from_der.get()));

  // ---- 3. Test encode (marshal) and decode (parse) of private key ----
  // The private key must encode properly.
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  ASSERT_TRUE(EVP_marshal_private_key(cbb.get(), pkey.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
  free_der.reset(der);

  // The private key must parse properly.
  CBS_init(&cbs, der, der_len);
  bssl::UniquePtr<EVP_PKEY> priv_pkey_from_der(EVP_parse_private_key(&cbs));
  ASSERT_TRUE(priv_pkey_from_der);
  EXPECT_EQ(Bytes(priv_pkey_from_der->pkey.pqdsa_key->private_key, GetParam().private_key_len),
            Bytes(pkey->pkey.pqdsa_key->private_key, GetParam().private_key_len));

  // When importing a PQDSA private key, the public key will be calculated and
  // used to populate the public key. To test the calculated key is correct,
  // we first check that the public key has been populated, then test for equality
  // with the expected public key:
  ASSERT_NE(priv_pkey_from_der, nullptr);
  EXPECT_NE(priv_pkey_from_der->pkey.pqdsa_key->public_key, nullptr);
  EXPECT_NE(priv_pkey_from_der->pkey.pqdsa_key->private_key, nullptr);

  EXPECT_EQ(Bytes(priv_pkey_from_der->pkey.pqdsa_key->public_key, GetParam().public_key_len),
            Bytes(pkey->pkey.pqdsa_key->public_key, GetParam().public_key_len));
}

TEST_P(PQDSAParameterTest, SIGOperations) {
  // ---- 1. Setup phase: generate PQDSA EVP KEY and sign/verify contexts ----
  bssl::UniquePtr<EVP_PKEY> pkey(generate_key_pair(GetParam().nid));
  bssl::ScopedEVP_MD_CTX md_ctx, md_ctx_verify;

 // msg2 differs from msg1 by one byte
  std::vector<uint8_t> msg1 = {
      0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49,
      0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x32, 0x2e};
  std::vector<uint8_t> msg2 = {
      0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49,
      0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x31, 0x2e};

  // ---- 2. Test signature round trip (sign + verify) ----

  // Initalize the signing context |md_ctx| with the |pkey| we generated
  ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey.get()));

  // To sign, we first need to allocate memory for the signature. We call
  // EVP_DigestSign with sig = nullptr to indicate that we are doing a size check
  // on the signature size. The variable |sig_len| will be returned with the
  // correct signature size, so we can allocate memory.
  size_t sig_len = 0;
  ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), nullptr, &sig_len, msg1.data(), msg1.size()));

  // Verify that the returned signature size is as expected
  ASSERT_EQ(sig_len, GetParam().signature_len);

  // Allocate memory for the signature and sign first message; msg1
  std::vector<uint8_t> sig1(sig_len);
  ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), sig1.data(), &sig_len, msg1.data(), msg1.size()));

  // Verify the correct signed message
  ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), nullptr, nullptr, nullptr, pkey.get()));
  ASSERT_TRUE(EVP_DigestVerify(md_ctx_verify.get(), sig1.data(), sig_len, msg1.data(), msg1.size()));

  // ---- 3. Test signature failure modes: incompatible messages/signatures ----
  // Check that the verification of signature1 fails for a different message; msg2
  ASSERT_FALSE(EVP_DigestVerify(md_ctx_verify.get(), sig1.data(), sig_len, msg2.data(), msg2.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);

  // reset the contexts between tests
  md_ctx.Reset();
  md_ctx_verify.Reset();

  // PQDSA signature schemes can be either in randomized (every signature on a
  // fixed message is different) or in deterministic mode (every signature is
  // the same). We currently support randomized signatures (as they are preferable),
  // thus, signing the same message twice should result in unique signatures.
  std::vector<uint8_t> sig3(sig_len);
  ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey.get()));
  ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), sig3.data(), &sig_len, msg1.data(), msg1.size()));
  EXPECT_NE(0, OPENSSL_memcmp(sig1.data(), sig3.data(), sig_len));

  // Sign a different message, msg2 and verify that  the signature for
  // msg1 is not the same as the signature for msg2.
  std::vector<uint8_t> sig2(sig_len);
  ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey.get()));
  ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), sig2.data(), &sig_len, msg2.data(), msg2.size()));
  EXPECT_NE(0, OPENSSL_memcmp(sig1.data(), sig2.data(), sig_len));

  // Check that the signature for msg2 fails to verify with msg1
  ASSERT_FALSE(EVP_DigestVerify(md_ctx.get(), sig2.data(), sig_len, msg1.data(), msg1.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);

  md_ctx.Reset();
  md_ctx_verify.Reset();

  // ---- 4. Test signature failure modes: invalid keys and signatures ----
  // Check that verification fails upon providing a different public key
  // than the one that was used to sign.
  bssl::UniquePtr<EVP_PKEY> new_pkey(generate_key_pair(GetParam().nid));
  ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), nullptr, nullptr, nullptr, new_pkey.get()));
  ASSERT_FALSE(EVP_DigestVerify(md_ctx_verify.get(), sig1.data(), sig_len, msg1.data(), msg1.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);

  // Check that verification fails upon providing a signature of invalid length
  sig_len = GetParam().signature_len - 1;
  ASSERT_FALSE(EVP_DigestVerify(md_ctx_verify.get(), sig1.data(), sig_len, msg1.data(), msg1.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);

  sig_len = GetParam().signature_len + 1;
  ASSERT_FALSE(EVP_DigestVerify(md_ctx_verify.get(), sig1.data(), sig_len, msg1.data(), msg1.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);

  md_ctx.Reset();
  md_ctx_verify.Reset();
}

TEST_P(PQDSAParameterTest, ParsePublicKey) {
  // Test the example public key kPublicKey encodes correctly as kPublicKeySPKI
  // Public key version of d2i_PrivateKey as part of the EVPExtraTest Gtest

  // ---- 1. Setup phase: generate PQDSA key from raw ----
  int nid = GetParam().nid;
  size_t pk_len = GetParam().public_key_len;
  const uint8_t * kPublicKey = GetParam().kPublicKey;
  const uint8_t * kPublicKeySPKI = GetParam().kPublicKeySPKI;
  size_t kPublicKeySPKI_len = GetParam().kPublicKeySPKI_len;

  bssl::UniquePtr<EVP_PKEY> pkey_pk_new(EVP_PKEY_pqdsa_new_raw_public_key(nid, kPublicKey, pk_len));
  ASSERT_TRUE(pkey_pk_new);

  // ---- 2. 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<uint8_t> free_der(der);

  // ---- 3. Verify that the public key encodes as expected ----
  EXPECT_EQ(Bytes(kPublicKeySPKI, kPublicKeySPKI_len), Bytes(der, der_len));

  // ---- 4. Decode the DER structure, then parse as a PKEY ----
  CBS cbs;
  CBS_init(&cbs, der, der_len);
  bssl::UniquePtr<EVP_PKEY> pkey_from_der(EVP_parse_public_key(&cbs));
  ASSERT_TRUE(pkey_from_der);
}

TEST_P(PQDSAParameterTest, ParsePrivateKeySeed) {
  // ---- 1. Setup phase: parse provided public/private from PEM strings ----
  CBS cbs_pub, cbs_priv;
  uint8_t *der_pub = nullptr, *der_priv = nullptr;
  long der_pub_len = 0, der_priv_len = 0;

  ASSERT_TRUE(PEM_to_DER(GetParam().public_pem_str, &der_pub, &der_pub_len));
  ASSERT_TRUE(PEM_to_DER(GetParam().private_pem_seed_str, &der_priv, &der_priv_len));

  CBS_init(&cbs_pub, der_pub, der_pub_len);
  CBS_init(&cbs_priv, der_priv, der_priv_len);

  // ---- 2. Attempt to parse private key ----
  bssl::UniquePtr<EVP_PKEY> pkey1(EVP_parse_private_key(&cbs_priv));
  ASSERT_TRUE(pkey1);

  // ---- 3. Attempt to parse public key ----
  bssl::UniquePtr<EVP_PKEY> pkey2(EVP_parse_public_key(&cbs_pub));
  ASSERT_TRUE(pkey2);

  // ---- 4. Compare public keys ----
  // EVP_parse_private_key will populate both public and private key, we verify
  // that the public key calculated by EVP_parse_private_key is equivalent to
  // the public key that was parsed from PEM.
  ASSERT_EQ(1, EVP_PKEY_cmp(pkey1.get(), pkey2.get()));

  // ---- 5. test failure modes ----
  // Test case in which a parsed key does not contain a seed
  bssl::ScopedCBB cbb;
  void *tmp = (void*) pkey1.get()->pkey.pqdsa_key->seed;
  pkey1.get()->pkey.pqdsa_key->seed =nullptr;
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  ASSERT_FALSE(EVP_marshal_private_key(cbb.get(), pkey1.get()));
  pkey1.get()->pkey.pqdsa_key->seed = (uint8_t *)tmp;

  // Clean up
  OPENSSL_free(der_pub);
  OPENSSL_free(der_priv);
}

TEST_P(PQDSAParameterTest, ParsePrivateKeyBoth) {
  // ---- 1. Setup phase: parse provided public/private from PEM strings ----
  CBS cbs_pub, cbs_priv;
  uint8_t *der_pub = nullptr, *der_priv = nullptr;
  long der_pub_len = 0, der_priv_len = 0;

  ASSERT_TRUE(PEM_to_DER(GetParam().public_pem_str, &der_pub, &der_pub_len));
  ASSERT_TRUE(PEM_to_DER(GetParam().private_pem_both_str, &der_priv, &der_priv_len));

  CBS_init(&cbs_pub, der_pub, der_pub_len);
  CBS_init(&cbs_priv, der_priv, der_priv_len);

  // ---- 2. Basic positive test ----
  bssl::UniquePtr<EVP_PKEY> pkey1(EVP_parse_private_key(&cbs_priv));
  ASSERT_TRUE(pkey1);
  bssl::UniquePtr<EVP_PKEY> pkey2(EVP_parse_public_key(&cbs_pub));
  ASSERT_TRUE(pkey2);
  ASSERT_EQ(1, EVP_PKEY_cmp(pkey1.get(), pkey2.get()));

  // ---- 3. Test with corrupted expanded key ----
  uint8_t *der_corrupt = (uint8_t*)OPENSSL_malloc(der_priv_len);
  ASSERT_TRUE(der_corrupt);
  OPENSSL_memcpy(der_corrupt, der_priv, der_priv_len);

  // ASN.1 DER "both" format accumulative offsets:
  // SEQUENCE(2) + INT(3) + SEQ/OID(13) + OCTET/SEQ(4) + seed(34) =
  // expanded_key starts at offset 62
  const size_t asn1_expanded_key_offset = 62;
  for(size_t i = 0; i < 4; i++) {
    der_corrupt[asn1_expanded_key_offset + i] ^= 0xff;
  }

  CBS cbs_corrupt;
  CBS_init(&cbs_corrupt, der_corrupt, der_priv_len);
  EXPECT_FALSE(EVP_parse_private_key(&cbs_corrupt));
  ERR_clear_error();

  // ---- 4. Test with corrupted seed ----
  OPENSSL_memcpy(der_corrupt, der_priv, der_priv_len);
  // The seed is in the 32 bytes immediately before the expanded key
  const size_t asn1_seed_offset = asn1_expanded_key_offset - 32;
  for(size_t i = 0; i < 4; i++) {
    der_corrupt[asn1_seed_offset + i] ^= 0xff;
  }
  CBS_init(&cbs_corrupt, der_corrupt, der_priv_len);
  EXPECT_FALSE(EVP_parse_private_key(&cbs_corrupt));
  ERR_clear_error();

  // Clean up
  OPENSSL_free(der_corrupt);
  OPENSSL_free(der_pub);
  OPENSSL_free(der_priv);
}

TEST_P(PQDSAParameterTest, KeyConsistencyTest) {
  // This test: generates a random PQDSA key pair extracts the private key, and
  // runs the public key calculator function to populate the coresponding public key.
  // The test is sucessful when the calculated public key is equal to the original
  // public key generated.

  // ---- 1. Setup phase: generate a key and key buffers ----
  int nid = GetParam().nid;
  size_t pk_len = GetParam().public_key_len;
  size_t sk_len = GetParam().private_key_len;

  std::vector<uint8_t> pk(pk_len);
  std::vector<uint8_t> sk(sk_len);
  bssl::UniquePtr<EVP_PKEY> pkey(generate_key_pair(nid));

  // ---- 2. Extract raw private key from the generated PKEY ----
  EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len);

  // ---- 3. Generate a raw public key from the raw private key ----
  ASSERT_TRUE(GetParam().pack_key(pk.data(), sk.data()));

  // ---- 4. Test that the calculated pk is equal to original pkey ----
  CMP_VEC_AND_PKEY_PUBLIC(pk, pkey, pk_len);
}

// ML-DSA specific test framework to test pre-hash modes only applicable to ML-DSA
struct KnownMLDSA {
  const char name[20];
  const int nid;
  const size_t public_key_len;
  const size_t private_key_len;
  const size_t signature_len;
  const char *ACVP_keyGen;
  const char *ACVP_sigGen;
  const char *ACVP_sigVer;

  int (*keygen)(uint8_t *public_key, uint8_t *private_key, const uint8_t *seed);

  int (*sign)(const uint8_t *private_key,
              uint8_t *sig, size_t *sig_len,
              const uint8_t *message, size_t message_len,
              const uint8_t *pre, size_t pre_len,
              const uint8_t *rnd);

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

static const struct KnownMLDSA kMLDSAs[] = {
  {
    "MLDSA44",
    NID_MLDSA44,
    1312,
    2560,
    2420,
    "ml_dsa/kat/MLDSA_44_ACVP_keyGen.txt",
    "ml_dsa/kat/MLDSA_44_ACVP_sigGen.txt",
    "ml_dsa/kat/MLDSA_44_ACVP_sigVer.txt",
    ml_dsa_44_keypair_internal,
    ml_dsa_44_sign_internal,
    ml_dsa_44_verify_internal
  },
  {
    "MLDSA65",
    NID_MLDSA65,
    1952,
    4032,
    3309,
    "ml_dsa/kat/MLDSA_65_ACVP_keyGen.txt",
    "ml_dsa/kat/MLDSA_65_ACVP_sigGen.txt",
    "ml_dsa/kat/MLDSA_65_ACVP_sigVer.txt",
    ml_dsa_65_keypair_internal,
    ml_dsa_65_sign_internal,
    ml_dsa_65_verify_internal
  },
  {
    "MLDSA87",
    NID_MLDSA87,
    2592,
    4896,
    4627,
    "ml_dsa/kat/MLDSA_87_ACVP_keyGen.txt",
    "ml_dsa/kat/MLDSA_87_ACVP_sigGen.txt",
    "ml_dsa/kat/MLDSA_87_ACVP_sigVer.txt",
    ml_dsa_87_keypair_internal,
    ml_dsa_87_sign_internal,
    ml_dsa_87_verify_internal
  },
  {
    "MLDSAEXTMU44",
    NID_MLDSA44,
    1312,
    2560,
    2420,
    "ml_dsa/kat/MLDSA_44_ACVP_keyGen.txt",
    "ml_dsa/kat/MLDSA_EXTMU_44_ACVP_sigGen.txt",
    "ml_dsa/kat/MLDSA_EXTMU_44_ACVP_sigVer.txt",
    ml_dsa_44_keypair_internal,
    ml_dsa_extmu_44_sign_internal,
    ml_dsa_extmu_44_verify_internal
  },
  {
    "MLDSAEXTMU65",
    NID_MLDSA65,
    1952,
    4032,
    3309,
    "ml_dsa/kat/MLDSA_65_ACVP_keyGen.txt",
    "ml_dsa/kat/MLDSA_EXTMU_65_ACVP_sigGen.txt",
    "ml_dsa/kat/MLDSA_EXTMU_65_ACVP_sigVer.txt",
    ml_dsa_65_keypair_internal,
    ml_dsa_extmu_65_sign_internal,
    ml_dsa_extmu_65_verify_internal
  },
  {
    "MLDSAEXTMU87",
    NID_MLDSA87,
    2592,
    4896,
    4627,
    "ml_dsa/kat/MLDSA_87_ACVP_keyGen.txt",
    "ml_dsa/kat/MLDSA_EXTMU_87_ACVP_sigGen.txt",
    "ml_dsa/kat/MLDSA_EXTMU_87_ACVP_sigVer.txt",
    ml_dsa_87_keypair_internal,
    ml_dsa_extmu_87_sign_internal,
    ml_dsa_extmu_87_verify_internal
  },
};

class PerMLDSATest : public testing::TestWithParam<KnownMLDSA> {};

INSTANTIATE_TEST_SUITE_P(All, PerMLDSATest, testing::ValuesIn(kMLDSAs),
                         [](const testing::TestParamInfo<KnownMLDSA> &params)
                             -> std::string { return params.param.name; });

TEST_P(PerMLDSATest, ExternalMu) {
  // ---- 1. Setup phase: generate PQDSA EVP KEY and sign/verify contexts ----
  bssl::UniquePtr<EVP_PKEY> pkey(generate_key_pair(GetParam().nid));
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  bssl::UniquePtr<EVP_MD_CTX> md_ctx_mu(EVP_MD_CTX_new()), md_ctx_pk(EVP_MD_CTX_new());
  bssl::ScopedEVP_MD_CTX md_ctx_verify;

  std::vector<uint8_t> msg1 = {
    0x4a, 0x41, 0x4b, 0x45, 0x20, 0x4d, 0x41, 0x53, 0x53, 0x49,
    0x4d, 0x4f, 0x20, 0x41, 0x57, 0x53, 0x32, 0x30, 0x32, 0x32, 0x2e};

  // ---- 2. Pre-hash setup phase: compute tr, mu ----
  size_t TRBYTES = 64;
  size_t CRHBYTES = 64;
  size_t pk_len = GetParam().public_key_len;

  std::vector<uint8_t> pk(pk_len);
  std::vector<uint8_t> tr(TRBYTES);
  std::vector<uint8_t> mu(TRBYTES);

  uint8_t pre[2];
  pre[0] = 0;
  pre[1] = 0;

  //get public key and hash it
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  ASSERT_TRUE(EVP_DigestInit_ex(md_ctx_pk.get(), EVP_shake256(), nullptr));
  ASSERT_TRUE(EVP_DigestUpdate(md_ctx_pk.get(), pk.data(), pk_len));
  ASSERT_TRUE(EVP_DigestFinalXOF(md_ctx_pk.get(), tr.data(), TRBYTES));

  // compute mu
  ASSERT_TRUE(EVP_DigestInit_ex(md_ctx_mu.get(), EVP_shake256(), nullptr));
  ASSERT_TRUE(EVP_DigestUpdate(md_ctx_mu.get(), tr.data(), TRBYTES));
  ASSERT_TRUE(EVP_DigestUpdate(md_ctx_mu.get(), pre, 2));
  ASSERT_TRUE(EVP_DigestUpdate(md_ctx_mu.get(), msg1.data(), msg1.size()));
  ASSERT_TRUE(EVP_DigestFinalXOF(md_ctx_mu.get(), mu.data(), CRHBYTES));

  // ---- 2. Init signing, get signature size and allocate signature buffer ----
  size_t sig_len = GetParam().signature_len;
  std::vector<uint8_t> sig1(sig_len);

  // ---- 3. Sign mu ----
  ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_sign(ctx.get(), sig1.data(), &sig_len, mu.data(), mu.size()));

  // ---- 4. Verify mu (pre-hash) ----
  ASSERT_TRUE(EVP_PKEY_verify_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_verify(ctx.get(), sig1.data(), sig_len, mu.data(), mu.size()));

  // ---- 5. Bonus: Verify raw message with digest verify (no pre-hash) ----
  ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), nullptr, nullptr, nullptr, pkey.get()));
  ASSERT_TRUE(EVP_DigestVerify(md_ctx_verify.get(), sig1.data(), sig_len, msg1.data(), msg1.size()));

  // reset the contexts between tests
  md_ctx_verify.Reset();

  // ---- 6. Test signature failure modes: invalid keys and signatures  ----
  // Check that verification fails upon providing a signature of invalid length
  sig_len = GetParam().signature_len - 1;
  ASSERT_FALSE(EVP_PKEY_verify(ctx.get(), sig1.data(), sig_len, mu.data(), mu.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);

  sig_len = GetParam().signature_len + 1;
  ASSERT_FALSE(EVP_PKEY_verify(ctx.get(), sig1.data(), sig_len, mu.data(), mu.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);

  // Check that verification fails upon providing a different public key
  // than the one that was used to sign.
  bssl::UniquePtr<EVP_PKEY> new_pkey(generate_key_pair(GetParam().nid));
  bssl::UniquePtr<EVP_PKEY_CTX> new_ctx(EVP_PKEY_CTX_new(new_pkey.get(), nullptr));

  ASSERT_TRUE(EVP_PKEY_verify_init(new_ctx.get()));
  ASSERT_FALSE(EVP_PKEY_verify(new_ctx.get(), sig1.data(), sig_len, mu.data(), mu.size()));
  GET_ERR_AND_CHECK_REASON(EVP_R_INVALID_SIGNATURE);
  md_ctx_verify.Reset();
}

TEST_P(PerMLDSATest, ACVPKeyGen) {
  std::string kat_filepath = "crypto/fipsmodule/";
  kat_filepath += GetParam().ACVP_keyGen;

  FileTestGTest(kat_filepath.c_str(), [&](FileTest *t) {
    std::string count;
    std::vector<uint8_t> seed, pk, sk;

    ASSERT_TRUE(t->GetAttribute(&count, "count"));
    ASSERT_TRUE(t->GetBytes(&seed, "keygen_seed"));
    ASSERT_TRUE(t->GetBytes(&pk, "keygen_pk"));
    ASSERT_TRUE(t->GetBytes(&sk, "keygen_sk"));

    size_t pk_len = GetParam().public_key_len;
    size_t sk_len = GetParam().private_key_len;
    std::vector<uint8_t> generated_pk(pk_len);
    std::vector<uint8_t> generated_sk(sk_len);

    //generate key pair from provided seed
    ASSERT_TRUE(GetParam().keygen(generated_pk.data(), generated_sk.data(), seed.data()));

    // Assert that key pair is as expected
    ASSERT_EQ(Bytes(pk), Bytes(generated_pk));
    ASSERT_EQ(Bytes(sk), Bytes(generated_sk));
  });
}

TEST_P(PerMLDSATest, ACVPSigGen) {
  std::string kat_filepath = "crypto/fipsmodule/";
  kat_filepath += GetParam().ACVP_sigGen;

  FileTestGTest(kat_filepath.c_str(), [&](FileTest *t) {
    std::string count;
    std::vector<uint8_t> rnd, msg, pk, sk, mu, sig, data;

    ASSERT_TRUE(t->GetAttribute(&count, "count"));
    ASSERT_TRUE(t->GetBytes(&mu, "siggen_mu"));
    ASSERT_TRUE(t->GetBytes(&msg, "siggen_msg"));
    ASSERT_TRUE(t->GetBytes(&rnd, "siggen_rnd"));
    ASSERT_TRUE(t->GetBytes(&pk, "siggen_pk"));
    ASSERT_TRUE(t->GetBytes(&sk, "siggen_sk"));
    ASSERT_TRUE(t->GetBytes(&sig, "siggen_sig"));

    // Choose which data to use for signing, the KAT can either have mu or msg
    if (mu.empty()) {
      data = msg;
    } else {
      data = mu;
    }

    size_t sig_len = GetParam().signature_len;
    std::vector<uint8_t> signature(sig_len);

    // Generate signature by signing |data|.
    ASSERT_TRUE(GetParam().sign(sk.data(),
                                signature.data(), &sig_len,
                                data.data(), data.size(),
                                nullptr, 0,
                                rnd.data()));

    // Assert that signature is equal to expected signature
    ASSERT_EQ(Bytes(signature), Bytes(sig));

    // Assert that the signature verifies correctly.
    ASSERT_TRUE(GetParam().verify(pk.data(),
                                  signature.data(), sig_len,
                                  data.data(), data.size(),
                                  nullptr, 0));
  });
}

TEST_P(PerMLDSATest, ACVPSigVer) {
  std::string kat_filepath = "crypto/fipsmodule/";
  kat_filepath += GetParam().ACVP_sigVer;

  FileTestGTest(kat_filepath.c_str(), [&](FileTest *t) {
    std::string count, result;
    std::vector<uint8_t> msg, pk, mu, sig, data;

    ASSERT_TRUE(t->GetAttribute(&count, "count"));
    ASSERT_TRUE(t->GetBytes(&mu, "sigver_mu"));
    ASSERT_TRUE(t->GetBytes(&msg, "sigver_msg"));
    ASSERT_TRUE(t->GetBytes(&pk, "sigver_pk"));
    ASSERT_TRUE(t->GetBytes(&sig, "sigver_sig"));
    ASSERT_TRUE(t->GetAttribute(&result, "sigver_result"));

    // Choose which data to use for signing, the KAT can either have mu or msg
    if (mu.empty()) {
      data = msg;
    } else {
      data = mu;
    }

    int res = GetParam().verify(pk.data(),
                                sig.data(), sig.size(),
                                data.data(), data.size(),
                                nullptr, 0);

    // ACVP test both positive and negative results we read the intended result
    // from the KAT and attest that the same result is in |res|.
    if(!res) {
      ASSERT_TRUE(strcmp(result.data(), "False") == 0);
    }
    else {
      ASSERT_TRUE(strcmp(result.data(), "True") == 0);
    }
  });
}

// Wycheproof test vector mapping for ML-DSA variants
struct WycheproofMLDSA {
  const char name[20];
  const int nid;
  const char *verify_test;
  const char *sign_seed_test;
  const char *sign_noseed_test;
};

static constexpr const char kWycheproofMLDSAPath[] =
    "third_party/vectors/converted/wycheproof/testvectors_v1/";

//= third_party/vectors/vectors_spec.md#wycheproof
//= type=test
//# AWS-LC MUST test against `testvectors_v1/mldsa_44_sign_noseed_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_44_sign_seed_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_44_verify_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_65_sign_noseed_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_65_sign_seed_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_65_verify_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_87_sign_noseed_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_87_sign_seed_test.txt`.
//# AWS-LC MUST test against `testvectors_v1/mldsa_87_verify_test.txt`.
static const struct WycheproofMLDSA kWycheproofMLDSAs[] = {
    {"MLDSA44", NID_MLDSA44, "mldsa_44_verify_test.txt",
     "mldsa_44_sign_seed_test.txt", "mldsa_44_sign_noseed_test.txt"},
    {"MLDSA65", NID_MLDSA65, "mldsa_65_verify_test.txt",
     "mldsa_65_sign_seed_test.txt", "mldsa_65_sign_noseed_test.txt"},
    {"MLDSA87", NID_MLDSA87, "mldsa_87_verify_test.txt",
     "mldsa_87_sign_seed_test.txt", "mldsa_87_sign_noseed_test.txt"},
};

class WycheproofMLDSATest : public testing::TestWithParam<WycheproofMLDSA> {};

INSTANTIATE_TEST_SUITE_P(
    All, WycheproofMLDSATest, testing::ValuesIn(kWycheproofMLDSAs),
    [](const testing::TestParamInfo<WycheproofMLDSA> &params) -> std::string {
      return params.param.name;
    });

// ComputeMLDSAExternalMu formats |pk|, |ctx|, and |msg_ctx| to the ExternalMu
// format expected by |EVP_PKEY_verify|. For more information, see the docstring
// for |EVP_PKEY_verify|.
//
// It returns true on success and false on error.
static bool ComputeMLDSAExternalMu(const std::vector<uint8_t> &pk,
                                   const std::vector<uint8_t> &msg_ctx,
                                   const std::vector<uint8_t> &msg,
                                   std::vector<uint8_t> &mu_out) {
  // Ensure |msg_ctx| <= 255 to be representable by a uint8
  // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#algorithm.4
  if (msg_ctx.size() > 255) {
    return false;
  }

  // Compute tr = SHAKE256(pk)
  // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#algorithm.8
  std::vector<uint8_t> tr(64);
  bssl::ScopedEVP_MD_CTX md_ctx_pk;
  if (!EVP_DigestInit_ex(md_ctx_pk.get(), EVP_shake256(), nullptr) ||
      !EVP_DigestUpdate(md_ctx_pk.get(), pk.data(), pk.size()) ||
      !EVP_DigestFinalXOF(md_ctx_pk.get(), tr.data(), tr.size())) {
    return false;
  }

  // Compute mu = SHAKE256(tr || 0 || |msg_ctx| || msg_ctx || M)
  // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#subsection.5.3
  mu_out.resize(64);
  bssl::ScopedEVP_MD_CTX md_ctx_mu;
  if (!EVP_DigestInit_ex(md_ctx_mu.get(), EVP_shake256(), nullptr) ||
      !EVP_DigestUpdate(md_ctx_mu.get(), tr.data(), tr.size())) {
    return false;
  }

  // Add 0 byte for "pure" mode, distinguished from "pre-hash" mode
  // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#subsection.5.4
  uint8_t zero = 0;
  if (!EVP_DigestUpdate(md_ctx_mu.get(), &zero, 1)) {
    return false;
  }

  // Add |msg_ctx|, msg_ctx, and msg, in that order
  uint8_t ctx_len = static_cast<uint8_t>(msg_ctx.size());
  if (!EVP_DigestUpdate(md_ctx_mu.get(), &ctx_len, 1)) {
    return false;
  }
  if (!msg_ctx.empty() &&
      !EVP_DigestUpdate(md_ctx_mu.get(), msg_ctx.data(), msg_ctx.size())) {
    return false;
  }
  if (!EVP_DigestUpdate(md_ctx_mu.get(), msg.data(), msg.size()) ||
      !EVP_DigestFinalXOF(md_ctx_mu.get(), mu_out.data(), mu_out.size())) {
    return false;
  }

  return true;
}

// VerifyMLDSAWithContext verifies that |sig| is a valid signature for |msg|
// with context |msg_ctx|. We need this wrapper because |EVP_DigestVerify| does
// not support verification with contexts.
//
// It returns one on success and zero on error.
static int VerifyMLDSAWithContext(EVP_PKEY *pkey,
                                  const std::vector<uint8_t> &pk,
                                  const std::vector<uint8_t> &sig,
                                  const std::vector<uint8_t> &msg,
                                  const std::vector<uint8_t> &msg_ctx) {
  // If there's a non-empty context string, do ExternalMu verification
  if (!msg_ctx.empty()) {
    std::vector<uint8_t> mu;
    if (!ComputeMLDSAExternalMu(pk, msg_ctx, msg, mu)) {
      return 0;
    }
    bssl::UniquePtr<EVP_PKEY_CTX> pkey_ctx(EVP_PKEY_CTX_new(pkey, nullptr));
    if (!pkey_ctx || !EVP_PKEY_verify_init(pkey_ctx.get())) {
      return 0;
    }
    return EVP_PKEY_verify(pkey_ctx.get(), sig.data(), sig.size(), mu.data(),
                           mu.size());
  }

  // Otherwise, do standard verification
  bssl::ScopedEVP_MD_CTX md_ctx;
  if (!EVP_DigestVerifyInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey)) {
    return 0;
  }
  return EVP_DigestVerify(md_ctx.get(), sig.data(), sig.size(), msg.data(),
                          msg.size());
}

// SignMLDSAWithContext produces a signature |sig| for message |msg| with
// context |msg_ctx|. We need this wrapper because |EVP_DigestSign| does not
// support signing with contexts.
//
// It returns one on success and zero on error.
static int SignMLDSAWithContext(EVP_PKEY *pkey, std::vector<uint8_t> &sig,
                                const std::vector<uint8_t> &pk,
                                const std::vector<uint8_t> &msg,
                                const std::vector<uint8_t> &msg_ctx) {
  // If there's a non-empty context string, do ExternalMu signing
  if (!msg_ctx.empty()) {
    std::vector<uint8_t> mu;
    if (!ComputeMLDSAExternalMu(pk, msg_ctx, msg, mu)) {
      return 0;
    }
    bssl::UniquePtr<EVP_PKEY_CTX> pkey_ctx(EVP_PKEY_CTX_new(pkey, nullptr));
    if (!pkey_ctx || !EVP_PKEY_sign_init(pkey_ctx.get())) {
      return 0;
    }

    size_t sig_len = sig.size();
    return EVP_PKEY_sign(pkey_ctx.get(), sig.data(), &sig_len, mu.data(),
                         mu.size());
  }

  // Otherwise, do standard signing
  bssl::ScopedEVP_MD_CTX md_ctx;
  if (!EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey)) {
    return 0;
  }
  size_t sig_len = sig.size();
  return EVP_DigestSign(md_ctx.get(), sig.data(), &sig_len, msg.data(),
                        msg.size());
}

TEST_P(WycheproofMLDSATest, Verify) {
  std::string test_path =
      std::string(kWycheproofMLDSAPath) + GetParam().verify_test;
  FileTestGTest(test_path.c_str(), [&](FileTest *t) {
    std::vector<uint8_t> msg, pk, pk_der, sig;
    // This is the ML-DSA context string, not to be confused with AWS-LC's |ctx|
    // objects
    // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#algorithm.2
    std::vector<uint8_t> msg_ctx;
    std::string flags;

    ASSERT_TRUE(t->GetInstructionBytes(&pk, "publicKey"));
    ASSERT_TRUE(t->GetInstructionBytes(&pk_der, "publicKeyDer"));

    ASSERT_TRUE(t->GetBytes(&msg, "msg"));
    ASSERT_TRUE(t->GetBytes(&sig, "sig"));
    ASSERT_TRUE(t->GetAttribute(&flags, "flags"));

    WycheproofResult result;
    ASSERT_TRUE(GetWycheproofResult(t, &result));

    if (t->HasAttribute("ctx")) {
      ASSERT_TRUE(t->GetBytes(&msg_ctx, "ctx"));
    } else {
      ASSERT_TRUE(msg_ctx.empty());
    }

    bssl::UniquePtr<EVP_PKEY> pub_pkey_from_raw(
        EVP_PKEY_pqdsa_new_raw_public_key(GetParam().nid, pk.data(),
                                          pk.size()));

    CBS cbs;
    CBS_init(&cbs, pk_der.data(), pk_der.size());
    bssl::UniquePtr<EVP_PKEY> pub_pkey_from_der(EVP_parse_public_key(&cbs));

    bool expect_invalid_public_key =
        (!result.IsValid() && result.HasFlag("IncorrectPublicKeyLength"));
    if (expect_invalid_public_key) {
      EXPECT_FALSE(pub_pkey_from_der.get());
      EXPECT_FALSE(pub_pkey_from_raw.get());
      return;
    }
    ASSERT_TRUE(pub_pkey_from_der.get());
    ASSERT_TRUE(pub_pkey_from_raw.get());
    ASSERT_TRUE(EVP_PKEY_cmp(pub_pkey_from_raw.get(), pub_pkey_from_der.get()));

    int verify_result =
        VerifyMLDSAWithContext(pub_pkey_from_der.get(), pk, sig, msg, msg_ctx);
    if (result.IsValid()) {
      EXPECT_TRUE(verify_result)
          << "Signature verification failed for valid test case";
    } else {
      EXPECT_FALSE(verify_result)
          << "Signature verification succeeded for invalid test case";
    }
  });
}

TEST_P(WycheproofMLDSATest, SignWithSeed) {
  std::string test_path =
      std::string(kWycheproofMLDSAPath) + GetParam().sign_seed_test;
  FileTestGTest(test_path.c_str(), [&](FileTest *t) {
    std::vector<uint8_t> msg, pk, sk_pkcs8, sk_seed, expected_sig;
    std::vector<uint8_t> msg_ctx;

    ASSERT_TRUE(t->GetInstructionBytes(&pk, "publicKey"));
    // privateKeyPkcs8 is optional - some test groups only have privateSeed
    bool has_pkcs8 = t->HasInstruction("privateKeyPkcs8");
    if (has_pkcs8) {
      ASSERT_TRUE(t->GetInstructionBytes(&sk_pkcs8, "privateKeyPkcs8"));
    }
    ASSERT_TRUE(t->GetInstructionBytes(&sk_seed, "privateSeed"));
    ASSERT_TRUE(t->GetBytes(&msg, "msg"));
    ASSERT_TRUE(t->GetBytes(&expected_sig, "sig"));

    WycheproofResult result;
    ASSERT_TRUE(GetWycheproofResult(t, &result));

    if (t->HasAttribute("ctx")) {
      ASSERT_TRUE(t->GetBytes(&msg_ctx, "ctx"));
    }

    bssl::UniquePtr<EVP_PKEY> sec_pkey_from_raw(
        EVP_PKEY_pqdsa_new_raw_private_key(GetParam().nid, sk_seed.data(),
                                           sk_seed.size()));

    bssl::UniquePtr<EVP_PKEY> sec_pkey_from_der;
    if (has_pkcs8) {
      CBS cbs;
      CBS_init(&cbs, sk_pkcs8.data(), sk_pkcs8.size());
      sec_pkey_from_der.reset(EVP_parse_private_key(&cbs));
    }

    bool expect_invalid_public_key =
        (!result.IsValid() && (result.HasFlag("IncorrectPublicKeyLength") ||
                               result.HasFlag("InvalidPrivateKey")));
    if (expect_invalid_public_key) {
      if (has_pkcs8) {
        EXPECT_FALSE(sec_pkey_from_der.get());
      }
      EXPECT_FALSE(sec_pkey_from_raw.get());
      return;
    }
    if (has_pkcs8) {
      ASSERT_TRUE(sec_pkey_from_der.get());
      ASSERT_TRUE(EVP_PKEY_cmp(sec_pkey_from_der.get(), sec_pkey_from_raw.get()));
    }
    ASSERT_TRUE(sec_pkey_from_raw.get());

    std::vector<uint8_t> sig(expected_sig.size());
    EVP_PKEY *signing_key = has_pkcs8 ? sec_pkey_from_der.get() : sec_pkey_from_raw.get();
    int sign_result =
        SignMLDSAWithContext(signing_key, sig, pk, msg, msg_ctx);
    if (result.IsValid()) {
      EXPECT_TRUE(sign_result) << "Signing failed for valid test case";
    } else {
      EXPECT_FALSE(sign_result) << "Signing succeeded for invalid test case";
    }
  });
}

TEST_P(WycheproofMLDSATest, SignWithoutSeed) {
  std::string test_path =
      std::string(kWycheproofMLDSAPath) + GetParam().sign_noseed_test;
  FileTestGTest(test_path.c_str(), [&](FileTest *t) {
    std::vector<uint8_t> msg, pk, sk_expanded, expected_sig;
    std::vector<uint8_t> msg_ctx;

    // publicKey is optional - it's omitted for some invalid test cases
    bool has_pk = t->HasInstruction("publicKey");
    if (has_pk) {
      ASSERT_TRUE(t->GetInstructionBytes(&pk, "publicKey"));
    }
    ASSERT_TRUE(t->GetInstructionBytes(&sk_expanded, "privateKey"));
    ASSERT_TRUE(t->GetBytes(&msg, "msg"));
    ASSERT_TRUE(t->GetBytes(&expected_sig, "sig"));

    WycheproofResult result;
    ASSERT_TRUE(GetWycheproofResult(t, &result));

    if (t->HasAttribute("ctx")) {
      ASSERT_TRUE(t->GetBytes(&msg_ctx, "ctx"));
    }

    bssl::UniquePtr<EVP_PKEY> sec_pkey_from_expanded(
        EVP_PKEY_pqdsa_new_raw_private_key(GetParam().nid, sk_expanded.data(),
                                           sk_expanded.size()));

    bool expect_invalid_private_key =
        (!result.IsValid() && (result.HasFlag("IncorrectPrivateKeyLength") ||
                               result.HasFlag("InvalidPrivateKey")));
    if (expect_invalid_private_key) {
      EXPECT_FALSE(sec_pkey_from_expanded.get());
      return;
    }
    ASSERT_TRUE(sec_pkey_from_expanded.get());

    std::vector<uint8_t> sig(expected_sig.size());
    int sign_result = SignMLDSAWithContext(sec_pkey_from_expanded.get(), sig,
                                           pk, msg, msg_ctx);
    if (result.IsValid()) {
      EXPECT_TRUE(sign_result) << "Signing failed for valid test case";
    } else {
      EXPECT_FALSE(sign_result) << "Signing succeeded for invalid test case";
    }
  });
}

static const uint8_t mldsa87kPublicKeyInvalidLength[] = {
    0x30, 0x11, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
    0x65, 0x03, 0x04, 0x03, 0x13, 0x03, 0x02, 0x00, 0xe4};

TEST(PQDSAParameterTest, ParsePublicKeyInvalidLength) {
  CBS cbs;
  CBS_init(&cbs, mldsa87kPublicKeyInvalidLength,
           sizeof(mldsa87kPublicKeyInvalidLength));
  bssl::UniquePtr<EVP_PKEY> pub_pkey_from_der(EVP_parse_public_key(&cbs));
  ASSERT_FALSE(pub_pkey_from_der.get());
}

static const uint8_t mldsa44kPrivateKeyInvalidLength[] = {
    0x30, 0x16, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
    0x01, 0x65, 0x03, 0x04, 0x03, 0x11, 0x04, 0x04, 0x82, 0x45, 0x52, 0xd8};

TEST(PQDSAParameterTest, ParsePrivateKeyInvalidLength) {
  CBS cbs;
  CBS_init(&cbs, mldsa44kPrivateKeyInvalidLength,
           sizeof(mldsa44kPrivateKeyInvalidLength));
  bssl::UniquePtr<EVP_PKEY> private_pkey_from_der(EVP_parse_private_key(&cbs));
  ASSERT_FALSE(private_pkey_from_der.get());
}

TEST(PQDSAParameterTest, ParsePrivateKeyInconsistentExamples) {
  // These test vectors from ML-DSA standard Section C.4 demonstrate
  // inconsistent private keys for ML-DSA-44
  // https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/

  // Case 1: "both" format with inconsistent seed and expanded key
  uint8_t *der_inconsistent = nullptr;
  long der_inconsistent_len = 0;
  ASSERT_TRUE(PEM_to_DER(mldsa_44_priv_both_pem_str_inconsistent,
                         &der_inconsistent, &der_inconsistent_len));
  CBS cbs_inconsistent;
  CBS_init(&cbs_inconsistent, der_inconsistent, der_inconsistent_len);
  EXPECT_FALSE(EVP_parse_private_key(&cbs_inconsistent));
  ERR_clear_error();
  OPENSSL_free(der_inconsistent);

  // Case 2: expandedKey format with mismatched public key/tr hash
  ASSERT_TRUE(PEM_to_DER(mldsa_44_priv_both_pem_str_inconsistent_tr,
                         &der_inconsistent, &der_inconsistent_len));
  CBS_init(&cbs_inconsistent, der_inconsistent, der_inconsistent_len);
  EXPECT_FALSE(EVP_parse_private_key(&cbs_inconsistent));
  ERR_clear_error();
  OPENSSL_free(der_inconsistent);
}
