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.
|
||||
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]]
|
||||
name = "lore"
|
||||
version = "2.0.0"
|
||||
version = "2.1.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",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"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]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
version = "1.0.144"
|
||||
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"
|
||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||
dependencies = [
|
||||
"half",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"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]]
|
||||
name = "syn"
|
||||
version = "1.0.81"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
name = "unicode-ident"
|
||||
version = "1.0.4"
|
||||
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"
|
||||
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "lore"
|
||||
version = "2.0.0"
|
||||
version = "2.1.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 = []
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "^0.3", features = ["html_reports"] }
|
||||
[dependencies]
|
||||
serde = { version = ">=1.0.0", features = ["derive"], optional = true }
|
||||
|
||||
[[bench]]
|
||||
name = "md5"
|
||||
harness = false
|
||||
[features]
|
||||
default = []
|
||||
serde = ["dep:serde"]
|
33
README.md
33
README.md
|
@ -1,19 +1,32 @@
|
|||
# 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
|
||||
use lore::md5;
|
||||
|
||||
fn main() {
|
||||
let input = "lol xd";
|
||||
let digest = md5::hash(input);
|
||||
assert_eq!(digest, "982d7f24f8985a6baa5cf129acc73561");
|
||||
}
|
||||
let digest = lore::md5(input);
|
||||
assert_eq!(digest.to_string(), "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() {
|
||||
let input = "lol xd";
|
||||
|
||||
assert_eq!(
|
||||
md5::hash(input).to_hex_string(),
|
||||
"982d7f24f8985a6baa5cf129acc73561"
|
||||
);
|
||||
}
|
||||
fn main() {}
|
||||
|
|
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