//! Static format compliance test vectors.
//!
//! Each constant is a pre-generated key pair and ciphertext blob that proves
//! the decoder can round-trip a specific format version and KEM variant. If
//! the wire format ever changes in a breaking way, these tests will fail
//! immediately rather than only when a user encounters an old file.
//!
//! Regenerate all constants with:
//! cargo run --example gen_vectors -p pqfile
//! Then update the constants below and commit gen_vectors.rs alongside this
//! file so they stay in sync.
//!
//! Plaintext (hex): 707166696c6520737461746963207465737420766563746f72207631
use pqfile::decrypt::decrypt_stream;
const PLAINTEXT: &[u8] = b"pqfile static test vector v1";
// ---- ML-KEM-512 v2 (whole-file AEAD, FORMAT.md section 5.1) ----------------
const V2_512_PRIV_PEM: &str = concat!(
"-----BEGIN ML-KEM-512 PRIVATE KEY-----\n",
"vsUL7v8ZHNQ370Yje3rL2SaYx530gMrq83uZuMMl1UAimxiD/hQ/ZMqrsN/TUH8O\n",
"rL6XQ2WVy7EH5bpQNytmOw==\n",
"-----END ML-KEM-512 PRIVATE KEY-----\n",
);
const V2_512_CT: &str = "5051464c0200021323ef809b65e8a640dfe8b9c5ff1aa74584cac59d6f9defa5d182db110f3a5c02bf3778a4e51cb10a6b33e8b969dd7e3c603fe16d864e134f920fcc3ce278c9a4d037521a93bc6592587c2f3a3eeb2725db69de317927881be517ca1147a8c5608055eda7a10b213515dfe3551e3fa4bc4945386fcad92376c1ad446c95aa9426a5871d7d5c95f9067b529ca629827fd2201d02ed1a4cee2a5ef80e4d40c43f7cb551ff9971fd4d656c5dacc1442e4e76adbfb7b90efdcde9f747ea66c99c7dff5af2b7c34891ce590d6d27b0a966a451bbc1889301718d28b6cfd7019a798d531be1a05a4f2c3915509edd3a9ff87add6cef5051a873f7aaf10e689d269db42d0ebe6343f4f4048fff7f07133661d39f1590700ecb618d9bfe4f314ea3c958288225031ffb751958880266fdbe8dfa45d201febde8281f34efd1c8a4b7b735b21748b4b77d0da5e4998ddaf62a7f12e52acd38f232a230c646ec706ba86c06d3a2f768d470f21102d2c86f2448487fd9888c696cf4a87a31bbdd47739379b32ae4de709958954ba74480830d830a218d8df3aef342994714780cd432aba3a540aafa5c2a79d1bb1fde1d51fd6edd5bb49595cbe13bb233ba1c83758f6a2d49505011611311d7720815d1d2023592886a90621abdd2f1bdd8ce9bcc049152c0bdbc28e494b44d18e92728d26fbf717f79fb6875ff5341126d80fd0241340c1efb80f08481ba828b3301c78da8738ba44c40eed9b2144312bb9da6de9128c9d7a7089a82c9a6276789775f776a01320b9bdc59f532ee49bb8148ae3f6d847cbad5f36986a6b6f04d688ca7f3bf32105a374cc936d5820d06597bfd8a2b043d4b21dca0fd5971c36e21876716e7eb821b783925bdeb542d76bd5b14d0e7c3d1b3efdd51a71a48422ad195aede8d1ef06537ed6c95036a1697a8d79e015b8519c9b01eaa072fe7ba295ebb789efdbf17e69c35e3afda2655ef2fbf28b89cb588a32378cc0e55cca43546e931c43dbf6d9d79955f48f8abcd093471f9872bdf15503399637911d96ce1880a4ba0fa0009cc5a984e9891ab9fb389d567db937ae4cbe7d99cb15b48027d2d105f4c1c0000000000000082530aa610efeb398a5aa6f130673fe2977f1053144f5ea4221aa1080f44427127b2b3dc14b4e7db242adf8d";
// ---- ML-KEM-768 v2 (whole-file AEAD, FORMAT.md section 5.1) ----------------
const V2_768_PRIV_PEM: &str = concat!(
"-----BEGIN ML-KEM-768 PRIVATE KEY-----\n",
"ogDy392L6RT7nBhtGSgOeE0+BB6Uiz9/drBlyzrgDd1sfdwC4faTUq0I/MhrBKne\n",
"I5VrS5cu734G6OHOPBnoxg==\n",
"-----END ML-KEM-768 PRIVATE KEY-----\n",
);
const V2_768_CT: &str = "5051464c020003802969ca6eba97e5fe808cf28582053ebf69f9d295d9ef0d6ded25ffaf7ec85dd4f5f217dcbbd510869b9f1339245b89367cd0b556c848084fb477989cbe437b831d3e3cded4fb8474ae3a31a22af8d3b7acdfb538d5f304616763231dd6b0dd26e7757800d644a496e1e1b25ca1e3354df886cdfc66761676f5da7ed7e801ee2e4d17317763256cc80f5c1a86ecb04bd06a556fe1fdca2473ef2c95a86f802ceaf0acf8bc6ebef3b2641b55c6fb9cf1f76430141ac0a843887a4995b7566b371c6d0da3c4240872110227eef8f935f92bece5b80b3c78cbdf0d47d9ea848211b018a9150e3775ba706c913af4da26f7d42661fb23f9e8449efa00dd92b1ed5d3979663335b96a4222f8293183eb6df17bfcb9554e7cf86a70fdf9f904bef814e671b3242366e5d23553c37e00f3d02ddea6ba9ec1b63f3c9d5381448275b9397690d7009aaaadcdcf8a7042d616f73fe84fcf6e5c30538c09025b05e00bc44be7fe11d50e5c089007c8cf8ffc4f0b18f6eefa365f7a68bb899ed0507a3c9c55a5497830926522cdfec3fa65adf7fe9f4268ad62260e634bd828173c3ffeb3438ef8653640ab89a9d0b5f1ffb0be7c1e2ea71344b9b5b8c3acb65d02b323a148cbd6f69ebb1785407da5bc40d1dcf8966e926dff27e90b16c9aee81293637d5bf3f7f23edeaf97c21fcacac15225e93183ad0b142ff9b0ea839e84e6ebbf034ba19ea2148e83332c8f9f743ab05c63d7cf5336a4bdee72d003fd6d0547b1c32a97c0eccabd2398b673ef43ce8e1d1460416d6b393c5afa6be5d1b948039c3483135b3ea74747c5f37ed6a8507dd4c356ab0822ca503b13a13593b80ec917de39df649f3240a12741b8be9dce56d1d9735cc5fce8794b518854693f27178222e5697de7172b1e38f88b84b1b08bd4f2c7918c482944229ccdc93071dbb517a4177b4f3daa8b2ac55eeb92122b82d8297bcc963e1d660c88f181b9f5b3b606a670633ff1fe45ef15cbaf190fd44c40825ace295e11b1f7a9099f43341ac185063e0c364442b784c6ecb3c46a687dce05d9b6c2e034af45b0d771f0a73e93017d8f98a413ef73c9c493f12c1f0af174ffbc8e2966050bdb091b33707d370b82582415be5e650b3842001c65af2531ae2a5d662c4b21f180291263658d06443ba3e17a088a1984a3d7d5308aa83d76304dd7cee2c008f3a55d8f7d8e5f009b69c2184c5b62a9ef245d9f73ad70d15901081b744e31d02ee84b8764a4fdceed98917bbb0f832e83eb583f556c8f49357271667e363d447d17dfa4013f0445d0feafd72f5ff6081b74bae79ae766287e0c9cd10b80967108fe524fa3eb3e948db66afa1e4395bc27c7308d5616262f8282d0335388cf76b96e8224063389a3764a39717e06f899255a5c509308886bc1017356638b8036e66b389aca1245ea4dd1acb6c80f8a04285077b36d46e8adbb09e1a781391986ea9c4577dbb97b30049396b6bb003bc55f8d32b6d71816f4e533d01a97c591ee0f9317d769a99f95e368ef1b003142e4ad5043d276861dee1c00000000000000014b11699c6128113da57a6ef2a559deb5db30b2e64798254b74e68b4362ff8b4a26653f9db3cf3a6c6d894a";
// ---- ML-KEM-1024 v2 (whole-file AEAD, FORMAT.md section 5.1) ---------------
const V2_1024_PRIV_PEM: &str = concat!(
"-----BEGIN ML-KEM-1024 PRIVATE KEY-----\n",
"0qSK8nEWgG4P+GT5ZyiW3BsMGGpSw3xWwOpAoEgpqsXSFYcI6BUMRnZjsa2/ZUC5\n",
"IPAF3qk2bsSY3QCcbtBD5g==\n",
"-----END ML-KEM-1024 PRIVATE KEY-----\n",
);
const V2_1024_CT: &str = "5051464c0200040edcf4933dded0e81fcfc3591d7999b819be6e930c30e58358c1e9d1cd44ff269460756b2257e66d6047571eeb521c19227e15f4fe7e6800cc59d084487b27f084e2dde7d165ceb85dc5dc1c6568051bcc7487057e974e853616a32559b2674472c4f683332abfc16cd7af93e41ec80d98a95d502fb0750b3360c4dcf06ef479d895d0ed5202d1c6cb30e13e64183ad2ef8547e48edad67826330b6e0c678c419d45725cd64a45ef92daba680c38f902fde0ec109ec88eb424f552d8d5ec449d0e1e5e4f07b4107ae9b92f94c047f143028b4d4810a85cbafcf738f0abbb6e4463bd2e9a7407ca06e032cd0f9eeaa0b995a6273984afa2ce0615f7546447600c98a453b1ed54347614af40c548b4743066d94051662d99d2eb683195075d43b08059f7a64bd7bbcea071cd35d1059299f811582cc8e6520a327a0a170bac8ed561c13002cf2a746e1d483dfdc37133d53cf91ce4314188fdaf3496608c7f64d5eb1585c83ecf91dda92fbf54b180bc9475dd1d0fbed15fad45acbe82ff29df35970c87aef2d0f796e5f60f788fc45ea8782389042a7ee62e85e099e025101f4f8fe9ad21aa6240742dfb2e8c119f3a7dc2b34c6a1f2237509faaca318fb4adfde2da040eb604ac6e75b2a2d8f2a52c0327059a74da79e5ee9d44cdc958e5302b1facb2922f8211dfffa66cfe60f18bb69f9b0bd3c252c3c46e59d7f27359e83ae81e0738c0b083deaf2dca8602769f9c8fca2a329f5c1b1e81b0d24d61aa1b0565550720627f7c0fe07b1aaf3b5befd4ac8fa3fe4f319accb762c21d261751639f7ad5c1c92cee9e5e19734d4bef175cdcb01f61a9975986fd801b7210c28c073f26895a4e98d97c6124086db6fbf0d97ca68600e2bce717669dfcabbfa72a7db6d833fe1485b9212d22ac75a96b280e44b422c66c98593dc84b051069d5c659ab1779f69e92827ca6aac47ed4e2b0bd11fdada74d7ccdbeef3d6b6a4bc28f42017fd0aa7d806a74ba1b450cb2a90d1646fdac43d1c8db42ad9648fb15936ae7e759d5b8ee38e072d49dbe43367e2c66303b9bb94cd66f2442620a638b3e4c4520e4970886ed5eafed8e3e30959c185feaed0d06689e4977ae329fb687340c372b1e901814d84f088cafa9a0e004894f992cccf615783d15546b344945b7de8ea32d2f4ad3beb33ce6e593cd4503ec8cb59fa40ed13ea3fa6e737d43d7ccf01a21faeb9a3c9e0f5c9c0f1c015d3463fac5161160be66b20c2717064de84a38d4bfad7567f503736d8c08a1b4557a55a33efe85570bcecb0798ed9442fd007f22aecffb52a4dd7fa3fdd8d5fd2c9d13cddaca368121e3c259bda64adfdbc26ff18f69e86f348a514d1738b899bf55ef19ae37b1f39ed19b72df283a5117c16de24d957af68101e4e467e10dcbd6238da54694188f480f672e31f5756104d7bb97fd0fd01c255efc165d700d33aa50cedba7cb11479f3d7c16ffef0b285e9bcfa99b706e4177a218e074ccc264ea4a1163ac8d3a390048bbaf6b6e3359d328e3c171240fdb20fdfaf6bd33570e6d4ab2cb338f6afcc4790a59e3fa0b617a1dfc35274f73132c36f821cb2385d9ad271fe855718cdafa68674c1d95d4fdde39675f659888b2b05dfd38bc94e8797c406182eb21f4f692e5bbd4f63db514324195e99f81c84aa14c37743b0961330fdbf165098cae29e889ee58cf012cea1520b567850f0864aecc4869a0193cb04002d312800a2f331e7519b13702836c1fbc9a83731f1a7bb9926518427b2404de5ebcba7683156238946956d0e16a7ef33074e03dee35cd7d06c8aaeb60968dcd95009c86f3929fb76165437bd31b27ed128840da7cf3842673239ed7a86a30bcc720d30a0f8f77c6392291657a7b9edeae9a10d3e79b504ac2b76ec57f19f2dfb32c2b37804f0eb17c4e7ec12a8d80ba788975a7fc7a3363be75e51bb5a153dcd556b6c77a95a43e302ed547e32daa50f44fe098adb50e70d913adfab9b2823535c2fd85e89e200a83c33630e7f54348b01b415de9d96a323f414463986ee06957cf9c881310779f25d2bdaf515dc43265ed0cae5816b14b19802918345c777bfef7f1b5131457ddd0008efc2cfe12d6bc4b86c6b7f42e070ae3544d5a4d9d7f5399f0232181e92597bef899d5ca56fcb9afccd6e813da7f51bb667e6b6d4a503bda0f3dc9c91b2fd1cd2ea570b5c6087ca79ed992001e30889d6bec8fa59d1c00000000000000c0f276038d1587b46d405099ce11348ec85611f3dc92bd61d5d6364dbca17924d11a835457a7fefa19341564";
// ---- ML-KEM-768 v3 (64 KiB chunked STREAM, FORMAT.md section 5.2) ----------
const V3_768_PRIV_PEM: &str = concat!(
"-----BEGIN ML-KEM-768 PRIVATE KEY-----\n",
"IbiQWIbEZuuwcv+0Qfu5Fx3s8JeZiLAImw5YdI6XelvHvDRIed6qZxT7hcGojC7T\n",
"pAZR3g2O+3eIP2mt/Nll/A==\n",
"-----END ML-KEM-768 PRIVATE KEY-----\n",
);
const V3_768_CT: &str = "5051464c030003b51f8a37a8068e3a22aafdc2f30c7a4ee5255183b7ae5ad4795c5140820e07532fbdacf80995a76709fb0e3e938268bc548d95b55815921fa5c5c532e98a973c78d1388c3abc2b78d1cfe74d48b9fa16202734bc24d4a3461f7cb3d1dcd8c6f190ea7eabee0328015c57d7732dd2c3ac28fbb25db4f7761da4bd6763b3cec8174b6e35cd7a9b4e03e4dbc876fe0cea40ce69322775d7666cccc77cb144fc2f5ed18c647c785ff38f69d5713cba3711d958d6ec495a2650c9f8ad5e7f330c3b8dd591a8089e20c7328eff64027d7b986c1c8a6f1b1d5a3645e1c10675345b67afbb6d3eda6e24b6a796a2f7973b9e454ce8aae6320557468e1a5b1c4ac881bbb8bd664eea9637dd91ffff6287e575e4c659eacd9bf5eec4f858bfcee731cd48ac257e2a802ee4b9ae1fb67ca226ce2e4a89e3bb9498a39e98d45f1cabee644b98e38f20c320d5b7b7e5f99cf06a869a00988286f58b816808a264e92f937923d8e0cbe657548c2150204f995cfb5b245ad5abf311e9e58b9ed5e096c92b9ac6c787f7920d3ea815a909bf2d25ede0d6c827ce96462d4599ae1c4e63170cfb7795b29c5f22158079363cd19bef0e6937d5f8f67df7c1ef7fa7ec1e71313f77edcbb07de679bc3a261ee5abf401690af0e35f667404aff9e805e3ac9e050514ee4fd01e208faa8f0c0f1ed2931eba6d4cbb75ce756e27f4d1535c6e044b21906ab12395958cd13950f7678604d4c7da0c0572ff6db9edc086e2b3941bbb4bac9ab41c451829a345b3e6f9d548a55518c94acd7eb92b501648378ae02a037e04d9890c0ce31daf07bfe543bd2ed8f576610653daf18cad3cf4571050096f6f25144924a22314d95b5004d2afb714df90bebd3182785cbd1338c64ee2572707cfdc64d74b7e6d2a6649b3f119d95370a12e60bbbeebda50c0e136e006ec9278c50ba066d741b15f5d722e97f865220ce5406757bab53c81844ccd36d4883155db457a3f72b83627be7effbe80ead1bd8962cf60a83452186bde2cf5a6c58b5c760c47bcf49db49e64b4ad2b074953f5dbc314f804531f5aa886a22a8450509b1841924760d3b0535f17c90b116f67c536ee9fbb5c10005e5c8971d394a975dc607c08fcc1e7cbc7cf3d30c1763b890ae2f716963bf8d80288947364d291d3479bfbf762ea290d5e6cdbad5a24a8705ccf3b348b4e088e85c7b59303914c26470d1ca1c2b0125bc0a612f4974c9b1afd9df4de08418deea817df13c92e5a7d3989c75f7dc2bf75f2521d16d0e030527e87a3d52fe9ac28b8c15d46c5accd3e7b18e6753a74b2737e9b2f4dd4af0cca636e2b46e20f392ca91c51b53e873b8e198c52dd5765ccd65d43816d69ca2d35f95123d3cae8e3a5277197537caa2fff877c70de193f618a87bcf3206543cf5244fdb22d214528bb64bb6879cb3796c9743aa9faba76a23bdac000adb199fd0a8982bed1a2c6b8f7dce007c811c00a230c578ba76195ca04ae3a532465313b3647aeb8d1256607081872d4ee0d83864d6be2e9434ce2737248568d12000000001c00000000000000d9fe5128747e4bc8638decac6db307c971b76064dba7e7b6da6cd39a66a17fd3639b41e4bdfdfa1eca1b19a7";
// ---- Hybrid X25519+ML-KEM-768 v3 (FORMAT.md section 2) ---------------------
const V3_HYBRID_PRIV_PEM: &str = concat!(
"-----BEGIN X25519+ML-KEM-768 PRIVATE KEY-----\n",
"bf2vjIpkDgcDy4SffaZLD2SrZ9GDVKEB17nDjKQgK5GBsVobnILI/61r1qXA8TU1\n",
"4r8ViBSQE6nckQ4kPr6i/4WbT3QEpX1e97IOJNn+0rQIebBg6I3QZcNspyuqg1Y3\n",
"-----END X25519+ML-KEM-768 PRIVATE KEY-----\n",
);
const V3_HYBRID_CT: &str = "5051464c0301030d2725f4acea95715f21ead29e2592354b30c3dc2532bff02589a00ebd7e9319e572fe2e91f315cae03451b642f25131db2bb3f052f9b5be0f8dd307db17ef4e30b3251191ee4ee79d55649de8ca0c1bd5db3f6ad951f382cab1264343c12bb828651929d752361d1d700efafdeb10669de638c049f6e45368dd6b004a1796f9d1c7633db37be36ed4b73da09bd8bc29a66e76acbc4d8ac220ab894d8ba74cb4600796e28236bec8b07dcb15520f45e27787f1b3beaef86fa2321b041860831a00a1db99107d10d83fc87234d65f1ec1bdb4ae7790d741ae79b6741bd4ed54cf2d5a470a9f8c9fdefa3a89f123fba989fb6a1fcbcd49bae4323085a05501ad7fc0113dfddc24e0ea2ec522c4c062ff0254b26eb0ec67c59e59f0e2964081790677c18a2c3228e48092c9158d7f6bb88ad4f9089c92d5cdf2d746c1a42d1aa2937fa0af1167724b90b98ea1b5ce5cc12f108b31e1ce50cfe21e31fe5eb89a00769cc992165b4fd64233289914d56610d8a89c66f3357fe768c53150b1754f571787c3b9490979c508f05ce6cce31645b02ce77e3474edf729a5f6d70746aef502bd14110d3e396c44c9bf46fb1df2aabe9cfceb969ba59af77a2612d89d9951132493fa04963368b9896ac4c8228874f51d8490e3befcda92e25ceb03379a3042ecfc4aaab2662a4a66e6639951509611938502778bddd0fc8b8d9e97fdda9daa4c54e9b880e39526b02e114091f8e03ab4fc1a9ada586d9df8427c42cedfcd6f16f6844b12cb39da8ebd449a5f955651e5bf0dd599110b2eb1fe9dd66fc388677bac8d16545fb912c774b7fc6282c769f5f662451da354287c6b9e56d8fef632025db844b72a997d35375e1bc6f87c16cf485170fff3748f2696c551421e19696808a356d84ee69d91978dd06f4e9f249e71e4a9fe6d2a4aa12e587b0bbde2a0a84f3c9f5c9bc4c961be4c61fdf68347e9883d279223b722c5ef02f26ab7c68a24adc1170c073d4412e3f89af9a6ceeb60a161554f77fdf6b15eec496a871e7175892d0eceb9e163ede3f2ebf5a922265f9a2271945c452439606858c4e34455e32dba648fcbbf114b29388bda65b6f6780f49bfd5a7c0451d9f337715fda86a44e450bb8d6345b3ddeaf9b381d2a3e9ca60f1a24a5f7e2d3d3152e663ce1b2e218a509daabc3eb75ee648d7dbbb096915d5a5a93767ff7a02d4ca22dfa6836fa9645c901975e9c8700411e3b49a007de86d06da7cf2c5a626cd2a6705863060240b0c7c217533ceab349405b723fe3ddcb4794e980a74ba1f4acbf2ca6d2d535d605c743f275e52d863ffed66f79e65cf286bbdca6971bf4a6362502ad69ad23bf66a44d295390941864291319f013f77c966dc7653cc2163b300e079bfd8db8dbb4dbeb0084a1ba5a59271e73f0b032aafa13b5d3de487652f7659c95cdb7f361f1bd8ce61ec5d5b6a8239107d41abc43371fd820926e062a60706cae9d9ba64aa627b43eb447d5bb2c8c141aee9b66083ff44484d276905b335fe230248f92d027eb88944794f359c99ade49ba9d8ffac11bdad5b3f1a4432ef6d85451db99c80af17f46ad0fd000000001c00000000000000db939f8082f777df908258d248d23ed90fbd3519bbe2d41654576498bbbbb98e5c119bfe24ef59244ef04d8d";
// ---- ML-KEM-768 v4 two-recipient (FORMAT.md section 5.5) -------------------
const V4_768_PRIV1_PEM: &str = concat!(
"-----BEGIN ML-KEM-768 PRIVATE KEY-----\n",
"+YoV9uusZ7SlRwYXG2X46u4RhJ+DsxTSaBNz629wc7ZKYuKSUAB1Zq2qqD6lYMjC\n",
"FFlCF5dvLSpGe7jCcR/mvg==\n",
"-----END ML-KEM-768 PRIVATE KEY-----\n",
);
const V4_768_PRIV2_PEM: &str = concat!(
"-----BEGIN ML-KEM-768 PRIVATE KEY-----\n",
"STZSoMd8RAsgZmtaaw47Wuua2e3DVqxvwn92aQHdK73R0oQ0/21QAKhFMIC+lVze\n",
"GYqJWoe+7tHN255ls5+rqQ==\n",
"-----END ML-KEM-768 PRIVATE KEY-----\n",
);
const V4_768_CT: &str = "5051464c04020000038af49e8efc82c04574192063029c869be8e05a5cf7558de0457dc59ad6b3c621691aa060aae498a2f04105f3558288822aa8d0061aa20f214888b32f1a2509c6eb308e9f01e221aef1b5e324b2974f53d069101ed23703bdd9dcea4ffcfda0b8573f764eca205e038aacb48f93773c2df1c8d5fe2a6e0d1c58b56dc1fa369f8bb2e77fbf9525561689948b394849b0c3e852ebdff63f8fe127c62ba20a52e4b3e184d0c175fc02e81f0a1d0a268805999d16c3b7e6c519138df60aaf3e42b90c5d72fa774a8027c1ac5ef70283abe1a7a4e10e4cef837c1032102cc428b4f7f4d0dcdb5459ce64362d82035410f2fb21def61114043ba7e81a71f089868667617f0d62e2e71c6570cc42a39cf2f2fb6529b2ec6b254fcfd05a6092c8d9104e1323b832ba5e8116118ed8e1efa91d7c07c64cc14ea9a219d23d19701d56d8d75efb267eedaf5abcaf3cfabbfc077f195bc75d0780fcacf6a0d54751ff288519d7649740a6444a0ebd532f252c5258f212360ba557fc3b7036535229f738ea231e3322b8c434a4e34d67aee9889c0ba658a31a9b48016b3394d3d127402bbbf655b108b18bb2640bf4572c0e4f5059c5f482dba410888bde5e227bfaa14441d1c3d05622b3975d0625e214de7ed42a26a2af9d0fceefd119cc4a7eb62badf33e23b43ff24082d4a6ef5693850eac38a531074371710f710d8495834a2d8e3aadf45cbe0b18896bc75addc7a628ef7b9e67bee0c5b7fc32ba02f195b0c05707dc13ef84de0ffc7fc0ec1b7adb51678c91cc4bc14d2496be67ed98cedf8df61c3fe5c1b2f9fd87a7623f1e158518a89bcee0cb479bd8516747f4be94a194e244550014251396baf2615b273b1fde1eda68853c2f5fa8d6fa72523139a48afc3483b049ca8e4f81fcf86280071a1bf269d771b543788828aaa0ac1bef33b12b68506bcd981557e48464879641c97bdcb4658626ebf704301367518a8f453723e258bd47488e55f5c9ca584c9dabd76361894a8e2ea25d714e4910aa096dc765872c5dd95e14d5686fcc23ab0e0bd80434f63ff59db78336b2ade57de57431b3edd5d2175277a8f9850d846eaab3d097c85e358b05f016d5a369ebe4024e1c1860b0de0dff4fb4944e508c6164a7d03457b966c891733a62607ceda74dd845246c2b989b7a368abf7b683c77d6bc1212936d993ee5ff4c3779e8ea750ca2a31ef473dd9500f6ff9c096ad9d682d86518850afc05d07724dca1d38cdeb67d89ae8c89155d2718712f2582508126ae1d3931e198080f2c794e290dbd9b13424ee189c16c5f62720f8557cf5af077fafcbcbfb592c1821035ac092da41e508275e74a091fd411f35073dad0b3d4e0744f16ca3c1412854801cc22e68996ec63cce2597c0b08b5252018b170e499641b04bebcb1b6989cdaa0479fb57e103bfe1a8176f5278630c4b56d40b555fb15e7f1aee25d45630f171b327fbf6c98fee1d8d1e14cba08c8c5b4f8bcb570d8c377411426a12b2292cc92316ee4c4af57f6b5664aaba6bec6dfdee083ec6765bcf7a5bcb5a8be898fe51e6105bdfe6b9e9fa3b7aec17658e06b21e2f7c5feeb670b654ea78af80003342417f87361b9161ff23fb9b5ddc95c2f1f18de5f79aeb110504c7a7779cf481ed79dc678915851bb88dae4a26c8f044473ff57c33dd9722d8aa58f3056fb17d14696de31e362d582f80475cf8f77590ee4e63eb0fe4a7511bbaf83990a862ebf28c1b53432b6c4b887402196eeeb57b22b4f8a7b6b869bbb17f080bf3876863e26e85dd4a280a8ffe9bffa6c5baa990da48ceb60ac6e59f78b404c680f41fb8925dba5e9643194dc994505236092510f1de0246d688867755399697bb37a5d6cbbde294b12c35fdb974a4b1d842601015e6f4b836b3f6faafd2e734f6c2a4546d122697506580bb02945be1d369d6e684c4a2d971ad2d69a886fdcaa2459ac93ce4138b1228269c09d694c61fb74c273ceb0969878eb4e45b4d182504868d1225db470c406c8996a36bc6653607d4423734b5d1d730f840df3b16d1c4b37171fb0068fd30bfa767a85c7ecd26a0b55d671a3877d8d0b213e4cc60a6348b69f0b70303930397371e2cd2ae1d6c07060aafcd486a537287f7270144429b6128f166a56dc56b9911dfddd7e7a0919e53b2f8f98c91f6ae79ef821d3fe1dd0c987057e02e1753b3daf1ccaab2698611b117918fff1773bbd7290072a042b13a3a19c79df2e6e682923ab178c071f997c16cf923564c814136c7ca7fd915227fd159cb6059ab2dc57fe350637eb5f574fa6e5984037254a1c0996b4b9e5607fbb3915ce0936e09c4914a3b35ca7e3e360d1bf00fac565bab0f5577619462c102491ecc46237cc73630bd2ca66a33bdc8af864909f89af372e6c8df1615fed8f811ab5b97d850a13442e6194a861041364e0f4ed4fc1337526785bb4a465785f8a3236066fff2ac61ee89fecbb99922e5aaac8cff4882cd43287acf1394b508d3b7126076197393824a06b23fa925d101e215af8565a410a7a38516adfbf6b6ed91e7f9ce30f3e27a158e70515975db9cf39d080b9a779b59234c2184dd465036b8607d47c05bd257174b192ea0331ed75276ead2cf4b35934441b650b4013f882a870b461d54cbf2bf5402f41d61597572169ae0a4b2cf7dc1ef65d00067029ba57b591065f6c187d2ec29f88adf48479e2f64cd483bc35499b9c8285fbeab6e285f432c75b0c9b14c1df8fad9bec7db1bcf8910047d15d53cd810420db08ef95e62c51c6bc41a4276f243f54bcfa952826aadd084c3c712d00ae6fe4916c037150cec7d34c9ae2e62db15e1498c7c32536785a4a67c726dd8b062d7251a3837b0145040291a941650f2cc0d31388802e6091fbb105ef777f517216abe206c67f4a7f77ca103d38a9bc60d88cf5668e1ece1b99eb0ff061545851bbe39a021937f544ab3b8ad5f396a9db0a173cf597cb505695015d730a8f6e97a729c818db88fd2e683c2412471d580d71a941cca53e14d53a0cdceede829e30b7dc268b507e5df45162b533717363ef23dfd205a7088bf8ebf52956969076d6441bcd8a1e33591a83f1a88aaacdcd0942f6355d072c630f23bf0a66214f241186caa16d179d3e075252bc379422043d771a16f387b0dd4454631f2b4f1480729fc00e1bd3f7477f1660afabf9cbbb15c2ce13e52e58fac9a196964b3dd198000000001c00000000000000014eaf51d13960b558f4de90dc1b30082cc72e62754e2adc6ecb6e59ac1182dc27bd1024c0f7ae91da93c6b9";
// ---- hex decode helper ------------------------------------------------------
fn hex_decode(s: &str) -> Vec<u8> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
.collect()
}
// ---- v2 decryption tests ----------------------------------------------------
#[test]
fn static_v2_512_decrypts_to_known_plaintext() {
let ct = hex_decode(V2_512_CT);
let mut out = Vec::new();
decrypt_stream(V2_512_PRIV_PEM, &mut ct.as_slice(), &mut out, None).unwrap();
assert_eq!(out, PLAINTEXT);
}
#[test]
fn static_v2_768_decrypts_to_known_plaintext() {
let ct = hex_decode(V2_768_CT);
let mut out = Vec::new();
decrypt_stream(V2_768_PRIV_PEM, &mut ct.as_slice(), &mut out, None).unwrap();
assert_eq!(out, PLAINTEXT);
}
#[test]
fn static_v2_1024_decrypts_to_known_plaintext() {
let ct = hex_decode(V2_1024_CT);
let mut out = Vec::new();
decrypt_stream(V2_1024_PRIV_PEM, &mut ct.as_slice(), &mut out, None).unwrap();
assert_eq!(out, PLAINTEXT);
}
// ---- v3 decryption tests ----------------------------------------------------
#[test]
fn static_v3_768_decrypts_to_known_plaintext() {
let ct = hex_decode(V3_768_CT);
let mut out = Vec::new();
decrypt_stream(V3_768_PRIV_PEM, &mut ct.as_slice(), &mut out, None).unwrap();
assert_eq!(out, PLAINTEXT);
}
#[test]
fn static_v3_hybrid_decrypts_to_known_plaintext() {
let ct = hex_decode(V3_HYBRID_CT);
let mut out = Vec::new();
decrypt_stream(V3_HYBRID_PRIV_PEM, &mut ct.as_slice(), &mut out, None).unwrap();
assert_eq!(out, PLAINTEXT);
}
// ---- v4 decryption tests ----------------------------------------------------
#[test]
fn static_v4_768_recipient1_decrypts_to_known_plaintext() {
let ct = hex_decode(V4_768_CT);
let mut out = Vec::new();
decrypt_stream(V4_768_PRIV1_PEM, &mut ct.as_slice(), &mut out, None).unwrap();
assert_eq!(out, PLAINTEXT);
}
#[test]
fn static_v4_768_recipient2_decrypts_to_known_plaintext() {
let ct = hex_decode(V4_768_CT);
let mut out = Vec::new();
decrypt_stream(V4_768_PRIV2_PEM, &mut ct.as_slice(), &mut out, None).unwrap();
assert_eq!(out, PLAINTEXT);
}
// ---- byte-layout spot checks ------------------------------------------------
#[test]
fn static_v2_512_magic_and_version_bytes_are_correct() {
let ct = hex_decode(V2_512_CT);
assert_eq!(&ct[0..4], b"PQFL", "magic");
assert_eq!(ct[4], 0x02, "v2 version byte");
assert_eq!(
u16::from_le_bytes([ct[5], ct[6]]),
512u16,
"KEM_VARIANT 512"
);
}
#[test]
fn static_v2_768_magic_and_version_bytes_are_correct() {
let ct = hex_decode(V2_768_CT);
assert_eq!(&ct[0..4], b"PQFL", "magic");
assert_eq!(ct[4], 0x02, "v2 version byte");
assert_eq!(
u16::from_le_bytes([ct[5], ct[6]]),
768u16,
"KEM_VARIANT 768"
);
}
#[test]
fn static_v2_1024_magic_and_version_bytes_are_correct() {
let ct = hex_decode(V2_1024_CT);
assert_eq!(&ct[0..4], b"PQFL", "magic");
assert_eq!(ct[4], 0x02, "v2 version byte");
assert_eq!(
u16::from_le_bytes([ct[5], ct[6]]),
1024u16,
"KEM_VARIANT 1024"
);
}
#[test]
fn static_v3_768_version_byte_and_original_size_are_correct() {
let ct = hex_decode(V3_768_CT);
assert_eq!(ct[4], 0x03, "v3 version byte");
// ORIGINAL_SIZE is at offset 7 + KEM_CT_LEN_768(1088) + NONCE(12) = 1107
let size_off = 7 + 1088 + 12;
let original_size = u64::from_le_bytes(ct[size_off..size_off + 8].try_into().unwrap());
assert_eq!(
original_size,
PLAINTEXT.len() as u64,
"ORIGINAL_SIZE matches plaintext length"
);
}
#[test]
fn static_v3_hybrid_variant_field_is_correct() {
let ct = hex_decode(V3_HYBRID_CT);
assert_eq!(ct[4], 0x03, "v3 version byte");
// Hybrid variant = 0x0301
assert_eq!(
u16::from_le_bytes([ct[5], ct[6]]),
0x0301u16,
"KEM_VARIANT hybrid"
);
}
#[test]
fn static_v4_768_recipient_count_is_two() {
let ct = hex_decode(V4_768_CT);
assert_eq!(ct[4], 0x04, "v4 version byte");
assert_eq!(
u16::from_le_bytes([ct[5], ct[6]]),
2u16,
"COUNT = 2 recipients"
);
}