SLH-DSA: add support for SHA-256 prehashing.
Turns out that we need this one too.
Change-Id: I9d9d8871f1a45576b1ef812207cb9ae44a376a2c
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/74509
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/slhdsa/slhdsa.cc.inc b/crypto/fipsmodule/slhdsa/slhdsa.cc.inc
index d80ee81..960836e 100644
--- a/crypto/fipsmodule/slhdsa/slhdsa.cc.inc
+++ b/crypto/fipsmodule/slhdsa/slhdsa.cc.inc
@@ -30,6 +30,8 @@
// The OBJECT IDENTIFIER header is also included in these values, per the spec.
+static const uint8_t kSHA256OID[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x65, 0x03, 0x04, 0x02, 0x01};
static const uint8_t kSHA384OID[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x02};
#define MAX_OID_LENGTH 11
@@ -169,14 +171,22 @@
size_t oid_len;
size_t expected_hash_len;
switch (hash_nid) {
- // The SLH-DSA spec only lists SHA-256 and SHA-512. This function supports
- // SHA-384, which is non-standard.
+ case NID_sha256:
+ oid = kSHA256OID;
+ oid_len = sizeof(kSHA256OID);
+ static_assert(sizeof(kSHA256OID) <= MAX_OID_LENGTH, "");
+ expected_hash_len = 32;
+ break;
+
+ // The SLH-DSA spec only lists SHA-256 and SHA-512. This function also
+ // supports SHA-384, which is non-standard.
case NID_sha384:
oid = kSHA384OID;
oid_len = sizeof(kSHA384OID);
static_assert(sizeof(kSHA384OID) <= MAX_OID_LENGTH, "");
expected_hash_len = 48;
break;
+
// If adding a hash function with a larger `oid_len`, update the size of
// `context_and_oid` in the callers.
default:
diff --git a/crypto/slhdsa/slhdsa.cc b/crypto/slhdsa/slhdsa.cc
index c0ec235..1ccac9a 100644
--- a/crypto/slhdsa/slhdsa.cc
+++ b/crypto/slhdsa/slhdsa.cc
@@ -60,6 +60,32 @@
context, context_len));
}
+int SLHDSA_SHA2_128S_prehash_sign(
+ uint8_t out_signature[SLHDSA_SHA2_128S_SIGNATURE_BYTES],
+ const uint8_t private_key[SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
+ const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
+ const uint8_t *context, size_t context_len) {
+ if (hash_nid != NID_sha256) {
+ return 0;
+ }
+ return bcm_success(BCM_slhdsa_sha2_128s_prehash_sign(
+ out_signature, private_key, hashed_msg, hashed_msg_len, hash_nid, context,
+ context_len));
+}
+
+int SLHDSA_SHA2_128S_prehash_verify(
+ const uint8_t *signature, size_t signature_len,
+ const uint8_t public_key[SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
+ const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
+ const uint8_t *context, size_t context_len) {
+ if (hash_nid != NID_sha256) {
+ return 0;
+ }
+ return bcm_success(BCM_slhdsa_sha2_128s_prehash_verify(
+ signature, signature_len, public_key, hashed_msg, hashed_msg_len,
+ hash_nid, context, context_len));
+}
+
int SLHDSA_SHA2_128S_prehash_warning_nonstandard_sign(
uint8_t out_signature[SLHDSA_SHA2_128S_SIGNATURE_BYTES],
const uint8_t private_key[SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
diff --git a/crypto/slhdsa/slhdsa_prehash.txt b/crypto/slhdsa/slhdsa_prehash.txt
index ef9c83f..bdc881b 100644
--- a/crypto/slhdsa/slhdsa_prehash.txt
+++ b/crypto/slhdsa/slhdsa_prehash.txt
@@ -1,8 +1,15 @@
# Generated from the BoringSSL implementation since NIST doesn't publish any
# end-to-end test vectors.
-priv: 14c784af6edaf2e5cc39d91372c41a8e8dbeb9e1dc9b857f1d2e8930e7fc4003747bb3e0f99d24de5623c86573a74351add397ae48d7032edc4279133dc17b47
+pub: 747bb3e0f99d24de5623c86573a74351add397ae48d7032edc4279133dc17b47
hash: SHA-384
msg: d08dc95a87e824643adbb78c19018cb57cd3eb0bfd15f03925935fe3cd047e5a333408a53dac250ce6bb6c00f73663dc
context: 01020304
sig: b2583d27146f0a8c7b5cfb6929dc3a02613497d4a07af7b0d560738833f138292326883723ac8c05b4279f14415d11962a797e35e472bbf9f29508db7643797712b65fa1ee31031cf1c2ee816a0bfdab6646b707d42af30c4b0ae925c9146feae83a3e0a68da3725dc659be1f6ad0b8e14d42ca695223a0448cd91bb065ea5a2ceafd7a5089e7c3e8f67407e870f79cb47c2099c73a8e1e114b5e72466786b8e226b4a704379e5f97e6214f4fd5d7cd338f9eabe7e0eec3208233bdd5a797c854a996ac0d82b22e7772fadd0f227a233a29a2178cf91e406e4d4a1f603d15e00d280c522db63955babb68961f42538c41341e452860b465d5c96454fe4d1279c0ea0fe192288e45e452249f18196a127ac787ecd4142f6fa2a3cf21a72b1b05ee125ca08d06e18465e1d1f3dd6575f8bf5989b0bfbc7bdb736c2be5aca1143ba9cf9daa721c819de91d5817057ad5f1a8b9ce2ad65ac8b19ac70966c8ba906f8a1718f70f48115fcfd6aa9ec6a9f142f3490fb2b11ba7a0e4eee899ebcbff5c7aba13a4031e147da50a2a5bca0156d717f8e9e43847621b2407e3b25393262898c0c00e7a52dbed3a9432f28e7794a3d6d7531ef51b3298e4ff6fd49757ba9c7a2a0f586a0dfe97595c872ef9e6d4aef9b616f733c03e352c3e06115979a40da4124927d5be1be5ff8031babcfc2efe9cdce48d7b047566b51aaa57285f6e089de437d9112178910d093d326589995f91de41d11eb1d68fa6bcf0fe58ed445a4aa18d97aa0bc540e53252f5468dabfa7d0d04fdd76849f5ae6e885dbc2cd7d73d42315ba714f434bff7389290ad93da0b26cddce4a3c7823bd1d1b897e054f3404231804d80d0b0fd00718e552ce340868c7622f4fb35e80380191f36f1a51dcb5fe96026caf3f616e58ee8392ef870162d3f94984b7b4c99744609841152eb5eb2b7a6c43c3c7514c2ef5515f51733bf79dd86964ba3fd8e16a74247cfae86b3fcd3f3f84c694305ea1bc906ebc43a367aedbdc9b1d88820af58873bbeddd89bb6cd88e5fa60b8616be9a8b536424cd5591e922df728d440cc3fd2c4843de6491b4dd2f22b3323690fc6cf2ae6257d5f7dc9a5e233cc1f62baceb633c109f13550574ad3bc06aace02d99a6edd05a2370ae7aa445b644fc3eb71ba039248120379c33e941b9292040a4a5be3d0ec2d374ad0172b18d0102ec2d677136d8d705491ccad09c00eef89ed9e3fa82226cb69fcc34e873117b1812e14877a92f9fa231be59cb7a2e81bce6aebcfb48affa5f0eb629e512e8c05d4b24c4639323f65e87afa9f57240d0c578e246506ad1907c7698991eba8e403f0d2d7f8e34deff817c07c575a6abc33b1c1b21d72c0431dc31e3950c62e8ce39436a00d94fa44ffa28bc817175199d346d8ea0bb9324bf92ae2a763f0415762fe9cf9e9f010456bfbc142b5f81e5e85c7ec1351c9d603df2a3af542f477fad5d8c8d38675cb4b4eb590fa8bffa745f2555ef22b0492966f2d150ca30766b2b7da6fc2d4d0085d76d60438c118c1586e70d07ecb49e2b049c9aafb8d42e949cb2ea814f07d47d3df8e6d3283b6abb85170600762e71ab5f95af2eb3a47e96dbeda84d896d9f885e7bc6bfde6a1040440c3872e2f870f5e6b82268479792a8942610015cc6ed70f7984e85af786ed1c9e444e601e0e80d80a30b2e798e47b50f8d9fb1eef58d4e5f5c2b17d01a1c24e3c301bb1cf36d02b48a9a0cafd3d5a60f8e05ccc6a0bfa7bb6ac952b0d119081b604664655ad6eb392c09d6461fc27d110f38299152457fa6e328572e326aa0656d4287974cd0b8b4c9d50f379d6d4a8a7bd6d5904d46a76cfb5601398fe1a4afdfcab4e2c24ca2467a054a303c91281ec0389bda21b48570c27c9b59a661a0cadca77887b6528fec0b0d95e25e2b5f44a282ec28e70440e554c93320ada8f688cdfb8940d1d5bdaae3774f19ad88c1e30980319932abb0842677efc9fece6e7e3f56fd6fb90a2ec034935ac88b1b2c708ad3be38cbe69352ff575660b6d44cf5e069f670b90d322fbb6f157ad2e1eb28a95343e60c21379a2070a602777213f51669c30c4b670cf698eee5151c77f31cbde9d12b222a7700756cb582d16c87931b9a076d1b7beea6a5001901d5871885ee730e88dbc2ef50bbf60971499e23feb04595e55281031aa402c3f15949ba7e2fe9465269a22b5c302d4067157c50aa87404591baeb32fd77bfe451e869e3d252c7aaa1bba260d7ea4e7ddd828192c87b6bfa8d63e8236a5efd57554808ed43ee1fa5010e1bfc99ae2eb147d5ca05ede64114e49407afe47487ef83004df9c09a2a6b3092ae47167291408e9a46c286465b08fc260297d326081f67d95dc4162248942776666a1c30eeeff108fabf0b645175130eed1e5846b2de60df1ce47c6327c9a6de50e6cc1ae0e90ac4fc1d04bafa2c2faba563eb50d31447a13f95ab4283bc32d95da3d29c3191d894f71193d04c3ccd3e50f74d9626f2f597ff7e4f98ef90d8ca93c6332c8b63a358972b54a411a416101a514020bed203d0187317cd585bd704703ea6cc52b606a0ad847cfcd1e6739f8631c5907be1fd45207d4e944621698fcfcf4f38cd21e24ed549788c4c1a8e12ab2160864f1999d34dc8655d4461b215c6f58f2bc48b740f46d7888fe0a20b41f48ef9542ff760b15233ac2d6c85a3f722164b9ace7196ed4417a404634e49a1a36690b8ba9763a923298e31464826cefd568e4fc3d37cae9314d59d02a41e1f147defe0363ec1b23ecb7b25bd358172a3b8aa38c425dca04e0f1035a51ad0eb39b37e321cfaa82f4bc21847ae09bbed31dcef4a7dcb305554da47fab675ce437e266c6b1c3a35c344721b20fe94f0deb481a53dad7804e0af19c3df83b273f069053311ac6cc4ce5024e0191ba0b829c43ca0fb596d0553f46737eb88c0438a147fa7242a003b925c31118ca8e10fe962a3c2520c59d22ae7c100fca7c3bb4c4058457da3e1d522a923f156801b764dd843e6f7474243055618dfc03910871b75f8e35e3e8b51de8a1a9472fb648e9c1927257d8a2e5572860649891e4d9e5e9213a58216bb4b21bee9a474bbeb3fe8a43c616b92bacb341606880c3741bca671131125c345012a6bdc18315ca0477a27c6121bf1f6a19df856524935b6a65fbd06dd588314a6a58d6de4c7569e4675b41938cef8c69b06a3026072c2b499738163d3701c02a5c9f897a80ce40d3f1dc7c99ed6a9535897ecb13a46a1116ce5bdb15bdae136ea49140115d00992910e5559d11ced8b685689a1535a9295974dd4ca708ec8ad222d306a7a214f60665a5647ccceda25ecb9dba89b27401904c32d2a0e72413e04dab9138841b40b5d29c32e1e01964af3274d5e077a22210ae98bd7bec133570ca568e0a64ed89694c0a80573fc13d48a4e997226115e68aa4385b0e02c947e77192649c4dfdfee053e4c7c0cc4b3fcdfd668189b39ac289ad46042ad9c87ec5e99f27b2149613e5d5e107d6e865da0788dd8362a219c465990bbb0f62c3d5b0b995c9124a027586d6898393696cba012da29a90fe3364f79ec2e3f6102717dd536840e0c9e58d2cb9d14d01662d875a517882887fc01dfd8884986166e90b604342b7e5d9750a1ddd3809a575b42089ee19000189ce1f1c98c5b149e4baf30e684e95b9d74a117ae4de9df6ca86976eefcbb81c8eabd206c2aa3fc863b25ccd813aeb2b18cf5e7366eea00d090dc28bf81ce8a8dfe2a7d5b892d35b3c6978d4a1a74c4c2d0a1fb8066eb422c2a9ea650f2379f71e9d4e6317688847a0f176cd2cd5f195514b39351b4724cc6e1a91479efc9585df888da88d964eb1f7f60ff32d87ba01c5c475357852108f37d1c726b22c1242df327cfdb3c18a0e8f451b72487618e0bdb74e55aa922e706fa173ee8dda83bf6ce0735e560c81d8117d3b89f37cc654619eda2ead4900448173450afd2edef1eb70e083dc83d9d7ab52ba183f4de7bc840007662776b92c26f54df9333621fa20afab96c8f6004147c870586bbcdb1013cfb842b15fa85d3e185878f9c768083df71e095f1fb8e371836a6dd6d35e842feccbf356f1d16cd3e0db7d6f0e54ff4c1faa35bd48da0d6803c9d15392ee55005bf633c3c7147e075ebcb5541294f35a85a5601ab22faf3dd4af87deffb3100821aa11afbf68d25f56359590db53fc1a5aa1136ef8328047b1d88c300bd14bce2b89139d3888ab2b159c522432edb2ac78a29584a7cca092264f6487d0a645f4c8c3b9f6f567a66c27eb8574a60d9439a997743ddf77763772cad36b8efa5ba7163fcbc79f2219f5b6c9b40051176e3226d7137e4869332a6a93659a4885275d71d8d7138c0b640bc29c1eec53b6d7f9b1446b73990131a5bb6a9957fecb47ca912d523a646cb06b2de0839caeb4dfe0fa4a06172c50ca783157e29675a57c7c11fcab124d09117dfcfefcd68a06dfbdc2e7f9ee5fb86840607000ddf9f5ecc9f1001cd7a5c9f68250b441babcddff713582fb876798ebf218d69c0c994d60704d1d56e73d8efd8dad7c659d3fad1c93bc836a8e131fa663565eee1d26dfaa47e71340908febec7590da7d9decf5ee4a35ca47e654776a647574b0b4e00ff0b3673b8907692cd6155aad2265fa1fd8d48319dc4ac81aa1434eac9afff45162d6e28e3a94d6eb0aa28873bddde556912024d452faf49cdb5cdcb460fd38d8751e0176461ecddde223a07562879c8a99574ce0a97c93a804c0a4b334d621e9e27aaf43c47e24f4d5e79ca216857fc37f75f9c6cc308d888964751a834a89f58569cf7ab95ed3a1c266b80070557bac1326e22da340a9a4e30a6dc979672b2c8a60a1436da76ff9637d57fca6027389ae10470f14cc98c1713bc0c947a7a5336ab70f5127c835cde244f062fc617d49e04bc7858cfcb93cf8efdc5e7af17ac50ad3c8649366d8993faa0ca4dcc6198c42fba716f6016bc7c258a4956fa7eae0e48739921659bee07ea78894877ca0802d7526a73a0e8344fd3e5d51c97584b227379f871b4734efa30011637e47ff304c6fccf96837dbf3b7223f7d60038e315b22e81931ee196fbf5ad6595674f60c5ea77d5561ec3a4541fb2c830b84d91512c7d929246f00dd0f9aa17de3f40028512e021381a9f3c59a9012f5160c5b8f5a353297d223815a486c2a7fd4c8154a78e8d276627581e63c45ca121a2c03eb16268a19a12877f57d981eacf5f96e91a19bf808de6f99a704daf5fc4406f7f5c0216734d8bd111017eeb140fc62150785f1c1ef653db98d18bc9629dca04f3a302412a60af4d43c623b5d68b84d1475dfbc8c79acca6147743b1915608f85091f839d46af030a21ec8d64177588e899e682016e14f1f7cc94c627de1cd0905fc005c6e17ef91eeb6e304591add028d46b10518cc8c8309bc71e0aad755c70a0d1f914d1d69273277f7bce1912a72f00cf1bde2776b4e6b46185179236976c60ced81f21f6679939c89817824a701c2c02c9058fb69002b6efb4d894ab1912e696086a9ea13e0dea886672aecd1d239a162e081bb4d7d1bc6244673eb46cb968c135aa32f39211221417fb93b87047ccb8a83f2630bdde4eb9a544afe8546d088439451fe522393bd36b4c3b3fbcead508ce510f7cdfa3d3befbb57ff671686eaaa67da25992fb1588dfb0647c8d45230693968a8e3c848b125ce3920ef20781528ddf2effe9249aa959ab76af2b0bc4e544e1887897c5145fb2faabbe31c937bbf5ef92f28e2f1dd1e92479efff433d4ad2f07e998a59bd345f53c3951fef76a74818dd41fd630dc48eb5f80b6e6b40e1a52858f44f9cecca6886b72dccc4272bb42ee80c12ee8649c1bbdd45c2a91a3b58c98e0361b695833893f828df21cd668d602f8e282a37bc89f88c21f58c18965263fd3d1ed08f749b4e3be510f72545f166e07cfe2b5bf134aef881cdbbbe095334b00f29fcb5dd78b9874ae5913736063e9255d33f89431356e596ff196e9e6032bd3f07b3e7bcc975aeb2b04586de731c23a85f523eabd9d273cfc0a7627a28584ae63b4e94e1079d138bb3a6ce89034671645980df057fdac9bc306c936db9ebf11970a92e16582f1aa8aeb75c2e890cec6172d9475875379344e6683e31ced62efb8b3816f94b4ece52721e4477ab37401581a143019914c365c631e98360b6169fc811bc5141b4cd81851c59db02349e5071723df4e0475a825aea16ce447d72d121fedfb5dfba349e836dd53fbb2fccc4ec35c6385441c5818517bccbe98f08f5d0ffbfdd14b9a0fe9c847151cb8350d022e0618efd75baa0e5dab74b6f02e8965c2b3d90b97cffe77ff773fdf46eb494cac52bfff8585f348bb020b309047fbe7d65e5131fcf6e78436072d2a88e571be9ee82c39b0bacb4839aec0ff42a94d2bb10706be1240c866bb33ae45996de64448b39059d1019e217c4474e140d08e416d7225ffefd6bde2cc9da2c8ca3ca0ceb53eb2dae749f774b1476222dcb48ff078699d00aecc2bec9264ad51b1d13e626227c0364b60b40eb7435b597b125a4d4da8fb736d9d642745124cbd6ee95b730e87b996de2026ec79900ca7f987b6013523ea89a939e5cdd263ff9298136ada395c32243dcf32ade4f4cd41147eb1bcb76835dd56af65d1d59809b4bac666af1edc2fc87a4070cb748d5148297be977f34afec39bec5749671799b8223f6de708581b75d300e5402db580b4b4f0e3de1ebfac82d3eecbb4c82d6a2b0cafa4cd10959675cb57c2afb28cf784d96188962f501fa8a8dcf5994f9ee8f3c6a8f88ef30d338513a6e65d18c68318ed3df1de0be39e02374a6e330d493707d172f292c614e12d11e071e11139d8c87c23213649ca991733bfdca6afeaa746adc859963e13106fff4648c46f830ca6211a5a8d05cb79a4aa8460f800aadb7372ecd8c143d118855fa3f92e2d57c120d88edcd53874385c44c543eb4308d8e31710d9615601929ef360bde0269dddfd5d19b471a3fcc7a2959773c2b996476c7da7bbe6239d607a6f1673c7270d46c8df384d84a751f426b5a2e7dc86c7dc74ff3e1d1c45333d48ce6ef12ae023cc23e0adbf6fbc86f2aa9ca6dace8f60b5cb5c25fe5f4f325c3cc7cfc8f23a2808d49fa8f375349a78fe940af3723f4d8496c4c4b000936ee5d003546ab5273b9800102e1691bd3f9581967bf2807ca2d744f1e287c3981a79f16297c7b59f6909f71c57c43891b80ee1169ddece8a83afd6acb49e93e5e0d7673f9eed5bb83669cfc5f6935b328aec0eed93addb675d182315ae95a90f63cebbad80c759a3af95e8054d4ae647364d8076856a554d57637125fffc17a9bb0a8b1775fd49997ec7fd753867b8de91726b887168370edcdb55d0a20f3851f3763c56cf831c429eda01d6268f5ffa716c37f498f6efb0a5dded996a035d977ec72a69d6ec38f92a73e64ba9163acac15273fe24f2593795397d03a005b8a2a99d22fa1461c470041a318683e1b34df3b4a522394282609924fd09633e48b5447deaa4ed785831a713bfd7350d58a556786596a8918c2125290882e21536ac2cbc7c9fa266f4f16847121ba89eff0b39ce622446954023b1af3e9cca035922bebf8ad3af9e55b65137dd4fd070e695946e4101d12fb48ad6c5d81363a3b2956e33acbf8dc4908768907cd5bd4085ec0c773f07105cf9d894806d374af523adcbe7dd0141affead3717c36278e83a706399581b372d471efcab1b0907aa38a866d2bf0a1aaaab964279bbbd4b45dddc78cb652275514109e040703de4cab899d1f9a1694cc56594442ea171b66e6b758b1d237a9788f092d45efa21228212d10e1ffda3bfe56fa4195284e1ffe8e02c08e7807e123c47afcb11ddb9cfa56a2a5f9b0e25454de13ff7fe0d9c4814e91f6b2504ee698795e4aa7d4539a9a21820630fcca4e62a0dbf309974614908c202b660bb720dc5ee4806abcefec45703cae96b3cf3e7ffb76585b3d060efaafc1a72c4c3c656ab3fad1db77e8231d3e1e60dcf7432a05f900b4b9a7688fad265a034c822b0cdeddff5888877976549c93dafaeea8eff4a4a3ad7c71eb86f2194c06f7b86c3bdf630133794db7e29f1c0302688ebf84de91e74fd400df312d44a383eba56c9daa76309d056c5782ee64890fed3e4e0ed5773a0d38ed3386cf1a212bfce09d3d270890fb211000f29087628b691fb02de760b1c2b45a4c5b6ff0b0f16693418ffea0941f23e4c009e32e302495635ff5fe80c2ac1a6e805efd994e0d24e09c8c24bc7602a2893822714f1f08e33bd05dd268dcfe7c30053e460a378e60722308731a163858ddd5752c6c26ac9d7be87ae86335b0c822bbfdfc72503014e544178893de68948dcddf86df29910b9a24b1f1dad45c1fc28b7f1fa4ba64e092ef9e5453a1cb620582efa863bdebc136a6bfa3f70a49a96e349367cbd89860702fd4da66eec59c2130fcee09507eaf2068fc0c49e891df961de9d63029c337a859760470c70e118e1b4e5893f1173b49195f195915fe11f73895318ffaa2435ef06e5775815df8ef769c7da798be79f19f2097eb627b8b026159841764b913c1b5d1b6e8f9638f9afc66329ad78d10b9b6cd1bb72b56d6e57432c43a7378797ebfda571f0d26fae757e79fa421519e71d738a4b017b13c5d63f8844151ce113c9c9b71aa1451714800cbaec14346086a643877f79cfba676d7d7f72f9cdd46580aa73c41e368f9fa289c7f5bea653a6bdf11cbf5e2041c5727c157dc07f842bdb4eadd80649d0943dcb1dd7596bd2e7605a5919c2ee62aa361e3432c3902625c7e452b6e25f5d5b5f8ca0c32e519f097f5e6ecd205a2e98a0a8c04f6cc874654b2dfd216103d98b4c57dccfac6b7561abeb9162fae838182a8cc811975919c2c44d87cdb7d4d24db1c2748eb7bf4a24e9e0dc2397b1fb626837c4347eea2eb4796815f17d00919e1cecfc0db6d1d058ce3b5ac58f965d37b8d7776611c3bbb7979001dce55f124d58a95365ef7eed6c1f5a0525a9179154b63cfb5c0ebf85979fc5364059697d220aba508c597374eb81bc930ded45c7685711863243559f35c35cea376e92ca187a50d99977f1dec4b83cc75fe87e0e00225841b969f8b46a57a52a2b4f09b42d13f21e5f5fd2bf0a6b2c88c4ce161a5a37bdb4288bbe71f07851e957e33855aba8bd5b77fd59fc4a72faac84bf9a5a947e68cadcfdd8fe690eed70caa7770582b3f83b99e7f8ce6c3997e7303b76f489ad6ff94825cec44f6f8e9040d0ea8973ff9da3d4080825d32b47762426553ad014bfb34a87eb03056481fa2b4ef5b81be18822228fced74763191ff0b4dc7a46070d73376a80ddf522e334252670e3d87fbfd075c9be111e973fd9f552d8173c9d38a67c7b106b035a32bd78b11fdbcb57b936d7ba13ba08d86b8c239ef4d56f0a5ddd8d935a303949ed40932a34c4d093eb5027db1c76378c0067e88d17c8ff2380df87d6caeab12db8ef48d64c76f8961e9e08a265d653d74ebad063d56a05e81f47c099f8d0c627c289531548fea4df8e8184ceb8195ff9f6d45bb23a1ff325add08a53c4ed7eadee95a30a366e4d3e85a760f2f269ca45b9b4a9c4bd04633a7bd800c1d221b565171d3e7adf7d4932b1d85db4e5e93d092657ece40fce1c588c16044404b45d16adfbf8c402a65f0311d4b5b4c98ed0259512908fe6acda19ac693712a606bf6760501b5c82910385d1f4b7d47e7e11df3ea0fb0406541f5d32327f58c94c3e7314650168f16293713664ed9d00716f5c86d62d6e5418c3f0f0e4eb4488e16aeb567c82a1e0be2c922455fb5d316d6bc2be4383e31f7f4a4fe55588e08d1154c7ef4827cf120be57e63cd068671e5d2642f23ed709b6e281961d3980fe8e5af6f2a68f2eb7247f68c18f49ebe60587a3aa103cc8b34df33bdac0ff8c0598d3b49d0e23ea0742b59ff98e33e15f3c1b9025b127c21fe1a4a6dccf1a45ce25268c1b8cf25a18a8f4fb578b22812c5857636a2b93405ea0ba37bbf1d4b1874be91ee118880d1ffac33d948075f555deb30cc0487dbe829266beca76607b86452437d455bd16b13c76a082aafd19bc7989623e0856e0c9c7241646ceb59f84bb0a4a116e2a99d30656c7481b569a310c4a7acfc9edc53995235adcf5d34d10155c0ef5efe1a9e136f813f7db42d33e895b7b2214922ac9758b661e4573da01a85867392909de0821c21c4ddff62c0d3d9df6c42b9b65be1bd3cbecdc9f423854196ee743544e6f2e666c850cc1a17badd959233c14794a8a18eb11d76336daea62fcea4193580a665c193b3f2aeab8e98ac38a3e698dcf1da7b3f969d353a4c852103e5c9b5e2b7319f0370f4407b243d4d981a67c963133206b0ce695883e61aaf4beacc918efe7b9b5ca37bbcc1453a50d0bc57f8c676ec8bd3085ab01d5feeb57d6d0e199d36084052c9f7dc19321de77a249c1fd7e77eca3f8586b3b87721e266d1a64a52d5611858f0e3c65c10f178bf9bead4f5e2730228dd25977790ccfb6512d8c3d369bfc04f73248473c435bdbb7cf3392d9643a2f78965d17bef3fd2111130d308c3c98d48fa43924337ac40b69463a88f7af6f63860e1e9fab9a2b139a0d68eca2d4e1d7944c814db40d1a90d2557ed617608d9a076c882ef6e8d08c0db66813a118f9a37ba9f97a85e1d9252aca1e475b84941fcd7dd1748e292d713027c5a7016ea980aee44a2c4c350216162f89f08978783ce3fb9208172c74ea00283ef71e29475a8bcd5f3956ab7d723a0a596536946f126bcd5c339ae0efe898a290617d428f06a8b7f3dfde1b6851aeb824daad1a5954ab344f1cecadfd13cec54ba8922cb5a6963da64fab78267ccc9b696238c82e334e12adf75e81a9ede7136f2ea589a0314a20e760a5225af5bdf706bbcc7d0835c1ff3c52fd18b4bb6e1cf1eea07852cd0574a18f2683abc8e0221b30434fc671b0c0f037d8a8deaaf5aae967c3d394e24dfad16e60d918c18d880b14f3e6490c7d6460569431ab0689a4b34ac880d1f70fc6a85fe14014842d5f1d39a5d02b1098bc0ce67b7e70dac83
+
+pub: d4bbe5b50e1cf0633c2d0e33e62b34ffb3738d7526036228a55336e58f2dab87
+hash: SHA-256
+msg: f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2
+context:
+sig: 5de4b7c5158d65d6fc2ab75325376e0401c88707586c715c5beb3016817bd9fc9a1cef95be0db443e169d780ee1675d77f7815737fb8c07bf6520adb03486eea15d5580fc78b65f9dcef1ba260466163db6eb8612bb024db0b5b191a1abbc57410f62f22c6074e9dddf0c3ae4b62238e7c9300ec624e7e91d49a5386ba04a5d23cfb7fe0d50a19594fc5c580a5149a088f91d975204804b720d04d7c186e5b995216cda3ad98669fc44856a56e8d7ba8a7d012236ec66e78d0c44cb03c9cd54c046f056395b3ddfefd8b3934e78aef696df89fbc51b65756378dbed25abc1e023877785453974471a03f78f3349899bb074e7ee932a7db3e483ba0e172d689ad2e5adc849a6f24d52c8d6379dfbe65686875342a845b0aa5dd0168cae6b2aebdfcbf69d130986657c1988e1772b910d96dd372d360745aed415001142003da8dfe48c92851cd5a8830f74975d7c0214ea86f4c5757fca6ddc0f8d24c21f992e62996be8b17c01316cb7fb4c0daffbd9bb684b8663f15f45929709638cb11e31ba8f06490d5d8dfce28724485d87e2c52a4aa0e71969cb72beba9775f448bd4d34016555b2171378625841eccd5a81bb0726345b513e797257a5866339a969b12f1e24811b0a601a033d3439a508cd41f25a59d68bd3bd2e53939eee39a9804748cd2cbc530b6366c2879c340b63db1b8152957face631e39c5220e92047c2c529118e14f1a4f49d011337144c3e19164de50d30a792df840810d22393d4a516a07404a037666df0c271592cd4675e2c6f548f92fa4d601050cb856523de0aec08e3dc66da79f08b0a9d1b34be8b48504cded7145e7e1ab4c00da62c5fe5376cc1d5a3df214c0108b9ce337bd240cae6f43c13fd5cc2ce08786d61de9f70a3022d480fc5db1668e480b458e5d7310dd5762a524061bd609880329a6670cc58645f70a0a3cdf8862e4ed18ba12787561f2ed7d54a655b3f295e24569078dc99a3dfff4c715814f6aebd5b990c8164d6347b7d86b51e257ff3f91f939f045c92c4170978204e78b34cb4389358ca19c5801a66b756ef4441e6f0cc20e4a7e249953716fe23fed12b429c24257aadae4d21662829994aac9c20afbf99c303730c294fed4e80eedeb180aefa9cd6b9f29ebb189b66229d011a81a5390fde6badb00bcf22a037ff2e6d670bc5544f05a108ea539de3f7340ea04dcdbe4b9c1bcf5c0875e84c050c9b71d96a4ab2a282f843f4b045001fbc641b42b0f4d63cf7ea20354468f489569705bd5ea2ebc47fc16974b6b4179385a65806f4a6e360a3047626cd860dd3e7e3b99f41db7028169118533dbb09b9ca26048d2d55df96b8cbb77d4f6e54737d72fa3c7765f2e836a1fd55c5514fea4956496f3f5fe4bb4cd98724a8b53eabaea51b3ed3f0b12069af6b0066350c9c99d5c8e1bc47fde1d4c0f0dd85b8d66114ca98a29c90277f0bdd2f58c2b8ccfe8719e559ff418829d6f3b602406ed679ec597caf35921b32ac046530868aa928ca58b84d5d165beb803b48413f7704a2d61d17b4c5ddaa80ef7e83a1b66c39500b235d698463dccf0cf567acd87306636d7805037e5ddab95486a9c8aa23a09cc1e0c564d5113f6f710e99588b1cd183eac6bb46926d264ab7efef7246711f3d220f042f4bc6a77d1d1d97ecbda9c985743745d11df76add3afda12fa4f1132d3817461f1490d2a2595e300265af1d7f28ead61201b4831c052efb6387ed3eb9423620b03d87901d62861df667faaaf9477ed5dfadbaf32de8832e1f3cee1007bff2acd135f37f8c168cb59c53eb6f24f4db1000ec063e50e4f73952e014a5eb536a8ff553a688a4f72b7c3133fa3335d1cc799e71f7476167a8757d6fe100d0001cce0c62692b415e46c41e6fa735566d67c2ade95d6a4c59925d50d373b574c60e6a7b5750508dc3607f4a27376e00b39b19b98d9cb525f861b72302a39e173abac71ff951f52d998d20db88947b641ae9af7c76c6399612218ad08cb7b20aa5b5f492df036456b606ffab807c1ba7a195b4d7f7692cf1080a90dc60df9bcb9da6bd8ff9b593fba23ad04dbae2baff0e019a0516ec523c36272d33f2adff088e27bade5145a8acdfe601b7b813e4e6ec5a1b3faf2198b87c950c8cfeb5617e1af2940f251d01130395028a44f2deea85a8691cc80da6097d77111302b504e9cf224b161fe2b03b3af953bf0b8609c6a9ed99045a803d44e317d8085c9bd36871b055ace2b43a04700d21fff9fbbae818c0eccb0c7f7c522aabcca9866f4b14c0f548917cfc041bb53b9ea597782751acc65bb713aa1783b746ae086370182fa3bd320ad70035d0166845e84b410565566f97ea178a89c6cbe8f3b23e35c495ce55ed4506996d7f142cfe902dfb483e1a98a8f480f6dbcc1cc3edc37b13996c3b30aa9cd711ddc19338811338bc841853cda56dcb0ee21a76588a6a274f400936093d6b9f307c5034b20e487b9b7424f52509056e5cca30bc5645a3d2119db30049b45af8f61272940e6dc22247ce93c7d04d6a4146236d94eb481ff282c48d33625690fdc7e22fdbe9feeadd29fb6ed1d8f4bbb0f8bbda5c25b82d926c6267b463516f7f2d6e81c6196bbc6181a87f705308059a2733aa172b2c08d93ae92aa5701bcbbf971a635595d8c838e6c2d4e2359f046760f8d944ad4ec5fbf6029140894594d2ca6c62c583eaa8b8771cdf2f26d4a931f15bb8b6b9f14dc37ecd1e2ff742bfaf15c21c5aa1cbe2e8cf37666988a92285b5629c4be64ad7f3b3aba4515ccb738cee5e77d96f99aa6dab1d71c52ee840165fe9bcdd19b14beaf39333e0f85c62e7235fb67871ee8e39c75f0876ccaefec5b226323c23f9d594147b26c5d4c30a61ddaeffdb607dc7167931a0cbd41fae07a66f23f323dab7d4811763a81cae5cb9c822dbddb8c52b1e68b5ca93f4c7042fc6f1df8f6b8d465ce2f933d302908edb02c9c308c5b260847829785935d102ff4f8ff799fdc8d3cc709bb4028eb7ee882c6950541bdddf72732fb6bdd6dd53fdf9897086930faa08d7680b6e76faf4387ed91e44fde3acb5c1d236a6278c9bc02a369bf1c56bebe6bd6d82b5a6e12e21dad972cfec06060f27106431c55b72c92661c4d9267902f4f289eaff1a3d4cd1535102070c4d43fe5f499252e5ca679ca00eae4458ae710f65b205036e7781782b69dfe613f7c0b6d5b69d485ee77e0edb301b685117a6e67b15a03c3b08bd8e326f42e5bd1cbbaf9b9bbd109283cff6ebef55df92efd1024f5c4cd3001d34b6f9bfe395b0de16d1f440af325ad6c43888af6dfbb97ab2c114180aca3b9a50e6569719a54e14d6a38b8415d6ab30f05ad7edb34f4a2656b148613881e81a1b7d72040764eeeb8fba28d2e0e24434b85bb43defcc1d0c41ba26425587ace8d372de2f3c7acd12f4a670ca0e97c3039380ccd2a66d4b3c5f08cc7f944e4f1635378e6022b842add8a2cd79cd137dcc6fb867e14111878071c3e58013b468de4ac5a31423efb0a65bdb25ac1407f8fd3903751af89eedfc929996a2ab0bda04a5660e03a3bda2c79b1c6ab0f0fdcb1e72896de7ba7b3715e15e5b3de3c793b1d100bf269e8e5aa5e0df906d24fb12883c792a7ce0c6cfb85f27eb97b5d6ca940db3ea15077b3bba28f9bbb002392744c2615f31dc9bccdd4094dbe26728905655f5fee86853468e81fa2fdae98f00337abb15c0e12b72323749c0f67a0c8d9bd7167800c43618c0ea77931dc56b7ade30d738106c0b6843fd91ea08d1e074429bfc6fc6d79c441f4d84ed2cf42439ed0e71cd555579513bcefa77ece33b64d27852e59db35f5b94f0ba7ed8d41429ab5e95772683b04eae24c653f4acfcd6b31c3efe0a71195ac9deae95a126d49f04b4d9ecff2bec647eb7bcf12c465cdbd858719ee58780f33e0ffe6817ad05c0c53267efd64e4a3a1c0972c7fa89f5e37f65a2c385ddf3cf2d460025b3da15b2bf7248a7553e836959d6f3f196e440da8ca62e08ad3db2307f43b8b1d38b0ce606b2076549fa5dd41a625d2e0dbd137b7021f2341acb1a118e5ba99200644bb48bfef786884300b0fe970cdc1b933684d9ce253c6600fae9f54d4955508458d2e73c46a2b1b9c8c044eaccd7e9dbf9f9b1fbe895c6b1c5d2f067ed9da0a5369ca7fedcf8141d6b311a9fb7e2e6d798e0cb6c0221f5d2886fa7b2918cd39b524849b37152de55e3e6e30031af29186be300b53c412d03d95a1f1fd0fcd28ec29d1a57d39e49ec50a466dec61cf8412363875d7b0ca43eff7178c6bcb1dcb8922729d7bfa6acbf47f1a1f1c560583ff0d25b5de742d0ef54b91643807c7cbc3e7e7dae85c729f3c822bb88529a3c35bac236ccf66d208ac8f6cdd672a184d113cde2743a4a5af8210067799470ad883f16a45ad7dcc3c4188d1c72163ee4fec0f847a6ae1bb92385c0c1e8ef89f9b30928852803b6ec3de62d21db9b0fe2c981d522dc1330f26262a612715ef456af3563bce1ae528e2b87d8d20ca69c7a488d135441b50025c2b1c6cb6a77b8ea254fcaecb626286e5e9bde7583f31a3b2eca4741e7cfb7d48b9ce8d9bcc7027815613ecd9fdd840fb0111a4d8b8516303abf44e43665ecc28e4446ca1d0784195120c1937b87548de297e1d059f2f67eabbc90327adb4e149cefce6c3269305377b20a1bfbcca45c59246492fbcadbec94be4c71f706cf3da227111981c1f9dd0e5b8c7676b31bd9cce55afe3fd6eb2d97f0e22cb51a989b0ddf48b70a76c2ba219b9b6ace794a5e632624e82c3f3ce56d2c1859957ee5f60f35a0fe67eb64fa3cbe48a936a466352a84f9eeb940f150c4c16d28a62e82cca96ff379b3348646a969bc968c178e9265cd7f40667a7efeb7bb1287d2500b68e8faab0869fe0120f0a91fe78836181ebf1e0dc2d02d36d36736ebb07c3d12ca0987f624d70b0131b95b153978e8a54f70c94654df6c5afeb6b8f1d3445bef254408bd0feeea02199b49e307cfcedc62a8694423528611d52ccfa04b7ae430dd5cd5d50e145641ff871c841996eced60117aef92d3bb67e8bbbf8acaa43a6369f24ada8a90bd3d124ef332b5949e1352c1e07bbdfeff76c23e6e72f0504f8d88b48c20f019809d1ed5fb3cfb4f788ad6bfefc677d3927c05c397e59c598771df230cc271c67bc9179bdb37562e0b6388c340ec570ff068ed0e4b99de348f92385422478f42fe72bfa8d700b0fe3846c2f15fc3325a1809b6ad68ab943145050df706c2ee64cb8504854d5162ecc8e46605b3c4b53b9cdfc7ebfb058660d48a0b31628109681ff36a4de2f3efc3c0f1f4f4124c051133cbafb3dcad41e8b6dd4cff734fee4ee27282418c07308dc83e40379c8e92f51096e5550c7e8659a85ad96b6c1f0f084125bb5226703550194b76090b2961ad619a54a4b6de12241f87b43ce6ac480ded04756d26d16c020dbb56931f70a9bab58d60f3925700e2aab5c02f4fb0ff158ab72b1d5d3baa7d3e2b3da16b1b319971cf2f94d890ab374297bc7e7933488b47da35ac78ba27a973d6738082f3bb424337f37be1201972c2dc41adc67772d7da0daed042667634a55abbd07e50b5c61e4d0fa04e30b21cd132e8790d34e16fde8c4fd5e55b1b22d0232009e80a313e8ff04b0bdccafb38cff9dfd8f9152d2a704ede38bfc2955efd96a15223072a87bfe5aa6db4621b912db1846441a35d4106e25a1755e59674b39143c0d81460cd0ecc377e14124fdd2d5146322065b183eecdbfa59b290c0e10c7c3789d059d714a6c493fadaa8062ce73ca1720548d13ddad3fd98dce0b6b8ee900eaebbc260decc615ef411b3debf1e796b1f8fcf87ef0ad5f2c316a51c289a54dcefc1748be7ef986207772b95fc825e6c917dc8c6bde85dcebbba3af814076afc262b39b3a8e943eb0f2fce379161162ed4c66d102bc60fdea79e8b7e86f84add48e5487159e8b217b47b5d600866fe4291ceabeaa752cbed1eb319dcb3d3dee90720fc47535043da28a6f2b9e70652292a39fbc39944b71d01bdefa7c09263a465c7383169bc4c921f1df33207c8359b32dc19bba241283916e3bba5804a52ac4f0926927963cbbc694b9017e3a82e399cae5829a2673b196ea560117316583f51f43b1a8ccf3e6518419a62f70a17dbb3451e431a651f8931748062ca0fe8495bd42f799b24c2d9942661feb206f6ee093e4cc529d2bcf76c853b85a50c702fceddaa7c33fe11ee88be6ff8d4adc06ac35004d4dc59669ad51b72d4c2957e71996dba4eda95ce2273e6ff4c3fc65e02efac077347778cda017f8ec1f0dd3f1cdb1598580ed73617de52f8776401cd70dd8a6638adeb4286fac3174b7d8549e09f571b5c0de86b95a32ce7ae80dbe69128772c04e3b8729d37e21033655201d04f3fa8921113da1021d1412320d9ef8e529526f03d4df848bc385764168e7b8a684530379e02a27cb831ee1b52dd096039c2f968251ebfd54063107e4ac3b9270721a12ab90f60ab1c9dc81b918cee8dc90667ae203bfd25e3014345ce46e70d379b11038a6597918a706c188cd059a684186e3139577aaff0aaab0a9be7b0613b5a522eee512076ea61a6a077681e22de4afd9d1779ae034d075f309bcdec98eca779d206b717b30bf7053978b08fbe716a8b649d40c6285e3f5fd5f47a61033d45a4ee76ac6ef15a0bd419ead0195998c51c7353e796a73006d470e82ffbb78f0a1cd1f5bd1d64503f0309550c400e6a9a241d57116bc1d1b2c1285ef5985d165fc0441a485f821357a47325b699fd4a79326a4745bdd3b79172b03ec9ba6d8f23f284f65298081c57dacf57442c224333427539d77d43d49b756016669eed8cf42cf6675185626af10d52dd7513a3cb6f1ce9432ca303344cff1f5469d71eee433c8fd2c9576a5dc518ddf724d48a353cb96f105b71341c2b10505d1374c24ee413ce6b5af391fad8163ac42260c6e01c2abb79e439fe8b5ea2f884e005f477e36af466d4bbbe2a613a81e2d0310814abbfbd1f15db7b91d05630bc93a71ecd64c2bafa9d53580b5856b7449e7813686cd1f99f9dec564bf4649b4c8578becb8889909a12071330f741d96085d4cae319fb798f04a7c86f5a3ac9af1ca24e32edfeb5b70a96d305ce6358d98f0a38713ae77b8e029b82e24a16d2aadd8ffce89334e355cab86b0bea7df2e819bcef78546bb7d0f9223c550067341139a47db65715a3d1e5349e316982088ac813026adff314d7735afd37b8f1bb39bb15635c633ffe3f5c403eeba2b8f30f4d37b70ea4e0ee0127162f6a1c79e488cea73e3933603fdf53459c356c6acf4499957e91061f01501c4db23a274bc788c072cb1348e52192c89f31b737a1b0c3a896764cf85a79d73fe5ecbd46cfe7883b620eccc8aeb17a266077b79e7738eac26c07b0cff006a70281e5d4fe44ec00044e87bc5ccc1d045ea5508953af89ea55549880d8cf41a84baf20988c38584d5e8f5d00b070701bdaf65d2d48d4329c75a9e0640573819f4b83709c4c034d99080b986238df1c87d90b973aa61a0e485d18637df8b2d5a66b59428e11c4a35f2807b78dc1a08e9398b0243e46c5ded8fc5a4db8d5059bbc8c9a99159663300c98a20a8728b7361ce3ad69b56e43ff191e7edb92c91167386eea1b82a5918bad22b8b410627c8c2d8a953c611c696eb740d4f9678cd30489a60dd1651599e5929079f7187db174704e86b43a315c66b76ce14ef4e7d41889e6241cfbbbab40e6adc605bb6f23a453332093d65fbc8bd5372137c0ed1a3a214b59f0101d7477138ed795cf5e21172eeee77b2a3e5cc4a026ef9b6796c754c4b3e9ba0bb35c17deaa8f9fef8734411e988e5d48168658f4a43336eaa748ae320c3a5c591d01b157f7abd4d644cfd094f41a2eaef9d08fc6fc2eec5a2f739e448b9ba60475829965ec82066f78224bccb5f6839c287a3825ef491f9c6cab438d5f279543fb2cf98dd1f7a1302e471fd900f69f46b6bc64a3c096edb2c52abfb550946bb0cc531370c29646eb584d7581a9ec24b325185a6feb053585538825b5334fcce202311fa2474030f73c437d320e8eebf6c69eccec89ef84e061f0a158e5f655ccb8eb25a59c5f1bd848ed4953e59fcd1662b8dff2e6ca6a7764dbcff2fe7d044894dc3d6189d69b036e7febd751732eaf6375ffbc2f6fb79a1c93ccce9551d8ff99416c5ab4842ccbc0211e079ff09a68e53006ccc88091ea15dc2b2890201f98bf059d737fe97bc25cb9fec130018d1b83cc59c9e20582abde97fe6752466b6b7f5a014c721db42210d1931a6f79cee037b13814e3238c6cae0e4e2e270e16e5c4404837094941f0d1487d26e1fa079f1aa5ceba18e8475e2da212c05ad2b5c4fea2d2686051292853524b9084b69c5d67c7ff86b6dbeb915686469cbf83f0873902dd67700c54ff759de66c850253d7ae51a8be664ad62c44f6d1367ed47ec5b8cb6d231ed39f1e9d88dcb3f936b8ffd98c191ae5412a6d4070cfbb7da782c2c1dffc17f2613461f0cf5a39f6010866b53cedefbda49735dc7a3da2eb768ef7dfad4520b55cc5e7c5157d6a3d7babf259e97ad33dcf29a58759efea333dad44722d8051defd97d1be64d9da25faa01f92dea392fbae72ee753f07cfbcd7fd78d6d2a6daece00cb1b6bf939a894652206829ca12be6d107944a1a4247853f13dad50b02c6f2aa36b6f13d30646836c5c1d32b2cc4be772f0052c9127b65acb44a7e66157fdd5586990267380c345882838b6cd5cb6537df90f1253a48a9cd59045a1d9505b2088d306ddb62ed7dfe745e45f4aefd6714e48ae849ca756cfe57e65745564572fa6b711f142cd58c647cf560b18575afe64a5d47609ec7e11ce352ab42f19d75437519fd6393b654eb3a30d9af52d58cdf5b837d9ec12182f64fb1dd0591cced86046dbdc4fb4a516c146cb9211a67541f1fabd8f11d120e6cb7c8be03de90d15d877955ad09a025e873b1e28c5ba0a0b81c480b020520ef161014a6594e9ac7103fa2a439119117618aacff42acc15c3b39693582d89a605b5abaf494876fb3d74dade77668fa8a650111d270d52ee5ad642ed05da7f46051863eb4a6dd654ffa07e5b29fd84ee42930e81ab2ed4491ce1717a7043520585308b3ed43f4a085e3625170a9965720c37e674178a8619414cdf46ef4ca9d7ec7db8451fc789f44abdbd300dae83c857a36b0cabfcf988c0075ba5506af23a0c35c216db827c9ac0f089731f7df45822d16e8a28d9b42c9691c87f1dbe4536fdb89ebc19e83d8d950ae6ae5dd8ede9af5da05f5400d3d29c4f879dcade2d56af522ecf26589275894785e274e0a401502bc82e15ba2c1710dfbbaf3d1785ffa515c133ea2038dab57c575be04ae11b2fb18cfae30535694d565e224cc25620e1aecbd619b22f3fd5b780419b079141f31003272cb390333a4ec62f23b01d4aa2c32ebe015c98804f48d012d0c0ee891f5eba5893af6e340a148701370057f3fb5552ef3de151feb44c09daa52d107b14caeb51b50cc5719d61b941a7fe4b33fbfea9064ab0954b17712d177ffca9f0e2685bbb3062972a195f64a1ba0fee4bc43dfc72c094e6fcf9d23382b0dec98f8666d176fb37d51018bb2f049f83d8d312215e7c61241bcf93232cf4caae48e12738e676b6c9dc8c0353642df8f8e28337a6709ca46c2878eba078662a3d84eb1cfd46d9263375aff5cb4ce5f28ab4c1044bd047a39d6c3072c2abb553fd041ca3c2116466d6fa4c385ea114ed5fca1ccbe17b5577e772e523be672986238f6fbe7bd6b2c2deedb67d5aca3ae6cb1d92ba5e7a38734a48632a776ab543fcd168e38330280f6f4c2692156fd812cb302d1cf4006d8a0f3137a81986b7628bf15c233ba135e4b3563e08796f8cba683f9706886a6d652108fe830ebe0cddf6288bbf964715bbbe2770f85ccc9abd89003eb76d7321d3ea1e0b2ee79a8bf31c5852197a543cc1e32a2f53127f1c6b10b1819637ebedeb442547092748130ab53520f7fd657d2543d9264231fdd154335dc1fa52e56a9f9bf077745f1367557ec669961d847cd55015ac1575fbefc3cd1a2758ae7ab38c03d62613591439e0a05ebbd5330910d4f94cf74ca22f60f743088033adc25890b131e6c24e7e84220ea08f0a0f8e8281cb75e5df8331de8bfe1c26e5ca50bc50bb8cc5af2001221520e792b3358966a516b78323927d399d300b6ffe91cb4cdc77fd3c93e1064d90506ab3ba26e3986948ce0cd5c085483af51e1e76f84eba1bb18ce798ef8bd7cd6be9a361d5a977df620eaa00d5870ebd626a36bd6a153f8f4a89b25222d105b4658c11d426c50d36dce847aebbf2be08ad62bb59288e9ff00cad31705e691e44a6a218140d2ad896f1fab613d09abacb2c047e670af95cdcfb28aebf0b48f7bfc508b5771722aa1aa8e71766b10f49c4b671b5056fb0857899f08213a55ad1f74abcd41302cd546d3598b354998667be7268a446c62c59065c25a4ad27a121bbc0e0e522fdb88d3acf663765f59c44c11dac8f6a1077e43dc7331b6b7222831dc61f53c9b63c71fbbb54be94745ecbdaf5433d9f1b5d1cd5582362cdc86ecf0cae9aa76e21bf2d94f14fef03143b4a133100cfda6c88a7c700c6f8610dcf9181e7e2282a4f1c3fc9c723afcca084a1cc67dcf87042fcd5bb60e144eef813f4806d1e92a4bea5a60aa61692d04ebce9761c3f354060f22ce773b3e9bd41dead5dd8a377f1c77a4b71184630fe5d96a7564bfc968d64e2deb532c056196b6b3b9152d0406caae5f63e80f055e63c2f0ee1790cef1fcf8187fdf21c3a26e4c5615ff27127556af55e3b5db748ef494940cf4610f131aad933cf5f555df4dfcb2e402d75d067fcd01f6c41b1a8a1c79aef23281e3d9a962fe58416c857206cb96ae6648ef686b1c30ca4cded1ce84537951d257c0a757e6e74e41dbb360de31e05cfc0a4d72fbb267f85f2e7c3f3d91733cac50610113bd1c30ec3fda65045e4c7e00633af85b1b6d1912fa814665d5f2e75197e8f839379d55e3ae0be04e4db3dccd3bd07619c6beb7138b0fdaa16cd9967fb2c
+
diff --git a/crypto/slhdsa/slhdsa_test.cc b/crypto/slhdsa/slhdsa_test.cc
index 3790d2c..932f055 100644
--- a/crypto/slhdsa/slhdsa_test.cc
+++ b/crypto/slhdsa/slhdsa_test.cc
@@ -121,7 +121,6 @@
nullptr, 0));
}
-
static void NISTKeyGenerationFileTest(FileTest *t) {
std::vector<uint8_t> seed, expected_pub, expected_priv;
ASSERT_TRUE(t->GetBytes(&seed, "seed"));
@@ -183,11 +182,10 @@
NISTSignatureVerificationFileTest);
}
-static void NISTPrehashSignatureGenerationFileTest(FileTest *t) {
- std::vector<uint8_t> priv, msg, sig, context;
- ASSERT_TRUE(t->GetBytes(&priv, "priv"));
- ASSERT_EQ(priv.size(),
- static_cast<size_t>(SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES));
+static void NISTPrehashSignatureVerificationFileTest(FileTest *t) {
+ std::vector<uint8_t> pub, msg, sig, context;
+ ASSERT_TRUE(t->GetBytes(&pub, "pub"));
+ ASSERT_EQ(pub.size(), static_cast<size_t>(SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES));
ASSERT_TRUE(t->GetBytes(&msg, "msg"));
ASSERT_TRUE(t->GetBytes(&sig, "sig"));
ASSERT_EQ(sig.size(), size_t{SLHDSA_SHA2_128S_SIGNATURE_BYTES});
@@ -196,23 +194,30 @@
std::string hash_func;
ASSERT_TRUE(t->GetAttribute(&hash_func, "hash"));
int nid = 0;
- if (hash_func == "SHA-384") {
+ bool nonstandard = false;
+ if (hash_func == "SHA-256") {
+ nid = NID_sha256;
+ } else if (hash_func == "SHA-384") {
nid = NID_sha384;
+ nonstandard = true;
} else {
abort();
}
- uint8_t pub[SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES];
- SLHDSA_SHA2_128S_public_from_private(pub, priv.data());
- EXPECT_TRUE(SLHDSA_SHA2_128S_prehash_warning_nonstandard_verify(
- sig.data(), sig.size(), pub, msg.data(), msg.size(), nid, context.data(),
- context.size()));
+ if (nonstandard) {
+ EXPECT_TRUE(SLHDSA_SHA2_128S_prehash_warning_nonstandard_verify(
+ sig.data(), sig.size(), pub.data(), msg.data(), msg.size(), nid,
+ context.data(), context.size()));
+ } else {
+ EXPECT_TRUE(SLHDSA_SHA2_128S_prehash_verify(
+ sig.data(), sig.size(), pub.data(), msg.data(), msg.size(), nid,
+ context.data(), context.size()));
+ }
}
-
TEST(SLHDSATest, NISTPrehashSignatureVerification) {
FileTestGTest("crypto/slhdsa/slhdsa_prehash.txt",
- NISTPrehashSignatureGenerationFileTest);
+ NISTPrehashSignatureVerificationFileTest);
}
} // namespace
diff --git a/include/openssl/slhdsa.h b/include/openssl/slhdsa.h
index f363393..6d6806d 100644
--- a/include/openssl/slhdsa.h
+++ b/include/openssl/slhdsa.h
@@ -84,6 +84,47 @@
// b) A single private key is used to sign both prehashed and raw messages,
// and there's no other way to prevent ambiguity.
+// SLHDSA_SHA2_128S_prehash_sign slowly generates a SLH-DSA-SHA2-128s signature
+// of the prehashed |hashed_msg| using |private_key| and writes it to
+// |out_signature|. The |context| argument is also signed over and can be used
+// to include implicit contextual information that isn't included in
+// |hashed_msg|. The same value of |context| must be presented to
+// |SLHDSA_SHA2_128S_prehash_verify| in order for the generated signature to be
+// considered valid. |context| and |context_len| may be |NULL| and 0 to use an
+// empty context (this is common).
+//
+// The |hash_nid| argument must specify the hash function that was used to
+// generate |hashed_msg|. This function only accepts hash functions listed in
+// FIPS 205.
+//
+// This function returns 1 on success and 0 if |context_len| is larger than 255,
+// if the hash function is not supported, or if |hashed_msg| is the wrong
+// length.
+OPENSSL_EXPORT int SLHDSA_SHA2_128S_prehash_sign(
+ uint8_t out_signature[SLHDSA_SHA2_128S_SIGNATURE_BYTES],
+ const uint8_t private_key[SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
+ const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
+ const uint8_t *context, size_t context_len);
+
+// SLHDSA_SHA2_128S_prehash_verify verifies that |signature| is a valid
+// SLH-DSA-SHA2-128s signature of the prehashed |hashed_msg| by |public_key|,
+// using the hash algorithm identified by |hash_nid|. The value of |context|
+// must equal the value that was passed to |SLHDSA_SHA2_128S_prehash_sign| when
+// the signature was generated.
+//
+// The |hash_nid| argument must specify the hash function that was used to
+// generate |hashed_msg|. This function only accepts hash functions that are
+// listed in FIPS 205.
+//
+// This function returns 1 if the signature is valid and 0 if the signature is
+// invalid, the hash function is not supported, or if |hashed_msg| is the wrong
+// length.
+OPENSSL_EXPORT int SLHDSA_SHA2_128S_prehash_verify(
+ const uint8_t *signature, size_t signature_len,
+ const uint8_t public_key[SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
+ const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
+ const uint8_t *context, size_t context_len);
+
// SLHDSA_SHA2_128S_prehash_warning_nonstandard_sign slowly generates a
// SLH-DSA-SHA2-128s signature of the prehashed |hashed_msg| using |private_key|
// and writes it to |out_signature|. The |context| argument is also signed over