Compare commits
10 commits
1c43531f3f
...
6b02b20dad
Author | SHA1 | Date | |
---|---|---|---|
6b02b20dad | |||
2baa7ab62a | |||
f1958765bc | |||
40e2593a5e | |||
e9ab63efe4 | |||
e8c0d38021 | |||
57ab36f117 | |||
9799c875a7 | |||
c5ca4a85df | |||
167a6cb25a |
13 changed files with 935 additions and 799 deletions
570
Cargo.lock
generated
570
Cargo.lock
generated
|
@ -2,598 +2,64 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
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 = "bumpalo"
|
|
||||||
version = "3.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cast"
|
|
||||||
version = "0.2.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
|
|
||||||
dependencies = [
|
|
||||||
"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]]
|
[[package]]
|
||||||
name = "lore"
|
name = "lore"
|
||||||
version = "2.0.0"
|
version = "2.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"serde",
|
||||||
]
|
|
||||||
|
|
||||||
[[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]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.32"
|
version = "1.0.43"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.10"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
|
|
||||||
dependencies = [
|
|
||||||
"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]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.130"
|
version = "1.0.144"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_cbor"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"half",
|
"serde_derive",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.130"
|
version = "1.0.144"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
|
|
||||||
dependencies = [
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.81"
|
version = "1.0.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "unicode-ident"
|
||||||
version = "0.11.0"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||||
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]
|
[package]
|
||||||
name = "lore"
|
name = "lore"
|
||||||
version = "2.0.0"
|
version = "2.1.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Zero-dependency hashing algorithms"
|
description = "Zero-dependency hashing algorithms"
|
||||||
license = "BSD-3-Clause"
|
license = "BSD-3-Clause"
|
||||||
|
@ -11,9 +11,9 @@ keywords = ["algorithms", "compression", "cryptography", "md5", "hash"]
|
||||||
categories = ["algorithms", "compression", "cryptography"]
|
categories = ["algorithms", "compression", "cryptography"]
|
||||||
exclude = []
|
exclude = []
|
||||||
|
|
||||||
[dev-dependencies]
|
[dependencies]
|
||||||
criterion = { version = "^0.3", features = ["html_reports"] }
|
serde = { version = ">=1.0.0", features = ["derive"], optional = true }
|
||||||
|
|
||||||
[[bench]]
|
[features]
|
||||||
name = "md5"
|
default = []
|
||||||
harness = false
|
serde = ["dep:serde"]
|
35
README.md
35
README.md
|
@ -1,19 +1,32 @@
|
||||||
# Lore
|
# Lore
|
||||||
|
|
||||||
Hashing algorithms. Currently only implements md5.
|
Nightly-only hashing algorithms with a straight-forward API and no required dependencies.
|
||||||
|
|
||||||
Doesn't use any dependencies.
|
This crate currently implements:
|
||||||
|
|
||||||
Performance/stability not guaranteed.
|
- MD2, MD4, and MD5
|
||||||
|
- SHA-1
|
||||||
|
|
||||||
## Example
|
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:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use lore::md5;
|
let input = "lol xd";
|
||||||
|
let digest = lore::md5(input);
|
||||||
fn main() {
|
assert_eq!(digest.to_string(), "982d7f24f8985a6baa5cf129acc73561");
|
||||||
let input = "lol xd";
|
|
||||||
let digest = md5::hash(input);
|
|
||||||
assert_eq!(digest, "982d7f24f8985a6baa5cf129acc73561");
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
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
rust-toolchain
Normal file
1
rust-toolchain
Normal file
|
@ -0,0 +1 @@
|
||||||
|
nightly
|
|
@ -1,10 +1 @@
|
||||||
use lore::md5;
|
fn main() {}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let input = "lol xd";
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
md5::hash(input).to_hex_string(),
|
|
||||||
"982d7f24f8985a6baa5cf129acc73561"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
120
src/hash.rs
Normal file
120
src/hash.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#[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
Normal file
146
src/hash/md2.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
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
Normal file
245
src/hash/md4.rs
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
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
Normal file
205
src/hash/md5.rs
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
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
Normal file
148
src/hash/sha1.rs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
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 +1,21 @@
|
||||||
pub mod md5;
|
// 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;
|
||||||
|
|
205
src/md5.rs
205
src/md5.rs
|
@ -1,205 +0,0 @@
|
||||||
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