diff --git a/recon-silly-ation/wasm-modules/Cargo.lock b/recon-silly-ation/wasm-modules/Cargo.lock new file mode 100644 index 00000000..e759e5ce --- /dev/null +++ b/recon-silly-ation/wasm-modules/Cargo.lock @@ -0,0 +1,1603 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures 0.2.17", + "password-hash", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bon" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" +dependencies = [ + "darling", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + +[[package]] +name = "caseless" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" +dependencies = [ + "unicode-normalization", +] + +[[package]] +name = "cc" +version = "1.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "comrak" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab87129dce2f2d7e75e753b1df0e5093b27dec8fa5970b6eb51280faacb25bd6" +dependencies = [ + "bon", + "caseless", + "clap", + "emojis", + "entities", + "fmt2io", + "jetscii", + "shell-words", + "syntect", + "typed-arena", + "unicode_categories", + "xdg", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "emojis" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e1f1df1f181f2539bac8bf027d31ca5ffbf9e559e3f2d09413b9107b5c02f4" +dependencies = [ + "phf", +] + +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fmt2io" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b6129284da9f7e5296cc22183a63f24300e945e297705dcc0672f7df01d62c8" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hybrid-array" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9" +dependencies = [ + "typenum", +] + +[[package]] +name = "hybrid-array" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d15931895091dea5c47afa5b3c9a01ba634b311919fd4d41388fa0e3d76af" +dependencies = [ + "typenum", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "indextree" +version = "4.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cee462cd93b03891663339b59a21246cc5fc2cc95060d0bb5059e25cd50edc4" +dependencies = [ + "indextree-macros", +] + +[[package]] +name = "indextree-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f85dac6c239acc85fd61934c572292d93adfd2de459d9c032aa22b553506e915" +dependencies = [ + "either", + "itertools", + "proc-macro2", + "quote", + "strum", + "syn", + "thiserror", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jetscii" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" + +[[package]] +name = "jotdown" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5afa77b05ee2811a1c1f4d6b7dce44b65bad966c81072e55ea604d084ad4162b" + +[[package]] +name = "js-sys" +version = "0.3.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures 0.2.17", +] + +[[package]] +name = "kem" +version = "0.3.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8645470337db67b01a7f966decf7d0bafedbae74147d33e641c67a91df239f" +dependencies = [ + "rand_core", + "zeroize", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "ml-dsa" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac4a46643af2001eafebcc37031fc459eb72d45057aac5d7a15b00046a2ad6db" +dependencies = [ + "const-oid", + "hybrid-array 0.3.1", + "num-traits", + "pkcs8", + "rand_core", + "sha3", + "signature", +] + +[[package]] +name = "ml-kem" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de49b3df74c35498c0232031bb7e85f9389f913e2796169c8ab47a53993a18f" +dependencies = [ + "hybrid-array 0.2.3", + "kem", + "rand_core", + "sha3", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "onig" +version = "6.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc3cbf698f9438986c11a880c90a6d04b9de27575afd28bbf45b154b6c709e2" +dependencies = [ + "bitflags", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e68317604e77e53b85896388e1a803c1d21b74c899ec9e5e1112db90735edd7" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "orgize" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4998a8f863c00c06e18f83ed3c4de39e01f5a7ee5bddd072f0fb31bacfd7fa" +dependencies = [ + "bytecount", + "indexmap 1.9.3", + "indextree", + "jetscii", + "lazy_static", + "memchr", + "nom", + "serde", + "serde_indextree", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plist" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" +dependencies = [ + "base64", + "indexmap 2.14.0", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "recon-wasm" +version = "0.2.0" +dependencies = [ + "argon2", + "blake3", + "chacha20poly1305", + "comrak", + "getrandom", + "hex", + "hkdf", + "jotdown", + "js-sys", + "ml-dsa", + "ml-kem", + "orgize", + "rand_chacha", + "rand_core", + "serde", + "serde-wasm-bindgen", + "serde_json", + "sha2", + "sha3", + "thiserror", + "wasm-bindgen", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_indextree" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a70e7d58005454b0ba863a8775df0c4391a8128c3a34974001de556d661bf74f" +dependencies = [ + "indextree", + "serde", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syntect" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" +dependencies = [ + "bincode", + "fancy-regex", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/recon-silly-ation/wasm-modules/Cargo.toml b/recon-silly-ation/wasm-modules/Cargo.toml index 3199c944..5cc0ff97 100644 --- a/recon-silly-ation/wasm-modules/Cargo.toml +++ b/recon-silly-ation/wasm-modules/Cargo.toml @@ -16,6 +16,23 @@ serde-wasm-bindgen = "0.6" thiserror = "2.0" js-sys = "0.3" +# --- Real cryptography (security.rs) --- +# Audited / community-reviewed pure-Rust RustCrypto crates. Pinned to +# patch-stable releases. ml-dsa/ml-kem are the pure-Rust FIPS 204/203 +# implementations (used instead of C-backed pqcrypto-* because this is a +# wasm32-unknown-unknown cdylib where PQClean C cannot be linked). +sha3 = "=0.10.9" +blake3 = "=1.8.5" +argon2 = "=0.5.3" +chacha20poly1305 = "=0.10.1" +hkdf = "=0.12.4" +rand_chacha = "=0.3.1" +rand_core = "=0.6.4" +hex = "=0.4.3" +ml-dsa = "=0.0.4" +ml-kem = "=0.2.3" +getrandom = "0.2" + # formatrix-docs integration (local path for development) # formatrix-core = { path = "../../formatrix-docs/crates/formatrix-core" } @@ -24,6 +41,11 @@ comrak = "0.49" # Markdown (GFM) jotdown = "0.7" # Djot orgize = "0.9" # Org-mode +[target.'cfg(target_arch = "wasm32")'.dependencies] +# On wasm32-unknown-unknown getrandom needs the JS entropy backend so +# the CSPRNG used for ML-DSA / ML-KEM key generation has a real source. +getrandom = { version = "0.2", features = ["js"] } + [profile.release] opt-level = "z" # Optimize for size lto = true # Link-time optimization diff --git a/recon-silly-ation/wasm-modules/src/security.rs b/recon-silly-ation/wasm-modules/src/security.rs index 5e9e19c6..08c8f3d1 100644 --- a/recon-silly-ation/wasm-modules/src/security.rs +++ b/recon-silly-ation/wasm-modules/src/security.rs @@ -2,195 +2,291 @@ // // security.rs - Post-quantum cryptographic primitives for recon-silly-ation // -// This module provides WASM-exported stub functions for post-quantum -// and modern cryptographic operations. Each function is annotated with -// the algorithm it will implement and what crate/library the real -// implementation should use. +// This module provides WASM-exported cryptographic operations. Every +// function is now backed by a real, well-known audited (or community- +// reviewed pure-Rust) implementation from the RustCrypto ecosystem. // -// Current state: stubs that return placeholder values. The signatures -// are stable and match the ReScript external bindings in -// src/SecurityScheme.res. +// SECURITY NOTE: This is a security-sensitive module. No primitive is +// hand-rolled. The crates used are: +// - sha3 (SHA-3 / SHAKE256 XOF, SHA3-512) +// - blake3 (BLAKE3) +// - argon2 (Argon2id, PHC string output) +// - ml-dsa (ML-DSA-87 / "Dilithium5", FIPS 204, pure Rust) +// - ml-kem (ML-KEM-1024 / "Kyber1024", FIPS 203, pure Rust) +// - chacha20poly1305 (XChaCha20-Poly1305 AEAD) +// - hkdf + sha3 (HKDF-Expand/Extract over SHA3-512) +// - rand_chacha (ChaCha20-based DRBG) // -// Real implementations will require the following crates (not yet in -// Cargo.toml — add them when moving beyond stubs): -// - sha3 (SHAKE3-512, Keccak) -// - blake3 (BLAKE3) -// - argon2 (Argon2id) -// - pqcrypto-dilithium (ML-DSA-87 / Dilithium5) -// - pqcrypto-kem (ML-KEM-1024 / Kyber1024) -// - chacha20poly1305 (XChaCha20-Poly1305) -// - hkdf (HKDF key derivation) -// - rand_chacha (ChaCha20-DRBG) +// The pure-Rust `ml-dsa` / `ml-kem` crates are used instead of the +// C-backed `pqcrypto-*` crates specifically because this crate is a +// `cdylib` targeting `wasm32-unknown-unknown`, where linking PQClean C +// code is not viable. Both crates are `#![no_std]` and wasm-friendly. +// +// Public function signatures are unchanged; only internals were swapped +// from placeholder stubs to real implementations. use wasm_bindgen::prelude::*; +use argon2::{ + password_hash::{PasswordHasher, SaltString}, + Algorithm, Argon2, Params, Version, +}; +use chacha20poly1305::{ + aead::{Aead, KeyInit}, + Key, XChaCha20Poly1305, XNonce, +}; +use hkdf::Hkdf; +use ml_dsa::{ + signature::{Signer, Verifier}, + EncodedSignature, EncodedSigningKey, EncodedVerifyingKey, KeyGen, MlDsa87, Signature, + SigningKey, VerifyingKey, +}; +use ml_kem::{ + kem::{Decapsulate, Encapsulate}, + Encoded, EncodedSizeUser, KemCore, MlKem1024, +}; +use rand_chacha::ChaCha20Rng; +use rand_core::SeedableRng; +use sha3::{ + digest::{ExtendableOutput, Update, XofReader}, + Sha3_512, Shake256, +}; + +// ============================================================================= +// CSPRNG helper +// ============================================================================= + +/// A cryptographically secure RNG seeded from the platform entropy source. +/// +/// On `wasm32-unknown-unknown` this resolves through `getrandom` (the +/// consumer must enable the `getrandom/js` feature, which is wired in +/// `Cargo.toml` via a target-gated dependency). On native targets it +/// uses the OS CSPRNG directly. We expand the 32-byte OS seed with +/// ChaCha20 so all downstream key generation draws from a single +/// well-defined CSPRNG. +fn secure_rng() -> Result { + let mut seed = [0u8; 32]; + getrandom::getrandom(&mut seed).map_err(|e| format!("entropy source unavailable: {e}"))?; + Ok(ChaCha20Rng::from_seed(seed)) +} + // ============================================================================= // Hash Functions // ============================================================================= -/// Compute a SHAKE3-512 (Keccak XOF) digest of the input. +/// Compute a SHAKE-512 (SHA-3 / Keccak XOF) digest of the input. /// -/// Real implementation: use the `sha3` crate's `Shake256` (or a -/// SHAKE3 wrapper once standardised). Output should be 512 bits -/// (64 bytes), hex-encoded. +/// "SHAKE3-512" denotes the SHA-3-family extendable-output function with +/// 512 bits (64 bytes) of squeezed output. Implemented with the `sha3` +/// crate's `Shake256` XOF. #[wasm_bindgen] pub fn shake3_512_hash(input: &str) -> String { - // TODO: Replace with real SHAKE3-512 via the sha3 crate. - // use sha3::{Shake256, digest::{Update, ExtendableOutput, XofReader}}; - // let mut hasher = Shake256::default(); - // hasher.update(input.as_bytes()); - // let mut reader = hasher.finalize_xof(); - // let mut output = [0u8; 64]; - // reader.read(&mut output); - // hex::encode(output) - format!("stub:shake3_512:{}", hex_stub(input)) + let mut hasher = Shake256::default(); + hasher.update(input.as_bytes()); + let mut reader = hasher.finalize_xof(); + let mut output = [0u8; 64]; + reader.read(&mut output); + hex::encode(output) } -/// Compute a BLAKE3 digest of the input. -/// -/// Real implementation: use the `blake3` crate. Output is 256 bits -/// (32 bytes), hex-encoded. BLAKE3 is used for database content -/// hashing because it is parallelisable and extremely fast. +/// Compute a BLAKE3 digest of the input (256-bit, hex-encoded). #[wasm_bindgen] pub fn blake3_hash(input: &str) -> String { - // TODO: Replace with real BLAKE3 via the blake3 crate. - // let hash = blake3::hash(input.as_bytes()); - // hash.to_hex().to_string() - format!("stub:blake3:{}", hex_stub(input)) + let hash = blake3::hash(input.as_bytes()); + hash.to_hex().to_string() } /// Compute an Argon2id hash of the input with the given salt. /// -/// Real implementation: use the `argon2` crate with Argon2id variant, -/// memory cost 64 MiB, time cost 3, parallelism 4. Output is the -/// PHC-format string ($argon2id$v=19$...). +/// Argon2id, memory cost 64 MiB, time cost 3, parallelism 4, 32-byte +/// output. Returns the PHC-format string (`$argon2id$v=19$...`). The +/// `salt` argument is used as the salt material (base64-encoded per the +/// PHC `SaltString` format). #[wasm_bindgen] pub fn argon2id_hash(input: &str, salt: &str) -> String { - // TODO: Replace with real Argon2id via the argon2 crate. - // use argon2::{Argon2, Algorithm, Version, Params, PasswordHasher}; - // let params = Params::new(65536, 3, 4, Some(32)).unwrap(); - // let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params); - // let salt_obj = argon2::password_hash::SaltString::from_b64(salt).unwrap(); - // let hash = argon2.hash_password(input.as_bytes(), &salt_obj).unwrap(); - // hash.to_string() - format!("stub:argon2id:{}:{}", hex_stub(input), hex_stub(salt)) + let params = match Params::new(65536, 3, 4, Some(32)) { + Ok(p) => p, + Err(e) => return format!("error:argon2id:params:{e}"), + }; + let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params); + let salt_obj = match SaltString::from_b64(salt) { + Ok(s) => s, + Err(e) => return format!("error:argon2id:salt:{e}"), + }; + match argon2.hash_password(input.as_bytes(), &salt_obj) { + Ok(h) => h.to_string(), + Err(e) => format!("error:argon2id:hash:{e}"), + } } // ============================================================================= -// Dilithium5 / ML-DSA-87 (FIPS 204) — Digital Signatures +// ML-DSA-87 (FIPS 204, "Dilithium5") — Digital Signatures // ============================================================================= -/// Generate a Dilithium5-AES (ML-DSA-87) key pair. -/// -/// Returns a JSON object: { "public_key": "", "private_key": "" } +/// Generate an ML-DSA-87 (Dilithium5-class) key pair. /// -/// Real implementation: use `pqcrypto-dilithium` crate's `keypair()` -/// function. Public key is 2592 bytes, private key is 4864 bytes. +/// Returns JSON: `{ "public_key": "", "private_key": "" }`. +/// Keys are encoded with the FIPS 204 fixed-size encodings. #[wasm_bindgen] pub fn dilithium5_keygen() -> JsValue { - // TODO: Replace with real Dilithium5 key generation. - // use pqcrypto_dilithium::dilithium5aes; - // let (pk, sk) = dilithium5aes::keypair(); - // return JSON with hex-encoded keys - let json = serde_json::json!({ - "public_key": "stub:dilithium5:public_key:0000", - "private_key": "stub:dilithium5:private_key:0000" - }); - JsValue::from_str(&json.to_string()) + JsValue::from_str(&dilithium5_keygen_impl()) } -/// Sign a message using Dilithium5-AES (ML-DSA-87). -/// -/// Returns the hex-encoded signature (4627 bytes for Dilithium5). +/// Pure-Rust core for [`dilithium5_keygen`]; returns the JSON string. +/// Kept separate so it is unit-testable on native targets without the +/// wasm-bindgen runtime. +fn dilithium5_keygen_impl() -> String { + let mut rng = match secure_rng() { + Ok(r) => r, + Err(e) => return format!("{{\"error\":\"{e}\"}}"), + }; + let kp = MlDsa87::key_gen(&mut rng); + let pk = kp.verifying_key().encode(); + let sk = kp.signing_key().encode(); + serde_json::json!({ + "public_key": hex::encode(pk.as_slice()), + "private_key": hex::encode(sk.as_slice()), + }) + .to_string() +} + +/// Sign a message using ML-DSA-87 (deterministic variant, empty context). /// -/// Real implementation: use `pqcrypto_dilithium::dilithium5aes::detached_sign`. +/// Returns the hex-encoded fixed-size signature. #[wasm_bindgen] pub fn dilithium5_sign(message: &str, private_key: &str) -> String { - // TODO: Replace with real Dilithium5 signing. - // use pqcrypto_dilithium::dilithium5aes; - // let sk = dilithium5aes::SecretKey::from_bytes(hex::decode(private_key)?)?; - // let sig = dilithium5aes::detached_sign(message.as_bytes(), &sk); - // hex::encode(sig.as_bytes()) - let _ = private_key; // Suppress unused warning - format!("stub:dilithium5_sig:{}", hex_stub(message)) + let sk_bytes = match hex::decode(private_key) { + Ok(b) => b, + Err(e) => return format!("error:dilithium5_sign:hex:{e}"), + }; + let enc = match EncodedSigningKey::::try_from(sk_bytes.as_slice()) { + Ok(e) => e, + Err(_) => return "error:dilithium5_sign:bad_private_key_length".to_string(), + }; + let sk = SigningKey::::decode(&enc); + let sig = sk.sign(message.as_bytes()); + hex::encode(sig.encode().as_slice()) } -/// Verify a Dilithium5-AES (ML-DSA-87) signature. -/// -/// Returns true if the signature is valid for the given message and -/// public key. -/// -/// Real implementation: use `pqcrypto_dilithium::dilithium5aes::verify_detached_signature`. +/// Verify an ML-DSA-87 signature. Returns true iff valid. #[wasm_bindgen] pub fn dilithium5_verify(message: &str, signature: &str, public_key: &str) -> bool { - // TODO: Replace with real Dilithium5 verification. - // use pqcrypto_dilithium::dilithium5aes; - // let pk = dilithium5aes::PublicKey::from_bytes(hex::decode(public_key)?)?; - // let sig = dilithium5aes::DetachedSignature::from_bytes(hex::decode(signature)?)?; - // dilithium5aes::verify_detached_signature(&sig, message.as_bytes(), &pk).is_ok() - let _ = (message, signature, public_key); - false // Stub always returns false — real impl verifies the signature + let pk_bytes = match hex::decode(public_key) { + Ok(b) => b, + Err(_) => return false, + }; + let sig_bytes = match hex::decode(signature) { + Ok(b) => b, + Err(_) => return false, + }; + let pk_enc = match EncodedVerifyingKey::::try_from(pk_bytes.as_slice()) { + Ok(e) => e, + Err(_) => return false, + }; + let sig_enc = match EncodedSignature::::try_from(sig_bytes.as_slice()) { + Ok(e) => e, + Err(_) => return false, + }; + let sig = match Signature::::decode(&sig_enc) { + Some(s) => s, + None => return false, + }; + let vk = VerifyingKey::::decode(&pk_enc); + vk.verify(message.as_bytes(), &sig).is_ok() } // ============================================================================= -// Kyber1024 / ML-KEM-1024 (FIPS 203) — Key Encapsulation +// ML-KEM-1024 (FIPS 203, "Kyber1024") — Key Encapsulation // ============================================================================= -/// Generate a Kyber1024 (ML-KEM-1024) key pair. -/// -/// Returns JSON: { "public_key": "", "private_key": "" } +/// Generate an ML-KEM-1024 (Kyber1024-class) key pair. /// -/// Real implementation: use `pqcrypto_kem::kyber1024::keypair()`. -/// Public key is 1568 bytes, private key is 3168 bytes. +/// Returns JSON: `{ "public_key": "", "private_key": "" }` +/// where `public_key` is the encapsulation key and `private_key` is the +/// decapsulation key, FIPS 203 fixed-size encodings. #[wasm_bindgen] pub fn kyber1024_keygen() -> JsValue { - // TODO: Replace with real Kyber1024 key generation. - // use pqcrypto_kem::kyber1024; - // let (pk, sk) = kyber1024::keypair(); - // return JSON with hex-encoded keys - let json = serde_json::json!({ - "public_key": "stub:kyber1024:public_key:0000", - "private_key": "stub:kyber1024:private_key:0000" - }); - JsValue::from_str(&json.to_string()) + JsValue::from_str(&kyber1024_keygen_impl()) } -/// Encapsulate a shared secret using a Kyber1024 public key. -/// -/// Returns JSON: { "ciphertext": "", "shared_secret": "" } -/// The shared secret is 32 bytes. The ciphertext is 1568 bytes. +/// Pure-Rust core for [`kyber1024_keygen`]; returns the JSON string. +fn kyber1024_keygen_impl() -> String { + let mut rng = match secure_rng() { + Ok(r) => r, + Err(e) => return format!("{{\"error\":\"{e}\"}}"), + }; + let (dk, ek) = MlKem1024::generate(&mut rng); + serde_json::json!({ + "public_key": hex::encode(ek.as_bytes().as_slice()), + "private_key": hex::encode(dk.as_bytes().as_slice()), + }) + .to_string() +} + +/// Encapsulate a shared secret to an ML-KEM-1024 public (encapsulation) +/// key. /// -/// Real implementation: use `pqcrypto_kem::kyber1024::encapsulate`. +/// Returns JSON: `{ "ciphertext": "", "shared_secret": "" }`. #[wasm_bindgen] pub fn kyber1024_encapsulate(public_key: &str) -> JsValue { - // TODO: Replace with real Kyber1024 encapsulation. - // use pqcrypto_kem::kyber1024; - // let pk = kyber1024::PublicKey::from_bytes(hex::decode(public_key)?)?; - // let (ss, ct) = kyber1024::encapsulate(&pk); - // return JSON with hex-encoded ciphertext and shared_secret - let _ = public_key; - let json = serde_json::json!({ - "ciphertext": "stub:kyber1024:ciphertext:0000", - "shared_secret": "stub:kyber1024:shared_secret:0000" - }); - JsValue::from_str(&json.to_string()) + JsValue::from_str(&kyber1024_encapsulate_impl(public_key)) } -/// Decapsulate a shared secret from a Kyber1024 ciphertext. -/// -/// Returns the hex-encoded 32-byte shared secret. -/// -/// Real implementation: use `pqcrypto_kem::kyber1024::decapsulate`. +/// Pure-Rust core for [`kyber1024_encapsulate`]; returns the JSON string. +fn kyber1024_encapsulate_impl(public_key: &str) -> String { + let err = |m: &str| format!("{{\"error\":\"{m}\"}}"); + let ek_bytes = match hex::decode(public_key) { + Ok(b) => b, + Err(e) => return err(&format!("hex:{e}")), + }; + let ek_enc = + match Encoded::<::EncapsulationKey>::try_from(ek_bytes.as_slice()) { + Ok(e) => e, + Err(_) => return err("bad_public_key_length"), + }; + let ek = ::EncapsulationKey::from_bytes(&ek_enc); + let mut rng = match secure_rng() { + Ok(r) => r, + Err(e) => return err(&e), + }; + let (ct, ss) = match ek.encapsulate(&mut rng) { + Ok(v) => v, + Err(_) => return err("encapsulation_failed"), + }; + serde_json::json!({ + "ciphertext": hex::encode(ct.as_slice()), + "shared_secret": hex::encode(ss.as_slice()), + }) + .to_string() +} + +/// Decapsulate a shared secret from an ML-KEM-1024 ciphertext using the +/// private (decapsulation) key. Returns the hex-encoded 32-byte shared +/// secret. #[wasm_bindgen] pub fn kyber1024_decapsulate(ciphertext: &str, private_key: &str) -> String { - // TODO: Replace with real Kyber1024 decapsulation. - // use pqcrypto_kem::kyber1024; - // let sk = kyber1024::SecretKey::from_bytes(hex::decode(private_key)?)?; - // let ct = kyber1024::Ciphertext::from_bytes(hex::decode(ciphertext)?)?; - // let ss = kyber1024::decapsulate(&ct, &sk); - // hex::encode(ss.as_bytes()) - let _ = (ciphertext, private_key); - "stub:kyber1024:shared_secret:0000".to_string() + let dk_bytes = match hex::decode(private_key) { + Ok(b) => b, + Err(e) => return format!("error:kyber1024_decapsulate:hex_sk:{e}"), + }; + let ct_bytes = match hex::decode(ciphertext) { + Ok(b) => b, + Err(e) => return format!("error:kyber1024_decapsulate:hex_ct:{e}"), + }; + let dk_enc = + match Encoded::<::DecapsulationKey>::try_from(dk_bytes.as_slice()) { + Ok(e) => e, + Err(_) => return "error:kyber1024_decapsulate:bad_private_key_length".to_string(), + }; + let ct = match ml_kem::Ciphertext::::try_from(ct_bytes.as_slice()) { + Ok(c) => c, + Err(_) => return "error:kyber1024_decapsulate:bad_ciphertext_length".to_string(), + }; + let dk = ::DecapsulationKey::from_bytes(&dk_enc); + match dk.decapsulate(&ct) { + Ok(ss) => hex::encode(ss.as_slice()), + Err(_) => "error:kyber1024_decapsulate:decapsulation_failed".to_string(), + } } // ============================================================================= @@ -199,144 +295,184 @@ pub fn kyber1024_decapsulate(ciphertext: &str, private_key: &str) -> String { /// Encrypt plaintext using XChaCha20-Poly1305 with a 256-bit key. /// -/// The nonce must be 192 bits (24 bytes), hex-encoded. -/// Returns hex-encoded ciphertext with appended Poly1305 tag (16 bytes). -/// -/// Real implementation: use the `chacha20poly1305` crate's `XChaCha20Poly1305`. +/// `key` is 32 bytes hex-encoded, `nonce` is 24 bytes hex-encoded. +/// Returns hex-encoded ciphertext with the 16-byte Poly1305 tag +/// appended. #[wasm_bindgen] pub fn xchacha20poly1305_encrypt(plaintext: &str, key: &str, nonce: &str) -> String { - // TODO: Replace with real XChaCha20-Poly1305 encryption. - // use chacha20poly1305::{XChaCha20Poly1305, Key, XNonce, aead::Aead, KeyInit}; - // let cipher_key = Key::from_slice(&hex::decode(key)?); - // let cipher_nonce = XNonce::from_slice(&hex::decode(nonce)?); - // let cipher = XChaCha20Poly1305::new(cipher_key); - // let ciphertext = cipher.encrypt(cipher_nonce, plaintext.as_bytes())?; - // hex::encode(ciphertext) - let _ = (key, nonce); - format!("stub:xchacha20:encrypted:{}", hex_stub(plaintext)) + let key_bytes = match hex::decode(key) { + Ok(b) => b, + Err(e) => return format!("error:xchacha20_encrypt:hex_key:{e}"), + }; + let nonce_bytes = match hex::decode(nonce) { + Ok(b) => b, + Err(e) => return format!("error:xchacha20_encrypt:hex_nonce:{e}"), + }; + if key_bytes.len() != 32 { + return "error:xchacha20_encrypt:key_must_be_32_bytes".to_string(); + } + if nonce_bytes.len() != 24 { + return "error:xchacha20_encrypt:nonce_must_be_24_bytes".to_string(); + } + let cipher = XChaCha20Poly1305::new(Key::from_slice(&key_bytes)); + match cipher.encrypt(XNonce::from_slice(&nonce_bytes), plaintext.as_bytes()) { + Ok(ct) => hex::encode(ct), + Err(_) => "error:xchacha20_encrypt:aead_failure".to_string(), + } } /// Decrypt ciphertext using XChaCha20-Poly1305 with a 256-bit key. -/// -/// The nonce must match the one used during encryption. /// Returns the decrypted plaintext as a UTF-8 string. -/// -/// Real implementation: use the `chacha20poly1305` crate's `XChaCha20Poly1305`. #[wasm_bindgen] pub fn xchacha20poly1305_decrypt(ciphertext: &str, key: &str, nonce: &str) -> String { - // TODO: Replace with real XChaCha20-Poly1305 decryption. - // use chacha20poly1305::{XChaCha20Poly1305, Key, XNonce, aead::Aead, KeyInit}; - // let cipher_key = Key::from_slice(&hex::decode(key)?); - // let cipher_nonce = XNonce::from_slice(&hex::decode(nonce)?); - // let cipher = XChaCha20Poly1305::new(cipher_key); - // let plaintext = cipher.decrypt(cipher_nonce, hex::decode(ciphertext)?.as_ref())?; - // String::from_utf8(plaintext)? - let _ = (key, nonce); - format!("stub:xchacha20:decrypted:{}", hex_stub(ciphertext)) + let key_bytes = match hex::decode(key) { + Ok(b) => b, + Err(e) => return format!("error:xchacha20_decrypt:hex_key:{e}"), + }; + let nonce_bytes = match hex::decode(nonce) { + Ok(b) => b, + Err(e) => return format!("error:xchacha20_decrypt:hex_nonce:{e}"), + }; + let ct_bytes = match hex::decode(ciphertext) { + Ok(b) => b, + Err(e) => return format!("error:xchacha20_decrypt:hex_ct:{e}"), + }; + if key_bytes.len() != 32 { + return "error:xchacha20_decrypt:key_must_be_32_bytes".to_string(); + } + if nonce_bytes.len() != 24 { + return "error:xchacha20_decrypt:nonce_must_be_24_bytes".to_string(); + } + let cipher = XChaCha20Poly1305::new(Key::from_slice(&key_bytes)); + match cipher.decrypt(XNonce::from_slice(&nonce_bytes), ct_bytes.as_ref()) { + Ok(pt) => match String::from_utf8(pt) { + Ok(s) => s, + Err(_) => "error:xchacha20_decrypt:plaintext_not_utf8".to_string(), + }, + Err(_) => "error:xchacha20_decrypt:authentication_failed".to_string(), + } } // ============================================================================= -// HKDF-SHAKE512 — Key Derivation +// HKDF-SHA3-512 — Key Derivation // ============================================================================= -/// Derive keying material using HKDF with SHAKE-512 as the underlying PRF. +/// Derive 32 bytes of keying material using HKDF with SHA3-512 as the +/// underlying hash. /// /// Arguments: -/// - ikm: input keying material (hex-encoded) -/// - salt: optional salt (hex-encoded, can be empty string for no salt) -/// - info: context/application-specific info string +/// - `ikm`: input keying material (hex-encoded) +/// - `salt`: optional salt (hex-encoded, empty string = no salt) +/// - `info`: context/application-specific info string /// /// Returns 32 bytes of derived key material, hex-encoded. -/// -/// Real implementation: use the `hkdf` crate with a SHAKE-512 hash. #[wasm_bindgen] pub fn hkdf_shake512_derive(ikm: &str, salt: &str, info: &str) -> String { - // TODO: Replace with real HKDF-SHAKE512 derivation. - // use hkdf::Hkdf; - // use sha3::Sha3_512; // or SHAKE-512 wrapper - // let salt_bytes = if salt.is_empty() { None } else { Some(hex::decode(salt)?) }; - // let hk = Hkdf::::new(salt_bytes.as_deref(), &hex::decode(ikm)?); - // let mut okm = [0u8; 32]; - // hk.expand(info.as_bytes(), &mut okm)?; - // hex::encode(okm) - let _ = (salt, info); - format!("stub:hkdf_shake512:{}", hex_stub(ikm)) + let ikm_bytes = match hex::decode(ikm) { + Ok(b) => b, + Err(e) => return format!("error:hkdf:hex_ikm:{e}"), + }; + let salt_bytes = if salt.is_empty() { + None + } else { + match hex::decode(salt) { + Ok(b) => Some(b), + Err(e) => return format!("error:hkdf:hex_salt:{e}"), + } + }; + let hk = Hkdf::::new(salt_bytes.as_deref(), &ikm_bytes); + let mut okm = [0u8; 32]; + match hk.expand(info.as_bytes(), &mut okm) { + Ok(()) => hex::encode(okm), + Err(_) => "error:hkdf:expand_failed".to_string(), + } } // ============================================================================= -// ChaCha20-DRBG — Random Number Generation +// ChaCha20-DRBG — Deterministic Random Byte Generation // ============================================================================= -/// Generate pseudorandom bytes using a ChaCha20-based DRBG. +/// Generate pseudorandom bytes using a ChaCha20-based DRBG seeded from +/// the provided 256-bit seed. /// /// Arguments: -/// - seed: 256-bit seed, hex-encoded (64 hex characters) -/// - length: number of pseudorandom bytes to generate +/// - `seed`: 256-bit seed, hex-encoded (64 hex characters) +/// - `length`: number of pseudorandom bytes to generate /// /// Returns hex-encoded pseudorandom output. -/// -/// Real implementation: use the `rand_chacha` crate's `ChaCha20Rng` -/// seeded from the provided seed bytes. #[wasm_bindgen] pub fn chacha20_drbg_generate(seed: &str, length: u32) -> String { - // TODO: Replace with real ChaCha20-DRBG generation. - // use rand_chacha::ChaCha20Rng; - // use rand::SeedableRng; - // use rand::RngCore; - // let seed_bytes: [u8; 32] = hex::decode(seed)?[..32].try_into()?; - // let mut rng = ChaCha20Rng::from_seed(seed_bytes); - // let mut output = vec![0u8; length as usize]; - // rng.fill_bytes(&mut output); - // hex::encode(output) - let _ = seed; - // Return a deterministic stub of the requested length - "00".repeat(length as usize) + use rand_core::RngCore; + let seed_bytes = match hex::decode(seed) { + Ok(b) => b, + Err(e) => return format!("error:chacha20_drbg:hex_seed:{e}"), + }; + let seed_arr: [u8; 32] = match seed_bytes.as_slice().try_into() { + Ok(a) => a, + Err(_) => return "error:chacha20_drbg:seed_must_be_32_bytes".to_string(), + }; + let mut rng = ChaCha20Rng::from_seed(seed_arr); + let mut output = vec![0u8; length as usize]; + rng.fill_bytes(&mut output); + hex::encode(output) } // ============================================================================= // User-Friendly Hash Name // ============================================================================= -/// Convert a hex-encoded hash digest to a human-readable name. -/// -/// Maps pairs of hex bytes to words from a curated wordlist (based on -/// the EFF large wordlist), producing a sequence like -/// "correct-horse-battery-staple" that is easier for humans to recognise -/// and compare than raw hex. +/// A small curated wordlist (subset of the EFF large wordlist) used to +/// render a hash digest as a memorable hyphen-joined phrase. 256 words +/// so each byte maps directly to one word. +const WORDLIST: [&str; 256] = [ + "abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", + "abuse", "access", "accident", "account", "accuse", "achieve", "acid", "acoustic", "acquire", + "across", "action", "actor", "actual", "adapt", "addict", "address", "adjust", "admit", + "adult", "advance", "advice", "aerobic", "affair", "afford", "afraid", "again", "agent", + "agree", "ahead", "aim", "air", "airport", "aisle", "alarm", "album", "alcohol", "alert", + "alien", "alley", "allow", "almost", "alone", "alpha", "already", "also", "alter", "always", + "amateur", "amazing", "among", "amount", "amused", "anchor", "ancient", "anger", "angle", + "angry", "animal", "ankle", "announce", "annual", "another", "answer", "antenna", "antique", + "anxiety", "any", "apart", "apology", "appear", "apple", "approve", "april", "arch", "arctic", + "area", "arena", "argue", "arm", "armed", "armor", "army", "around", "arrange", "arrest", + "arrive", "arrow", "art", "artist", "artwork", "ask", "aspect", "assault", "asset", "assist", + "assume", "asthma", "athlete", "atom", "attack", "attend", "attitude", "attract", "auction", + "audit", "august", "aunt", "author", "auto", "autumn", "average", "avocado", "avoid", "awake", + "aware", "away", "awesome", "awful", "awkward", "axis", "baby", "bachelor", "bacon", "badge", + "bag", "balance", "balcony", "ball", "bamboo", "banana", "banner", "bar", "barely", "bargain", + "barrel", "base", "basic", "basket", "battle", "beach", "bean", "beauty", "because", "become", + "beef", "before", "begin", "behave", "behind", "believe", "below", "belt", "bench", "benefit", + "best", "betray", "better", "between", "beyond", "bicycle", "bid", "bike", "bind", "biology", + "bird", "birth", "bitter", "black", "blade", "blame", "blanket", "blast", "bleak", "bless", + "blind", "blood", "blossom", "blouse", "blue", "blur", "blush", "board", "boat", "body", + "boil", "bomb", "bone", "bonus", "book", "boost", "border", "boring", "borrow", "boss", + "bottom", "bounce", "box", "boy", "bracket", "brain", "brand", "brass", "brave", "bread", + "breeze", "brick", "bridge", "brief", "bright", "bring", "brisk", "broccoli", "broken", + "bronze", "broom", "brother", "brown", "brush", "bubble", "buddy", "budget", "buffalo", + "build", "bulb", "bulk", "bullet", "bundle", "bunker", "burden", "burger", "burst", "bus", + "business", "busy", "butter", "buyer", "buzz", "cabbage", "cabin", "cable", "cactus", "cage", + "cake", "call", "calm", "camera", "camp", +]; + +/// Convert a hex-encoded hash digest to a human-readable phrase. /// -/// Real implementation: embed the EFF wordlist and map byte pairs to -/// word indices. +/// Decodes the hex digest and maps the first four bytes to four words +/// from a curated 256-word list, producing a phrase like +/// "correct-horse-battery-staple". If the hash cannot be hex-decoded +/// the input is hashed with BLAKE3 first so a phrase is always +/// produced. #[wasm_bindgen] pub fn user_friendly_hash_name(hash: &str) -> String { - // TODO: Replace with real wordlist mapping. - // 1. Decode hex hash to bytes - // 2. Take first 8 bytes (4 word-pairs) - // 3. Map each u16 (big-endian) to wordlist[index % wordlist.len()] - // 4. Join with hyphens - // Example: "a1b2c3d4e5f6a7b8..." -> "correct-horse-battery-staple" - let prefix = if hash.len() >= 10 { - &hash[..10] - } else { - hash + let bytes = match hex::decode(hash) { + Ok(b) if b.len() >= 4 => b, + _ => blake3::hash(hash.as_bytes()).as_bytes().to_vec(), }; - format!("doc-{}", prefix) -} - -// ============================================================================= -// Internal Helpers (not exported to WASM) -// ============================================================================= - -/// Produce a short deterministic hex-like stub from an input string. -/// Used only by stub functions to create distinguishable placeholder output. -fn hex_stub(input: &str) -> String { - // Simple non-cryptographic hash for stub differentiation. - // This is NOT a real hash — it just makes stubs distinguishable. - let mut hash: u64 = 0xcbf29ce484222325; // FNV-1a offset basis - for byte in input.as_bytes() { - hash ^= *byte as u64; - hash = hash.wrapping_mul(0x100000001b3); // FNV-1a prime - } - format!("{:016x}", hash) + let words: Vec<&str> = bytes + .iter() + .take(4) + .map(|b| WORDLIST[*b as usize]) + .collect(); + words.join("-") } #[cfg(test)] @@ -344,59 +480,116 @@ mod tests { use super::*; #[test] - fn test_shake3_512_hash_returns_stub() { - let result = shake3_512_hash("hello"); - assert!(result.starts_with("stub:shake3_512:")); + fn test_shake3_512_hash_known_vector() { + // SHAKE256 of the empty string, first 64 bytes (NIST test vector). + let result = shake3_512_hash(""); + assert_eq!( + result, + "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f\ + d75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be" + ); } #[test] - fn test_blake3_hash_returns_stub() { - let result = blake3_hash("hello"); - assert!(result.starts_with("stub:blake3:")); + fn test_blake3_hash_known_vector() { + // BLAKE3 of the empty string. + let result = blake3_hash(""); + assert_eq!( + result, + "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262" + ); } #[test] - fn test_argon2id_hash_returns_stub() { - let result = argon2id_hash("password", "salt123"); - assert!(result.starts_with("stub:argon2id:")); + fn test_argon2id_hash_phc_format() { + let salt = "c29tZXNhbHR2YWx1ZQ"; // base64 "somesaltvalue" + let result = argon2id_hash("password", salt); + assert!( + result.starts_with("$argon2id$v=19$"), + "got: {result}" + ); } #[test] - fn test_dilithium5_verify_returns_false() { - // Stub always returns false - assert!(!dilithium5_verify("msg", "sig", "pk")); + fn test_dilithium5_sign_verify_round_trip() { + let kp_json = dilithium5_keygen_impl(); + let kp: serde_json::Value = serde_json::from_str(&kp_json).unwrap(); + let pk = kp["public_key"].as_str().unwrap(); + let sk = kp["private_key"].as_str().unwrap(); + let sig = dilithium5_sign("attestation message", sk); + assert!(!sig.starts_with("error:"), "sign error: {sig}"); + assert!(dilithium5_verify("attestation message", &sig, pk)); + assert!(!dilithium5_verify("tampered message", &sig, pk)); } #[test] - fn test_chacha20_drbg_length() { - let result = chacha20_drbg_generate("00".repeat(32).as_str(), 16); - // 16 bytes = 32 hex characters - assert_eq!(result.len(), 32); + fn test_kyber1024_encap_decap_round_trip() { + let kp_json = kyber1024_keygen_impl(); + let kp: serde_json::Value = serde_json::from_str(&kp_json).unwrap(); + let pk = kp["public_key"].as_str().unwrap(); + let sk = kp["private_key"].as_str().unwrap(); + let enc_json = kyber1024_encapsulate_impl(pk); + let enc: serde_json::Value = serde_json::from_str(&enc_json).unwrap(); + let ct = enc["ciphertext"].as_str().unwrap(); + let ss_sender = enc["shared_secret"].as_str().unwrap(); + let ss_receiver = kyber1024_decapsulate(ct, sk); + assert_eq!(ss_sender, ss_receiver); } #[test] - fn test_user_friendly_hash_name_short() { - let result = user_friendly_hash_name("abcdef0123"); - assert_eq!(result, "doc-abcdef0123"); + fn test_xchacha20poly1305_round_trip() { + let key = "00".repeat(32); + let nonce = "00".repeat(24); + let ct = xchacha20poly1305_encrypt("hello world", &key, &nonce); + assert!(!ct.starts_with("error:"), "encrypt error: {ct}"); + let pt = xchacha20poly1305_decrypt(&ct, &key, &nonce); + assert_eq!(pt, "hello world"); } #[test] - fn test_user_friendly_hash_name_long() { - let result = user_friendly_hash_name("abcdef0123456789abcdef"); - assert_eq!(result, "doc-abcdef0123"); + fn test_xchacha20poly1305_tamper_detected() { + let key = "11".repeat(32); + let nonce = "22".repeat(24); + let mut ct = xchacha20poly1305_encrypt("secret", &key, &nonce); + // Flip the last hex nibble to corrupt the tag. + let last = ct.pop().unwrap(); + ct.push(if last == '0' { '1' } else { '0' }); + let pt = xchacha20poly1305_decrypt(&ct, &key, &nonce); + assert!(pt.starts_with("error:"), "tamper not detected: {pt}"); } #[test] - fn test_hex_stub_deterministic() { - let a = hex_stub("test"); - let b = hex_stub("test"); + fn test_hkdf_shake512_deterministic() { + let a = hkdf_shake512_derive("00112233", "aabb", "context"); + let b = hkdf_shake512_derive("00112233", "aabb", "context"); assert_eq!(a, b); + assert_eq!(a.len(), 64); // 32 bytes hex + let c = hkdf_shake512_derive("00112233", "aabb", "different"); + assert_ne!(a, c); + } + + #[test] + fn test_chacha20_drbg_deterministic_and_length() { + let seed = "00".repeat(32); + let a = chacha20_drbg_generate(&seed, 16); + let b = chacha20_drbg_generate(&seed, 16); + assert_eq!(a, b); + assert_eq!(a.len(), 32); // 16 bytes hex + // ChaCha20 keystream of an all-zero key/nonce is a known value; + // assert it is not trivially all zeros. + assert_ne!(a, "00".repeat(16)); + } + + #[test] + fn test_user_friendly_hash_name_is_words() { + let result = user_friendly_hash_name("00010203"); + assert_eq!(result, "abandon-ability-able-about"); } #[test] - fn test_hex_stub_different_inputs() { - let a = hex_stub("hello"); - let b = hex_stub("world"); - assert_ne!(a, b); + fn test_user_friendly_hash_name_non_hex_fallback() { + let result = user_friendly_hash_name("not-hex!"); + // Deterministic phrase from BLAKE3 of the input. + assert_eq!(result.split('-').count(), 4); } }