Compare commits
No commits in common. "6b02b20dadb558888c330873f04d014aa6f45bd4" and "1c43531f3fe5d574764046c7e1fc3ecbf5779e20" have entirely different histories.
6b02b20dad
...
1c43531f3f
13 changed files with 804 additions and 940 deletions
580
Cargo.lock
generated
580
Cargo.lock
generated
|
@ -3,44 +3,436 @@
|
|||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "lore"
|
||||
version = "2.1.0"
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.43"
|
||||
name = "bumpalo"
|
||||
version = "3.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"cast",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"csv",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lore"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.144"
|
||||
name = "rayon"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[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 = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
||||
dependencies = [
|
||||
"half",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.144"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -48,18 +440,160 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.99"
|
||||
name = "serde_json"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
||||
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.4"
|
||||
name = "syn"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "lore"
|
||||
version = "2.1.0"
|
||||
version = "2.0.0"
|
||||
edition = "2018"
|
||||
description = "Zero-dependency hashing algorithms"
|
||||
license = "BSD-3-Clause"
|
||||
|
@ -11,9 +11,9 @@ keywords = ["algorithms", "compression", "cryptography", "md5", "hash"]
|
|||
categories = ["algorithms", "compression", "cryptography"]
|
||||
exclude = []
|
||||
|
||||
[dependencies]
|
||||
serde = { version = ">=1.0.0", features = ["derive"], optional = true }
|
||||
[dev-dependencies]
|
||||
criterion = { version = "^0.3", features = ["html_reports"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
serde = ["dep:serde"]
|
||||
[[bench]]
|
||||
name = "md5"
|
||||
harness = false
|
35
README.md
35
README.md
|
@ -1,32 +1,19 @@
|
|||
# Lore
|
||||
|
||||
Nightly-only hashing algorithms with a straight-forward API and no required dependencies.
|
||||
Hashing algorithms. Currently only implements md5.
|
||||
|
||||
This crate currently implements:
|
||||
Doesn't use any dependencies.
|
||||
|
||||
- MD2, MD4, and MD5
|
||||
- SHA-1
|
||||
Performance/stability not guaranteed.
|
||||
|
||||
Performance is not a priority of this crate, rather, the primary purpose of this crate is learning, as well as providing tests for the intermediate steps of algorithms.
|
||||
This includes padding, checksums and round step functions.
|
||||
|
||||
The functions of this crate should probably not be used for production purposes.
|
||||
|
||||
Once [`slice::array_chunks`] is stabilized, this crate can be made to work on stable Rust.
|
||||
The crate could be rewritten to use stable already, but this would increase the verbosity of many expressions.
|
||||
|
||||
[`slice::array_chunks`]: https://doc.rust-lang.org/std/primitive.slice.html#method.array_chunks
|
||||
|
||||
# Features
|
||||
|
||||
[Serde](https://crates.io/crates/serde) support is included, and is gated behind the `serde` feature.
|
||||
|
||||
# Examples
|
||||
|
||||
Basic usage:
|
||||
## Example
|
||||
|
||||
```rust
|
||||
let input = "lol xd";
|
||||
let digest = lore::md5(input);
|
||||
assert_eq!(digest.to_string(), "982d7f24f8985a6baa5cf129acc73561");
|
||||
use lore::md5;
|
||||
|
||||
fn main() {
|
||||
let input = "lol xd";
|
||||
let digest = md5::hash(input);
|
||||
assert_eq!(digest, "982d7f24f8985a6baa5cf129acc73561");
|
||||
}
|
||||
```
|
||||
|
|
14
benches/md5.rs
Normal file
14
benches/md5.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use criterion::*;
|
||||
use lore::md5;
|
||||
|
||||
fn md5(c: &mut Criterion) {
|
||||
c.bench_function("md5", |b| {
|
||||
b.iter(|| {
|
||||
let hash = md5::hash(black_box("tihi xd"));
|
||||
hash.to_hex_string();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, md5);
|
||||
criterion_main!(benches);
|
|
@ -1 +0,0 @@
|
|||
nightly
|
|
@ -1 +1,10 @@
|
|||
fn main() {}
|
||||
use lore::md5;
|
||||
|
||||
fn main() {
|
||||
let input = "lol xd";
|
||||
|
||||
assert_eq!(
|
||||
md5::hash(input).to_hex_string(),
|
||||
"982d7f24f8985a6baa5cf129acc73561"
|
||||
);
|
||||
}
|
||||
|
|
120
src/hash.rs
120
src/hash.rs
|
@ -1,120 +0,0 @@
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt::Display, hash::Hash};
|
||||
|
||||
pub mod md2;
|
||||
pub mod md4;
|
||||
pub mod md5;
|
||||
pub mod sha1;
|
||||
|
||||
/// A variable-size digest, which can easily be converted into a hexadecimal string for user-facing output.
|
||||
///
|
||||
/// This struct is returned by all hashing functions.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`Digest`] implements [`Display`], which means it can automatically be converted to a human-readable format by formatting it:
|
||||
///
|
||||
/// ```rust
|
||||
/// let digest = lore::md5("example");
|
||||
/// println!("Digest: {}", digest); // -> Digest: 1a79a4d60de6718e8e5b326e338ae533
|
||||
/// ```
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Digest<const S: usize>([u8; S]);
|
||||
|
||||
/// Convert the digest into a hexadecimal string representation.
|
||||
impl<const S: usize> Display for Digest<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(
|
||||
&self
|
||||
.0
|
||||
.iter()
|
||||
.map(|u| format!("{:02x}", u))
|
||||
.collect::<String>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const S: usize> From<Digest<S>> for [u8; S] {
|
||||
fn from(digest: Digest<S>) -> Self {
|
||||
digest.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const S: usize> From<&'a Digest<S>> for &'a [u8] {
|
||||
fn from(digest: &'a Digest<S>) -> Self {
|
||||
digest.0.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const S: usize> From<Digest<S>> for Vec<u8> {
|
||||
fn from(digest: Digest<S>) -> Self {
|
||||
digest.0.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const S: usize> AsRef<[u8]> for Digest<S> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes_to_words_le(bytes: impl AsRef<[u8]>) -> Vec<u32> {
|
||||
bytes
|
||||
.as_ref()
|
||||
.array_chunks::<4>()
|
||||
.map(|chunk| u32::from_le_bytes(*chunk))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn words_to_bytes_le(words: impl AsRef<[u32]>) -> Vec<u8> {
|
||||
words
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|w| w.to_le_bytes())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn bytes_to_words_be(bytes: impl AsRef<[u8]>) -> Vec<u32> {
|
||||
bytes
|
||||
.as_ref()
|
||||
.array_chunks::<4>()
|
||||
.map(|chunk| u32::from_be_bytes(*chunk))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn words_to_bytes_be(words: impl AsRef<[u32]>) -> Vec<u8> {
|
||||
words
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|w| w.to_be_bytes())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn bytes_to_words_le_works() {
|
||||
assert_eq!(
|
||||
vec![0x6745_2301, 0xefcd_ab89, 0x98ba_dcfe, 0x1032_5476],
|
||||
bytes_to_words_le([
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
|
||||
0x32, 0x10
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn words_to_bytes_le_works() {
|
||||
assert_eq!(
|
||||
vec![
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
|
||||
0x32, 0x10
|
||||
],
|
||||
words_to_bytes_le([0x6745_2301, 0xefcd_ab89, 0x98ba_dcfe, 0x1032_5476])
|
||||
);
|
||||
}
|
||||
}
|
146
src/hash/md2.rs
146
src/hash/md2.rs
|
@ -1,146 +0,0 @@
|
|||
use crate::hash::Digest;
|
||||
|
||||
/// see RFC1319
|
||||
const S: [u8; 256] = [
|
||||
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
|
||||
0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
|
||||
0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
|
||||
0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
|
||||
0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
|
||||
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
|
||||
0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
|
||||
0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
|
||||
0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
|
||||
0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
|
||||
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
|
||||
0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
|
||||
0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
|
||||
0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
|
||||
0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
|
||||
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14,
|
||||
];
|
||||
|
||||
fn pad(message: impl AsRef<[u8]>) -> Vec<u8> {
|
||||
let mut message = message.as_ref().to_vec();
|
||||
let padding_length = 16 - (message.len() % 16);
|
||||
message.append(&mut vec![padding_length as u8; padding_length]);
|
||||
message
|
||||
}
|
||||
|
||||
fn checksum(message: impl AsRef<[u8]>) -> Vec<u8> {
|
||||
let mut message = message.as_ref().to_vec();
|
||||
let mut checksum = vec![0u8; 16];
|
||||
|
||||
let mut last = 0;
|
||||
for block in message.array_chunks::<16>() {
|
||||
for i in 0..16 {
|
||||
checksum[i] ^= S[(block[i] ^ last) as usize];
|
||||
last = checksum[i];
|
||||
}
|
||||
}
|
||||
|
||||
message.append(&mut checksum);
|
||||
message
|
||||
}
|
||||
|
||||
/// Computes the MD2 hash value (digest) of the input bytes.
|
||||
///
|
||||
/// Returns a 16-byte `Digest` which implements `Display` in order to get at hexadecimal-string representation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let input = "abc";
|
||||
/// let digest = lore::md2(input);
|
||||
///
|
||||
/// assert_eq!(digest.to_string(), "da853b0d3f88d99b30283a69e6ded6bb");
|
||||
/// ```
|
||||
pub fn hash(msg: impl AsRef<[u8]>) -> Digest<16> {
|
||||
let padded = checksum(pad(msg));
|
||||
let buffer = padded
|
||||
.array_chunks::<16>()
|
||||
.fold([0u8; 48], |mut buffer, chunk| {
|
||||
// copy chunk into buffer
|
||||
for i in 0..16 {
|
||||
buffer[16 + i] = chunk[i];
|
||||
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
|
||||
}
|
||||
|
||||
// do 18 rounds
|
||||
let mut t = 0;
|
||||
for i in 0..18 {
|
||||
for b in buffer.iter_mut() {
|
||||
*b ^= S[t as usize];
|
||||
t = *b;
|
||||
}
|
||||
t = t.wrapping_add(i);
|
||||
}
|
||||
|
||||
buffer
|
||||
});
|
||||
let digest = *buffer.array_chunks::<16>().next().unwrap();
|
||||
|
||||
Digest(digest)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn md2_pad() {
|
||||
// assert that padding length is always correct
|
||||
assert!(pad([]).len() % 16 == 0);
|
||||
assert!(pad([0u8]).len() % 16 == 0);
|
||||
assert!(pad([0u8; 15]).len() % 16 == 0);
|
||||
assert!(pad([0u8; 16]).len() % 16 == 0);
|
||||
assert!(pad([0u8; 476]).len() % 16 == 0);
|
||||
|
||||
// check some simple cases
|
||||
assert_eq!(vec![16u8; 16], pad([]));
|
||||
assert_eq!(
|
||||
vec![0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15],
|
||||
pad([0u8])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn md2_checksum() {
|
||||
assert_eq!(
|
||||
vec![
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 98, 56, 103, 182,
|
||||
175, 82, 121, 94, 95, 33, 78, 151, 32, 190, 234, 141
|
||||
],
|
||||
checksum(vec![16u8; 16])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
0u8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 41, 224, 10, 216,
|
||||
109, 48, 122, 164, 206, 220, 139, 100, 42, 212, 254, 68
|
||||
],
|
||||
checksum(vec![
|
||||
0u8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn md2_hash() {
|
||||
assert_eq!(
|
||||
"a9046c73e00331af68917d3804f70655",
|
||||
hash(b"hello").to_string()
|
||||
);
|
||||
|
||||
assert_eq!("8350e5a3e24c153df2275c9f80692773", hash(b"").to_string());
|
||||
assert_eq!("32ec01ec4a6dac72c0ab96fb34c0b5d1", hash(b"a").to_string());
|
||||
assert_eq!("da853b0d3f88d99b30283a69e6ded6bb", hash(b"abc").to_string());
|
||||
|
||||
assert_eq!(
|
||||
"03d85a0d629d2c442e987525319fc471",
|
||||
hash(b"The quick brown fox jumps over the lazy dog").to_string()
|
||||
);
|
||||
}
|
||||
}
|
245
src/hash/md4.rs
245
src/hash/md4.rs
|
@ -1,245 +0,0 @@
|
|||
use crate::hash::{bytes_to_words_le, words_to_bytes_le, Digest};
|
||||
|
||||
// based on RFC1320
|
||||
const A: u32 = 0x67452301;
|
||||
const B: u32 = 0xefcdab89;
|
||||
const C: u32 = 0x98badcfe;
|
||||
const D: u32 = 0x10325476;
|
||||
|
||||
// additional constants for round 1, 2 & 3
|
||||
const C1: u32 = 0;
|
||||
const C2: u32 = 0x5a827999;
|
||||
const C3: u32 = 0x6ed9eba1;
|
||||
|
||||
// shifts & indices for each step
|
||||
const S: [u32; 48] = [
|
||||
3, 7, 11, 19, 3, 7, 11, 19, 3, 7, 11, 19, 3, 7, 11, 19, 3, 5, 9, 13, 3, 5, 9, 13, 3, 5, 9, 13,
|
||||
3, 5, 9, 13, 3, 9, 11, 15, 3, 9, 11, 15, 3, 9, 11, 15, 3, 9, 11, 15,
|
||||
];
|
||||
const W: [usize; 48] = [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14,
|
||||
3, 7, 11, 15, 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15,
|
||||
];
|
||||
|
||||
// round functions
|
||||
const F: fn(u32, u32, u32) -> u32 = |x, y, z| (x & y) | (!x & z);
|
||||
const G: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & y) | (x & z) | (y & z);
|
||||
const H: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| x ^ y ^ z;
|
||||
|
||||
// pad the message to next 512-bit interval
|
||||
pub fn pad(message: impl AsRef<[u8]>) -> Vec<u8> {
|
||||
let mut message = message.as_ref().to_vec();
|
||||
let message_length = message.len().wrapping_mul(8) as u64;
|
||||
|
||||
// add 1 bit (le)
|
||||
message.push(0x80);
|
||||
|
||||
// add 0 bits until length in bits is congruent to 448 mod 512
|
||||
while (message.len()) % 64 != 56 {
|
||||
message.push(0u8);
|
||||
}
|
||||
|
||||
// append message length (64 bits)
|
||||
message.extend(message_length.to_le_bytes());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
// compute an invidiual step in the md4 algorithm
|
||||
fn step([mut a, b, c, d]: [u32; 4], words: &[u32], i: usize) -> [u32; 4] {
|
||||
// choose function and constant based on which round is currently active
|
||||
let (f, k) = match i {
|
||||
0..=15 => (F, C1),
|
||||
16..=31 => (G, C2),
|
||||
32..=47 => (H, C3),
|
||||
_ => panic!("This function shouldn't be called using an index outside 0..48"),
|
||||
};
|
||||
|
||||
// main operation
|
||||
a = f(b, c, d)
|
||||
.wrapping_add(a)
|
||||
.wrapping_add(words[W[i]])
|
||||
.wrapping_add(k)
|
||||
.rotate_left(S[i]);
|
||||
|
||||
[a, b, c, d]
|
||||
}
|
||||
|
||||
/// Computes the MD4 hash value (digest) of the input bytes.
|
||||
///
|
||||
/// Returns a 16-byte `Digest` which implements `Display` in order to get at hexadecimal-string representation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let input = "abc";
|
||||
/// let digest = lore::md4(input);
|
||||
///
|
||||
/// assert_eq!(digest.to_string(), "a448017aaf21d8525fc10ae87aa6729d");
|
||||
/// ```
|
||||
pub fn hash(message: impl AsRef<[u8]>) -> Digest<16> {
|
||||
let padded = pad(message);
|
||||
let buffer = padded.array_chunks::<64>().map(bytes_to_words_le).fold(
|
||||
[A, B, C, D],
|
||||
|[a, b, c, d], words| {
|
||||
// perform rounds on this chunk of data
|
||||
let mut state = [a, b, c, d];
|
||||
for i in 0..48 {
|
||||
state = step(state, &words, i);
|
||||
state.rotate_right(1);
|
||||
}
|
||||
|
||||
[
|
||||
a.wrapping_add(state[0]),
|
||||
b.wrapping_add(state[1]),
|
||||
c.wrapping_add(state[2]),
|
||||
d.wrapping_add(state[3]),
|
||||
]
|
||||
},
|
||||
);
|
||||
let digest = *words_to_bytes_le(buffer)
|
||||
.array_chunks::<16>()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
Digest(digest)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn md4_pad() {
|
||||
assert_eq!(pad([1u8]).len() % 64, 0);
|
||||
assert_eq!(pad([1u8; 63]).len() % 64, 0);
|
||||
assert_eq!(pad([1u8; 65]).len() % 64, 0);
|
||||
assert_eq!(pad([1u8; 511]).len() % 64, 0);
|
||||
assert_eq!(pad([1u8; 512]).len() % 64, 0);
|
||||
assert_eq!(pad([1u8; 513]).len() % 64, 0);
|
||||
assert_eq!(pad([1u8; 4472]).len() % 64, 0);
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
],
|
||||
pad([1u8])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn md4_hash() {
|
||||
assert_eq!(
|
||||
"1bee69a46ba811185c194762abaeae90",
|
||||
hash("The quick brown fox jumps over the lazy dog").to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"b86e130ce7028da59e672d56ad0113df",
|
||||
hash("The quick brown fox jumps over the lazy cog").to_string()
|
||||
);
|
||||
assert_eq!("31d6cfe0d16ae931b73c59d7e0c089c0", hash("").to_string());
|
||||
|
||||
// RFC 1320 test suite
|
||||
assert_eq!(hash("").to_string(), "31d6cfe0d16ae931b73c59d7e0c089c0");
|
||||
assert_eq!(hash("a").to_string(), "bde52cb31de33e46245e05fbdbd6fb24");
|
||||
assert_eq!(hash("abc").to_string(), "a448017aaf21d8525fc10ae87aa6729d");
|
||||
assert_eq!(
|
||||
hash("message digest").to_string(),
|
||||
"d9130a8164549fe818874806e1c7014b"
|
||||
);
|
||||
assert_eq!(
|
||||
hash("abcdefghijklmnopqrstuvwxyz").to_string(),
|
||||
"d79e1c308aa5bbcdeea8ed63df412da9"
|
||||
);
|
||||
assert_eq!(
|
||||
hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789").to_string(),
|
||||
"043f8582f241db351ce627e153e7f0e4"
|
||||
);
|
||||
assert_eq!(
|
||||
hash(
|
||||
"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
)
|
||||
.to_string(),
|
||||
"e33b4ddc9c38f2199c3e7b164fcc0536"
|
||||
);
|
||||
assert_eq!(
|
||||
hash("Rosetta Code").to_string(),
|
||||
"a52bcfc6a0d0d300cdc5ddbfbefe478b"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn md4_steps() {
|
||||
let expected: [[u32; 4]; 48] = [
|
||||
[0x2b9b7a8b, 0xefcdab89, 0x98badcfe, 0x10325476],
|
||||
[0x1ebbf3f6, 0x2b9b7a8b, 0xefcdab89, 0x98badcfe],
|
||||
[0xf636674f, 0x1ebbf3f6, 0x2b9b7a8b, 0xefcdab89],
|
||||
[0x3e787c49, 0xf636674f, 0x1ebbf3f6, 0x2b9b7a8b],
|
||||
[0x127b1453, 0x3e787c49, 0xf636674f, 0x1ebbf3f6],
|
||||
[0x9c35a18a, 0x127b1453, 0x3e787c49, 0xf636674f],
|
||||
[0x7e1c9145, 0x9c35a18a, 0x127b1453, 0x3e787c49],
|
||||
[0x0adad780, 0x7e1c9145, 0x9c35a18a, 0x127b1453],
|
||||
[0x85c62aed, 0x0adad780, 0x7e1c9145, 0x9c35a18a],
|
||||
[0x881a850b, 0x85c62aed, 0x0adad780, 0x7e1c9145],
|
||||
[0xf71e7006, 0x881a850b, 0x85c62aed, 0x0adad780],
|
||||
[0x135c5da7, 0xf71e7006, 0x881a850b, 0x85c62aed],
|
||||
[0x0727d7d9, 0x135c5da7, 0xf71e7006, 0x881a850b],
|
||||
[0x9b7d493d, 0x0727d7d9, 0x135c5da7, 0xf71e7006],
|
||||
[0x1e300fd2, 0x9b7d493d, 0x0727d7d9, 0x135c5da7],
|
||||
[0xb60174a1, 0x1e300fd2, 0x9b7d493d, 0x0727d7d9],
|
||||
[0x2a7873ab, 0xb60174a1, 0x1e300fd2, 0x9b7d493d],
|
||||
[0x86074f26, 0x2a7873ab, 0xb60174a1, 0x1e300fd2],
|
||||
[0x68021c3d, 0x86074f26, 0x2a7873ab, 0xb60174a1],
|
||||
[0xc9ad2750, 0x68021c3d, 0x86074f26, 0x2a7873ab],
|
||||
[0x6b1b8763, 0xc9ad2750, 0x68021c3d, 0x86074f26],
|
||||
[0x329a0609, 0x6b1b8763, 0xc9ad2750, 0x68021c3d],
|
||||
[0x3f3a2e5c, 0x329a0609, 0x6b1b8763, 0xc9ad2750],
|
||||
[0x34e64be9, 0x3f3a2e5c, 0x329a0609, 0x6b1b8763],
|
||||
[0x0de3f443, 0x34e64be9, 0x3f3a2e5c, 0x329a0609],
|
||||
[0x5fddbd79, 0x0de3f443, 0x34e64be9, 0x3f3a2e5c],
|
||||
[0x494abd6f, 0x5fddbd79, 0x0de3f443, 0x34e64be9],
|
||||
[0x9069bba6, 0x494abd6f, 0x5fddbd79, 0x0de3f443],
|
||||
[0x0d815e5e, 0x9069bba6, 0x494abd6f, 0x5fddbd79],
|
||||
[0x753ed018, 0x0d815e5e, 0x9069bba6, 0x494abd6f],
|
||||
[0xee224d71, 0x753ed018, 0x0d815e5e, 0x9069bba6],
|
||||
[0xd232eb01, 0xee224d71, 0x753ed018, 0x0d815e5e],
|
||||
[0x57e97dc9, 0xd232eb01, 0xee224d71, 0x753ed018],
|
||||
[0x252ee4a0, 0x57e97dc9, 0xd232eb01, 0xee224d71],
|
||||
[0x8d5bd7ef, 0x252ee4a0, 0x57e97dc9, 0xd232eb01],
|
||||
[0x92942054, 0x8d5bd7ef, 0x252ee4a0, 0x57e97dc9],
|
||||
[0x38475e43, 0x92942054, 0x8d5bd7ef, 0x252ee4a0],
|
||||
[0x22f47377, 0x38475e43, 0x92942054, 0x8d5bd7ef],
|
||||
[0xe6878422, 0x22f47377, 0x38475e43, 0x92942054],
|
||||
[0x5ab5fed1, 0xe6878422, 0x22f47377, 0x38475e43],
|
||||
[0x32463ee3, 0x5ab5fed1, 0xe6878422, 0x22f47377],
|
||||
[0x85465040, 0x32463ee3, 0x5ab5fed1, 0xe6878422],
|
||||
[0xb801aa18, 0x85465040, 0x32463ee3, 0x5ab5fed1],
|
||||
[0xd796ec48, 0xb801aa18, 0x85465040, 0x32463ee3],
|
||||
[0x5f8a08a4, 0xd796ec48, 0xb801aa18, 0x85465040],
|
||||
[0x7b15aa48, 0x5f8a08a4, 0xd796ec48, 0xb801aa18],
|
||||
[0x2722e8cf, 0x7b15aa48, 0x5f8a08a4, 0xd796ec48],
|
||||
[0x11062517, 0x2722e8cf, 0x7b15aa48, 0x5f8a08a4],
|
||||
];
|
||||
|
||||
// perform first step of md4 round 1
|
||||
let words: [u32; 16] = [
|
||||
0x65736f52, 0x20617474, 0x65646f43, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000060, 0x00000000,
|
||||
];
|
||||
let mut state: [u32; 4] = [A, B, C, D];
|
||||
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..48 {
|
||||
state = step(state, &words, i);
|
||||
assert_eq!(expected[i], state);
|
||||
state.rotate_right(1);
|
||||
}
|
||||
}
|
||||
}
|
205
src/hash/md5.rs
205
src/hash/md5.rs
|
@ -1,205 +0,0 @@
|
|||
use crate::hash::{bytes_to_words_le, md4::pad, words_to_bytes_le, Digest};
|
||||
|
||||
// based on RFC1321
|
||||
const A: u32 = 0x67452301;
|
||||
const B: u32 = 0xefcdab89;
|
||||
const C: u32 = 0x98badcfe;
|
||||
const D: u32 = 0x10325476;
|
||||
|
||||
const K: [u32; 64] = [
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
|
||||
];
|
||||
|
||||
// shifts & indices for each step
|
||||
const S: [u32; 64] = [
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
|
||||
14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15,
|
||||
21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
|
||||
];
|
||||
const W: [usize; 64] = [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8,
|
||||
13, 2, 7, 12, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 0, 7, 14, 5, 12, 3, 10, 1,
|
||||
8, 15, 6, 13, 4, 11, 2, 9,
|
||||
];
|
||||
|
||||
// round functions
|
||||
const F: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & y) | (!x & z);
|
||||
const G: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & z) | (y & !z);
|
||||
const H: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| x ^ y ^ z;
|
||||
const I: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| y ^ (x | !z);
|
||||
|
||||
fn step([mut a, b, c, d]: [u32; 4], words: &[u32], index: usize) -> [u32; 4] {
|
||||
let round_function = match index {
|
||||
0..=15 => F,
|
||||
16..=31 => G,
|
||||
32..=47 => H,
|
||||
48..=63 => I,
|
||||
_ => panic!("This function shouldn't be called using an index outside 0..48"),
|
||||
};
|
||||
|
||||
a = round_function(b, c, d)
|
||||
.wrapping_add(a)
|
||||
.wrapping_add(words[W[index]])
|
||||
.wrapping_add(K[index])
|
||||
.rotate_left(S[index])
|
||||
.wrapping_add(b);
|
||||
|
||||
[a, b, c, d]
|
||||
}
|
||||
|
||||
/// Computes the MD5 hash value (digest) of the input bytes.
|
||||
///
|
||||
/// Returns a 16-byte `Digest` which implements `Display` in order to get at hexadecimal-string representation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let input = "lol";
|
||||
/// let digest = lore::md5(input);
|
||||
///
|
||||
/// assert_eq!(digest.to_string(), "9cdfb439c7876e703e307864c9167a15");
|
||||
///
|
||||
/// ```
|
||||
pub fn hash(message: impl AsRef<[u8]>) -> Digest<16> {
|
||||
// the padding function for MD5 is exactly equivalent to the MD4 version, so we reuse it.
|
||||
let padded = pad(message);
|
||||
let buffer = padded.array_chunks::<64>().map(bytes_to_words_le).fold(
|
||||
[A, B, C, D],
|
||||
|[a, b, c, d], words| {
|
||||
// initialize state
|
||||
let mut state = [a, b, c, d];
|
||||
|
||||
for i in 0..64 {
|
||||
state = step(state, &words, i);
|
||||
println!("{state:08x?}");
|
||||
state.rotate_right(1);
|
||||
}
|
||||
|
||||
// add the computed state to the buffer
|
||||
[
|
||||
a.wrapping_add(state[0]),
|
||||
b.wrapping_add(state[1]),
|
||||
c.wrapping_add(state[2]),
|
||||
d.wrapping_add(state[3]),
|
||||
]
|
||||
},
|
||||
);
|
||||
let digest = *words_to_bytes_le(buffer)
|
||||
.array_chunks::<16>()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
Digest(digest)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn md5_hash() {
|
||||
assert_eq!("d41d8cd98f00b204e9800998ecf8427e", hash("").to_string());
|
||||
assert_eq!(
|
||||
"73e51861b65c1e83d6136fb6a002585e",
|
||||
hash("tihi xd").to_string()
|
||||
);
|
||||
assert_eq!("9cdfb439c7876e703e307864c9167a15", hash("lol").to_string());
|
||||
assert_eq!(
|
||||
"fd6f92edff2b7db7cd92b494c4926ef0",
|
||||
hash("Lorem ipsum dolor sit amet. Nam placeat iste aut dolorem necessitatibus sit unde magni. Nam cumque quia nam fugit quibusdam ut incidunt minima nam dignissimos iusto et voluptatum magnam. Et pariatur eius vel excepturi odit libero sit molestiae consequatur vel nostrum ullam. Sit sint beatae eos doloribus sapiente aut aperiam ullam ut laboriosam debitis! Qui reiciendis rerum est omnis galisum aut similique iure est dolores fuga sit rerum dicta. Aut excepturi fuga et enim ipsum a quia ut velit atque id iste nobis. Non molestiae vero et veritatis aliquam sed enim ducimus. At sunt tempora quo quisquam unde aut ipsum nulla et fugit eius in nulla fugit qui magnam excepturi aut rerum officia. Et officia magnam eos reiciendis voluptatum ea voluptas recusandae in similique enim. Ut provident laudantium ut temporibus eius ut laudantium voluptate aut ducimus impedit. Et asperiores aperiam sit deleniti voluptas ex porro omnis ut voluptas assumenda aut necessitatibus aliquid.").to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn md5_steps() {
|
||||
let expected: [[u32; 4]; 64] = [
|
||||
[0x5954a129, 0xefcdab89, 0x98badcfe, 0x10325476],
|
||||
[0x3171555d, 0x5954a129, 0xefcdab89, 0x98badcfe],
|
||||
[0x24368ecc, 0x3171555d, 0x5954a129, 0xefcdab89],
|
||||
[0x1d414db3, 0x24368ecc, 0x3171555d, 0x5954a129],
|
||||
[0x9da81fec, 0x1d414db3, 0x24368ecc, 0x3171555d],
|
||||
[0x983a9b4c, 0x9da81fec, 0x1d414db3, 0x24368ecc],
|
||||
[0x01f76eec, 0x983a9b4c, 0x9da81fec, 0x1d414db3],
|
||||
[0x82251f6b, 0x01f76eec, 0x983a9b4c, 0x9da81fec],
|
||||
[0x3648b77a, 0x82251f6b, 0x01f76eec, 0x983a9b4c],
|
||||
[0xa57749ed, 0x3648b77a, 0x82251f6b, 0x01f76eec],
|
||||
[0x69859a5a, 0xa57749ed, 0x3648b77a, 0x82251f6b],
|
||||
[0x8dd64e23, 0x69859a5a, 0xa57749ed, 0x3648b77a],
|
||||
[0x4cc08388, 0x8dd64e23, 0x69859a5a, 0xa57749ed],
|
||||
[0x9a1db095, 0x4cc08388, 0x8dd64e23, 0x69859a5a],
|
||||
[0xf3a1ec18, 0x9a1db095, 0x4cc08388, 0x8dd64e23],
|
||||
[0x68bf5f16, 0xf3a1ec18, 0x9a1db095, 0x4cc08388],
|
||||
[0x08cf03db, 0x68bf5f16, 0xf3a1ec18, 0x9a1db095],
|
||||
[0x03bceaa0, 0x08cf03db, 0x68bf5f16, 0xf3a1ec18],
|
||||
[0x2809715f, 0x03bceaa0, 0x08cf03db, 0x68bf5f16],
|
||||
[0xc305e2e6, 0x2809715f, 0x03bceaa0, 0x08cf03db],
|
||||
[0x0386e9c7, 0xc305e2e6, 0x2809715f, 0x03bceaa0],
|
||||
[0x0f4c9f59, 0x0386e9c7, 0xc305e2e6, 0x2809715f],
|
||||
[0x8814e065, 0x0f4c9f59, 0x0386e9c7, 0xc305e2e6],
|
||||
[0xd8d052d2, 0x8814e065, 0x0f4c9f59, 0x0386e9c7],
|
||||
[0x8ff59707, 0xd8d052d2, 0x8814e065, 0x0f4c9f59],
|
||||
[0x4069945d, 0x8ff59707, 0xd8d052d2, 0x8814e065],
|
||||
[0x213a0570, 0x4069945d, 0x8ff59707, 0xd8d052d2],
|
||||
[0xf2affb96, 0x213a0570, 0x4069945d, 0x8ff59707],
|
||||
[0x555223a9, 0xf2affb96, 0x213a0570, 0x4069945d],
|
||||
[0x37ba19ca, 0x555223a9, 0xf2affb96, 0x213a0570],
|
||||
[0x003749f2, 0x37ba19ca, 0x555223a9, 0xf2affb96],
|
||||
[0x20617338, 0x003749f2, 0x37ba19ca, 0x555223a9],
|
||||
[0xf3e971ee, 0x20617338, 0x003749f2, 0x37ba19ca],
|
||||
[0x4ec4ee85, 0xf3e971ee, 0x20617338, 0x003749f2],
|
||||
[0xe62bf9a6, 0x4ec4ee85, 0xf3e971ee, 0x20617338],
|
||||
[0x0ae8a02f, 0xe62bf9a6, 0x4ec4ee85, 0xf3e971ee],
|
||||
[0xbc31561a, 0x0ae8a02f, 0xe62bf9a6, 0x4ec4ee85],
|
||||
[0x6a9f6576, 0xbc31561a, 0x0ae8a02f, 0xe62bf9a6],
|
||||
[0x42e91ea3, 0x6a9f6576, 0xbc31561a, 0x0ae8a02f],
|
||||
[0x7a181668, 0x42e91ea3, 0x6a9f6576, 0xbc31561a],
|
||||
[0xedcc403b, 0x7a181668, 0x42e91ea3, 0x6a9f6576],
|
||||
[0x1fcae4da, 0xedcc403b, 0x7a181668, 0x42e91ea3],
|
||||
[0x217c84d1, 0x1fcae4da, 0xedcc403b, 0x7a181668],
|
||||
[0xf02591fa, 0x217c84d1, 0x1fcae4da, 0xedcc403b],
|
||||
[0x5375b853, 0xf02591fa, 0x217c84d1, 0x1fcae4da],
|
||||
[0xecd77499, 0x5375b853, 0xf02591fa, 0x217c84d1],
|
||||
[0x4bd1053f, 0xecd77499, 0x5375b853, 0xf02591fa],
|
||||
[0x7625a818, 0x4bd1053f, 0xecd77499, 0x5375b853],
|
||||
[0xf7223b53, 0x7625a818, 0x4bd1053f, 0xecd77499],
|
||||
[0x2e422a17, 0xf7223b53, 0x7625a818, 0x4bd1053f],
|
||||
[0xe5235245, 0x2e422a17, 0xf7223b53, 0x7625a818],
|
||||
[0x8e8a212d, 0xe5235245, 0x2e422a17, 0xf7223b53],
|
||||
[0x551950d2, 0x8e8a212d, 0xe5235245, 0x2e422a17],
|
||||
[0xf067530c, 0x551950d2, 0x8e8a212d, 0xe5235245],
|
||||
[0xdb4e97cc, 0xf067530c, 0x551950d2, 0x8e8a212d],
|
||||
[0x5b429768, 0xdb4e97cc, 0xf067530c, 0x551950d2],
|
||||
[0xb0c06d7a, 0x5b429768, 0xdb4e97cc, 0xf067530c],
|
||||
[0xd1906cf3, 0xb0c06d7a, 0x5b429768, 0xdb4e97cc],
|
||||
[0x3fc74ed9, 0xd1906cf3, 0xb0c06d7a, 0x5b429768],
|
||||
[0xa6b24624, 0x3fc74ed9, 0xd1906cf3, 0xb0c06d7a],
|
||||
[0xf9d3c272, 0xa6b24624, 0x3fc74ed9, 0xd1906cf3],
|
||||
[0x4e25ae2a, 0xf9d3c272, 0xa6b24624, 0x3fc74ed9],
|
||||
[0x1db436d8, 0x4e25ae2a, 0xf9d3c272, 0xa6b24624],
|
||||
[0x9350b12d, 0x1db436d8, 0x4e25ae2a, 0xf9d3c272],
|
||||
];
|
||||
|
||||
let words: [u32; 16] = [
|
||||
0x69686974, 0x80647820, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000038, 0x00000000,
|
||||
];
|
||||
let mut state = [A, B, C, D];
|
||||
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..64 {
|
||||
state = step(state, &words, i);
|
||||
assert_eq!(expected[i], state);
|
||||
state.rotate_right(1);
|
||||
}
|
||||
}
|
||||
}
|
148
src/hash/sha1.rs
148
src/hash/sha1.rs
|
@ -1,148 +0,0 @@
|
|||
use crate::hash::{bytes_to_words_be, words_to_bytes_be, Digest};
|
||||
|
||||
// based on RFC3174, Secure Hash Algorithm 1
|
||||
|
||||
// round functions
|
||||
const F1: fn(u32, u32, u32) -> u32 = |x, y, z| (x & y) | ((!x) & z);
|
||||
const F2: fn(u32, u32, u32) -> u32 = |x, y, z| x ^ y ^ z;
|
||||
const F3: fn(u32, u32, u32) -> u32 = |x, y, z| (x & y) | (x & z) | (y & z);
|
||||
const F4: fn(u32, u32, u32) -> u32 = |x, y, z| x ^ y ^ z;
|
||||
|
||||
// round constants
|
||||
const K1: u32 = 0x5a827999;
|
||||
const K2: u32 = 0x6ed9eba1;
|
||||
const K3: u32 = 0x8f1bbcdc;
|
||||
const K4: u32 = 0xca62c1d6;
|
||||
|
||||
// buffer 2 initial constants
|
||||
const H0: u32 = 0x67452301;
|
||||
const H1: u32 = 0xefcdab89;
|
||||
const H2: u32 = 0x98badcfe;
|
||||
const H3: u32 = 0x10325476;
|
||||
const H4: u32 = 0xc3d2e1f0;
|
||||
|
||||
fn pad(message: impl AsRef<[u8]>) -> Vec<u8> {
|
||||
let mut message = message.as_ref().to_vec();
|
||||
let message_length = message.len().wrapping_mul(8) as u64;
|
||||
|
||||
// push 1 bit (little endian)
|
||||
message.push(0x80);
|
||||
|
||||
// pad with 0 bits until length is congruent with 64 mod 56 bytes
|
||||
while (message.len() % 64) < 56 {
|
||||
message.push(0);
|
||||
}
|
||||
|
||||
// append the length of the original message (big endian)
|
||||
message.extend(message_length.to_be_bytes());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn step([a, b, c, d, e]: [u32; 5], words: &[u32], i: usize) -> [u32; 5] {
|
||||
let (k, f) = match i {
|
||||
0..=19 => (K1, F1),
|
||||
20..=39 => (K2, F2),
|
||||
40..=59 => (K3, F3),
|
||||
60..=79 => (K4, F4),
|
||||
_ => panic!("step function should not be called with index outside of range 0..80"),
|
||||
};
|
||||
|
||||
[
|
||||
a.rotate_left(5)
|
||||
.wrapping_add(f(b, c, d))
|
||||
.wrapping_add(e)
|
||||
.wrapping_add(k)
|
||||
.wrapping_add(words[i]),
|
||||
a,
|
||||
b.rotate_left(30),
|
||||
c,
|
||||
d,
|
||||
]
|
||||
}
|
||||
|
||||
/// Computes the SHA1 hash value (digest) of the input bytes.
|
||||
///
|
||||
/// Returns a 20-byte `Digest` which implements `Display` in order to get at hexadecimal-string representation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```rust
|
||||
/// let input = "abc";
|
||||
/// let digest = lore::sha1(input);
|
||||
///
|
||||
/// assert_eq!(digest.to_string(), "a9993e364706816aba3e25717850c26c9cd0d89d")
|
||||
/// ```
|
||||
pub fn hash(message: impl AsRef<[u8]>) -> Digest<20> {
|
||||
let padded = pad(message);
|
||||
|
||||
let buffer = padded
|
||||
.array_chunks::<64>()
|
||||
.map(|chunk| bytes_to_words_be(*chunk))
|
||||
.fold([H0, H1, H2, H3, H4], |[a, b, c, d, e], mut words| {
|
||||
// extend 16 words to 80 words
|
||||
for i in 16..80 {
|
||||
words.push(
|
||||
(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]).rotate_left(1),
|
||||
);
|
||||
}
|
||||
|
||||
// initialize state
|
||||
let mut state = [a, b, c, d, e];
|
||||
|
||||
// perform 80 steps
|
||||
for i in 0..80 {
|
||||
state = step(state, &words, i);
|
||||
}
|
||||
|
||||
// add computed round state to buffer
|
||||
[
|
||||
a.wrapping_add(state[0]),
|
||||
b.wrapping_add(state[1]),
|
||||
c.wrapping_add(state[2]),
|
||||
d.wrapping_add(state[3]),
|
||||
e.wrapping_add(state[4]),
|
||||
]
|
||||
});
|
||||
|
||||
let digest = *words_to_bytes_be(buffer)
|
||||
.array_chunks::<20>()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
Digest(digest)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sha1_pad() {
|
||||
let expected: [u8; 64] = [
|
||||
0x61, 0x62, 0x63, 0x64, 0x65, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x28,
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
expected.to_vec(),
|
||||
pad([0b01100001, 0b01100010, 0b01100011, 0b01100100, 0b01100101])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha1_hash() {
|
||||
assert_eq!(
|
||||
hash("").to_string(),
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
hash("abc").to_string(),
|
||||
"a9993e364706816aba3e25717850c26c9cd0d89d"
|
||||
);
|
||||
}
|
||||
}
|
22
src/lib.rs
22
src/lib.rs
|
@ -1,21 +1 @@
|
|||
// rust nightly features
|
||||
#![feature(array_chunks)]
|
||||
// lints
|
||||
#![deny(missing_docs)]
|
||||
#![warn(clippy::all, clippy::pedantic, clippy::cargo)]
|
||||
#![allow(
|
||||
clippy::unreadable_literal,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::many_single_char_names
|
||||
)]
|
||||
// docs
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
mod hash;
|
||||
|
||||
pub use hash::md2::hash as md2;
|
||||
pub use hash::md4::hash as md4;
|
||||
pub use hash::md5::hash as md5;
|
||||
pub use hash::sha1::hash as sha1;
|
||||
pub use hash::Digest;
|
||||
pub mod md5;
|
||||
|
|
205
src/md5.rs
Normal file
205
src/md5.rs
Normal file
|
@ -0,0 +1,205 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
// round functions as defined in RFC1321
|
||||
const F: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & y) | (!x & z);
|
||||
const G: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & z) | (y & !z);
|
||||
const H: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| x ^ y ^ z;
|
||||
const I: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| y ^ (x | !z);
|
||||
|
||||
// constants used in RFC132
|
||||
const K: [u32; 64] = [
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
|
||||
];
|
||||
|
||||
// shifts per round
|
||||
const S: [u32; 64] = [
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
|
||||
14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15,
|
||||
21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
|
||||
];
|
||||
|
||||
pub struct Hash([u32; 4]);
|
||||
|
||||
impl Hash {
|
||||
pub fn to_hex_string(&self) -> String {
|
||||
format!(
|
||||
"{:08x}{:08x}{:08x}{:08x}",
|
||||
self.0[0], self.0[1], self.0[2], self.0[3]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn preprocess(msg: impl AsRef<[u8]>) -> Vec<u8> {
|
||||
let mut message = msg.as_ref().to_vec();
|
||||
let len_in_bits = message.len().wrapping_mul(8) as u64;
|
||||
|
||||
// padding
|
||||
// add one bit first (le), then pad with zeroes
|
||||
message.push(0b10000000);
|
||||
while (message.len() * 8) % 512 != 448 {
|
||||
message.push(0u8);
|
||||
}
|
||||
|
||||
// append length
|
||||
message.extend(len_in_bits.to_le_bytes());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn op(
|
||||
function: impl Fn(u32, u32, u32) -> u32,
|
||||
state: (u32, u32, u32, u32),
|
||||
word: u32,
|
||||
index: usize,
|
||||
) -> u32 {
|
||||
function(state.1, state.2, state.3)
|
||||
.wrapping_add(state.0)
|
||||
.wrapping_add(word)
|
||||
.wrapping_add(K[index])
|
||||
.rotate_left(S[index])
|
||||
.wrapping_add(state.1)
|
||||
}
|
||||
|
||||
pub fn hash(input: impl AsRef<[u8]>) -> Hash {
|
||||
let (a, b, c, d) = preprocess(input).chunks_exact(64).fold(
|
||||
(0x67452301u32, 0xefcdab89u32, 0x98badcfeu32, 0x10325476u32),
|
||||
|(mut a0, mut b0, mut c0, mut d0), chunk| {
|
||||
let mut words = [0u32; 16];
|
||||
for (word, c) in words.iter_mut().zip(chunk.chunks_exact(4)) {
|
||||
*word = u32::from_le_bytes(c.try_into().unwrap());
|
||||
}
|
||||
let (mut a, mut b, mut c, mut d) = (a0, b0, c0, d0);
|
||||
|
||||
// round 1
|
||||
a = op(F, (a, b, c, d), words[0], 0);
|
||||
d = op(F, (d, a, b, c), words[1], 1);
|
||||
c = op(F, (c, d, a, b), words[2], 2);
|
||||
b = op(F, (b, c, d, a), words[3], 3);
|
||||
|
||||
a = op(F, (a, b, c, d), words[4], 4);
|
||||
d = op(F, (d, a, b, c), words[5], 5);
|
||||
c = op(F, (c, d, a, b), words[6], 6);
|
||||
b = op(F, (b, c, d, a), words[7], 7);
|
||||
|
||||
a = op(F, (a, b, c, d), words[8], 8);
|
||||
d = op(F, (d, a, b, c), words[9], 9);
|
||||
c = op(F, (c, d, a, b), words[10], 10);
|
||||
b = op(F, (b, c, d, a), words[11], 11);
|
||||
|
||||
a = op(F, (a, b, c, d), words[12], 12);
|
||||
d = op(F, (d, a, b, c), words[13], 13);
|
||||
c = op(F, (c, d, a, b), words[14], 14);
|
||||
b = op(F, (b, c, d, a), words[15], 15);
|
||||
|
||||
// round 2
|
||||
a = op(G, (a, b, c, d), words[1], 16);
|
||||
d = op(G, (d, a, b, c), words[6], 17);
|
||||
c = op(G, (c, d, a, b), words[11], 18);
|
||||
b = op(G, (b, c, d, a), words[0], 19);
|
||||
|
||||
a = op(G, (a, b, c, d), words[5], 20);
|
||||
d = op(G, (d, a, b, c), words[10], 21);
|
||||
c = op(G, (c, d, a, b), words[15], 22);
|
||||
b = op(G, (b, c, d, a), words[4], 23);
|
||||
|
||||
a = op(G, (a, b, c, d), words[9], 24);
|
||||
d = op(G, (d, a, b, c), words[14], 25);
|
||||
c = op(G, (c, d, a, b), words[3], 26);
|
||||
b = op(G, (b, c, d, a), words[8], 27);
|
||||
|
||||
a = op(G, (a, b, c, d), words[13], 28);
|
||||
d = op(G, (d, a, b, c), words[2], 29);
|
||||
c = op(G, (c, d, a, b), words[7], 30);
|
||||
b = op(G, (b, c, d, a), words[12], 31);
|
||||
|
||||
// round 3
|
||||
a = op(H, (a, b, c, d), words[5], 32);
|
||||
d = op(H, (d, a, b, c), words[8], 33);
|
||||
c = op(H, (c, d, a, b), words[11], 34);
|
||||
b = op(H, (b, c, d, a), words[14], 35);
|
||||
|
||||
a = op(H, (a, b, c, d), words[1], 36);
|
||||
d = op(H, (d, a, b, c), words[4], 37);
|
||||
c = op(H, (c, d, a, b), words[7], 38);
|
||||
b = op(H, (b, c, d, a), words[10], 39);
|
||||
|
||||
a = op(H, (a, b, c, d), words[13], 40);
|
||||
d = op(H, (d, a, b, c), words[0], 41);
|
||||
c = op(H, (c, d, a, b), words[3], 42);
|
||||
b = op(H, (b, c, d, a), words[6], 43);
|
||||
|
||||
a = op(H, (a, b, c, d), words[9], 44);
|
||||
d = op(H, (d, a, b, c), words[12], 45);
|
||||
c = op(H, (c, d, a, b), words[15], 46);
|
||||
b = op(H, (b, c, d, a), words[2], 47);
|
||||
|
||||
// round 4
|
||||
a = op(I, (a, b, c, d), words[0], 48);
|
||||
d = op(I, (d, a, b, c), words[7], 49);
|
||||
c = op(I, (c, d, a, b), words[14], 50);
|
||||
b = op(I, (b, c, d, a), words[5], 51);
|
||||
|
||||
a = op(I, (a, b, c, d), words[12], 52);
|
||||
d = op(I, (d, a, b, c), words[3], 53);
|
||||
c = op(I, (c, d, a, b), words[10], 54);
|
||||
b = op(I, (b, c, d, a), words[1], 55);
|
||||
|
||||
a = op(I, (a, b, c, d), words[8], 56);
|
||||
d = op(I, (d, a, b, c), words[15], 57);
|
||||
c = op(I, (c, d, a, b), words[6], 58);
|
||||
b = op(I, (b, c, d, a), words[13], 59);
|
||||
|
||||
a = op(I, (a, b, c, d), words[4], 60);
|
||||
d = op(I, (d, a, b, c), words[11], 61);
|
||||
c = op(I, (c, d, a, b), words[2], 62);
|
||||
b = op(I, (b, c, d, a), words[9], 63);
|
||||
|
||||
a0 = a0.wrapping_add(a);
|
||||
b0 = b0.wrapping_add(b);
|
||||
c0 = c0.wrapping_add(c);
|
||||
d0 = d0.wrapping_add(d);
|
||||
|
||||
(a0, b0, c0, d0)
|
||||
},
|
||||
);
|
||||
|
||||
Hash([
|
||||
a.swap_bytes(),
|
||||
b.swap_bytes(),
|
||||
c.swap_bytes(),
|
||||
d.swap_bytes(),
|
||||
])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::md5;
|
||||
|
||||
#[test]
|
||||
fn md5() {
|
||||
assert_eq!(
|
||||
"73e51861b65c1e83d6136fb6a002585e",
|
||||
md5::hash("tihi xd").to_hex_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"9cdfb439c7876e703e307864c9167a15",
|
||||
md5::hash("lol").to_hex_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"d41d8cd98f00b204e9800998ecf8427e",
|
||||
md5::hash("").to_hex_string()
|
||||
);
|
||||
|
||||
assert_eq!("fd6f92edff2b7db7cd92b494c4926ef0", md5::hash("Lorem ipsum dolor sit amet. Nam placeat iste aut dolorem necessitatibus sit unde magni. Nam cumque quia nam fugit quibusdam ut incidunt minima nam dignissimos iusto et voluptatum magnam. Et pariatur eius vel excepturi odit libero sit molestiae consequatur vel nostrum ullam. Sit sint beatae eos doloribus sapiente aut aperiam ullam ut laboriosam debitis! Qui reiciendis rerum est omnis galisum aut similique iure est dolores fuga sit rerum dicta. Aut excepturi fuga et enim ipsum a quia ut velit atque id iste nobis. Non molestiae vero et veritatis aliquam sed enim ducimus. At sunt tempora quo quisquam unde aut ipsum nulla et fugit eius in nulla fugit qui magnam excepturi aut rerum officia. Et officia magnam eos reiciendis voluptatum ea voluptas recusandae in similique enim. Ut provident laudantium ut temporibus eius ut laudantium voluptate aut ducimus impedit. Et asperiores aperiam sit deleniti voluptas ex porro omnis ut voluptas assumenda aut necessitatibus aliquid.").to_hex_string());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue