SLH-DSA: support SHA-384 as the prehash function instead.
Change-Id: I931e660d6ad8e6fae0e17b414a40bb0a0ea7e9c3
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/72967
Reviewed-by: Bob Beck <bbe@google.com>
Auto-Submit: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/slhdsa/slhdsa.c b/crypto/slhdsa/slhdsa.c
index 7082694..efb82cd 100644
--- a/crypto/slhdsa/slhdsa.c
+++ b/crypto/slhdsa/slhdsa.c
@@ -30,10 +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 kSHA512OID[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
- 0x65, 0x03, 0x04, 0x02, 0x03};
+static const uint8_t kSHA384OID[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x65, 0x03, 0x04, 0x02, 0x02};
#define MAX_OID_LENGTH 11
#define MAX_CONTEXT_LENGTH 255
@@ -155,31 +153,22 @@
return 1;
}
-static int slhdsa_get_context_and_oid(uint8_t *out_context_and_oid,
- size_t *out_context_and_oid_len,
- size_t max_out_context_and_oid,
- const uint8_t *context,
- size_t context_len, int hash_nid,
- size_t hashed_msg_len) {
+static int slhdsa_get_nonstandard_context_and_oid(
+ uint8_t *out_context_and_oid, size_t *out_context_and_oid_len,
+ size_t max_out_context_and_oid, const uint8_t *context, size_t context_len,
+ int hash_nid, size_t hashed_msg_len) {
const uint8_t *oid;
size_t oid_len;
size_t expected_hash_len;
switch (hash_nid) {
- // The SLH-DSA spec only lists SHA-256 and SHA-512.
- case NID_sha256: {
- oid = kSHA256OID;
- oid_len = sizeof(kSHA256OID);
- static_assert(sizeof(kSHA256OID) <= MAX_OID_LENGTH, "");
- expected_hash_len = 32;
+ // The SLH-DSA spec only lists SHA-256 and SHA-512. This function 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;
- }
- case NID_sha512: {
- oid = kSHA512OID;
- oid_len = sizeof(kSHA512OID);
- static_assert(sizeof(kSHA512OID) <= MAX_OID_LENGTH, "");
- expected_hash_len = 64;
- break;
- }
// If adding a hash function with a larger `oid_len`, update the size of
// `context_and_oid` in the callers.
default:
@@ -202,7 +191,7 @@
}
-int SLHDSA_SHA2_128S_prehash_sign(
+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],
const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
@@ -217,9 +206,9 @@
uint8_t context_and_oid[MAX_CONTEXT_LENGTH + MAX_OID_LENGTH];
size_t context_and_oid_len;
- if (!slhdsa_get_context_and_oid(context_and_oid, &context_and_oid_len,
- sizeof(context_and_oid), context, context_len,
- hash_nid, hashed_msg_len)) {
+ if (!slhdsa_get_nonstandard_context_and_oid(
+ context_and_oid, &context_and_oid_len, sizeof(context_and_oid),
+ context, context_len, hash_nid, hashed_msg_len)) {
return 0;
}
@@ -251,7 +240,7 @@
msg, msg_len);
}
-int SLHDSA_SHA2_128S_prehash_verify(
+int SLHDSA_SHA2_128S_prehash_warning_nonstandard_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,
@@ -266,9 +255,9 @@
uint8_t context_and_oid[MAX_CONTEXT_LENGTH + MAX_OID_LENGTH];
size_t context_and_oid_len;
- if (!slhdsa_get_context_and_oid(context_and_oid, &context_and_oid_len,
- sizeof(context_and_oid), context, context_len,
- hash_nid, hashed_msg_len)) {
+ if (!slhdsa_get_nonstandard_context_and_oid(
+ context_and_oid, &context_and_oid_len, sizeof(context_and_oid),
+ context, context_len, hash_nid, hashed_msg_len)) {
return 0;
}
diff --git a/crypto/slhdsa/slhdsa_prehash.txt b/crypto/slhdsa/slhdsa_prehash.txt
index dd04963..ef9c83f 100644
--- a/crypto/slhdsa/slhdsa_prehash.txt
+++ b/crypto/slhdsa/slhdsa_prehash.txt
@@ -2,13 +2,7 @@
# end-to-end test vectors.
priv: 14c784af6edaf2e5cc39d91372c41a8e8dbeb9e1dc9b857f1d2e8930e7fc4003747bb3e0f99d24de5623c86573a74351add397ae48d7032edc4279133dc17b47
-hash: SHA-256
-msg: 1f7ddf1b9acf7a5fec3a58749e7c1a96ab70eccf5f5de7b8aa2580189f2a62d5
+hash: SHA-384
+msg: d08dc95a87e824643adbb78c19018cb57cd3eb0bfd15f03925935fe3cd047e5a333408a53dac250ce6bb6c00f73663dc
context: 01020304
-sig: 1dcc9a3a8b41e62cdda98ae5da1511f2073090b3ba7b5604ce1bccec1708dd8eae2875e1d92a981affec022807c7b7a446488fecc7f3a819533981893fbf13b2802c07b1961859ee9ac5679f237ec134681e48a5a08fd9133e65490f3042d7f49c467b6b94c0369b135da7ee8efd264e8c55efdc1ce5c7999320948219fcc659286ca0ca3cba8f5020ef3486e2805aacd7085e3eee66df492eea1f94dcef1d0b92fab14497230bf7f4bed11698b33222af268fefc4290a868c78d9c28bb40be287b867a1813acbb86af2070cd513e3ae074e288c9f6491cc0bb48ce9331c92392b9bd7c7aca50fe4b1719e01849af72f5c8ccb2b75b2f864cfbbacf448e542fcaa1ba1cd25cd27dfac45e0fa78aafeb9e558c9d9829e0b0253e81f1c5f9d00b9df3a5687781513543bfee49aaf5d5f45b426cfe255e9dd7fe37f846d9b12c5b6b25d1c13ffa6d4cfc0f2ab4f9227d82be6be908cbd553652a9bab17a3a010f475b353d951ed250781c7ec72b6d03be0ab2fa9df94dbd86b98763eeb53bdc62ba0b6d4d05deeb5f5c25d54807cee7ad79825dccb120e82b3a71e85709d819a86e81f7cb5744207a009767adee687acd3324802d24b876a1fff5194b3bcdaac98053dbe2d584c976a4f49317640b64aeb129ba596c6e1ababcad287cfeda0fe883ad0432c5d520c8e54698c990df526399e003fe1a8927368e27870c889aedc835fd26867d60b662445ce543f885a72944f4da6d2036affb1e524d14abb3f1ae82eacccc4d9a2295aca77c4d4cb9ecd2d43be353da481c341da13547432756da7cc5e2dff4e7729b348cb9331c0a152b399ef4fd6862d52529adf12d820a84723c637f81c6e15e02bfba3c8e11210d9cd9ae2d3bcddc2f23143d3ec03c54525379c1b789a62f7023b71ab66d735d98320905a5493cd83ef20c81174ac1052cf6c973710453226f15a7f3638ad02c6a580ce7cc3b685929fa1d01d7a7a7b14c95670a018499760be800122851bde267aad1880fa270e01d185570aea329460739bbcff622c5e7b59a46bfc8d56b5010f4b27cbb526c1d96d98ce2866018179b0042df457d01e25d2bbff4b2aee80adfaade964e0b8454b9ed728b3f6da1fde9038c7676591769c16bbbacf35ef6bc92b5fd3d1f66eb4f92d24fe755778849dffc9fab1af62b986a570f22523e12a540f43fa78338efd1f14573cb400a39c39d341ce4d6afa511526fcfd6ce6a36401d5447a9b7152190734f83fc81d6681ed696d675adc88107afc473850cdea6e9e064d6e992c9143c12289d482026b1e8486c0be08f874e335443193880f6eae2a4d0143b16ae848bfc7ac070b9aac3094e68b8c41962c30a4a0dfbefcadd7bf1811d6969521fb115523746adfd76fe0c261c8dcf6daa11ed18f42ad24ec68dd20768a11225e81c2842ed98052fadbe69fce460739f0ea27b1ae9c5c63d6b15780bde9637cf7380e1041130bf1bd6998809056ace9d333782277103a7b3d21daab8f3a323ed933efb962435c8f7aeb15b594697251bf510c0eb40ead8c0391ecbfd6239ce17d7db75035df741e1fefa7aad01295215b6d8e078584a3e5e25ac8e02b6e1c02b4092669ecede4cd65bf1328940e596da87ba19398db5f2326addbf8d4d6fbe75a0d89de1304d7f1c127af328ea10f177cb91c2642cd506343d506b69cd7f4e6e7a1fc6fdd2fc0c8c076d8ecaccddf6d5ff2ca6f49b365f976abc207ce7c48f770322d2536942a7c4811e60f6f62ce241a830f546b9b5f4357630fc404b7eaa770229b01c849c691bc8d6f106621c269f8408808b5b4c6a4d587b14ee413dad082fb3fedbf8f4b4592436476e54a46efc6eaedec57cc1a706d24e0abd3343553889d30044bbb9b80e854e0c1504b6d40cf2ed2a92745149d869bf4ee31d4eda2ec3d2b56791127579ad6b8dc29dcb4f1816859de56116045914cc46addf189a5fd03582d7e3451c50c5922db9b12f8d2fa89a4e62a69de0165c0220f127f24424398ff9c7e956140b88efd9cb3f5f1602a8326f4945364d9efdc7a216bbb16d4c144e8614916fd4b53dfe63d8aa5595bc95cc5d0393455a85b8e4e44957d0bd5f3b3c6b740aa1dd37b9affa4a2d25583a0f73a7789a2ac07974f964cbe91c3d134e1504d6208b797ae5ab5c4aec639cde488a98846562f1646d969f9d23a2b484c30c8ae47536c306eff62f40f6c612fd150f316e0cda92af7af5856f9af9b8dd38505c5023a2babc7cfe231b2cd8ae5c04df6fcf1ce9947c90eed4e99025d8ba3eeaa49bc965d90d0f26cf2bdb2e595dab9b010020a2d7ca8037d434fbea39a699bff8aba9c07e8d81748c87e02514b3cd62c108057243dbf8932beb1134074d338433b021524f7f9a5a081845dfe80b7858828f4915e2beeb09c512e204ece35fdcbfa7d19e115d8af11b50d6aa6e4a27cc2bd6be77a5517c7e8e9be924a2899727409854d0b03f1739be0a23b9f1ab6dd6765a141db699f4f1a23dad5cf558002bc0150f07e0620e9b2c65924845828c644600d29e51f568b5b4ebe40c8779882fefaf99206da9b9ce56c8037173aff964bed06feca7205eeb9e7f93447518a42a25a4fe2651beb6bf8379004924ac99523bcc36523201c3a6dfc902ebcc36847836a8ddf9bd09e71669589b00ce27b91924bf860235ec6537b9c44d7bd9955088d3eafaa7d6201b3c8af59edfdbc0f5151ae34e119523ac1e1d85971204c11fe875f31b599f9c56c72eddc261116163ecf09c10e86140e05e885b95453cf75b9ed277a4ef506cf46cf1076855c95d741f6c36a8503033392cf173d7e3299315090b15338fb00f9ab324ffe0b502463bb1b64b18450727cd8b73dae718dd31115d5c78af8b16e9f57227ff2da90cd2eb7342c5e1257d1078dff5bc7f583c801bde2c90857ce346fd11faf3e5477fdce3c711042b1b6c0a811142b2d38054a8eb5ec4c61b1c9d6dedb79ffb2f3270f97ec1f4a5906809bdbdf3b7ce67b20c2f4de46acbb727bb681a47e0157278795c8bee17068d517302adfce8c4ea6cb23f430e9e1438422e9b65e5293de744a8557cafd4987928caf4f0fb8fbc4790363b7c1a50d667410bed52ce7e3e22ab6cd18943a6059a078748c6cb4c9e2fbf65bf23780f43906ee5a1c430c4945661de877a1bbfab27a65de76362d138aa7f89e8028e3a5da9bc7b713c2da05a23087f653a515e1b978493fb510558cca7204458400f293a2cbb3d60e61e6080782215a5558d0d9e6b77215a5dfe3eb3d24c514d349daf483a6a79f1a7a20c6f2b7444401488f753ec11b46e3e62442250e28b8948aafce9554900cc1a80a30d5c58b8684a96e71d78a8b96b32b2de324acfe0de102ef463f1a36fd844e71c26af6a35427d4c01d78a095b914698173dac428a0963b7b6ec003d3176f8cec41df9799f652cca74108b41b9b95b844d653c3b5003d20977212256a743552856cddd5cc926fa9de9a0a6927418c2f0d740af9ee05fe2e2c8cfb8abcef997b1d5274613750db84d69ec33cd8c3beca13c09b135d66b49bf632cd8dc0273e998984cb7d183b304af7ea34ce51899b6a74bdb138b87ebff63478d849adc417ae7692b781c67017f9a5107cfd46ad865eddace19920152ee7bc9a27ddcc702592389087ae633e03f6e7f89310a6958e7d31f0b2c6ec99017de1daf1860e6c56d6894e2ae214702224c7b92ead2900ed16a7d68e5b84c118fd7bd1daae041ed6c1156905a846565cdf7211149365e1791e3fdd0a23fa0c628eacc5101a7d3312fef0b42b18ff81b443b825f8bcfd6b6078e4c9c27a246e87ffe6433495e81ffa35dee27dc30e1159a240f2ecd5a407d4e723592848f63d03c31b1af606be3ed4f962c71ba506bec49ddc27301bf3259d851499920870fcafe188bd1c0e6a6d8d4e48dd16dc8364bf783dae1b13a25aa6080a9f009231c43ad005451390bd6d61313d07d7c082bb2880df3af283f808fffb157fa6cfc015a9377ffcc5c5fc0abec485dc9c4eb896cfca2d0e925dea2ad2b9bcc243eed45dff11da1c7c7f139aa5f7ad75cb709915c2dbde5c8f86d6021d174221b4a2e8e922cb8e530dab363837439fb3c352061d3c19454d65096722c98cdc811a36b631b51314a6151c6e86644361a123e609a6ff44a3b8b5443d92b26ebd0906dd6191abfee87dc1fe72a37c21a79365b4e556ff009cfe8d502ff47362b46adbb994a475158713b12544b5cf23a6bf33d893030ed31d96e8646dd11cbe6c4c9d5e5b71f359d50ab49d41f0aefbbaeb24e9ae65ce50ab0e08d1bb5b979ce33730eb9033ab386c30c885c82cf75f1cfedc54d6f5f3891edbeb7019ca837542ac7140bcdd4cb2c57e5c934ab047bc2d4aa4d8669d8f1415461d883d6437738ae924fde9b98c92da45ab9fef79f88a72cef264607d5048f5eea48882c49247a1bd659941f394c27bcfb34b75e0164d16c740aa82e89732faf3112f8e5f09743635faba1a90abeea80aeb2ca05a80c9f6cbc44e32367d99548085d729d5d8b6dc1b360d924a9710a797d24683676e4c1f8b3e0ac167f94eb205844b3882e011a23bf1b94c9f84fe8c613401a4cd7cce921eddcd4a16a0e599cddcf2d7cf23ff41beab62d48d8686fc9ad452fc1e799ff705e9b5fafd3daad2e608d21e6eb62339a934eac2c8e07c0a1d51c546964ca7130968837fa2e74d2f1427e02640bba0f6323b522318631482c0696f8a550c9f7fece2bc83acf948b4cf79701bd9a0b127255a6f0419596562d68e7e693f5a2ee8fe8be8656143451605e151b6735e0b08bb8b3889025428d48d9b16859bf3b1a08fe15c1ec0fc3acbdcfcdb99644cf51c922a05c22906e9812f1051e63815c6b104f55b52772ebac8b625e62b3b5a7ee18ed7d8ec4a3c5e52c8d7157963ad03c005470b92b41bce89e1463bc5203e4f7da8c62f7b7c55639da6fb4040ef2c076ce637f75738d0795967c1ede985544c0b2abe87312ca1ff0932810a3e3c296c38d384da06520ff14841c8923abdd66721fad46cd6a7232946c86e43bc9753bdbbd56af4813e810f4217cc525909f80999f35de7acd69596ce6bac791e9fc5f3c7a8ee508048da7f15ebad0e397045de48eb536889edf451aa8e83a6ffbdc8c7f011ec854d26db9b8e620b9d0c566da7c0cb06eed5b4c865b98f8bbeebaf23bdceb5b174acc4abdc169ead445f7f2a12d82289fd3219e3cb56828dfadafa87367e6f1b2460d70c387d717cc3181e5f6716a1f6d013ce42707940236f9fbd882ea8bf3bf192733a725d23cf2af55ff551ca75df3648698fc8ae44b8f8c1f3886c4cc136ecd25b752086eab3606d1fb942c4249cee0e543a937b77f805ed74decf88565ebceddbd1ae958e0e1c4253ae498fece09db76c85a589ebbf934bdf7d35f211eb6eaf07de59544b65d82dc50128ce9a7a6f99eb4a6b077e67589b206e661842084c9d94b7ec358c95ceab90df3b5ec0015dfef40503e7c437c6195f844f407fee41b6c52a1ef01076e6d4bbb9c7507861cbb92d39e327b28cd085c50f2fdc09502806f5e77168b35d46ae0bb3910e1397100d3db2af946a4faf00ca1a4c33e5e3d412ccb3185b5ef0d433bedc616880cca8043bd70d3119e81c7b35d145d78911809c54265e59c13606464dd305512011999b4854a5c39b3dd966f259742bf51cb9a0ed1b33eb86602e9100776aa3cdb2ce9df5ecfc676f1059af970a229fd99347c6b75bd200e623357e43cb90532f81bc6029b9fcfd2ab33e561b2fc17559b52cb672ff07cf1b285d30c958e7fbc00a044fca879e9944e6ec2d4588a84a7a09a46a1bd8d907717d9a97c71fe445c4ff379bd7d9aa2915d3302656e5b42cea64c74f7e6d03bf8b41f8bf1155e7012ebb6779ca17dc9cbe137acc6888b8b699ea09c4bbfb5126f5dbe9e13682e391443d0d346a3b29b749dd7118124bbf669a4c06741d1a6eb36f732cbe60e57fb0472e4950a454a30dd83604badc8a691637f234f380c26af9e02a3f510918def46426c9450b8b9574b695dc2ba0f209ed54ce88d72ccfabc6236cbc0cc33e9a56d533ed1840bb73b4f37d90de3f7e93b2254f81d8b300a6ce82a4eeeb4980c611fb594f3c729eb564c8e16edbd7a67e0620d92773bb556e75d323879df0328fcb41331e67f1cd975ab5433f666bb380306acdcbc01a55b9aa07a10d6baf623fe8cade64712fc4d007a5c915e208dbfd846b8457ba1d80e6e207714ae2394e80d790756974b3a02faabb9eee7245ca362960a42d02c4d0705cd1f1d65463f84b19272f7bd72fac88c39cbea0aeee84335718f34581a3fa81f58a26b4c5e71fda7c838a8a903ec46b4b4940439b9b85acd807c378e3df1dc32abce532eedb8008a031f559cb979fd68c70087818d3ec7ffe03d6d6cd15f9fec92981a868cbccb558b1339121a592b7f54371dbb4bd71bd3751f28e153a7d3d2fc68edd8b8d84b010b51758dc7149e9ebf6baad6979242fde24fd6fb9c3270c56d34f1dad5f51099475ea5d79f6fbc8bf235b4f4e87bfb65e5123d69e20eb69edab8560c35120e44db14d9af9cff14665a3d5aa2c0653781e78601481b6e57f6bfc2ffa622fa1ff1bbb515d5d3af1de7c46160e629b2cff13c2205ecb6562cc6867f88e001fa2d232a4974a5c7d46934722ee60708dfcda748232f0b97db1df6f442d12f32ec4320630e45557c3d7de70ec7eb19dd3b427d7b606c8b3a55ba77cbbd9117bd26d01a08b2f8e16fe3eca2516a8d0c84dc06ce350d36f8467e8c9847c0ee92ae7d205acecb368dc0abdc695d96915bb24e3a837cc76b52536f0b6553b0e3b14671b3ff6511f42ed50b8638dc118deec1c29ad429a6cf73b1004926edceb956d0204ce9ddc598b770f57a77a1317cd1185ede98e37bf4f4ff84bfeacde28130d1025de12b33af8ac167d47ef5b2d394adf9fdac0077fe254cbf52efceb982ce97eb8b7517a0a138685a5f046e28455e1e8a02ea7b2c415529aa0b444260aa206ddeba44effc05a623fefa4528e8d8972ad129d03f066036187329c8d2f10c73a240a739fd6f16d9d87a9718ba0b9c3c10e5dec50fb772dc23d75178f090878ab2fe9a242203118c4ee85a4bae76d03273aa83dfbde2dfb2777796fad975c1dd7d68cbd86874f02e50867d06caf64021d9c454af5c42d8e621048661f9c8306013e464777e2b2127c66041d1b62a2669cf0eec42f93bbb9cec2a33bef11e4023bac47732797415d1414b63a666684fbaf9c0ed6a89bf064b48b3b80e4515454b70ba2f368d43feed6c316b049cff31412439d27a84e6a53dd9a0c7d899f1a71312d8f1d74e7775630d6c3c3cab2b5d92b1f89da40d175b4c089568651ee8a36c0dc99c2daebc9c45143a8e6b06bae50cd4218f55e90b326a4be9a5ef5d1bcc7e7cecddbac5684c89e6a6cafe1a87c2631619f8d9333b9c453238f0610a9dfd9ac7f07e75fe66ee77d61ddc015c842e900a7c0fe23bb359ad701c1afafc4bcc13193f5c5e4364b5d6fac261b5690c54d0341efd6d5966f81393e54a42c637027b214f4171eb216a5662accf996a1190652925f0d490f883670bb4d14903a68e966cfbf4b0a40a1ca156aeb5248361cc00b1708347641b6cfc9ba185473820f43761976edcaf0f946d132255aa22d99110f40333d03e3d3e8830d7414bbedcb3c62ed4577d8b8cdb97a7e0f1d77186a808391a3b4ed56ef21752c5ece11dc115e36128180837e8b0c42bed9ca20fb58580b41f6d4e41e8523d8b8e94b3ef8f15ec9cfc271607320688122e5e8fe4a556aba895b3468e42f77b3a5443e72348d1f953871fb37b94f33b478921879b4a144a4bf40d8c3b7cae969f7fec69ae9d19b514b6bb0ba11a4014c60178a46179337e16d189cebf12a806fd092d0820361924bacf568bac3fc6c5ad55b6958bab457e7d09b9dd65654caac85760badb3b2098c1818b6b5fc7641de971d98e5f9afd83883e883a5950d9f83ee2224cd4a2628e9bff3e391b0fe20ffe35b494318e9fca4419d5ed994ee605bef505bd4d36c942f676e260dbb5f2a2242dfc41f439400c6783c3a4a1f37300849c96ac0c752cc5adb4d1fbb069fe83d2cb60c07c6adec6f5e27c5f1fb5ce8d2179c95d71c7aa39de72ba5c3d136ea905b064e38766508afb1baf2eae98bf26ab5cc77de7b9d41125742787bfb802038c5cadd9ecc5c30ea8e9d4809e97b5240e6d844a9aa7c6cae16d027cdfaf4b42b937276dbc7b4e3659a6bc6070856213878646c0f92916243fb3c841cbe5b2ae195e641143d072b1a6ae87543b6280cf5f54dad8c4ebbdfe772a5e775a07e47554add7354df72f89011da814bdb3a16e656cad8cbd5d0ee9aaf9f6ebb037b531689302041e46fc0844b0dadb0dfc7e9f8943356ecfda726f98adb0489a1097dd64269fe1ec4ac470f9004aa306565243e65143f6fd58d3161f7e9499c5817e86780ea4296b43f29ba42e0ff6eadffac03feda867d0d024b5d025d1601eab343d65ba2b227044839c5fc1b67d75d8e25aba2b2f226ccf0db9f2b4c6c3d5977c0412b208f429bac47a7f55580b446f6087160015197be75a69d23e9849b5f67079b5fc7010642aff6222d4d78668ad0fbf2bdee5bd47626824b2b66f5a4a5c7c86e2db77ef8f60016e39b80762752cc9f222c49d27da74f790f925799fe0504f5f29aa7878e7faac1ebaa9f17523f9593744177dee12c9b2d1a274dd4066a899e18de6bede7d2b1c5a54e121e384ca352c1cbef5d0cc1486004b147df5f9b0736a2dfa9f3fb39ec9b0b01792b94636406e653b8f39b218d3b71e25263f8a9677714b26509d7d28491f88fb6f526f005c83d09b3eff1af13a36e5849a14f9ea58bc11f5c2f3035c40eb1212e0f0ef2d5719e91e66080fec1bf8dece04a003853c6ba7c2fa1bb64e769deee3d2528260c447836392412f8aab5cac91ba39033373177d727171eedb4fec981e2d578f9f22ac5fb5c98c2a3363729bc2311c5557a9a0aefef39c41f5cf8025c11da3819f380ed992194e09a9e17abd0be03b2e1cd4a279fdffb4f35d85da9274ef855f44abfdae551707db06912faa54684a6a1d96895a583735b298223795ca22dcfb73b4c6f1f358828d1a4bb7948b35aa78c7dea8434ff70f887dc6a2755d5d38fd93aeae6edd4b926c211afad126d2806aca79189b691c4d877951efa0529dbbbce56cad1b9c625d4c895eeff607a6ad901ace157a5469faab764b1e2afd0d26ccd0bcc207ef2a0f657ad926898615b8a686cea921b1f5107591677ebd9fd505f62f5a96343dff42af930776026c150fe0b48554944cd91a2349c7eef12819050c2737c1f45bf6f48c67289edfe2c305638902a2048bc380fa3a0de634db4efa21e34580315358eb70ed0f9bdfce4b75113982caeebd6bb9574022fceab9fc61fe0af9c89bd4ab0987c67ee4361a2681672c8f999f6a37059cb9fdffe8cbf60c94288dee7052a01c705d625cf2afbb09a0da299ebbfd1a467719db9a6adc5fbc36d52d9adddcfe82382dab724d756d71f26e544c82f384fd831068a5d3187b7ef5785a4470c36cc1da100e2f58ef3b6a5423dc909b1b1992848458e31e80ba6e9aa5f0b15595390b11c39bd22640cfc7660c2c30f291ac6ec3647316697687b427fc4e9938771f7fad444dab145897f5992ccd3dc8c6a84315fdb763df038c063c4f3f0e016301ce07fdbbb48d23186f5e9dd402c988f7277d8fe8de21b79c17583b6f38dd6f5901ea31e754bbe86b0171b8fd8da91e960ed98b184aae1b9d880244f35cfc10ae12ec9adf9743570e781c36d85bf7f711fed953d05d5131086f060b01e4cb4907a8d2281158d356247ccad2c0c1ba2927ba97fe20624d88be10fc1c01f50519601b03f6eb19cc2d23288e2ff332c8eaae57bd4253c1e65f91254777876e8e696ca307883c6e1933ae5fd93208b4a224b5be242cb479cf460a49af05b0ec910fcfb7a8bea5a32e913d63c5f20f39f8b02af6faeb1619e52fc8b3aa039e7f8f6dbee2ab8ed2dec2f72bc118d02b2e95eb6519ebe9a899c431ff31344192a8898cd420eb435f070c3244e305e3f0a8e5051765ac6889c62bf3591d3e82f8045cceb016a6ddc2ee634573bc6f8fd808985d973375525d5f0b05df30ffe9ec8e499c559e7f8aa9146eba12d83eb4ef3534b0c4ec9ffe889caa48248a501ddac5dd010bcc37f2ff38944147e8775aa548e279b0bb1b2f280b332908b665d14b4bfa868f7456f071827500e4f4df8ff63144d1fe0d7b7d8e507835b66e6d3b84bb1a297f95995f94465dc26c6467a37400edad7e136581d279cdd65dfb2371e7b526e1ebcad54f76c91957b3778ea6bae9948ee2748fa1f705628eb89703e3e18dead83593c445aa4b13130259d23cb1dc12477655ef9592613e413c17ed749b5a81bd26f0e0a493ef3cf1c5ca6b48b663c906e677a94dc3b192bb795285fe0063dbbeac6ab36bf1e4aa68b5ee711e2315aaec772de07829e8ec4649ce676cf64127d81da5e3b428f654305a1914da6e38ee04ac3fd43f47a8a1507823a5aeb01ab199aae0cb17b85a64a24e5e4f4f37ec34438c85807dec8d62fe4e9bb7b9df6d8c5bba13d1e7483563e5196f8647b1e507e20702fbaa195f5be1ed5dcf2a7163615184bf050bdda6012d6e4abd53e1fd4a9bc0be6a82eadf60d5990f9c2b4011702ce7494c07485d66042d39b244fd59de6b0307f8f3931c43b9ca8db794db697849bf953b8b5dc7a0e9743fee899413bf20ec94d7f73aa3b7db31257c6b54e937d57252a351b92b5bdee685f7741b87073b0693f239300436bc4d5c6625cd510528e57231b1da77eb9e798465866a92bee7c17072bbe310418eb7cdbb9fffd50173c2866d3cfddf35b9a9c66b3a1604a5b47c89b42db1ffa379c9998486de9d478816853876d6c2334f0238bce989d7bcce42a571e6c144a403002861a96d2b6aa011f15818ebadddbf77173a30dd36ebfdafa9617beb9ea8de143e735e48a21b5e34591ba79bc26a432c5a0d76b2f5c4f4ea1bb43c7817884f724c410d51c8c329a5400b2503bfe505fba98c3a4938
-
-priv: faca70144c5f364e7ad130d00b7904408719cb11cfdabce2e6d65b1c780f2ea52a230264b27730ab77f892c298823cee80bed6135864f1cbfcc566b6ddcf55f1
-hash: SHA-512
-msg: 5da00c4fb88ef5a6b0c6cbc43993c7360f82670298b994885d06f4c0b7465f4081e82079024cec4bd0e032efdf7eb2ae818a5ea5afc4023e7ce5a935952e8c93
-context: 01020304
-sig: f44e913e175291534d4bed86ee6cce502e687678ae09ea0df9615f5b10e806c831276bbbf2b41b9186d7d135b1714d76aa1e36363b9a26e03842ed337bb5c95a7988fbcfacc0408efee8d309d1dad91b652d6e4f1b0f9f628deabc0ce7be35d6810eac8be64b413950bc65bb765936a351ae57dd8eddda37321229f97f2190624dd5aae968d8e224fff9d5c892b312f7be8e4a40219fb62505e3bcd60aeb0ff840b9533f657d1511b71d678bccca9f8d1332bcff588124e36e937ba6075da0b2af5ddb2d243da771c1fe09ce0afec0c12d55df53a4a820249a7b2020267e1d95d6fccd2e3ceb837609bab6c54d855ee9ad4d9edd6ba0cc590c820e4f990bd320971b65d83615db40f2b8c8491742bc1853047032281d68a7b5b205cf0edfb2ecbcabc63fef38c10f9524d8d341295c5b8d9517b6ede43362952292e7ba01a5d1caec153807cae3cfe4dac1d05e3fe33bd0b4184842310564cddb1da0b277998b096f94bdfa184896261a3eeca6d86cabeb18615d24385bc9f99309c0947d3b698a423f66619efdae6ba3703ec5595b10d7b51b5d7cf99e74e697c15e39d5504d21fa950688fb8d24460de3c620e14f9046fd0b1e44fc4def0448f9e73c93e940f40a879c8ae0ee33b6e077f1c79a70daf928c24be3033de80f42707d8f136901199a61c47537424204dd466bd769d93bdad01cd8f7295b5afe8ef5402bd0feab6d59fcf3d203a920e15cc02ed39df1d0a87e599eb85922753cb8f17a383d760af2a0b6e0bf3d4ae687ab2b244a56f6683d35d688b2cff52573193812e80f8d8caa94257cd85f407f24fe4baa8075f463c5fe5ee53141f58a13851044f3d9c02a01957ecf12feefe70dfa77aa332bfa72a3693028688d126d74f6aa52d1af9cf794b5e4ba54383b7903f0c6e6620423dd52063e3059d2d590193d58f35237dbd7481776946b7bdaf6ca970ae4d05cea625eb583dad41fe822957660622a7690fe311fa74a39dcf4ecec2f6e7d570e026f2063e2997b55510b8f51769628bf8885a53948e2e3e4c1c554fabbca272fbe90171824986016d9ccf46d0a152b728a75c6404d8c0f8ac1881312f93f3bf12e1a354627afb5399a83079b790ed7fe758ef4c9544f48fd27f4acacd4c1777e8e7105daee6b26fb21d6ef792726db179bd8ec45d757bbce49e9da87e328af85a1563290fcb5640853bf17f4c7f63b05f8e6d00e453a257d6a9691602bedf9dab77a3bd44c460b38a175fb627990e65ccd212e9bc0d70e355a280a897e2df64eec10041fe7c58e29c90304fca1b7e7485ace79376009afa13645c997a71137c0f5d1f394880ebc13517b89652936af7baaa9ec7546b1e8733aaa54e5dbcfafc8378b61e80d0afae2ad68b16085972fcfa3e63c159c8abe47807ced60224fb12ae97f01bf3faa0f6602f5aca2bc5b7896c631f04ba2d1a6c17cb5eaaa06c2882e86e9567f6722016e5fb1bbee6e5e4484c8fcb45c613486919ae5cecde31a21a7ade8f3bfacaed572480d27e4588e61798aac51ad04b4f0467eb2d1e46433c98b32e0daa1b377f3743b924f39f427a06e63a6b531074a855fdd0038422faa59c6cbd8ee3601deea6385d536143e8b95dd8be3b31ddd0aa2f8898fb3fda4db9f806b755d3a97969283678063b99af30c3cacd37f25264dd85843fca174b1c6c503a3f05db575a5b4776831861af8283338495090f79f79b4f61c127fc07cc1234e7fda25175ca2be0c27d01d17fc116cfa17b6f3cad42d218d1084c78705d3abbe2e20b2ba05ae0ab18bcfc545d64d89145d59d92415ca05035bdc425b02f6c07bcf59c2c5eb9a2e215b14ca9a785f02178b40feecb57f012c081f715eb8178acab3dac4e75430579ca3036aa72438d34f8efae46a71ac0a261ba83bca95a411be3cb7055bf359278db347ac64f4567d80a588e1a94cec11ff70982535793026ee0e59b414feade101ba9d4421350fc4b2ec79121565617ef377500a620bb78ec823aecde5111c4a41e6a7287f9a7a5d9c1b343ec483a1954401e7a91a4a9d67014cfa2fcd5a4acae72a98491b0b930989e22585fc97101f31b046c5b588d1bb67d65c79bc9faace53026d98fe9fde07c2974c7ab6785f31293732083c267083492b323d6b1d5b396f919cb63595799ff3aa646634a08a76df47264955bc686784b37d9a757e9918d68d54b3551c4bd5635733e76802c63640bdc5dbc6059f16df03cab630995ca04d6be15e2747d420393e8c6fbf50f8661cd14d16a2e46889ad3ac943017f2b6cf689283dfde8b8d1a4d085bf719255b6ccaf0d93534f6424e8406cd281867ba372765c094acd90408001c49cd031c4c1c90a1a5541e53506dd1b555b3b3b5328ca8942945be9de80fb90ee81ed34f7a2e2a1c8bed4bd0ecf13f4aceb459c51bb96532bf72e3efdf1272ba10c9a3196dabe9fc97d5ed2444a738d570fdf9052227972ce560be429f1d95d31072d3d50092f318edc1961b39d0757a3d72e1b99b44d581a89bbd969599922e9856d74707374a58af618e017985c6d068390f37f5634cf80325480cb2391e642be1f8cb9e8c8d9022d071e1933505fa1d328de771850b9322231d0e86a10c1610d3a2bf528acaaa36847395c947cc1bbc34ed0b36494e81f12ed5a8f6b3af256791de6f94206c2700c5eaaabae14a17c3f1064b1c957334351193cebf91596fa872a1c72e8d28d1fa95b9ec433723248c5da4334e63e9b5ca5267a945575f123a63a7714c353ba9565bf1bfbdbcf4bc78f4bacf02dc6ec792270b90f9fa88bd153acd9f7f65a82d37b02dbe9c0c43f3a512d3d046ffe517f0f3c614b0b07704247c445d9009d3a13073da8085ea3e65de3180581246e0d08ab4fd7b026a13a210d428b7469a8be390232f5cb676fffe9274181c899b38b2e8eb93d59d151784c43370ee07787db464b833511074468b5bbc4577e1850d85357b596d56044ba4e1bfd53c82279964aa6fa941b17db3b4e2aa993892deb6a4cca305c32b39ce8d38d83f5d861e7bf6b5016a6debe41f472711a27b8305beaccb2e61b038e8a9553598807670fa212dce84a06ffcb9be8139d616e04dc51fbe99de8a11f1f69525234e4c679340288c6bfe9b4f5ddd15ec565941d6ed77c40e16e59b056760e317f2900e50224f70074f91ba1bdb549f640ef7b8db92a497fbf0d17d5665929a0e8af7d9f5628182c3fafeca136b1025796c1c49364f7033f910e7f64be0f810754e21d9a12711d19036d0a535591d10859fb23a1d2c4616134023f29c409a5b5bdd0d64472bb123797eb78b56436de5ed51da3084cb27dc2320d636d4fdaa415df1b1f2510426744febb4053a0bbd292bf6dad0ea2f53b122898de59aa6d91a29ead86c9ed4a932e00a53d6ca98f9968973081be105c010806999714425c74c1cd60e420493914aed939bee8a53a951f4af3dc9cb08c09998f19e0c4be828ec45c7094ab17ad5b04839222677fe5fad019fe7b8976013a1be05be945becac55f83a8011fcd954fb31ebe59f0f8e9b6703640acdbac92bbaeeb1dd49d1a87ea4cdb73bda33f5831a0cb1d703d1780eb8d58a83b5987d594a609d7a2ebf76098fff480361ca0250cb8f80b8716a5f74d7eba912d176ee792986bcb785990d039dffa2d2187b34f6cd92e4e253aa7dccb9926cd3e74370f99f74a3ace19631f538a23d5014b213f5d8534d08187ed8de335d0b12d87bb440638bd9e98a5a774b3efe162323fc3e902549121c2b1fc75804f4a0f674c5b0b2fa5042ef1da93072fa4b3be2463986351bf4cf6e28373ae71a2fb1ba6529cf9a8e295945d5cff4308e9776bdb3ca8a03b828872a12f475942bed1081b2e9594e1c0cf38f3a6079478792d530887137848ece8a655193e6c55ecaee074498bec6ebfc84ae53ed7d70403b718b1144168befd99446ee3c9d1183a8bd30515f23c09fa0f368b73a71a74c9d7a559f304761cefb3edafd15a3e94c428b967a0d199ef9184177c33dde55d3326afbe2be9ea25c72bc5f62ff2c97cb7140d6ab47415b108b4e24ce1839d640364a0237738953515475978829a56aadc913d83ace9873b3c07828531915fb5b5bdeedb27bdcba3009c45681d8e74c2f6ab4a23cd2f2738ffcb54cebe4c4d781bb85c310dbb40e0fc06382023b8449382f5e3c58df5bd8e9d936940462726314f058ce766643ed3c96e083c20dec8b844f7f5a32a1987b0b31dd91d0d5daa4db9d0bd263eede67b1698f47138f6b6326ec48e2ad0b1d4893bfdae2d46c5645301ca3bc541c1d6ca92f462b2828b5a40204afeb34c997c6a99a6d8a5d2db3a72cbfa43b80be812dadf9eec9adbdddd26d9d087a59a7539dda313355184f06283dbd854eaf403a206674e6c999fa76965e724e251e2d1591276bcd0f614e91093efaeb8065d91bda89a9650c0f2ec0b8c2a3e2b883ed26a49d63412a66729d28ecbb7adef79bbb6754022f29e70bad3652e002e1186b53d056a1641bf82bd9cdc46c9e308fc88a502de46def8a07b7796433c8b4f9e185a3f9a535450383628aefc00b9e96c8b1b0861590fa6a90a3f949420f5a7d0955c827260844f0335c60389f7c87319c63031e3fc2a20b0ebae3de6a185a75f0d183245451f88cb835b5d7ef4662a321bb21860870ef95070e9a6b464fdd97ff378a47fa458235e6224b3dba77453e33b7eda2691d6eec44dcce2f444b092c0317ab8f7758d80d2f00ef8b079f9faef8fa45b433da617507fcd086378cb53e3cc1efc857e3381d039421e04a974e4adeb947791edaf7eb9b2f8cec84ae72c75172d8c8749019add828043ab3d94874ddc0149fe99caebd5fbdb7638d14cc542cf981e74afe1f7090c4d41c13e8fcd6e4c29b3bce58a1764f7e7c440ae4d0f308ce1652568c84475fad4141059b411db8e102ccda511f6fbbc20d3b22797adddfdfe57f45d9b6cb8cd883a386a7e0cad7987a5778be753fd5b65f036e97bfce9dc3fee2c75fb96a9f3fdc7b849d4b4c9903bc627ead11b9207d27e9088512de844817eb9a5cfdb44e945fba66c717f8539b714b48ee546ae494f5b78069f72fcb680b303d4bb40d1d5ce57276f492a3876e65be9987206beba36df5c22e57dd53aeb356c9c75ca3f377149c99a9bb3a38db1d7bb53cb33a0d3db5182239b07c2eb70ef4ba46b4a0461d420438e2f73d75fef5156bc03f96d5badab98912788e171c8084631a7510ddf52e662e13f17b43f4aabef59eef3f22c432082c8478867a1a370fe34d72c83311818b93df70765cf82114d988319a3f1146b220da6c230424c77dc56d58fa29b1d9d994ba69dd7604cbb616744137952188eb450cf4698e051dbfac24b24deca105da9cc77325acb41fe9fcc5225ca713d94bf1c6128e53575a34048e53eeb6f0a0a405e4021da8112e0393f4929734f6c90bb2708e2bf404c03d1bce2ec15a1337af92fdc0f90e2edbc324b02a5a03d0383dd15dc487302da0bb19326998d1f4afc8bdbadbff9ed7045a7da3e7fe6f07aa24244f333fb1888c19708e6cf222663b1c741bdce171ccc5a0bb076c729835f1f0819fd352b33678341245dae69f351e5e6cd6a633e2d6487334ecc19d0661e5b3f19125eb52f4d70f067f1748ce1720bea244935b02ffb2ce275e4a7fe19cec145d70f8d101cee9baa5eb3ca22dd999770596b8cbad2e68dd8de8b4ea7b50c3a7f5aeeb7a26d6b7f034c81643aafe69ea7990f4ea2b718c9825d399e85a757717696df1ffcda66c11c462663d1a3a1169a852c5657d79aafcecb3e40fa6c95c57a3fb50268874a71030b52b85c88b7fe28d17f1b6420bbfe21bcf94cbd67b2952bea2527a724ce2da5287cf5c3a9c9b55d59df9715b95598d98d79eefc218bf3d14eee0c19497450517066a063bc2cb0fb24794d1684ec173f8e4f150a98066a38fa5fcb0d3be1776812b6b7223a26f278fe9a427075a7aa665862c39a5985bf4be41f4c51f40d15f15fe9725ea53b210dc94be4dea44eafeab4d1436a3343a7b982637dc5cac74d657f6ee919fb2fd0581d8d2e93bbb4b079204e7c60ef93b9f0b9acc5e68f82019ecac38f9b5406a203f889aae180bf0e0526eed40a6e5c2e9d34b0e35813ed1a301d099f8efbc994cae6f9ab6a88cb5fbb790263f15ac7e98fc72db80de9c136143f5e2aee5a4c32b8d158d37dc0b914140df5583560702f6e116fd1aff19f73bb52e1e3cefcf427b5fcafd57b7c512ceb62f1b569271cf12a11cd9ca42fd1e6e962ff0a845756610ccba3390e0b9d8ea33c75b99863f1c44795f14367450454e24f0144e7e1a98b5151b9dccd7484458c7ee9f9ee267c21e9822ca58b37ac0ab30e5c7201af2d933692f30b4f615829f46adeb36c12d4bdaf8e4ab84c25ff5f10285704bd9afdebd30dfaca36b435baf0361a5eecd4dc22838eed44fa3df4f97f16add5e83e759a54ec2029dd709eda39033161df32bca4d9bc728147f9bb00cf6a91219faee7de9be4a5dac4632b893e2161b6fc893aeae076ed95ad27f7d7f6a3298bd7eb72110a2bb8eb4c90fd3dba0d3b02667c423b59e9ea87d5e8965cfa60f51413fa45fba49de3436bb79c0a02b3826426877994665776ab3c76c2512240c62ff2c8f8d18e9ad866422ff22bc3534185a612b93c08f5fb35b48618a9213b4871ebb67cd2f7fa90339e61a076f2a35c02d580dbfc8b6f3ba27ad8e9a670bfe3df3ba0292c1182b200472d42d6e55a01826574b6241174cd36978f8811e81b51b7c57c564f7b7afb0fb2daa08cd87798ebd15454cd74cb21482a28022504aadcab5756771cb0885d894b4093d49b1572bbf1f81a84a736913701e580e82b7d2dab700f4e5420433c580bec82761bb45b34ab8f797ca99e36c088bae1a8a18fb38e65152f8284578054c4946aa2604105bf5d2ca92fb98cc63ba52930b79ba3a96c21ca76a242a61dfc1429d5dc0b9ab727f9cf5a0cf76afd7455c62a9731927fabbcab645c4ea57c972eb47d6d41a0d87cd50862b652f8ddb09d1dafe8c2701dfb0b2dc133c5c3308987c0b193a9bf78435effff2fa31a35f5bb0298dc8feecb91084fe83fe184d7173bc6b4148ddf058bae5ca86b0dd4a09e66904f4810644a5d457bd28132e2d87d074ba46597da715f4aa7b01aa6b302e9b8cc796eb56fb5b25d39d19dd12437543a24d489a97ef8d0d4125e1b909104e7e75a1994212625fdd7c3b185ca40a40be4fd15024df0411d293c31aa3650fb48ba77e5810d89dea5ef71b554372e389f72e886eadadd62c48778f5fbdf1259f0dffc31b3140d95431b691c06c81f24673224a1c3d7c8c5df54e229ddd1f85b2b574fe0a7e92825c3636ea3728889c34b941aa78543b384897674d5289158be74b62f47ba307def60843d5c9330d366b345a484da12a014e0d6f876a01f373874aca593f40efaf8a8e4e8d1388375c2ce9708cc787582b866d0b121d3de5153cff0a635920c41e5038ba56f6d3478a40805ec8dcb384a78f2047214d85a16a1e9a29837bbc753f88fa6b40308590a537da7f417ff14bea11ec355b99933597da42686454c4513d2e42114320c12d76bce709d6136b90902fe8d26587f1fa9c810b4593d1290a70f1e140252c726e462b4b730b458a104422a4d6b726c930c5d6e50c49a0bbb0a0ddb2c4dbfbaa728ec11acaf5423051933b1c1022e2859858ce6d1e9f3441254c84781c00c53b23562269caf4d12ba4a7be6dce61f99fdb73810b7d20da133d077e1f02a4bb1655a0f78df6a32d8f602efcbe3f1ed0c0f2b1fcd4373fbe1299aeb6db6dfc1bdd66fb357b69c4418ef116473eede7c2384552ea536dcabf7df48972c126cfb8c5fa248f783550edffff0f4df7396ba647e90b550a4e10a05e5984fb503bc05f1ce0ce16342e8f3490fa7fef807423c5fbfba8cfdb92fb683be5acb5c36bf830195b74c158c126a9adb40b320a364f5ebc4c76c1249efed43433d7f75d3a16e46723d1bf6ded5bafd760b41d0d052486de7b0a8a1d939264ea5ef4439f600ede15dfbfa565c721b53aa3b6689dd161290ef25c96d43eefbbfd665b6f0ae9a6c9816287ecaef6f01f643d9ea0f402c1cebd4c468ebf2c868bffc70d70008a6cece23d97da4fd6e6f1600d496cbb84ce4a046a01fcc685edc6812a9b0459a6d42756ec27fa830c407412b3dac948111e36dc4b471c4a33a8a074319af131eee805b71171e13e278fb55042ae7f789743b125f187b574e5e694f0566724bd7fd901f0f1b4d55e23f9601649ba6e9c138256f83534d0af8fbf544634e2eeb9a63284fc095b103d60b5193c448ac9740d181b26c3dcc09d82f58a2577fe03a45043a9005c96a5210aa77e2eb9eb9599bdba0a3c330816691e89aa5be20096631be26a8df17372fe19fe29c2dd7e3ab50d20f277d2d30e52ee4901eac12aa2929238fe5707b7761e9541ce7d26cc86ae9c0e9e914d12772369e9d6aaf505643aaca9068370cc2dfaa97e5784d0deb1060071dfab86ce43672743d4d5c94691f4fe3dc10a182f32726f1390ccac739a7345fad39e9a3003382f9d660b542e15cb85f3561ec5bc323df3f0c4cd8e0a00a616ce7985b3b7ba3834b99d75ed86f0f9bedc4f605b6a74d1b12ca7f40715048420c3134766022b47b4b8bbf776ef513c1727187820c8ef953b4d1f12c3d124598d51c8c6c63a272ae7cc126ff50a77e12e49af716d6838e8b58995bd867b0fc87c971eb056142eb797ab250bc3b64ca2a83015b94136c29ce235e589c258cb303d1f6be1f798b9db0208fe29fe8b8cbb6a947e49ae4fdd87cf25e41c2a048f2cf1d80dd7b9eca7ff3e0727ad3711840e6c3adf347d5c575ffb5eb7e3e75a530898176d16c13dd18b7c5d5d51cf5e881a16b262dd9f54ffef8083e9a07981540869625be124d62eab53677315c610c0914beffdc0d1075dd6a26feb45df83482503f688df8b7ac9fc0d140194ddfee04878febd1e2c0031e807669c138c411a590f07613cdc3cb9342687b7f914e5a638f4969add398a2745ad995df3ff260c304bbf42d6a97f889796a8dcec9e4f6f02ef9e9a34ca650b69181cc45fa977af798924b7d0775c1539aae9009928443915c1f918b9024f27dfd988fa95cbd328dc91709a9696a1d87f1715cd39c186061fd88b4c4b813f5f48d912ca614481bebf59852341d5800b970c08d72f13b8ae022905be040288e249bf093703f9d67bb672bec5de5f5250a068be8d55c33699a091b74e6092a76ba2faa28ae2f334306734f46e7cec5707e024fab2b38b145e765740f8bf67bdd40b08c6daed74191d0fea209bdc76ef29d6684bc9867e61cd6b8dc9d02526eaa04efb396c7ba16d7a58fd5b9d73ec0e1f8f126212eb40af4622dda5dec9a410cf2c66749b13b486406ae42eb5c70a67e0b9aeb49a4d8f02f166386dab52181dfcb12b46d78a6c6750805f3998f9063ecf9b52a7d809d9fe0f49e4d31375374e250b4133cbff1b254e995df58b1ab395c8f2265160c8e3f24a18322792a0226d726eea890ba532cda1db86966f887a992286b94a2e328df03909a79f504dd72fb4ebbee10537bafa0dda1ff3cdd8b51cbb40b8de55d9845c575962034d318e1a9c806036bb75231097355a18e0625a5d4db7e5cbf4ac03c56f8aeee89cc4a088ab90a0c6c9654bf863e63faaa697074131025b9a43a8e4737d00d779e5be0c02263078609a8905548bf3937e77e4e9eee7c92318c6ef989f66e951203d1bd99b2f7df79e1f3772bfeb95c1380c2aaf7446589ecde5c829f371cc4bc5bf50d190ef45f6247dbc5662aa69785d2e9888fefc20c3ac5cc99edc153559055100906c8e97721b0fb3d273a4a7f06215e5ad9bca4619729d16dae6e8ad0a7af9f67bb4cd1591bc16409f675e5148aadface02adbcde26cfe493f6eec0d2d01c0bdfe962e5f1e442a00651d562f06a233f4cb986d780b5b954c4e0c7cec18a6d0a7a2bdddf6f3ab8ec6f0193385cc931dd934bde471215e5a24a6ba5b47f7af90596be5cd88676819e3180b673801a282f9e66a636ce71948534c6504e6a0e124c170c8a7b8ba283d1e1dfe8d50c08d28a8d9b0f6ec427a438d012079b5b728e3ca57e1837cac77f0a160badc6b070e276ed9e0cfc3dd8244edbb7a93275c7a142085f0f0176a997b9dc97bacf54a68a159311202475e2574cd80922450e2e24d4b8ec136b342466119bb2ed888819aa46bc55a9de175e8ea59493cb187e33d6cda451142730a9fbb30411a5ee8ef149f128faeccc8017dccbf223926ce60adce5d960e12c4221005a0a13dd8c6aa2942d16f05458e784b4694d91ae0e94a15f751d2b4dd8288ddb6aabbbc24d1fb4099b577a165046165897f217799d7a5034daf2225211a4254465e1b99c08619953dcfde0c27e265f9622f83950a4a40029790bd69a1169e0c11289609e2447ce6eb7b8475dd06f3f22b981f9a00ceb09439154da1d5771734383b2c4cf104c6f4ba5c9a5216dddf2cf9cad27620c5c703b14ad201ca8d6d2318662e4e78d67f7db74a31803e7902c077c77b42c6880de690bca1d81ba796819408d314f5a4335dcd23850df3d2172325a9169861177858ef23811ac0a212fe7a9b7fa36764cb5f24a593719d69ca1a0111a805144ccc87cb72799be0a3a1dadff4ba106f99122298e2ffe5d11de9fd434999580375a5fe4458de845809c8770539dbbcb2fcd945bdc20f43c20dc54433b953f8a8685e3737525f112aff82da794a125a4e21b9b0d1904e5e69d43fe4485c065ecadfe6f26b1bf48807d5a7f2cf69024bc49471626158ceb2f7c51bb841bb0aa65d456fa1f0f2ca13ef58fde075f8f53ab5a458a7c24a06b4485e44fe1b25dec9a952bace9c8388a59ea82ffa609e3381591b2a626b2665d7718b05943024d8657ecdc6d551d9fa5848b970749c2c0a868223df3f010e660df2d1957abd433530c300ee0e299912bebf5cc417b86230bddf9d0dfae3b7389935213ebeceb9cd3a19f106252df9fd53470b4715c69d5dc196fb7a39c194bc233b9da9593da8bb4ce72f34332dbbcc0d0eb29ea22b0915ed7bd39070d0680c3
+sig: b2583d27146f0a8c7b5cfb6929dc3a02613497d4a07af7b0d560738833f138292326883723ac8c05b4279f14415d11962a797e35e472bbf9f29508db7643797712b65fa1ee31031cf1c2ee816a0bfdab6646b707d42af30c4b0ae925c9146feae83a3e0a68da3725dc659be1f6ad0b8e14d42ca695223a0448cd91bb065ea5a2ceafd7a5089e7c3e8f67407e870f79cb47c2099c73a8e1e114b5e72466786b8e226b4a704379e5f97e6214f4fd5d7cd338f9eabe7e0eec3208233bdd5a797c854a996ac0d82b22e7772fadd0f227a233a29a2178cf91e406e4d4a1f603d15e00d280c522db63955babb68961f42538c41341e452860b465d5c96454fe4d1279c0ea0fe192288e45e452249f18196a127ac787ecd4142f6fa2a3cf21a72b1b05ee125ca08d06e18465e1d1f3dd6575f8bf5989b0bfbc7bdb736c2be5aca1143ba9cf9daa721c819de91d5817057ad5f1a8b9ce2ad65ac8b19ac70966c8ba906f8a1718f70f48115fcfd6aa9ec6a9f142f3490fb2b11ba7a0e4eee899ebcbff5c7aba13a4031e147da50a2a5bca0156d717f8e9e43847621b2407e3b25393262898c0c00e7a52dbed3a9432f28e7794a3d6d7531ef51b3298e4ff6fd49757ba9c7a2a0f586a0dfe97595c872ef9e6d4aef9b616f733c03e352c3e06115979a40da4124927d5be1be5ff8031babcfc2efe9cdce48d7b047566b51aaa57285f6e089de437d9112178910d093d326589995f91de41d11eb1d68fa6bcf0fe58ed445a4aa18d97aa0bc540e53252f5468dabfa7d0d04fdd76849f5ae6e885dbc2cd7d73d42315ba714f434bff7389290ad93da0b26cddce4a3c7823bd1d1b897e054f3404231804d80d0b0fd00718e552ce340868c7622f4fb35e80380191f36f1a51dcb5fe96026caf3f616e58ee8392ef870162d3f94984b7b4c99744609841152eb5eb2b7a6c43c3c7514c2ef5515f51733bf79dd86964ba3fd8e16a74247cfae86b3fcd3f3f84c694305ea1bc906ebc43a367aedbdc9b1d88820af58873bbeddd89bb6cd88e5fa60b8616be9a8b536424cd5591e922df728d440cc3fd2c4843de6491b4dd2f22b3323690fc6cf2ae6257d5f7dc9a5e233cc1f62baceb633c109f13550574ad3bc06aace02d99a6edd05a2370ae7aa445b644fc3eb71ba039248120379c33e941b9292040a4a5be3d0ec2d374ad0172b18d0102ec2d677136d8d705491ccad09c00eef89ed9e3fa82226cb69fcc34e873117b1812e14877a92f9fa231be59cb7a2e81bce6aebcfb48affa5f0eb629e512e8c05d4b24c4639323f65e87afa9f57240d0c578e246506ad1907c7698991eba8e403f0d2d7f8e34deff817c07c575a6abc33b1c1b21d72c0431dc31e3950c62e8ce39436a00d94fa44ffa28bc817175199d346d8ea0bb9324bf92ae2a763f0415762fe9cf9e9f010456bfbc142b5f81e5e85c7ec1351c9d603df2a3af542f477fad5d8c8d38675cb4b4eb590fa8bffa745f2555ef22b0492966f2d150ca30766b2b7da6fc2d4d0085d76d60438c118c1586e70d07ecb49e2b049c9aafb8d42e949cb2ea814f07d47d3df8e6d3283b6abb85170600762e71ab5f95af2eb3a47e96dbeda84d896d9f885e7bc6bfde6a1040440c3872e2f870f5e6b82268479792a8942610015cc6ed70f7984e85af786ed1c9e444e601e0e80d80a30b2e798e47b50f8d9fb1eef58d4e5f5c2b17d01a1c24e3c301bb1cf36d02b48a9a0cafd3d5a60f8e05ccc6a0bfa7bb6ac952b0d119081b604664655ad6eb392c09d6461fc27d110f38299152457fa6e328572e326aa0656d4287974cd0b8b4c9d50f379d6d4a8a7bd6d5904d46a76cfb5601398fe1a4afdfcab4e2c24ca2467a054a303c91281ec0389bda21b48570c27c9b59a661a0cadca77887b6528fec0b0d95e25e2b5f44a282ec28e70440e554c93320ada8f688cdfb8940d1d5bdaae3774f19ad88c1e30980319932abb0842677efc9fece6e7e3f56fd6fb90a2ec034935ac88b1b2c708ad3be38cbe69352ff575660b6d44cf5e069f670b90d322fbb6f157ad2e1eb28a95343e60c21379a2070a602777213f51669c30c4b670cf698eee5151c77f31cbde9d12b222a7700756cb582d16c87931b9a076d1b7beea6a5001901d5871885ee730e88dbc2ef50bbf60971499e23feb04595e55281031aa402c3f15949ba7e2fe9465269a22b5c302d4067157c50aa87404591baeb32fd77bfe451e869e3d252c7aaa1bba260d7ea4e7ddd828192c87b6bfa8d63e8236a5efd57554808ed43ee1fa5010e1bfc99ae2eb147d5ca05ede64114e49407afe47487ef83004df9c09a2a6b3092ae47167291408e9a46c286465b08fc260297d326081f67d95dc4162248942776666a1c30eeeff108fabf0b645175130eed1e5846b2de60df1ce47c6327c9a6de50e6cc1ae0e90ac4fc1d04bafa2c2faba563eb50d31447a13f95ab4283bc32d95da3d29c3191d894f71193d04c3ccd3e50f74d9626f2f597ff7e4f98ef90d8ca93c6332c8b63a358972b54a411a416101a514020bed203d0187317cd585bd704703ea6cc52b606a0ad847cfcd1e6739f8631c5907be1fd45207d4e944621698fcfcf4f38cd21e24ed549788c4c1a8e12ab2160864f1999d34dc8655d4461b215c6f58f2bc48b740f46d7888fe0a20b41f48ef9542ff760b15233ac2d6c85a3f722164b9ace7196ed4417a404634e49a1a36690b8ba9763a923298e31464826cefd568e4fc3d37cae9314d59d02a41e1f147defe0363ec1b23ecb7b25bd358172a3b8aa38c425dca04e0f1035a51ad0eb39b37e321cfaa82f4bc21847ae09bbed31dcef4a7dcb305554da47fab675ce437e266c6b1c3a35c344721b20fe94f0deb481a53dad7804e0af19c3df83b273f069053311ac6cc4ce5024e0191ba0b829c43ca0fb596d0553f46737eb88c0438a147fa7242a003b925c31118ca8e10fe962a3c2520c59d22ae7c100fca7c3bb4c4058457da3e1d522a923f156801b764dd843e6f7474243055618dfc03910871b75f8e35e3e8b51de8a1a9472fb648e9c1927257d8a2e5572860649891e4d9e5e9213a58216bb4b21bee9a474bbeb3fe8a43c616b92bacb341606880c3741bca671131125c345012a6bdc18315ca0477a27c6121bf1f6a19df856524935b6a65fbd06dd588314a6a58d6de4c7569e4675b41938cef8c69b06a3026072c2b499738163d3701c02a5c9f897a80ce40d3f1dc7c99ed6a9535897ecb13a46a1116ce5bdb15bdae136ea49140115d00992910e5559d11ced8b685689a1535a9295974dd4ca708ec8ad222d306a7a214f60665a5647ccceda25ecb9dba89b27401904c32d2a0e72413e04dab9138841b40b5d29c32e1e01964af3274d5e077a22210ae98bd7bec133570ca568e0a64ed89694c0a80573fc13d48a4e997226115e68aa4385b0e02c947e77192649c4dfdfee053e4c7c0cc4b3fcdfd668189b39ac289ad46042ad9c87ec5e99f27b2149613e5d5e107d6e865da0788dd8362a219c465990bbb0f62c3d5b0b995c9124a027586d6898393696cba012da29a90fe3364f79ec2e3f6102717dd536840e0c9e58d2cb9d14d01662d875a517882887fc01dfd8884986166e90b604342b7e5d9750a1ddd3809a575b42089ee19000189ce1f1c98c5b149e4baf30e684e95b9d74a117ae4de9df6ca86976eefcbb81c8eabd206c2aa3fc863b25ccd813aeb2b18cf5e7366eea00d090dc28bf81ce8a8dfe2a7d5b892d35b3c6978d4a1a74c4c2d0a1fb8066eb422c2a9ea650f2379f71e9d4e6317688847a0f176cd2cd5f195514b39351b4724cc6e1a91479efc9585df888da88d964eb1f7f60ff32d87ba01c5c475357852108f37d1c726b22c1242df327cfdb3c18a0e8f451b72487618e0bdb74e55aa922e706fa173ee8dda83bf6ce0735e560c81d8117d3b89f37cc654619eda2ead4900448173450afd2edef1eb70e083dc83d9d7ab52ba183f4de7bc840007662776b92c26f54df9333621fa20afab96c8f6004147c870586bbcdb1013cfb842b15fa85d3e185878f9c768083df71e095f1fb8e371836a6dd6d35e842feccbf356f1d16cd3e0db7d6f0e54ff4c1faa35bd48da0d6803c9d15392ee55005bf633c3c7147e075ebcb5541294f35a85a5601ab22faf3dd4af87deffb3100821aa11afbf68d25f56359590db53fc1a5aa1136ef8328047b1d88c300bd14bce2b89139d3888ab2b159c522432edb2ac78a29584a7cca092264f6487d0a645f4c8c3b9f6f567a66c27eb8574a60d9439a997743ddf77763772cad36b8efa5ba7163fcbc79f2219f5b6c9b40051176e3226d7137e4869332a6a93659a4885275d71d8d7138c0b640bc29c1eec53b6d7f9b1446b73990131a5bb6a9957fecb47ca912d523a646cb06b2de0839caeb4dfe0fa4a06172c50ca783157e29675a57c7c11fcab124d09117dfcfefcd68a06dfbdc2e7f9ee5fb86840607000ddf9f5ecc9f1001cd7a5c9f68250b441babcddff713582fb876798ebf218d69c0c994d60704d1d56e73d8efd8dad7c659d3fad1c93bc836a8e131fa663565eee1d26dfaa47e71340908febec7590da7d9decf5ee4a35ca47e654776a647574b0b4e00ff0b3673b8907692cd6155aad2265fa1fd8d48319dc4ac81aa1434eac9afff45162d6e28e3a94d6eb0aa28873bddde556912024d452faf49cdb5cdcb460fd38d8751e0176461ecddde223a07562879c8a99574ce0a97c93a804c0a4b334d621e9e27aaf43c47e24f4d5e79ca216857fc37f75f9c6cc308d888964751a834a89f58569cf7ab95ed3a1c266b80070557bac1326e22da340a9a4e30a6dc979672b2c8a60a1436da76ff9637d57fca6027389ae10470f14cc98c1713bc0c947a7a5336ab70f5127c835cde244f062fc617d49e04bc7858cfcb93cf8efdc5e7af17ac50ad3c8649366d8993faa0ca4dcc6198c42fba716f6016bc7c258a4956fa7eae0e48739921659bee07ea78894877ca0802d7526a73a0e8344fd3e5d51c97584b227379f871b4734efa30011637e47ff304c6fccf96837dbf3b7223f7d60038e315b22e81931ee196fbf5ad6595674f60c5ea77d5561ec3a4541fb2c830b84d91512c7d929246f00dd0f9aa17de3f40028512e021381a9f3c59a9012f5160c5b8f5a353297d223815a486c2a7fd4c8154a78e8d276627581e63c45ca121a2c03eb16268a19a12877f57d981eacf5f96e91a19bf808de6f99a704daf5fc4406f7f5c0216734d8bd111017eeb140fc62150785f1c1ef653db98d18bc9629dca04f3a302412a60af4d43c623b5d68b84d1475dfbc8c79acca6147743b1915608f85091f839d46af030a21ec8d64177588e899e682016e14f1f7cc94c627de1cd0905fc005c6e17ef91eeb6e304591add028d46b10518cc8c8309bc71e0aad755c70a0d1f914d1d69273277f7bce1912a72f00cf1bde2776b4e6b46185179236976c60ced81f21f6679939c89817824a701c2c02c9058fb69002b6efb4d894ab1912e696086a9ea13e0dea886672aecd1d239a162e081bb4d7d1bc6244673eb46cb968c135aa32f39211221417fb93b87047ccb8a83f2630bdde4eb9a544afe8546d088439451fe522393bd36b4c3b3fbcead508ce510f7cdfa3d3befbb57ff671686eaaa67da25992fb1588dfb0647c8d45230693968a8e3c848b125ce3920ef20781528ddf2effe9249aa959ab76af2b0bc4e544e1887897c5145fb2faabbe31c937bbf5ef92f28e2f1dd1e92479efff433d4ad2f07e998a59bd345f53c3951fef76a74818dd41fd630dc48eb5f80b6e6b40e1a52858f44f9cecca6886b72dccc4272bb42ee80c12ee8649c1bbdd45c2a91a3b58c98e0361b695833893f828df21cd668d602f8e282a37bc89f88c21f58c18965263fd3d1ed08f749b4e3be510f72545f166e07cfe2b5bf134aef881cdbbbe095334b00f29fcb5dd78b9874ae5913736063e9255d33f89431356e596ff196e9e6032bd3f07b3e7bcc975aeb2b04586de731c23a85f523eabd9d273cfc0a7627a28584ae63b4e94e1079d138bb3a6ce89034671645980df057fdac9bc306c936db9ebf11970a92e16582f1aa8aeb75c2e890cec6172d9475875379344e6683e31ced62efb8b3816f94b4ece52721e4477ab37401581a143019914c365c631e98360b6169fc811bc5141b4cd81851c59db02349e5071723df4e0475a825aea16ce447d72d121fedfb5dfba349e836dd53fbb2fccc4ec35c6385441c5818517bccbe98f08f5d0ffbfdd14b9a0fe9c847151cb8350d022e0618efd75baa0e5dab74b6f02e8965c2b3d90b97cffe77ff773fdf46eb494cac52bfff8585f348bb020b309047fbe7d65e5131fcf6e78436072d2a88e571be9ee82c39b0bacb4839aec0ff42a94d2bb10706be1240c866bb33ae45996de64448b39059d1019e217c4474e140d08e416d7225ffefd6bde2cc9da2c8ca3ca0ceb53eb2dae749f774b1476222dcb48ff078699d00aecc2bec9264ad51b1d13e626227c0364b60b40eb7435b597b125a4d4da8fb736d9d642745124cbd6ee95b730e87b996de2026ec79900ca7f987b6013523ea89a939e5cdd263ff9298136ada395c32243dcf32ade4f4cd41147eb1bcb76835dd56af65d1d59809b4bac666af1edc2fc87a4070cb748d5148297be977f34afec39bec5749671799b8223f6de708581b75d300e5402db580b4b4f0e3de1ebfac82d3eecbb4c82d6a2b0cafa4cd10959675cb57c2afb28cf784d96188962f501fa8a8dcf5994f9ee8f3c6a8f88ef30d338513a6e65d18c68318ed3df1de0be39e02374a6e330d493707d172f292c614e12d11e071e11139d8c87c23213649ca991733bfdca6afeaa746adc859963e13106fff4648c46f830ca6211a5a8d05cb79a4aa8460f800aadb7372ecd8c143d118855fa3f92e2d57c120d88edcd53874385c44c543eb4308d8e31710d9615601929ef360bde0269dddfd5d19b471a3fcc7a2959773c2b996476c7da7bbe6239d607a6f1673c7270d46c8df384d84a751f426b5a2e7dc86c7dc74ff3e1d1c45333d48ce6ef12ae023cc23e0adbf6fbc86f2aa9ca6dace8f60b5cb5c25fe5f4f325c3cc7cfc8f23a2808d49fa8f375349a78fe940af3723f4d8496c4c4b000936ee5d003546ab5273b9800102e1691bd3f9581967bf2807ca2d744f1e287c3981a79f16297c7b59f6909f71c57c43891b80ee1169ddece8a83afd6acb49e93e5e0d7673f9eed5bb83669cfc5f6935b328aec0eed93addb675d182315ae95a90f63cebbad80c759a3af95e8054d4ae647364d8076856a554d57637125fffc17a9bb0a8b1775fd49997ec7fd753867b8de91726b887168370edcdb55d0a20f3851f3763c56cf831c429eda01d6268f5ffa716c37f498f6efb0a5dded996a035d977ec72a69d6ec38f92a73e64ba9163acac15273fe24f2593795397d03a005b8a2a99d22fa1461c470041a318683e1b34df3b4a522394282609924fd09633e48b5447deaa4ed785831a713bfd7350d58a556786596a8918c2125290882e21536ac2cbc7c9fa266f4f16847121ba89eff0b39ce622446954023b1af3e9cca035922bebf8ad3af9e55b65137dd4fd070e695946e4101d12fb48ad6c5d81363a3b2956e33acbf8dc4908768907cd5bd4085ec0c773f07105cf9d894806d374af523adcbe7dd0141affead3717c36278e83a706399581b372d471efcab1b0907aa38a866d2bf0a1aaaab964279bbbd4b45dddc78cb652275514109e040703de4cab899d1f9a1694cc56594442ea171b66e6b758b1d237a9788f092d45efa21228212d10e1ffda3bfe56fa4195284e1ffe8e02c08e7807e123c47afcb11ddb9cfa56a2a5f9b0e25454de13ff7fe0d9c4814e91f6b2504ee698795e4aa7d4539a9a21820630fcca4e62a0dbf309974614908c202b660bb720dc5ee4806abcefec45703cae96b3cf3e7ffb76585b3d060efaafc1a72c4c3c656ab3fad1db77e8231d3e1e60dcf7432a05f900b4b9a7688fad265a034c822b0cdeddff5888877976549c93dafaeea8eff4a4a3ad7c71eb86f2194c06f7b86c3bdf630133794db7e29f1c0302688ebf84de91e74fd400df312d44a383eba56c9daa76309d056c5782ee64890fed3e4e0ed5773a0d38ed3386cf1a212bfce09d3d270890fb211000f29087628b691fb02de760b1c2b45a4c5b6ff0b0f16693418ffea0941f23e4c009e32e302495635ff5fe80c2ac1a6e805efd994e0d24e09c8c24bc7602a2893822714f1f08e33bd05dd268dcfe7c30053e460a378e60722308731a163858ddd5752c6c26ac9d7be87ae86335b0c822bbfdfc72503014e544178893de68948dcddf86df29910b9a24b1f1dad45c1fc28b7f1fa4ba64e092ef9e5453a1cb620582efa863bdebc136a6bfa3f70a49a96e349367cbd89860702fd4da66eec59c2130fcee09507eaf2068fc0c49e891df961de9d63029c337a859760470c70e118e1b4e5893f1173b49195f195915fe11f73895318ffaa2435ef06e5775815df8ef769c7da798be79f19f2097eb627b8b026159841764b913c1b5d1b6e8f9638f9afc66329ad78d10b9b6cd1bb72b56d6e57432c43a7378797ebfda571f0d26fae757e79fa421519e71d738a4b017b13c5d63f8844151ce113c9c9b71aa1451714800cbaec14346086a643877f79cfba676d7d7f72f9cdd46580aa73c41e368f9fa289c7f5bea653a6bdf11cbf5e2041c5727c157dc07f842bdb4eadd80649d0943dcb1dd7596bd2e7605a5919c2ee62aa361e3432c3902625c7e452b6e25f5d5b5f8ca0c32e519f097f5e6ecd205a2e98a0a8c04f6cc874654b2dfd216103d98b4c57dccfac6b7561abeb9162fae838182a8cc811975919c2c44d87cdb7d4d24db1c2748eb7bf4a24e9e0dc2397b1fb626837c4347eea2eb4796815f17d00919e1cecfc0db6d1d058ce3b5ac58f965d37b8d7776611c3bbb7979001dce55f124d58a95365ef7eed6c1f5a0525a9179154b63cfb5c0ebf85979fc5364059697d220aba508c597374eb81bc930ded45c7685711863243559f35c35cea376e92ca187a50d99977f1dec4b83cc75fe87e0e00225841b969f8b46a57a52a2b4f09b42d13f21e5f5fd2bf0a6b2c88c4ce161a5a37bdb4288bbe71f07851e957e33855aba8bd5b77fd59fc4a72faac84bf9a5a947e68cadcfdd8fe690eed70caa7770582b3f83b99e7f8ce6c3997e7303b76f489ad6ff94825cec44f6f8e9040d0ea8973ff9da3d4080825d32b47762426553ad014bfb34a87eb03056481fa2b4ef5b81be18822228fced74763191ff0b4dc7a46070d73376a80ddf522e334252670e3d87fbfd075c9be111e973fd9f552d8173c9d38a67c7b106b035a32bd78b11fdbcb57b936d7ba13ba08d86b8c239ef4d56f0a5ddd8d935a303949ed40932a34c4d093eb5027db1c76378c0067e88d17c8ff2380df87d6caeab12db8ef48d64c76f8961e9e08a265d653d74ebad063d56a05e81f47c099f8d0c627c289531548fea4df8e8184ceb8195ff9f6d45bb23a1ff325add08a53c4ed7eadee95a30a366e4d3e85a760f2f269ca45b9b4a9c4bd04633a7bd800c1d221b565171d3e7adf7d4932b1d85db4e5e93d092657ece40fce1c588c16044404b45d16adfbf8c402a65f0311d4b5b4c98ed0259512908fe6acda19ac693712a606bf6760501b5c82910385d1f4b7d47e7e11df3ea0fb0406541f5d32327f58c94c3e7314650168f16293713664ed9d00716f5c86d62d6e5418c3f0f0e4eb4488e16aeb567c82a1e0be2c922455fb5d316d6bc2be4383e31f7f4a4fe55588e08d1154c7ef4827cf120be57e63cd068671e5d2642f23ed709b6e281961d3980fe8e5af6f2a68f2eb7247f68c18f49ebe60587a3aa103cc8b34df33bdac0ff8c0598d3b49d0e23ea0742b59ff98e33e15f3c1b9025b127c21fe1a4a6dccf1a45ce25268c1b8cf25a18a8f4fb578b22812c5857636a2b93405ea0ba37bbf1d4b1874be91ee118880d1ffac33d948075f555deb30cc0487dbe829266beca76607b86452437d455bd16b13c76a082aafd19bc7989623e0856e0c9c7241646ceb59f84bb0a4a116e2a99d30656c7481b569a310c4a7acfc9edc53995235adcf5d34d10155c0ef5efe1a9e136f813f7db42d33e895b7b2214922ac9758b661e4573da01a85867392909de0821c21c4ddff62c0d3d9df6c42b9b65be1bd3cbecdc9f423854196ee743544e6f2e666c850cc1a17badd959233c14794a8a18eb11d76336daea62fcea4193580a665c193b3f2aeab8e98ac38a3e698dcf1da7b3f969d353a4c852103e5c9b5e2b7319f0370f4407b243d4d981a67c963133206b0ce695883e61aaf4beacc918efe7b9b5ca37bbcc1453a50d0bc57f8c676ec8bd3085ab01d5feeb57d6d0e199d36084052c9f7dc19321de77a249c1fd7e77eca3f8586b3b87721e266d1a64a52d5611858f0e3c65c10f178bf9bead4f5e2730228dd25977790ccfb6512d8c3d369bfc04f73248473c435bdbb7cf3392d9643a2f78965d17bef3fd2111130d308c3c98d48fa43924337ac40b69463a88f7af6f63860e1e9fab9a2b139a0d68eca2d4e1d7944c814db40d1a90d2557ed617608d9a076c882ef6e8d08c0db66813a118f9a37ba9f97a85e1d9252aca1e475b84941fcd7dd1748e292d713027c5a7016ea980aee44a2c4c350216162f89f08978783ce3fb9208172c74ea00283ef71e29475a8bcd5f3956ab7d723a0a596536946f126bcd5c339ae0efe898a290617d428f06a8b7f3dfde1b6851aeb824daad1a5954ab344f1cecadfd13cec54ba8922cb5a6963da64fab78267ccc9b696238c82e334e12adf75e81a9ede7136f2ea589a0314a20e760a5225af5bdf706bbcc7d0835c1ff3c52fd18b4bb6e1cf1eea07852cd0574a18f2683abc8e0221b30434fc671b0c0f037d8a8deaaf5aae967c3d394e24dfad16e60d918c18d880b14f3e6490c7d6460569431ab0689a4b34ac880d1f70fc6a85fe14014842d5f1d39a5d02b1098bc0ce67b7e70dac83
diff --git a/crypto/slhdsa/slhdsa_test.cc b/crypto/slhdsa/slhdsa_test.cc
index c7898f4..f9cdc2b 100644
--- a/crypto/slhdsa/slhdsa_test.cc
+++ b/crypto/slhdsa/slhdsa_test.cc
@@ -83,43 +83,43 @@
1);
}
-TEST(SLHDSATest, BasicPrehashSignVerify) {
+TEST(SLHDSATest, BasicNonstandardPrehashSignVerify) {
uint8_t pub[SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES];
uint8_t priv[SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES];
SLHDSA_SHA2_128S_generate_key(pub, priv);
- // Use a constant 32-byte value as the prehashed message
- uint8_t kHashedMessage[32] = {0x42};
+ // Use a constant 48-byte value as the prehashed message
+ uint8_t kHashedMessage[48] = {0x42};
uint8_t kContext[256] = {0};
uint8_t signature[SLHDSA_SHA2_128S_SIGNATURE_BYTES];
- ASSERT_TRUE(SLHDSA_SHA2_128S_prehash_sign(signature, priv, kHashedMessage,
- sizeof(kHashedMessage), NID_sha256,
- nullptr, 0));
- EXPECT_EQ(SLHDSA_SHA2_128S_prehash_verify(
+ ASSERT_TRUE(SLHDSA_SHA2_128S_prehash_warning_nonstandard_sign(
+ signature, priv, kHashedMessage, sizeof(kHashedMessage), NID_sha384,
+ nullptr, 0));
+ EXPECT_EQ(SLHDSA_SHA2_128S_prehash_warning_nonstandard_verify(
signature, sizeof(signature), pub, kHashedMessage,
- sizeof(kHashedMessage), NID_sha256, nullptr, 0),
+ sizeof(kHashedMessage), NID_sha384, nullptr, 0),
1);
- EXPECT_EQ(SLHDSA_SHA2_128S_prehash_verify(
+ EXPECT_EQ(SLHDSA_SHA2_128S_prehash_warning_nonstandard_verify(
signature, sizeof(signature), pub, kHashedMessage,
- sizeof(kHashedMessage), NID_sha256, kContext, 1),
+ sizeof(kHashedMessage), NID_sha384, kContext, 1),
0);
- EXPECT_EQ(SLHDSA_SHA2_128S_prehash_verify(
+ EXPECT_EQ(SLHDSA_SHA2_128S_prehash_warning_nonstandard_verify(
signature, sizeof(signature), pub, kHashedMessage,
- sizeof(kHashedMessage), NID_sha256, kContext, 256),
+ sizeof(kHashedMessage), NID_sha384, kContext, 256),
0);
- ASSERT_TRUE(SLHDSA_SHA2_128S_prehash_sign(signature, priv, kHashedMessage,
- sizeof(kHashedMessage), NID_sha256,
- kContext, 1));
- EXPECT_EQ(SLHDSA_SHA2_128S_prehash_verify(
+ ASSERT_TRUE(SLHDSA_SHA2_128S_prehash_warning_nonstandard_sign(
+ signature, priv, kHashedMessage, sizeof(kHashedMessage), NID_sha384,
+ kContext, 1));
+ EXPECT_EQ(SLHDSA_SHA2_128S_prehash_warning_nonstandard_verify(
signature, sizeof(signature), pub, kHashedMessage,
- sizeof(kHashedMessage), NID_sha256, kContext, 1),
+ sizeof(kHashedMessage), NID_sha384, kContext, 1),
1);
uint8_t kWrongLengthHash[16] = {0x42};
- EXPECT_FALSE(SLHDSA_SHA2_128S_prehash_sign(signature, priv, kWrongLengthHash,
- sizeof(kWrongLengthHash),
- NID_sha256, nullptr, 0));
+ EXPECT_FALSE(SLHDSA_SHA2_128S_prehash_warning_nonstandard_sign(
+ signature, priv, kWrongLengthHash, sizeof(kWrongLengthHash), NID_sha384,
+ nullptr, 0));
}
@@ -197,19 +197,17 @@
std::string hash_func;
ASSERT_TRUE(t->GetAttribute(&hash_func, "hash"));
int nid = 0;
- if (hash_func == "SHA-256") {
- nid = NID_sha256;
- } else if (hash_func == "SHA-512") {
- nid = NID_sha512;
+ if (hash_func == "SHA-384") {
+ nid = NID_sha384;
} 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_verify(sig.data(), sig.size(), pub,
- msg.data(), msg.size(), nid,
- context.data(), context.size()));
+ EXPECT_TRUE(SLHDSA_SHA2_128S_prehash_warning_nonstandard_verify(
+ sig.data(), sig.size(), pub, msg.data(), msg.size(), nid, context.data(),
+ context.size()));
}
diff --git a/include/openssl/slhdsa.h b/include/openssl/slhdsa.h
index ac3d636..6b83946 100644
--- a/include/openssl/slhdsa.h
+++ b/include/openssl/slhdsa.h
@@ -84,30 +84,42 @@
// 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). It 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(
+// 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
+// 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_warning_nonstandard_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 non-standard hash functions
+// that are not compliant with 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_warning_nonstandard_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. It 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(
+// SLHDSA_SHA2_128S_prehash_warning_nonstandard_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 non-standard hash functions
+// that are not compliant with 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_warning_nonstandard_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,
diff --git a/rust/bssl-crypto/src/slhdsa.rs b/rust/bssl-crypto/src/slhdsa.rs
index 47185f2..193db57 100644
--- a/rust/bssl-crypto/src/slhdsa.rs
+++ b/rust/bssl-crypto/src/slhdsa.rs
@@ -46,9 +46,7 @@
//! assert!(public_key.verify_with_context(message, &signature2, context).is_ok());
//! ```
-use crate::{
- digest, sealed, with_output_vec_fallible, FfiSlice, ForeignTypeRef, InvalidSignatureError,
-};
+use crate::{with_output_vec_fallible, FfiSlice, InvalidSignatureError};
use alloc::vec::Vec;
/// The number of bytes in an SLH-DSA-SHA2-128s public key.
@@ -132,48 +130,6 @@
})
}
}
-
- /// Signs a prehashed message using this private key.
- ///
- /// This function returns None if `context` is longer than 255 bytes, if
- /// the hash function is not supported, or if `hashed_msg` is the wrong length.
- ///
- /// This function generally should not be used. The general functions are
- /// perfectly capable of signing a hash if you wish. These functions should
- /// only be used when:
- ///
- /// 1. Compatibility with an external system that uses prehashed messages is
- /// required. (The general signature of a hash is not compatible with a
- /// "prehash" signature of the same hash.)
- /// 2. A single private key is used to sign both prehashed and raw messages,
- /// and there's no other way to prevent ambiguity.
- pub fn prehash_sign<Hash: digest::Algorithm>(
- &self,
- hashed_msg: &[u8],
- context: &[u8],
- ) -> Option<Vec<u8>> {
- unsafe {
- with_output_vec_fallible(SIGNATURE_BYTES, |signature| {
- let hash_nid = bssl_sys::EVP_MD_nid(Hash::get_md(sealed::Sealed).as_ptr());
- // Safety: the FFI function always writes exactly `SIGNATURE_BYTES` to
- // the first argument if it succeeds. Otherwise, all buffers are valid.
- if bssl_sys::SLHDSA_SHA2_128S_prehash_sign(
- signature,
- self.0.as_ptr(),
- hashed_msg.as_ffi_ptr(),
- hashed_msg.len(),
- hash_nid,
- context.as_ffi_ptr(),
- context.len(),
- ) == 1
- {
- Some(SIGNATURE_BYTES)
- } else {
- None
- }
- })
- }
- }
}
impl AsRef<[u8]> for PrivateKey {
@@ -221,40 +177,6 @@
Err(InvalidSignatureError)
}
}
-
- /// Verifies a signature for a prehashed message using this public key and
- /// the given context.
- ///
- /// This function returns `InvalidSignatureError` if `context` is longer
- /// than 255 bytes, if the hash function is not supported, or if
- /// `hashed_msg` is the wrong length.
- pub fn prehash_verify<Hash: digest::Algorithm>(
- &self,
- hashed_msg: &[u8],
- signature: &[u8],
- context: &[u8],
- ) -> Result<(), InvalidSignatureError> {
- let ok = unsafe {
- let hash_nid = bssl_sys::EVP_MD_nid(Hash::get_md(sealed::Sealed).as_ptr());
- // Safety: all buffers are valid
- bssl_sys::SLHDSA_SHA2_128S_prehash_verify(
- signature.as_ffi_ptr(),
- signature.len(),
- self.0.as_ptr(),
- hashed_msg.as_ffi_ptr(),
- hashed_msg.len(),
- hash_nid,
- context.as_ffi_ptr(),
- context.len(),
- )
- };
-
- if ok == 1 {
- Ok(())
- } else {
- Err(InvalidSignatureError)
- }
- }
}
impl AsRef<[u8]> for PublicKey {
@@ -301,38 +223,6 @@
}
#[test]
- fn test_sign_and_verify_prehashed() {
- let (public_key, private_key) = PrivateKey::generate();
- let digest = [42u8; 32];
- let context = b"test context";
-
- let sig = private_key
- .prehash_sign::<digest::Sha256>(&digest, context)
- .unwrap();
- assert!(public_key
- .prehash_verify::<digest::Sha256>(&digest, &sig, context)
- .is_ok());
-
- let mut incorrect_digest = digest;
- incorrect_digest[0] ^= 1;
- assert!(public_key
- .prehash_verify::<digest::Sha256>(&incorrect_digest, &sig, context)
- .is_err());
-
- assert!(public_key
- .prehash_verify::<digest::Sha256>(&digest, &sig, b"wrong context")
- .is_err());
-
- let incorrect_length_digest = [42u8; 16];
- assert!(private_key
- .prehash_sign::<digest::Sha256>(&incorrect_length_digest, context)
- .is_none());
- assert!(public_key
- .prehash_verify::<digest::Sha256>(&incorrect_length_digest, &sig, context)
- .is_err());
- }
-
- #[test]
fn test_public_key_from_private() {
let (public_key, private_key) = PrivateKey::generate();
let derived_public_key = private_key.to_public_key();