#define TEST_NAME "kem_mlkem768" #include "cmptest.h" static const char tv1_d[] = "7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d"; static const char tv1_z[] = "b505d7cfad1b497499323c8686325e4792f267aafa3f87ca60d01cb54f29202a"; static const char tv1_pk_prefix[] = "a8e651a1e685f22478a8954f007bc7711b930772c78f092e82878e3e937f3679"; static const char tv1_m[] = "eb4a7c66ef4eba2ddb38c88d8bc706b1d639002198172a7b1942eca8f6c001ba"; static const char tv1_ct_prefix[] = "3b835a5fa145387a0819c4daa1e65fbe2ba5400afcd640bbddbbe3585f24bedd"; static const char tv1_ss[] = "ac865f839fef1bf3d528dd7504bed2f64b5502b0fa81d1c32763658e4aac5037"; static const char tv2_d[] = "d60b93492a1d8c1c7ba6fc0b733137f3406cee8110a93f170e7a78658af326d9"; static const char tv2_z[] = "588522d326e7f105f11c4e8d97e119e193af42dc28409f4f7572ada538b52c1f"; static const char tv2_pk_prefix[] = "93c140f6c47b7e53b96f72bb18447d277cc021c144a0f7a35e30b57386a78ac9"; static const char tv2_m[] = "46401015603c5e2174cb94ac742e836b516e2d570f15de0b9d0204d79ac64ba3"; static const char tv2_ct_prefix[] = "4ddf4e2919943817ab3b4cb085daefe5fec774d83d96c2cee74149e25addd15f"; static const char tv2_ss[] = "950492e940bfa86ac28183de02efc04017d1755106a854fbb2ac68174f705b41"; static const char wycheproof_seed[] = "cbfc4405d1b2a3a386c94c25e0f2d5f5ee92cb0388ff4d6aa04223086d51c3fd" "24752da14c9fc3b8ae0d9e4a8b1016b8d8fc69e229c03ea2ef08a4ae0cffc37f"; static const char wycheproof_ek[] = "8b9a7354e8c1c17a9898f96caf99bba1c625ae0983c4d26e60c12f59bc25d756" "182b17979e713fff129e6c336a2317770380858129cb91a902ea5455ca076c20" "e4158f393aa2783053d8acf92c3286a10436d72af3e8903ce22f8cbab18b1309" "aca205aa8a3da45807e5b60e6967a640a713a5b81b0d82bc406934e3c88910cc" "06f09a68bce991009bb56ae233296218ff5baf1f475390b8b7494a4e08364598" "5437f2495a073222fea058e1672034151a2e14c2cbcb4ad9068c8e7bcb02886c" "4087c14bd8823ec66393fb2e12326b38e655dcab1c13cb2931358715c8be5153" "293229cc994a5702b7295a6a4a73249ac5a30a32a6b91dca768c177d8fa59054" "e548bee40257db6962a83b64ec6de0d3be7b1812c5d99e7a38cf54eaa8413aa0" "bd02bf374461f29c2b6aea56f7d33e10dbbc75bb1bf6b555213aac33e652443a" "186a618b6e9a293919693f1673ea159d0ee52c92d53e9a5cbd5f4c44419b5493" "f0286efcb9b5a2ad56a713c4f61ed431aa987805a90475391ccd4c7a28d884bf" "1a926b7675b9208897a89a6384c154acca3521c32a994949b2e80b2ff2518c0b" "bd34184cda443de498a05dfba9ce701bb914179a0188be0bcda6fbc2cd93afb0" "42481b4a84d821160a1b0ade8bcb97dbaf681547cce0bca674151a261a21aa04" "fda318c921c38425b775b995cd7b4eb6369f0b211da186594de815fa3b53a680" "43e1946468a5899b90578ad49397306f71acab67c258fa17a31893b72d22151c" "e1afee150fe550bffde8a24fe4740dd43f387c7ad20b5cca5997879536c30715" "74901147727341c1a6fc8043e6454903e88217f0c92b9a4ac54a86e790939087" "8a35ba18c1e26b13049f41c522bc049d74db6f76caba39f23d8f07abc26a07a1" "caba71cb5c12fbc20a715450b2228d17b2ba985cfe2496b033b55f300baf9929" "64388a5422298f627ba567730ddb03a195806a5c23a1d315481c52814b0681ea" "3c804b02c90688c2fbbce9b17d230a42f8b865417c9e93347f5ff624879962747c7eed886acd48a994b22064ca499c69aa4825be60260d12f63102799828b3cc" "ebaa4340b749605017eb4598ff13a634500a48470de9078a34106267d25a0b14" "4d8cdb1a4d527692153da013c0ab27ae2ca955e7c66238746022d50630892933" "a05c283a9f4c00c9f984646f75471081722ed3404ce60fed4a06702b8728b62d" "920b3224206ab0a4694f9c18e3162b529c16af04b87b4a61cd53a757906d67a1" "39629585d423a3b0986f29c95984e2095ea4608784b0b31c20cbc36cfd60b773" "389fe5a8c0958211a35b2c45f21f51a08693c19bfc388c2d677a214ccc5a7cb0" "b67030fd6987503c91b0f2646985a9048489dd882bd4141f5419554eb738fa73" "33c5c57a4ce5541fd6b8ad454c2dea67ad1c6f848c0a44a1872e40a17d987075" "d762ba5aaa21d435dd079b989a8ee21a2ce898934a98a02d5b381c302a2d7694" "8fa65de15666f57750d580ae1a541c700692dd0b0a6799b5cdb893413bb89bb6" "5182f219a4bc3c80b43bb591bcd05ac6e9a366552558ed5c5fbe7b4acfc7b233" "72094f6a87f26c0c46646c55a888871324fea7536e586a5149b9b707c86ea076" "486a6822b9bbf59fbfcaedc13284b9813cabdd526e326a6832d3b36efc3102ef"; static const char wycheproof_ct[] = "00e96c44eb5f5380d80b4cb05d608971a28fbe838b912b558bf9676c6c67c969" "2ed6ea063fc47b70d5d6004825c269b9cb8e68b5728d67f44844d97686a11154" "e3cbd4a6f9e47524d93d851bdce480d7762ded09be53d17cce3ee28dc5a06911" "c062b99b218355dd5822108c55e2c67f7ea0b74b6189b33b4589d8ff9d0c867d" "13edaaf1c5f724675320beda3e6acc673c048fa04a1b30f899227d5a555e08a4" "12a47b7db75eb118a8844a71b186880426f6bb6e77186d18e753cbcce93c9fb7" "6c729875b4d473eeca8dab9941969faef04df9ce3178e7341eab416d28bb7aee" "12bfb8f4c3df814eff45a0187329079acfc41a8e8dba7b08d111f02e37a1d2b6" "9e57eef808fcc6ae23385534a420a93dfb6a95c73e2f1016177c4fe9d3ced769" "e277293aaceded6d07efc7890eaa885bd1e73f9e5da2b9cfda0d44cbc9090705" "ac2ce3e7bcd7775b593c706e45ddc97d3a65d9b7e73673f9473df5bfec689671" "f73e7f6ee77c730a8ebda1f0b2c112a71904d6f28a51d8d479f8323fb485e722" "f5c4d5857e95989a9cbaf273efd04fc3cbde98baa9969e095e88accecfbd12ef" "2155497a5b15fe91a70d1106b91a568363bfc2d6736cc8138cbc41ddf1e54fd4" "0511e27d89e2c26c027b63c156e2bbb998faaed3d72186f0cc626dad39a782dc" "da2087fd13a9498e10b41b685646a227ea1166a5632c195983f4aba2b718b407" "4030d57126d34c38349892007acbea9e393b967dc3146b270f080a1f0bee90d6" "5a095a6352a7718ed1717a8025a2bd38c66d120baf4247676a1fe044a57ce268" "c078f8ff46cc26fe4f9c7a03d6467adacb8418d26273662bce1f7bc00b906e00" "88e95dc0fb419e2232e85aac77b9e7cd563e604de5e1d3e9693dcd3b19865cf4" "250773691e7e0af9c2755cd31f49d1f96708f3ba2f0b98184525abb869e12d5c" "ea0ac1740181a875035300b05a54b8d42ee3b4ae92b06e43cd807e2b096c977f" "23c61ef8c989c52ed83754076dea1323f639250bef61bdf903bf7961cec89ba6" "942d9d0647ac9c8195d93ed8abcedf25754644035719a5a0a1c8c0798912726a" "9a8258e4c10ae7485322ed9ba331f6f090c4b492a4fcf53d753cd34f28ec0443" "fce0724f43c89a3942169d5099a8f7430f38691ebce2e3fe4f600d82c7ccedf6" "0673f8e5d4c1a9f84b8b5b23f5ed63defb6a7205e0a8b105bdc6ff4568fc78cb" "4456b02fedb7f4c48f6fd6b69216a3319821039db40e19a31a0b0c9d471d5a7a" "73865d26f8be3595525b1ec4a8579efd07ea98e2602e2bffdfd8febc5c7b4c73" "6d326b5030ccc6faf9420a9c156a8f4516b9fff675459dfdcd4ef85d7adbdffd" "60f4a39628e399cc752c2e99ab2f431dc765e7c9d206bfe32649fbef4ef48b1d" "7936fc74766d724350ee2245a8d5f23fbc6c7ed8b57168ce1e864e49d7f8c475" "dcda140bd42473825b3c72eb8c54780188813011e1962a503f9b516e13226de6" "375b204733b0192183c8f55e870e61cf8947c3191790bc0b657bc43aebc9d86c"; static const char wycheproof_ss[] = "76c10bb1d86d96d7eb18e298363e51f7728e113f455df7d15017940ed3541451"; static const char *wycheproof_invalid_ek[] = { "016d4cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d212d0e896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "ff6f4cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2ffe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bb019da8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4f18d07da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbff9fa8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8ff7da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff86501ad1d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d1513d0ade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff8657da81d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15f3ffade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", "8b654cd2120d97581838192bb56463ee2b9a96e620bc7976bf3634f441ab0641ba3a904cfd4b55ba40cc6fdb906ac1a95637112c7a48dbf311d67004bb583e068b9936b32463245da31685a878a90d205162b587a322cebe475fc70186b8b52cab2c9e838873406a98574c65e83b0063d316a8654b5ef7537b487a25114c521bbfdb4780d58804c1c172cfac59b9bb8ba804a10fc6607633cc89d18bc5579d7a0825a2a72bc32869ba8518fafa522a9950ef7ab4625c417e6b6fa3f0165dd47d78ab8587f22b99abad73a90880b2b08c4876b61ca536f675b4b8a37460ad4400910d265e5146ae4be61a09c30a1de01f4636a802413fc8f051cde78e4fc51ba8f3a2cad1474775a7d7ec513a57541861702d6480c70cce8912bd2c01bf11378604005695d64c1969cf25714ae287c019da020d66af70c1528e12365fe25106e8179b04ccf0cba724fb6a89b83ca9f55012b66267337f6618484a7a70e8a1163cb17426ea132e1a56e53ab86e491e39dbbe4e4465a785106b5255dc2190d2f2bbe896a8cc64a228c2b9a8943214f97a3b40a8e41053fd4346a7fcab06fa72de8c33cca788e2e09e09dacd7034038ec13d1a065cf7d14c5de44a6d56873232ba84585b9d0811320659be5a19cdc759969a0bdeca5410977e40163dc2da6665c45954b900e3a97512897d1c7a6cc2a60acfb2175151043ae29a0d240e760c1d100a6877b5a10fb69054d0cf80dca4c15350fc685001899a7a6515e9c7ac3325938997b4387c16022a91ee5c2fa2ab8bd6fa898667831af38349fb1badb52b472210e36bca63342a0cd869a44a04a7e68859f66094d8c104c33b38444b8fb168025b479a5a7772c1bacd73b3ef88ae6fe66aab1846723c65d3d106c1722e2235ac7865a04584324062826e463edc13803c9796e54bce6b80933057abb9328ab501688e69148fbaa811ea9792316068a9abfa583e45ab6549ccb7e9e70d9139c0ebc7b995ec1463fc321f38bff2b2b995192eaa305daf1c44352371089637ed673dd82b8ad8bb3bb2299b9e5369f104a454357e5a2238e6315fa720343064be4ff865ffaf1d7c5c4b51c5b896669f029483f7c273f763ce26150ce3550c4ddcb26f37b2dea19b2dd197d449c9b693c10a3cb04de8c9f425a523d173240a69c4f0479bc177d836cda34b2cb64440acd464d904b66662295f0950460b710f089090b49fc7a6276e219eb4f19ee4dc12d2045141497064c4beae80a8ded00438d90a012963de54380f137666b2ab09844198ba807a4972f1b35f7b9789d847cc3e5a4a08cb17d4d9065ce09a74609ae935218c5bcd51f9bd774aa720e6423f75a974a3c21835a6018886dd119766909413aa576144c10b49c17ba1c793f78f7c580eba195bd8407f00f568c4d546c7d677dd02c78930c3e969b5584129e1815c6ce32162f09d6f7303f69c5f0216625c782666f9c8cf8678f1b63635067392aa3fba56204a1831491c2eee759ce674abd34251732949f9874059b35b66089a1905896c94111511a449f695e2c036d87b585a74834d676b9a2b2aa74a386cfa446f86934b844068147013396fa2d3bb8fa11d97b992a04a6ba65c189b238106cb8d15837bade3c278034d6d86bd50a3049feb37499b08aba61b38ffeaf94bc84cdb360fbc", }; static int test_kat_vector(const char *d_hex, const char *z_hex, const char *pk_prefix_hex, const char *m_hex, const char *ct_prefix_hex, const char *ss_hex) { unsigned char seed[crypto_kem_mlkem768_SEEDBYTES]; unsigned char pk[crypto_kem_mlkem768_PUBLICKEYBYTES]; unsigned char sk[crypto_kem_mlkem768_SECRETKEYBYTES]; unsigned char enc_seed[32]; unsigned char ct[crypto_kem_mlkem768_CIPHERTEXTBYTES]; unsigned char ss_enc[crypto_kem_mlkem768_SHAREDSECRETBYTES]; unsigned char ss_dec[crypto_kem_mlkem768_SHAREDSECRETBYTES]; unsigned char expected_pk_prefix[32]; unsigned char expected_ct_prefix[32]; unsigned char expected_ss[32]; char hex[65]; sodium_hex2bin(seed, 32, d_hex, 64, NULL, NULL, NULL); sodium_hex2bin(seed + 32, 32, z_hex, 64, NULL, NULL, NULL); sodium_hex2bin(enc_seed, 32, m_hex, 64, NULL, NULL, NULL); sodium_hex2bin(expected_pk_prefix, 32, pk_prefix_hex, 64, NULL, NULL, NULL); sodium_hex2bin(expected_ct_prefix, 32, ct_prefix_hex, 64, NULL, NULL, NULL); sodium_hex2bin(expected_ss, 32, ss_hex, 64, NULL, NULL, NULL); crypto_kem_mlkem768_seed_keypair(pk, sk, seed); if (memcmp(pk, expected_pk_prefix, 32) != 0) { sodium_bin2hex(hex, sizeof hex, pk, 32); printf("pk mismatch: got %s\n", hex); return -1; } assert(crypto_kem_mlkem768_enc_deterministic(ct, ss_enc, pk, enc_seed) == 0); if (memcmp(ct, expected_ct_prefix, 32) != 0) { sodium_bin2hex(hex, sizeof hex, ct, 32); printf("ct mismatch: got %s\n", hex); return -1; } if (memcmp(ss_enc, expected_ss, 32) != 0) { sodium_bin2hex(hex, sizeof hex, ss_enc, 32); printf("ss_enc mismatch: got %s\n", hex); return -1; } assert(crypto_kem_mlkem768_dec(ss_dec, ct, sk) == 0); if (memcmp(ss_dec, expected_ss, 32) != 0) { sodium_bin2hex(hex, sizeof hex, ss_dec, 32); printf("ss_dec mismatch: got %s\n", hex); return -1; } return 0; } static void tv_kem_mlkem768(void) { unsigned char *pk; unsigned char *sk; unsigned char *seed; unsigned char *ct; unsigned char *ss_enc; unsigned char *ss_dec; unsigned char *enc_seed; char hex[65]; int i; pk = (unsigned char *) sodium_malloc(crypto_kem_mlkem768_PUBLICKEYBYTES); sk = (unsigned char *) sodium_malloc(crypto_kem_mlkem768_SECRETKEYBYTES); seed = (unsigned char *) sodium_malloc(crypto_kem_mlkem768_SEEDBYTES); ct = (unsigned char *) sodium_malloc(crypto_kem_mlkem768_CIPHERTEXTBYTES); ss_enc = (unsigned char *) sodium_malloc(crypto_kem_mlkem768_SHAREDSECRETBYTES); ss_dec = (unsigned char *) sodium_malloc(crypto_kem_mlkem768_SHAREDSECRETBYTES); enc_seed = (unsigned char *) sodium_malloc(32); for (i = 0; i < (int) crypto_kem_mlkem768_SEEDBYTES; i++) { seed[i] = (unsigned char) i; } crypto_kem_mlkem768_seed_keypair(pk, sk, seed); sodium_bin2hex(hex, sizeof hex, pk, 32); printf("pk (first 32 bytes): [%s]\n", hex); sodium_bin2hex(hex, sizeof hex, sk, 32); printf("sk (first 32 bytes): [%s]\n", hex); for (i = 0; i < 32; i++) { enc_seed[i] = (unsigned char)(i + 64); } assert(crypto_kem_mlkem768_enc_deterministic(ct, ss_enc, pk, enc_seed) == 0); sodium_bin2hex(hex, sizeof hex, ct, 32); printf("ct (first 32 bytes): [%s]\n", hex); sodium_bin2hex(hex, sizeof hex, ss_enc, crypto_kem_mlkem768_SHAREDSECRETBYTES); printf("ss_enc: [%s]\n", hex); assert(crypto_kem_mlkem768_dec(ss_dec, ct, sk) == 0); sodium_bin2hex(hex, sizeof hex, ss_dec, crypto_kem_mlkem768_SHAREDSECRETBYTES); printf("ss_dec: [%s]\n", hex); if (memcmp(ss_enc, ss_dec, crypto_kem_mlkem768_SHAREDSECRETBYTES) != 0) { printf("ERROR: shared secrets don't match!\n"); } else { printf("shared secrets match: ok\n"); } crypto_kem_mlkem768_keypair(pk, sk); assert(crypto_kem_mlkem768_enc(ct, ss_enc, pk) == 0); assert(crypto_kem_mlkem768_dec(ss_dec, ct, sk) == 0); if (memcmp(ss_enc, ss_dec, crypto_kem_mlkem768_SHAREDSECRETBYTES) != 0) { printf("ERROR: shared secrets don't match (random keys)!\n"); } else { printf("random keypair test: ok\n"); } ct[0] ^= 0x01; assert(crypto_kem_mlkem768_dec(ss_dec, ct, sk) == 0); if (memcmp(ss_enc, ss_dec, crypto_kem_mlkem768_SHAREDSECRETBYTES) == 0) { printf("ERROR: decapsulation succeeded with modified ciphertext!\n"); } else { printf("modified ciphertext rejected: ok\n"); } assert(crypto_kem_mlkem768_publickeybytes() == crypto_kem_mlkem768_PUBLICKEYBYTES); assert(crypto_kem_mlkem768_secretkeybytes() == crypto_kem_mlkem768_SECRETKEYBYTES); assert(crypto_kem_mlkem768_ciphertextbytes() == crypto_kem_mlkem768_CIPHERTEXTBYTES); assert(crypto_kem_mlkem768_sharedsecretbytes() == crypto_kem_mlkem768_SHAREDSECRETBYTES); assert(crypto_kem_mlkem768_seedbytes() == crypto_kem_mlkem768_SEEDBYTES); assert(crypto_kem_mlkem768_PUBLICKEYBYTES == 1184U); assert(crypto_kem_mlkem768_SECRETKEYBYTES == 2400U); assert(crypto_kem_mlkem768_CIPHERTEXTBYTES == 1088U); assert(crypto_kem_mlkem768_SHAREDSECRETBYTES == 32U); assert(crypto_kem_mlkem768_SEEDBYTES == 64U); printf("constants: ok\n"); sodium_free(enc_seed); sodium_free(ss_dec); sodium_free(ss_enc); sodium_free(ct); sodium_free(seed); sodium_free(sk); sodium_free(pk); printf("tv_kem_mlkem768: ok\n"); } static void tv_kem_mlkem768_kat(void) { printf("NIST KAT vector 1: "); if (test_kat_vector(tv1_d, tv1_z, tv1_pk_prefix, tv1_m, tv1_ct_prefix, tv1_ss) == 0) { printf("ok\n"); } else { printf("FAILED\n"); } printf("NIST KAT vector 2: "); if (test_kat_vector(tv2_d, tv2_z, tv2_pk_prefix, tv2_m, tv2_ct_prefix, tv2_ss) == 0) { printf("ok\n"); } else { printf("FAILED\n"); } } static void tv_wycheproof_decapsulation(void) { unsigned char seed[64]; unsigned char pk[crypto_kem_mlkem768_PUBLICKEYBYTES]; unsigned char sk[crypto_kem_mlkem768_SECRETKEYBYTES]; unsigned char ct[crypto_kem_mlkem768_CIPHERTEXTBYTES]; unsigned char ss[crypto_kem_mlkem768_SHAREDSECRETBYTES]; unsigned char expected_ek[crypto_kem_mlkem768_PUBLICKEYBYTES]; unsigned char expected_ss[32]; sodium_hex2bin(seed, sizeof seed, wycheproof_seed, strlen(wycheproof_seed), NULL, NULL, NULL); sodium_hex2bin(ct, sizeof ct, wycheproof_ct, strlen(wycheproof_ct), NULL, NULL, NULL); sodium_hex2bin(expected_ek, sizeof expected_ek, wycheproof_ek, strlen(wycheproof_ek), NULL, NULL, NULL); sodium_hex2bin(expected_ss, sizeof expected_ss, wycheproof_ss, strlen(wycheproof_ss), NULL, NULL, NULL); crypto_kem_mlkem768_seed_keypair(pk, sk, seed); printf("Wycheproof decapsulation (tcId 1): "); if (memcmp(pk, expected_ek, crypto_kem_mlkem768_PUBLICKEYBYTES) != 0) { printf("FAILED (pk mismatch)\n"); return; } assert(crypto_kem_mlkem768_dec(ss, ct, sk) == 0); if (memcmp(ss, expected_ss, 32) == 0) { printf("ok\n"); } else { printf("FAILED (ss mismatch)\n"); } } static void tv_wycheproof_modulus_overflow(void) { unsigned char ek[crypto_kem_mlkem768_PUBLICKEYBYTES]; unsigned char ct[crypto_kem_mlkem768_CIPHERTEXTBYTES]; unsigned char ss[crypto_kem_mlkem768_SHAREDSECRETBYTES]; unsigned char m[32]; size_t i; memset(m, 0x42, 32); printf("Wycheproof modulus overflow: "); for (i = 0; i < sizeof wycheproof_invalid_ek / sizeof wycheproof_invalid_ek[0]; i++) { sodium_hex2bin(ek, sizeof ek, wycheproof_invalid_ek[i], strlen(wycheproof_invalid_ek[i]), NULL, NULL, NULL); if (crypto_kem_mlkem768_enc_deterministic(ct, ss, ek, m) == 0) { printf("FAILED (accepted invalid ek %u)\n", (unsigned int) i); return; } } printf("ok (rejected all invalid ek values)\n"); } int main(void) { tv_kem_mlkem768(); tv_kem_mlkem768_kat(); tv_wycheproof_decapsulation(); tv_wycheproof_modulus_overflow(); return 0; }