зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1516304 - Re-vendor rust dependencies. r=kats
Depends on D15315 Differential Revision: https://phabricator.services.mozilla.com/D15316 --HG-- rename : third_party/rust/block-buffer/src/paddings.rs => third_party/rust/block-buffer-0.3.3/src/paddings.rs rename : third_party/rust/byte-tools/src/read_single.rs => third_party/rust/byte-tools-0.2.0/src/read_single.rs rename : third_party/rust/byte-tools/src/read_slice.rs => third_party/rust/byte-tools-0.2.0/src/read_slice.rs rename : third_party/rust/byte-tools/src/write_single.rs => third_party/rust/byte-tools-0.2.0/src/write_single.rs rename : third_party/rust/byte-tools/src/write_slice.rs => third_party/rust/byte-tools-0.2.0/src/write_slice.rs rename : third_party/rust/sha2/tests/data/sha224/test1.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha224/test1.output.bin rename : third_party/rust/sha2/tests/data/sha224/test2.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha224/test2.input.bin rename : third_party/rust/sha2/tests/data/sha224/test2.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha224/test2.output.bin rename : third_party/rust/sha2/tests/data/sha224/test3.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha224/test3.input.bin rename : third_party/rust/sha2/tests/data/sha224/test3.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha224/test3.output.bin rename : third_party/rust/sha2/tests/data/sha256/one_million_a.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha256/one_million_a.output.bin rename : third_party/rust/sha2/tests/data/sha256/test1.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha256/test1.output.bin rename : third_party/rust/sha2/tests/data/sha224/test2.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha256/test2.input.bin rename : third_party/rust/sha2/tests/data/sha256/test2.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha256/test2.output.bin rename : third_party/rust/sha2/tests/data/sha224/test3.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha256/test3.input.bin rename : third_party/rust/sha2/tests/data/sha256/test3.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha256/test3.output.bin rename : third_party/rust/sha2/tests/data/sha384/test1.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha384/test1.output.bin rename : third_party/rust/sha2/tests/data/sha224/test2.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha384/test2.input.bin rename : third_party/rust/sha2/tests/data/sha384/test2.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha384/test2.output.bin rename : third_party/rust/sha2/tests/data/sha224/test3.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha384/test3.input.bin rename : third_party/rust/sha2/tests/data/sha384/test3.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha384/test3.output.bin rename : third_party/rust/sha2/tests/data/sha512/one_million_a.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512/one_million_a.output.bin rename : third_party/rust/sha2/tests/data/sha512/test1.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512/test1.output.bin rename : third_party/rust/sha2/tests/data/sha224/test2.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha512/test2.input.bin rename : third_party/rust/sha2/tests/data/sha512/test2.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512/test2.output.bin rename : third_party/rust/sha2/tests/data/sha224/test3.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha512/test3.input.bin rename : third_party/rust/sha2/tests/data/sha512/test3.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512/test3.output.bin rename : third_party/rust/sha2/tests/data/sha512_224/test1.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_224/test1.output.bin rename : third_party/rust/sha2/tests/data/sha224/test2.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_224/test2.input.bin rename : third_party/rust/sha2/tests/data/sha512_224/test2.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_224/test2.output.bin rename : third_party/rust/sha2/tests/data/sha224/test3.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_224/test3.input.bin rename : third_party/rust/sha2/tests/data/sha512_224/test3.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_224/test3.output.bin rename : third_party/rust/sha2/tests/data/sha512_256/test1.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_256/test1.output.bin rename : third_party/rust/sha2/tests/data/sha224/test2.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_256/test2.input.bin rename : third_party/rust/sha2/tests/data/sha512_256/test2.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_256/test2.output.bin rename : third_party/rust/sha2/tests/data/sha224/test3.input.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_256/test3.input.bin rename : third_party/rust/sha2/tests/data/sha512_256/test3.output.bin => third_party/rust/sha2-0.7.1/tests/data/sha512_256/test3.output.bin rename : third_party/rust/sha2/tests/data/sha256/one_million_a.output.bin => third_party/rust/sha2/tests/data/sha256_one_million_a.bin rename : third_party/rust/sha2/tests/data/sha512/one_million_a.output.bin => third_party/rust/sha2/tests/data/sha512_one_million_a.bin extra : moz-landing-system : lando
This commit is contained in:
Родитель
05bc857d23
Коммит
cdfba84b4e
|
@ -282,6 +282,25 @@ dependencies = [
|
|||
"byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "boxfnonce"
|
||||
version = "0.0.3"
|
||||
|
@ -297,6 +316,11 @@ name = "byte-tools"
|
|||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.1"
|
||||
|
@ -728,6 +752,14 @@ dependencies = [
|
|||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "1.0.4"
|
||||
|
@ -1012,6 +1044,14 @@ dependencies = [
|
|||
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gkrust"
|
||||
version = "0.1.0"
|
||||
|
@ -1765,6 +1805,11 @@ dependencies = [
|
|||
"uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "1.0.1"
|
||||
|
@ -2266,6 +2311,17 @@ dependencies = [
|
|||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd"
|
||||
version = "0.2.3"
|
||||
|
@ -2944,7 +3000,7 @@ dependencies = [
|
|||
"rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3130,9 +3186,12 @@ dependencies = [
|
|||
"checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
|
||||
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
|
||||
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
|
||||
"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d"
|
||||
"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3"
|
||||
"checksum boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8380105befe91099e6f69206164072c05bc92427ff6aa8a5171388317346dd75"
|
||||
"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9"
|
||||
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
||||
"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182"
|
||||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||
"checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8"
|
||||
"checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24"
|
||||
|
@ -3179,6 +3238,7 @@ dependencies = [
|
|||
"checksum devd-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c9ac481c38baf400d3b732e4a06850dfaa491d1b6379a249d9d40d14c2434c"
|
||||
"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
|
||||
"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
|
||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
|
||||
"checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
|
@ -3206,6 +3266,7 @@ dependencies = [
|
|||
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
|
||||
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
|
||||
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||
"checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604"
|
||||
"checksum gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4b47f5b15742aee359c7895ab98cf2cceecc89bb4feb6f4e42f802d7899877da"
|
||||
|
@ -3265,6 +3326,7 @@ dependencies = [
|
|||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
|
||||
"checksum object 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cca6ad89d0801138cb4ef606908ae12d83edc4c790ef5178fc7b4c72d959e90"
|
||||
"checksum opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682"
|
||||
"checksum ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0015e9e8e28ee20c581cfbfe47c650cedeb9ed0721090e0b7ebb10b9cdbcc2"
|
||||
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
|
@ -3320,6 +3382,7 @@ dependencies = [
|
|||
"checksum serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)" = "<none>"
|
||||
"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"
|
||||
"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0"
|
||||
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||
"checksum simd 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0048b17eb9577ac545c61d85c3559b41dfb4cbea41c9bd9ca6a4f73ff05fda84"
|
||||
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"373908618d7bdf561f84ddc5add92f69dab295c97ab0908d3a4ec428fad23bad","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/lib.rs":"bdf23c8a00fb4d51beabeb6600fe45ebf1be618632db885013b6f60a5666c124","src/paddings.rs":"7a18850dab9dca0a3e6cc49d6a94a9566ea2473628f42f726a69f8e07f95872a"},"package":"a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"}
|
|
@ -0,0 +1,27 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "block-buffer"
|
||||
version = "0.3.3"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Fixed size buffer for block processing of data"
|
||||
documentation = "https://docs.rs/block-buffer"
|
||||
keywords = ["block", "padding", "pkcs7", "ansix923", "iso7816"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/utils"
|
||||
[dependencies.arrayref]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.byte-tools]
|
||||
version = "0.2"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2017 Artyom Pavlov
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,144 @@
|
|||
#![no_std]
|
||||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
extern crate byte_tools;
|
||||
|
||||
use byte_tools::{zero, write_u64_le};
|
||||
|
||||
mod paddings;
|
||||
|
||||
pub use paddings::*;
|
||||
|
||||
macro_rules! impl_buffer {
|
||||
($name:ident, $len:expr) => {
|
||||
|
||||
pub struct $name {
|
||||
buffer: [u8; $len],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl Copy for $name {}
|
||||
|
||||
impl Clone for $name {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $name {
|
||||
fn default() -> Self {
|
||||
$name {buffer: [0; $len], pos: 0}
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
#[inline]
|
||||
pub fn input<F: FnMut(&[u8; $len])>(&mut self, mut input: &[u8], mut func: F) {
|
||||
// If there is already data in the buffer, copy as much as we can
|
||||
// into it and process the data if the buffer becomes full.
|
||||
if self.pos != 0 {
|
||||
let rem = self.remaining();
|
||||
|
||||
if input.len() >= rem {
|
||||
let (l, r) = input.split_at(rem);
|
||||
input = r;
|
||||
self.buffer[self.pos..].copy_from_slice(l);
|
||||
self.pos = 0;
|
||||
func(&self.buffer);
|
||||
} else {
|
||||
let end = self.pos + input.len();
|
||||
self.buffer[self.pos..end].copy_from_slice(input);
|
||||
self.pos = end;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// While we have at least a full buffer size chunks's worth of data,
|
||||
// process that data without copying it into the buffer
|
||||
while input.len() >= self.size() {
|
||||
let (l, r) = input.split_at(self.size());
|
||||
input = r;
|
||||
func(array_ref!(l, 0, $len));
|
||||
}
|
||||
|
||||
// Copy any input data into the buffer. At this point in the method,
|
||||
// the ammount of data left in the input vector will be less than
|
||||
// the buffer size and the buffer will be empty.
|
||||
self.buffer[..input.len()].copy_from_slice(input);
|
||||
self.pos = input.len();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn digest_pad<F>(&mut self, up_to: usize, func: &mut F)
|
||||
where F: FnMut(&[u8; $len])
|
||||
{
|
||||
self.buffer[self.pos] = 0x80;
|
||||
self.pos += 1;
|
||||
|
||||
zero(&mut self.buffer[self.pos..]);
|
||||
|
||||
if self.remaining() < up_to {
|
||||
func(&self.buffer);
|
||||
zero(&mut self.buffer[..self.pos]);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Will pad message with message length in big-endian format
|
||||
pub fn len_padding<F>(&mut self, data_len: u64, mut func: F)
|
||||
where F: FnMut(&[u8; $len])
|
||||
{
|
||||
self.digest_pad(8, &mut func);
|
||||
let s = self.size();
|
||||
write_u64_le(&mut self.buffer[s-8..], data_len);
|
||||
func(&self.buffer);
|
||||
self.pos = 0;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len_padding_u128<F>(&mut self, hi: u64, lo: u64, mut func: F)
|
||||
where F: FnMut(&[u8; $len])
|
||||
{
|
||||
self.digest_pad(16, &mut func);
|
||||
let s = self.size();
|
||||
write_u64_le(&mut self.buffer[s-16..s-8], hi);
|
||||
write_u64_le(&mut self.buffer[s-8..], lo);
|
||||
func(&self.buffer);
|
||||
self.pos = 0;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pad_with<P: Padding>(&mut self) -> &mut [u8; $len] {
|
||||
P::pad(&mut self.buffer[..], self.pos);
|
||||
self.pos = 0;
|
||||
&mut self.buffer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
$len
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn position(&self) -> usize {
|
||||
self.pos
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.size() - self.pos
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_buffer!(BlockBuffer128, 16);
|
||||
impl_buffer!(BlockBuffer256, 32);
|
||||
impl_buffer!(BlockBuffer512, 64);
|
||||
impl_buffer!(BlockBuffer1024, 128);
|
||||
|
||||
impl_buffer!(BlockBuffer576, 72);
|
||||
impl_buffer!(BlockBuffer832, 104);
|
||||
impl_buffer!(BlockBuffer1088, 136);
|
||||
impl_buffer!(BlockBuffer1152, 144);
|
||||
impl_buffer!(BlockBuffer1344, 168);
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"373908618d7bdf561f84ddc5add92f69dab295c97ab0908d3a4ec428fad23bad","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/lib.rs":"bdf23c8a00fb4d51beabeb6600fe45ebf1be618632db885013b6f60a5666c124","src/paddings.rs":"7a18850dab9dca0a3e6cc49d6a94a9566ea2473628f42f726a69f8e07f95872a"},"package":"a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"}
|
||||
{"files":{"Cargo.toml":"1f13fcd2c3ee3e1a47b5f1519a9840f6fc00a6c9b54ad29697e6120e3756f4b8","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/lib.rs":"13262364125a588d9cd179e1bd24a3286f8778b8d3f11fc86cce605939ebe5b1"},"package":"49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d"}
|
|
@ -12,16 +12,25 @@
|
|||
|
||||
[package]
|
||||
name = "block-buffer"
|
||||
version = "0.3.3"
|
||||
version = "0.7.0"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Fixed size buffer for block processing of data"
|
||||
documentation = "https://docs.rs/block-buffer"
|
||||
keywords = ["block", "padding", "pkcs7", "ansix923", "iso7816"]
|
||||
keywords = ["block", "buffer"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/utils"
|
||||
[dependencies.arrayref]
|
||||
version = "0.3"
|
||||
[dependencies.block-padding]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.byte-tools]
|
||||
version = "0.2"
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.byteorder]
|
||||
version = "1"
|
||||
default-features = false
|
||||
|
||||
[dependencies.generic-array]
|
||||
version = "0.12"
|
||||
[badges.travis-ci]
|
||||
repository = "RustCrypto/utils"
|
||||
|
|
|
@ -1,144 +1,170 @@
|
|||
#![no_std]
|
||||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
pub extern crate byteorder;
|
||||
pub extern crate block_padding;
|
||||
pub extern crate generic_array;
|
||||
extern crate byte_tools;
|
||||
|
||||
use byte_tools::{zero, write_u64_le};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use byte_tools::zero;
|
||||
use block_padding::{Padding, PadError};
|
||||
use generic_array::{GenericArray, ArrayLength};
|
||||
|
||||
mod paddings;
|
||||
|
||||
pub use paddings::*;
|
||||
|
||||
macro_rules! impl_buffer {
|
||||
($name:ident, $len:expr) => {
|
||||
|
||||
pub struct $name {
|
||||
buffer: [u8; $len],
|
||||
/// Buffer for block processing of data
|
||||
#[derive(Clone, Default)]
|
||||
pub struct BlockBuffer<BlockSize: ArrayLength<u8>> {
|
||||
buffer: GenericArray<u8, BlockSize>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl Copy for $name {}
|
||||
|
||||
impl Clone for $name {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn cast<N: ArrayLength<u8>>(block: &[u8]) -> &GenericArray<u8, N> {
|
||||
debug_assert_eq!(block.len(), N::to_usize());
|
||||
&*(block.as_ptr() as *const GenericArray<u8, N>)
|
||||
}
|
||||
|
||||
impl Default for $name {
|
||||
fn default() -> Self {
|
||||
$name {buffer: [0; $len], pos: 0}
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
impl<BlockSize: ArrayLength<u8>> BlockBuffer<BlockSize> {
|
||||
/// Process data in `input` in blocks of size `BlockSize` using function `f`.
|
||||
#[inline]
|
||||
pub fn input<F: FnMut(&[u8; $len])>(&mut self, mut input: &[u8], mut func: F) {
|
||||
// If there is already data in the buffer, copy as much as we can
|
||||
// into it and process the data if the buffer becomes full.
|
||||
if self.pos != 0 {
|
||||
pub fn input<F>(&mut self, mut input: &[u8], mut f: F)
|
||||
where F: FnMut(&GenericArray<u8, BlockSize>)
|
||||
{
|
||||
// If there is already data in the buffer, process it if we have
|
||||
// enough to complete the chunk.
|
||||
let rem = self.remaining();
|
||||
|
||||
if input.len() >= rem {
|
||||
if self.pos != 0 && input.len() >= rem {
|
||||
let (l, r) = input.split_at(rem);
|
||||
input = r;
|
||||
self.buffer[self.pos..].copy_from_slice(l);
|
||||
self.pos = 0;
|
||||
func(&self.buffer);
|
||||
} else {
|
||||
let end = self.pos + input.len();
|
||||
self.buffer[self.pos..end].copy_from_slice(input);
|
||||
self.pos = end;
|
||||
return;
|
||||
}
|
||||
f(&self.buffer);
|
||||
}
|
||||
|
||||
// While we have at least a full buffer size chunks's worth of data,
|
||||
// process that data without copying it into the buffer
|
||||
while input.len() >= self.size() {
|
||||
let (l, r) = input.split_at(self.size());
|
||||
let (block, r) = input.split_at(self.size());
|
||||
input = r;
|
||||
func(array_ref!(l, 0, $len));
|
||||
f(unsafe { cast(block) });
|
||||
}
|
||||
|
||||
// Copy any input data into the buffer. At this point in the method,
|
||||
// the ammount of data left in the input vector will be less than
|
||||
// the buffer size and the buffer will be empty.
|
||||
self.buffer[..input.len()].copy_from_slice(input);
|
||||
self.pos = input.len();
|
||||
// Copy any remaining data into the buffer.
|
||||
self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input);
|
||||
self.pos += input.len();
|
||||
}
|
||||
|
||||
/// Variant that doesn't flush the buffer until there's additional
|
||||
/// data to be processed. Suitable for tweakable block ciphers
|
||||
/// like Threefish that need to know whether a block is the *last*
|
||||
/// data block before processing it.
|
||||
#[inline]
|
||||
fn digest_pad<F>(&mut self, up_to: usize, func: &mut F)
|
||||
where F: FnMut(&[u8; $len])
|
||||
pub fn input_lazy<F>(&mut self, mut input: &[u8], mut f: F)
|
||||
where F: FnMut(&GenericArray<u8, BlockSize>)
|
||||
{
|
||||
let rem = self.remaining();
|
||||
if self.pos != 0 && input.len() > rem {
|
||||
let (l, r) = input.split_at(rem);
|
||||
input = r;
|
||||
self.buffer[self.pos..].copy_from_slice(l);
|
||||
self.pos = 0;
|
||||
f(&self.buffer);
|
||||
}
|
||||
|
||||
while input.len() > self.size() {
|
||||
let (block, r) = input.split_at(self.size());
|
||||
input = r;
|
||||
f(unsafe { cast(block) });
|
||||
}
|
||||
|
||||
self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input);
|
||||
self.pos += input.len();
|
||||
}
|
||||
|
||||
/// Pad buffer with `prefix` and make sure that internall buffer
|
||||
/// has at least `up_to` free bytes. All remaining bytes get
|
||||
/// zeroed-out.
|
||||
#[inline]
|
||||
fn digest_pad<F>(&mut self, up_to: usize, f: &mut F)
|
||||
where F: FnMut(&GenericArray<u8, BlockSize>)
|
||||
{
|
||||
if self.pos == self.size() {
|
||||
f(&self.buffer);
|
||||
self.pos = 0;
|
||||
}
|
||||
self.buffer[self.pos] = 0x80;
|
||||
self.pos += 1;
|
||||
|
||||
zero(&mut self.buffer[self.pos..]);
|
||||
|
||||
if self.remaining() < up_to {
|
||||
func(&self.buffer);
|
||||
f(&self.buffer);
|
||||
zero(&mut self.buffer[..self.pos]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pad message with 0x80, zeros and 64-bit message length
|
||||
/// in a byte order specified by `B`
|
||||
#[inline]
|
||||
/// Will pad message with message length in big-endian format
|
||||
pub fn len_padding<F>(&mut self, data_len: u64, mut func: F)
|
||||
where F: FnMut(&[u8; $len])
|
||||
pub fn len64_padding<B, F>(&mut self, data_len: u64, mut f: F)
|
||||
where B: ByteOrder, F: FnMut(&GenericArray<u8, BlockSize>)
|
||||
{
|
||||
self.digest_pad(8, &mut func);
|
||||
// TODO: replace `F` with `impl Trait` on MSRV bump
|
||||
self.digest_pad(8, &mut f);
|
||||
let s = self.size();
|
||||
write_u64_le(&mut self.buffer[s-8..], data_len);
|
||||
func(&self.buffer);
|
||||
B::write_u64(&mut self.buffer[s-8..], data_len);
|
||||
f(&self.buffer);
|
||||
self.pos = 0;
|
||||
}
|
||||
|
||||
|
||||
/// Pad message with 0x80, zeros and 128-bit message length
|
||||
/// in the big-endian byte order
|
||||
#[inline]
|
||||
pub fn len_padding_u128<F>(&mut self, hi: u64, lo: u64, mut func: F)
|
||||
where F: FnMut(&[u8; $len])
|
||||
pub fn len128_padding_be<F>(&mut self, hi: u64, lo: u64, mut f: F)
|
||||
where F: FnMut(&GenericArray<u8, BlockSize>)
|
||||
{
|
||||
self.digest_pad(16, &mut func);
|
||||
// TODO: on MSRV bump replace `F` with `impl Trait`, use `u128`, add `B`
|
||||
self.digest_pad(16, &mut f);
|
||||
let s = self.size();
|
||||
write_u64_le(&mut self.buffer[s-16..s-8], hi);
|
||||
write_u64_le(&mut self.buffer[s-8..], lo);
|
||||
func(&self.buffer);
|
||||
BE::write_u64(&mut self.buffer[s-16..s-8], hi);
|
||||
BE::write_u64(&mut self.buffer[s-8..], lo);
|
||||
f(&self.buffer);
|
||||
self.pos = 0;
|
||||
}
|
||||
|
||||
/// Pad message with a given padding `P`
|
||||
///
|
||||
/// Returns `PadError` if internall buffer is full, which can only happen if
|
||||
/// `input_lazy` was used.
|
||||
#[inline]
|
||||
pub fn pad_with<P: Padding>(&mut self) -> &mut [u8; $len] {
|
||||
P::pad(&mut self.buffer[..], self.pos);
|
||||
pub fn pad_with<P: Padding>(&mut self)
|
||||
-> Result<&mut GenericArray<u8, BlockSize>, PadError>
|
||||
{
|
||||
P::pad_block(&mut self.buffer[..], self.pos)?;
|
||||
self.pos = 0;
|
||||
&mut self.buffer
|
||||
Ok(&mut self.buffer)
|
||||
}
|
||||
|
||||
/// Return size of the internall buffer in bytes
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
$len
|
||||
BlockSize::to_usize()
|
||||
}
|
||||
|
||||
/// Return current cursor position
|
||||
#[inline]
|
||||
pub fn position(&self) -> usize {
|
||||
self.pos
|
||||
}
|
||||
|
||||
/// Return number of remaining bytes in the internall buffer
|
||||
#[inline]
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.size() - self.pos
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_buffer!(BlockBuffer128, 16);
|
||||
impl_buffer!(BlockBuffer256, 32);
|
||||
impl_buffer!(BlockBuffer512, 64);
|
||||
impl_buffer!(BlockBuffer1024, 128);
|
||||
|
||||
impl_buffer!(BlockBuffer576, 72);
|
||||
impl_buffer!(BlockBuffer832, 104);
|
||||
impl_buffer!(BlockBuffer1088, 136);
|
||||
impl_buffer!(BlockBuffer1152, 144);
|
||||
impl_buffer!(BlockBuffer1344, 168);
|
||||
/// Reset buffer by setting cursor position to zero
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.pos = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"31334ebd0923996ae8fb76ee87f9b2d75cc9e85c5126ef614e184af56dd96403","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"f7e8ab639afef15573680c97f796166835cbeb3865175882fea41c60d106b733","src/lib.rs":"812d9b3b472539aa4cc78745313d088879aafa8d1baa69872bc1ca8ee5bcfa41"},"package":"4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3"}
|
|
@ -0,0 +1,26 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "block-padding"
|
||||
version = "0.1.2"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Padding and unpadding of messages divided into blocks."
|
||||
documentation = "https://docs.rs/block-padding"
|
||||
keywords = ["padding", "pkcs7", "ansix923", "iso7816"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/utils"
|
||||
[dependencies.byte-tools]
|
||||
version = "0.3"
|
||||
[badges.travis-ci]
|
||||
repository = "RustCrypto/utils"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2018 Artyom Pavlov
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,276 @@
|
|||
//! Padding and unpadding of messages divided into blocks.
|
||||
//!
|
||||
//! This crate provides `Padding` trait which provides padding and unpadding
|
||||
//! operations. Additionally several common padding schemes are available out
|
||||
//! of the box.
|
||||
#![no_std]
|
||||
#![doc(html_logo_url =
|
||||
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
|
||||
extern crate byte_tools;
|
||||
|
||||
use byte_tools::{zero, set};
|
||||
|
||||
/// Error for indicating failed padding operation
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct PadError;
|
||||
|
||||
/// Error for indicating failed unpadding operation
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UnpadError;
|
||||
|
||||
/// Trait for padding messages divided into blocks
|
||||
pub trait Padding {
|
||||
/// Pads `block` filled with data up to `pos`.
|
||||
///
|
||||
/// `pos` should be inside of the block and block must not be full, i.e.
|
||||
/// `pos < block.len()` must be true. Otherwise method will return
|
||||
/// `PadError`. Some potentially irreversible padding schemes can allow
|
||||
/// padding of the full block, in this case aforementioned condition is
|
||||
/// relaxed to `pos <= block.len()`.
|
||||
fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError>;
|
||||
|
||||
/// Pads message with length `pos` in the provided buffer.
|
||||
///
|
||||
/// `&buf[..pos]` is percieved as the message, buffer must contain at
|
||||
/// least one block of leftover space, i.e. `buf.len() - pos >= block_size`
|
||||
/// must be true. Otherwise method will return `PadError`.
|
||||
fn pad(buf: &mut [u8], pos: usize, block_size: usize)
|
||||
-> Result<&mut [u8], PadError>
|
||||
{
|
||||
if buf.len() - pos < block_size { Err(PadError)? }
|
||||
if pos % block_size == 0 {
|
||||
Self::pad_block(&mut buf[pos..pos + block_size], 0)?;
|
||||
Ok(&mut buf[..pos+block_size])
|
||||
} else {
|
||||
let bs = block_size * (pos / block_size);
|
||||
Self::pad_block(&mut buf[bs..bs+block_size], pos - bs)?;
|
||||
Ok(&mut buf[..bs+block_size])
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpad given `data` by truncating it according to the used padding.
|
||||
/// In case of the malformed padding will return `UnpadError`
|
||||
fn unpad(data: &[u8]) -> Result<&[u8], UnpadError>;
|
||||
}
|
||||
|
||||
/// Pad block with zeros.
|
||||
///
|
||||
/// ```
|
||||
/// use block_padding::{ZeroPadding, Padding};
|
||||
///
|
||||
/// let msg = b"test";
|
||||
/// let n = msg.len();
|
||||
/// let mut buffer = [0xff; 16];
|
||||
/// buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = ZeroPadding::pad(&mut buffer, n, 8).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test\x00\x00\x00\x00");
|
||||
/// assert_eq!(ZeroPadding::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
/// ```
|
||||
/// # use block_padding::{ZeroPadding, Padding};
|
||||
/// # let msg = b"test";
|
||||
/// # let n = msg.len();
|
||||
/// # let mut buffer = [0xff; 16];
|
||||
/// # buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = ZeroPadding::pad(&mut buffer, n, 2).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test");
|
||||
/// assert_eq!(ZeroPadding::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
///
|
||||
/// Note that zero padding may not be reversible if the original message ends
|
||||
/// with one or more zero bytes.
|
||||
pub enum ZeroPadding{}
|
||||
|
||||
impl Padding for ZeroPadding {
|
||||
fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> {
|
||||
if pos > block.len() { Err(PadError)? }
|
||||
zero(&mut block[pos..]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pad(buf: &mut [u8], pos: usize, block_size: usize)
|
||||
-> Result<&mut [u8], PadError>
|
||||
{
|
||||
if pos % block_size == 0 {
|
||||
Ok(&mut buf[..pos])
|
||||
} else {
|
||||
let bs = block_size * (pos / block_size);
|
||||
let be = bs + block_size;
|
||||
if buf.len() < be { Err(PadError)? }
|
||||
Self::pad_block(&mut buf[bs..be], pos - bs)?;
|
||||
Ok(&mut buf[..be])
|
||||
}
|
||||
}
|
||||
|
||||
fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> {
|
||||
let mut n = data.len() - 1;
|
||||
while n != 0 {
|
||||
if data[n] != 0 {
|
||||
break;
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
Ok(&data[..n+1])
|
||||
}
|
||||
}
|
||||
|
||||
/// Pad block with bytes with value equal to the number of bytes added.
|
||||
///
|
||||
/// PKCS#7 described in the [RFC 5652](https://tools.ietf.org/html/rfc5652#section-6.3).
|
||||
///
|
||||
/// ```
|
||||
/// use block_padding::{Pkcs7, Padding};
|
||||
///
|
||||
/// let msg = b"test";
|
||||
/// let n = msg.len();
|
||||
/// let mut buffer = [0xff; 16];
|
||||
/// buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = Pkcs7::pad(&mut buffer, n, 8).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test\x04\x04\x04\x04");
|
||||
/// assert_eq!(Pkcs7::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
/// ```
|
||||
/// # use block_padding::{Pkcs7, Padding};
|
||||
/// # let msg = b"test";
|
||||
/// # let n = msg.len();
|
||||
/// # let mut buffer = [0xff; 16];
|
||||
/// # buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = Pkcs7::pad(&mut buffer, n, 2).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test\x02\x02");
|
||||
/// assert_eq!(Pkcs7::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
/// ```
|
||||
/// # use block_padding::{Pkcs7, Padding};
|
||||
/// # let buffer = [0xff; 16];
|
||||
/// assert!(Pkcs7::unpad(&buffer).is_err());
|
||||
/// ```
|
||||
///
|
||||
/// In addition to conditions stated in the `Padding` trait documentation,
|
||||
/// `pad_block` will return `PadError` if `block.len() > 255`, and in case of
|
||||
/// `pad` if `block_size > 255`.
|
||||
pub enum Pkcs7{}
|
||||
|
||||
impl Padding for Pkcs7 {
|
||||
fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> {
|
||||
if block.len() > 255 { Err(PadError)? }
|
||||
if pos >= block.len() { Err(PadError)? }
|
||||
let n = block.len() - pos;
|
||||
set(&mut block[pos..], n as u8);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> {
|
||||
if data.is_empty() { Err(UnpadError)? }
|
||||
let l = data.len();
|
||||
let n = data[l-1];
|
||||
if n == 0 || n as usize > l { Err(UnpadError)? }
|
||||
for v in &data[l-n as usize..l-1] {
|
||||
if *v != n { Err(UnpadError)? }
|
||||
}
|
||||
Ok(&data[..l - n as usize])
|
||||
}
|
||||
}
|
||||
|
||||
/// Pad block with zeros excpet the last byte which will be set to the number
|
||||
/// bytes.
|
||||
///
|
||||
/// ```
|
||||
/// use block_padding::{AnsiX923, Padding};
|
||||
///
|
||||
/// let msg = b"test";
|
||||
/// let n = msg.len();
|
||||
/// let mut buffer = [0xff; 16];
|
||||
/// buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = AnsiX923::pad(&mut buffer, n, 8).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test\x00\x00\x00\x04");
|
||||
/// assert_eq!(AnsiX923::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
/// ```
|
||||
/// # use block_padding::{AnsiX923, Padding};
|
||||
/// # let msg = b"test";
|
||||
/// # let n = msg.len();
|
||||
/// # let mut buffer = [0xff; 16];
|
||||
/// # buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = AnsiX923::pad(&mut buffer, n, 2).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test\x00\x02");
|
||||
/// assert_eq!(AnsiX923::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
/// ```
|
||||
/// # use block_padding::{AnsiX923, Padding};
|
||||
/// # let buffer = [0xff; 16];
|
||||
/// assert!(AnsiX923::unpad(&buffer).is_err());
|
||||
/// ```
|
||||
///
|
||||
/// In addition to conditions stated in the `Padding` trait documentation,
|
||||
/// `pad_block` will return `PadError` if `block.len() > 255`, and in case of
|
||||
/// `pad` if `block_size > 255`.
|
||||
pub enum AnsiX923{}
|
||||
|
||||
impl Padding for AnsiX923 {
|
||||
fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError>{
|
||||
if block.len() > 255 { Err(PadError)? }
|
||||
if pos >= block.len() { Err(PadError)? }
|
||||
let bs = block.len();
|
||||
zero(&mut block[pos..bs-1]);
|
||||
block[bs-1] = (bs - pos) as u8;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> {
|
||||
if data.is_empty() { Err(UnpadError)? }
|
||||
let l = data.len();
|
||||
let n = data[l-1] as usize;
|
||||
if n == 0 || n > l {
|
||||
return Err(UnpadError)
|
||||
}
|
||||
for v in &data[l-n..l-1] {
|
||||
if *v != 0 { Err(UnpadError)? }
|
||||
}
|
||||
Ok(&data[..l-n])
|
||||
}
|
||||
}
|
||||
|
||||
/// Pad block with byte sequence `\x80 00...00 00`.
|
||||
///
|
||||
/// ```
|
||||
/// use block_padding::{Iso7816, Padding};
|
||||
///
|
||||
/// let msg = b"test";
|
||||
/// let n = msg.len();
|
||||
/// let mut buffer = [0xff; 16];
|
||||
/// buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = Iso7816::pad(&mut buffer, n, 8).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test\x80\x00\x00\x00");
|
||||
/// assert_eq!(Iso7816::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
/// ```
|
||||
/// # use block_padding::{Iso7816, Padding};
|
||||
/// # let msg = b"test";
|
||||
/// # let n = msg.len();
|
||||
/// # let mut buffer = [0xff; 16];
|
||||
/// # buffer[..n].copy_from_slice(msg);
|
||||
/// let padded_msg = Iso7816::pad(&mut buffer, n, 2).unwrap();
|
||||
/// assert_eq!(padded_msg, b"test\x80\x00");
|
||||
/// assert_eq!(Iso7816::unpad(&padded_msg).unwrap(), msg);
|
||||
/// ```
|
||||
pub enum Iso7816{}
|
||||
|
||||
impl Padding for Iso7816 {
|
||||
fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> {
|
||||
if pos >= block.len() { Err(PadError)? }
|
||||
block[pos] = 0x80;
|
||||
zero(&mut block[pos+1..]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> {
|
||||
if data.is_empty() { Err(UnpadError)? }
|
||||
let mut n = data.len() - 1;
|
||||
while n != 0 {
|
||||
if data[n] != 0 { break; }
|
||||
n -= 1;
|
||||
}
|
||||
if data[n] != 0x80 { Err(UnpadError)? }
|
||||
Ok(&data[..n])
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"af6af6ea1dfa296af5dc58986d1afb46952328588069ec0b08723db439e9972d","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"52232c2cee3bb7d8cabe47ef367f1bf8bb607c22bdfca0219d6156cb7f446e9d","src/lib.rs":"9c96cffef7458fc7bd9e4e61270b69d539ff3a9225a0319b7996155c25ff96ab","src/read_single.rs":"3ab78b15754c2a7848a1be871ff6ee2a31a099f8f4f89be44ad210cda0dbcc9a","src/read_slice.rs":"b3790f2fd080db97e239c05c63da123ea375fb9b354dc9cacb859ed9c44f552e","src/write_single.rs":"1cee4f2f5d8690e47840ea7017539ead417a26abc0717137442a6d9d2875afe4","src/write_slice.rs":"de90e6b9cfca67125871bee7cef55c63574b1871a6584e51fc00a97e5877fe69"},"package":"560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"}
|
|
@ -0,0 +1,21 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "byte-tools"
|
||||
version = "0.2.0"
|
||||
authors = ["The Rust-Crypto Project Developers"]
|
||||
description = "Utility functions for working with bytes"
|
||||
documentation = "https://docs.rs/byte-tools"
|
||||
keywords = ["bytes"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/utils"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2006-2009 Graydon Hoare
|
||||
Copyright (c) 2009-2013 Mozilla Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,37 @@
|
|||
#![no_std]
|
||||
use core::ptr;
|
||||
|
||||
mod read_single;
|
||||
mod write_single;
|
||||
mod read_slice;
|
||||
mod write_slice;
|
||||
|
||||
pub use read_single::*;
|
||||
pub use write_single::*;
|
||||
pub use read_slice::*;
|
||||
pub use write_slice::*;
|
||||
|
||||
/// Copy bytes from src to dest
|
||||
#[inline]
|
||||
pub fn copy_memory(src: &[u8], dst: &mut [u8]) {
|
||||
assert!(dst.len() >= src.len());
|
||||
unsafe {
|
||||
let srcp = src.as_ptr();
|
||||
let dstp = dst.as_mut_ptr();
|
||||
ptr::copy_nonoverlapping(srcp, dstp, src.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Zero all bytes in dst
|
||||
#[inline]
|
||||
pub fn zero(dst: &mut [u8]) {
|
||||
set(dst, 0);
|
||||
}
|
||||
|
||||
/// Sets all bytes in `dst` equal to `value`
|
||||
#[inline]
|
||||
pub fn set(dst: &mut [u8], value: u8) {
|
||||
unsafe {
|
||||
ptr::write_bytes(dst.as_mut_ptr(), value, dst.len());
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"af6af6ea1dfa296af5dc58986d1afb46952328588069ec0b08723db439e9972d","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"52232c2cee3bb7d8cabe47ef367f1bf8bb607c22bdfca0219d6156cb7f446e9d","src/lib.rs":"9c96cffef7458fc7bd9e4e61270b69d539ff3a9225a0319b7996155c25ff96ab","src/read_single.rs":"3ab78b15754c2a7848a1be871ff6ee2a31a099f8f4f89be44ad210cda0dbcc9a","src/read_slice.rs":"b3790f2fd080db97e239c05c63da123ea375fb9b354dc9cacb859ed9c44f552e","src/write_single.rs":"1cee4f2f5d8690e47840ea7017539ead417a26abc0717137442a6d9d2875afe4","src/write_slice.rs":"de90e6b9cfca67125871bee7cef55c63574b1871a6584e51fc00a97e5877fe69"},"package":"560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"}
|
||||
{"files":{"Cargo.toml":"365cb0aa728934d2d9be1c45f2e135c1dc4b2305b20c7f34210c0ab11cadc21c","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"52232c2cee3bb7d8cabe47ef367f1bf8bb607c22bdfca0219d6156cb7f446e9d","src/lib.rs":"c8fb45d44cae0b1094bf8cef5059827b28b490eb14a3865fa536b61241c2c8c4"},"package":"980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182"}
|
|
@ -12,9 +12,9 @@
|
|||
|
||||
[package]
|
||||
name = "byte-tools"
|
||||
version = "0.2.0"
|
||||
authors = ["The Rust-Crypto Project Developers"]
|
||||
description = "Utility functions for working with bytes"
|
||||
version = "0.3.0"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Bytes related utility functions"
|
||||
documentation = "https://docs.rs/byte-tools"
|
||||
keywords = ["bytes"]
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -1,35 +1,27 @@
|
|||
#![no_std]
|
||||
use core::ptr;
|
||||
|
||||
mod read_single;
|
||||
mod write_single;
|
||||
mod read_slice;
|
||||
mod write_slice;
|
||||
|
||||
pub use read_single::*;
|
||||
pub use write_single::*;
|
||||
pub use read_slice::*;
|
||||
pub use write_slice::*;
|
||||
|
||||
/// Copy bytes from src to dest
|
||||
#[inline]
|
||||
pub fn copy_memory(src: &[u8], dst: &mut [u8]) {
|
||||
/// Copy bytes from `src` to `dst`
|
||||
///
|
||||
/// Panics if `src.len() < dst.len()`
|
||||
#[inline(always)]
|
||||
pub fn copy(src: &[u8], dst: &mut [u8]) {
|
||||
assert!(dst.len() >= src.len());
|
||||
unsafe {
|
||||
let srcp = src.as_ptr();
|
||||
let dstp = dst.as_mut_ptr();
|
||||
ptr::copy_nonoverlapping(srcp, dstp, src.len());
|
||||
ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Zero all bytes in dst
|
||||
#[inline]
|
||||
/// Zero all bytes in `dst`
|
||||
#[inline(always)]
|
||||
pub fn zero(dst: &mut [u8]) {
|
||||
set(dst, 0);
|
||||
unsafe {
|
||||
ptr::write_bytes(dst.as_mut_ptr(), 0, dst.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets all bytes in `dst` equal to `value`
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub fn set(dst: &mut [u8], value: u8) {
|
||||
unsafe {
|
||||
ptr::write_bytes(dst.as_mut_ptr(), value, dst.len());
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"b3667b1e1a3985dd2c9e7873f6945c2d7163ed7da95569f40c2097285a325ec4","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/dev.rs":"c824f834fa8b8c729024e4ec61138e89c26a56bfb6b50295600dddb5ff8fff62","src/digest.rs":"6710ac33c80e6159a2396839794fc76a61b94ab573516a69486457b3e291c793","src/errors.rs":"cff5bf2350bc109ad4f08caacf6780ff1e7016d9995f0847e84e96a8e31ab9d5","src/lib.rs":"bf4e93ebd066513001f3d6d77024ae8addf4df4fd89f76549fd1b73df386f3e4"},"package":"03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"}
|
|
@ -0,0 +1,32 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "digest"
|
||||
version = "0.7.6"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Traits for cryptographic hash functions"
|
||||
documentation = "https://docs.rs/digest"
|
||||
keywords = ["digest", "crypto", "hash"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/traits"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["std"]
|
||||
[dependencies.generic-array]
|
||||
version = "0.9"
|
||||
|
||||
[features]
|
||||
dev = []
|
||||
std = []
|
||||
[badges.travis-ci]
|
||||
repository = "RustCrypto/traits"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2017 Artyom Pavlov
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,171 @@
|
|||
use super::{Digest, Input, VariableOutput, ExtendableOutput, XofReader};
|
||||
use core::fmt::Debug;
|
||||
|
||||
pub struct Test {
|
||||
pub name: &'static str,
|
||||
pub input: &'static [u8],
|
||||
pub output: &'static [u8],
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! new_tests {
|
||||
( $( $name:expr ),* ) => {
|
||||
[$(
|
||||
Test {
|
||||
name: $name,
|
||||
input: include_bytes!(concat!("data/", $name, ".input.bin")),
|
||||
output: include_bytes!(concat!("data/", $name, ".output.bin")),
|
||||
},
|
||||
)*]
|
||||
};
|
||||
( $( $name:expr ),+, ) => (new_tests!($($name),+))
|
||||
}
|
||||
|
||||
pub fn main_test<D: Digest + Debug + Clone>(tests: &[Test]) {
|
||||
// Test that it works when accepting the message all at once
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
sh.input(t.input);
|
||||
|
||||
let out = sh.result();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
let len = t.input.len();
|
||||
let mut left = len;
|
||||
while left > 0 {
|
||||
let take = (left + 1) / 2;
|
||||
sh.input(&t.input[len - left..take + len - left]);
|
||||
left = left - take;
|
||||
}
|
||||
|
||||
let out = sh.result();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn variable_test<D>(tests: &[Test])
|
||||
where D: Input + VariableOutput + Clone + Debug
|
||||
{
|
||||
let mut buf = [0u8; 1024];
|
||||
// Test that it works when accepting the message all at once
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::new(t.output.len()).unwrap();
|
||||
sh.process(t.input);
|
||||
|
||||
let out = sh.variable_result(&mut buf[..t.output.len()]).unwrap();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::new(t.output.len()).unwrap();
|
||||
let len = t.input.len();
|
||||
let mut left = len;
|
||||
while left > 0 {
|
||||
let take = (left + 1) / 2;
|
||||
sh.process(&t.input[len - left..take + len - left]);
|
||||
left = left - take;
|
||||
}
|
||||
|
||||
let out = sh.variable_result(&mut buf[..t.output.len()]).unwrap();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn xof_test<D>(tests: &[Test])
|
||||
where D: Input + ExtendableOutput + Default + Debug + Clone
|
||||
{
|
||||
let mut buf = [0u8; 1024];
|
||||
// Test that it works when accepting the message all at once
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
sh.process(t.input);
|
||||
|
||||
let out = &mut buf[..t.output.len()];
|
||||
sh.xof_result().read(out);
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
let len = t.input.len();
|
||||
let mut left = len;
|
||||
while left > 0 {
|
||||
let take = (left + 1) / 2;
|
||||
sh.process(&t.input[len - left..take + len - left]);
|
||||
left = left - take;
|
||||
}
|
||||
|
||||
let out = &mut buf[..t.output.len()];
|
||||
sh.xof_result().read(out);
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
|
||||
// Test reeading from reader byte by byte
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
sh.process(t.input);
|
||||
|
||||
let mut reader = sh.xof_result();
|
||||
let out = &mut buf[..t.output.len()];
|
||||
for chunk in out.chunks_mut(1) {
|
||||
reader.read(chunk);
|
||||
}
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn one_million_a<D: Digest + Default + Debug + Clone>(expected: &[u8]) {
|
||||
let mut sh = D::default();
|
||||
for _ in 0..50000 {
|
||||
sh.input(&[b'a'; 10]);
|
||||
}
|
||||
sh.input(&[b'a'; 500000]);
|
||||
let out = sh.result();
|
||||
assert_eq!(out[..], expected[..]);
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bench_digest {
|
||||
($name:ident, $engine:path, $bs:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut d = <$engine>::default();
|
||||
let data = [0; $bs];
|
||||
|
||||
b.iter(|| {
|
||||
d.input(&data);
|
||||
});
|
||||
|
||||
b.bytes = $bs;
|
||||
}
|
||||
};
|
||||
|
||||
($engine:path) => {
|
||||
extern crate test;
|
||||
|
||||
use test::Bencher;
|
||||
use digest::Digest;
|
||||
|
||||
bench_digest!(bench1_16, $engine, 1<<4);
|
||||
bench_digest!(bench2_64, $engine, 1<<6);
|
||||
bench_digest!(bench3_256, $engine, 1<<8);
|
||||
bench_digest!(bench4_1k, $engine, 1<<10);
|
||||
bench_digest!(bench5_4k, $engine, 1<<12);
|
||||
bench_digest!(bench6_16k, $engine, 1<<14);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
use super::{Input, BlockInput, FixedOutput};
|
||||
use generic_array::GenericArray;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io;
|
||||
|
||||
type Output<N> = GenericArray<u8, N>;
|
||||
|
||||
/// The `Digest` trait specifies an interface common for digest functions.
|
||||
///
|
||||
/// It's a convinience wrapper around `Input`, `FixedOutput`, `BlockInput` and
|
||||
/// `Default` traits. It also provides additional convenience methods.
|
||||
pub trait Digest: Input + BlockInput + FixedOutput + Default {
|
||||
/// Create new hasher instance
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Digest input data. This method can be called repeatedly
|
||||
/// for use with streaming messages.
|
||||
fn input(&mut self, input: &[u8]) {
|
||||
self.process(input);
|
||||
}
|
||||
|
||||
/// Retrieve the digest result. This method consumes digest instance.
|
||||
fn result(self) -> Output<Self::OutputSize> {
|
||||
self.fixed_result()
|
||||
}
|
||||
|
||||
/// Convenience function to compute hash of the `data`. It will handle
|
||||
/// hasher creation, data feeding and finalization.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// println!("{:x}", sha2::Sha256::digest(b"Hello world"));
|
||||
/// ```
|
||||
#[inline]
|
||||
fn digest(data: &[u8]) -> Output<Self::OutputSize> {
|
||||
let mut hasher = Self::default();
|
||||
hasher.process(data);
|
||||
hasher.fixed_result()
|
||||
}
|
||||
|
||||
/// Convenience function to compute hash of the string. It's equivalent to
|
||||
/// `digest(input_string.as_bytes())`.
|
||||
#[inline]
|
||||
fn digest_str(str: &str) -> Output<Self::OutputSize> {
|
||||
Self::digest(str.as_bytes())
|
||||
}
|
||||
|
||||
/// Convenience function which takes `std::io::Read` as a source and computes
|
||||
/// value of digest function `D`, e.g. SHA-2, SHA-3, BLAKE2, etc. using 1 KB
|
||||
/// blocks.
|
||||
///
|
||||
/// Usage example:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use std::fs;
|
||||
/// use sha2::{Sha256, Digest};
|
||||
///
|
||||
/// let mut file = fs::File::open("Cargo.toml")?;
|
||||
/// let result = Sha256::digest_reader(&mut file)?;
|
||||
/// println!("{:x}", result);
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
fn digest_reader(source: &mut io::Read)
|
||||
-> io::Result<Output<Self::OutputSize>>
|
||||
{
|
||||
let mut hasher = Self::default();
|
||||
|
||||
let mut buf = [0u8; 8 * 1024];
|
||||
|
||||
loop {
|
||||
let len = match source.read(&mut buf) {
|
||||
Ok(0) => return Ok(hasher.result()),
|
||||
Ok(len) => len,
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
|
||||
Err(e) => Err(e)?,
|
||||
};
|
||||
hasher.process(&buf[..len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Input + FixedOutput + BlockInput + Default> Digest for D {}
|
|
@ -0,0 +1,37 @@
|
|||
use core::fmt;
|
||||
#[cfg(feature = "std")]
|
||||
use std::error;
|
||||
|
||||
/// The error type for variable hasher initialization
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct InvalidOutputSize;
|
||||
|
||||
/// The error type for variable hasher result
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct InvalidBufferLength;
|
||||
|
||||
impl fmt::Display for InvalidOutputSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("invalid output size")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InvalidBufferLength {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("invalid buffer length")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for InvalidOutputSize {
|
||||
fn description(&self) -> &str {
|
||||
"invalid output size"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for InvalidBufferLength {
|
||||
fn description(&self) -> &str {
|
||||
"invalid buffer size"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//! This crate provides traits for describing funcionality of cryptographic hash
|
||||
//! functions.
|
||||
//!
|
||||
//! By default std functionality in this crate disabled. (e.g. method for
|
||||
//! hashing `Read`ers) To enable it turn on `std` feature in your `Cargo.toml`
|
||||
//! for this crate.
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
pub extern crate generic_array;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std as core;
|
||||
use generic_array::{GenericArray, ArrayLength};
|
||||
|
||||
mod digest;
|
||||
mod errors;
|
||||
#[cfg(feature = "dev")]
|
||||
pub mod dev;
|
||||
|
||||
pub use errors::{InvalidOutputSize, InvalidBufferLength};
|
||||
pub use digest::Digest;
|
||||
|
||||
// `process` is choosen to not overlap with `input` method in the digest trait
|
||||
// change it on trait alias stabilization
|
||||
|
||||
/// Trait for processing input data
|
||||
pub trait Input {
|
||||
/// Digest input data. This method can be called repeatedly
|
||||
/// for use with streaming messages.
|
||||
fn process(&mut self, input: &[u8]);
|
||||
}
|
||||
|
||||
/// Trait to indicate that digest function processes data in blocks of size
|
||||
/// `BlockSize`. Main usage of this trait is for implementing HMAC generically.
|
||||
pub trait BlockInput {
|
||||
type BlockSize: ArrayLength<u8>;
|
||||
}
|
||||
|
||||
/// Trait for returning digest result with the fixed size
|
||||
pub trait FixedOutput {
|
||||
type OutputSize: ArrayLength<u8>;
|
||||
|
||||
/// Retrieve the digest result. This method consumes digest instance.
|
||||
fn fixed_result(self) -> GenericArray<u8, Self::OutputSize>;
|
||||
}
|
||||
|
||||
/// The error type for variable digest output
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct InvalidLength;
|
||||
|
||||
/// Trait for returning digest result with the varaible size
|
||||
pub trait VariableOutput: core::marker::Sized {
|
||||
/// Create new hasher instance with given output size. Will return
|
||||
/// `Err(InvalidLength)` in case if hasher can not work with the given
|
||||
/// output size. Will always return an error if output size equals to zero.
|
||||
fn new(output_size: usize) -> Result<Self, InvalidLength>;
|
||||
|
||||
/// Get output size of the hasher instance provided to the `new` method
|
||||
fn output_size(&self) -> usize;
|
||||
|
||||
/// Retrieve the digest result into provided buffer. Length of the buffer
|
||||
/// must be equal to output size provided to the `new` method, otherwise
|
||||
/// `Err(InvalidLength)` will be returned
|
||||
fn variable_result(self, buffer: &mut [u8]) -> Result<&[u8], InvalidLength>;
|
||||
}
|
||||
|
||||
/// Trait for decribing readers which are used to extract extendable output
|
||||
/// from the resulting state of hash function.
|
||||
pub trait XofReader {
|
||||
/// Read output into the `buffer`. Can be called unlimited number of times.
|
||||
fn read(&mut self, buffer: &mut [u8]);
|
||||
}
|
||||
|
||||
/// Trait which describes extendable output (XOF) of hash functions. Using this
|
||||
/// trait you first need to get structure which implements `XofReader`, using
|
||||
/// which you can read extendable output.
|
||||
pub trait ExtendableOutput {
|
||||
type Reader: XofReader;
|
||||
|
||||
/// Finalize hash function and return XOF reader
|
||||
fn xof_result(self) -> Self::Reader;
|
||||
}
|
||||
|
||||
/// Macro for defining opaque `Debug` implementation. It will use the following
|
||||
/// format: "HasherName { ... }". While it's convinient to have it
|
||||
/// (e.g. for including in other structs), it could be undesirable to leak
|
||||
/// internall state, which can happen for example through uncareful logging.
|
||||
#[macro_export]
|
||||
macro_rules! impl_opaque_debug {
|
||||
($state:ty) => {
|
||||
impl ::core::fmt::Debug for $state {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter)
|
||||
-> Result<(), ::core::fmt::Error>
|
||||
{
|
||||
write!(f, concat!(stringify!($state), " {{ ... }}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"b3667b1e1a3985dd2c9e7873f6945c2d7163ed7da95569f40c2097285a325ec4","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/dev.rs":"c824f834fa8b8c729024e4ec61138e89c26a56bfb6b50295600dddb5ff8fff62","src/digest.rs":"6710ac33c80e6159a2396839794fc76a61b94ab573516a69486457b3e291c793","src/errors.rs":"cff5bf2350bc109ad4f08caacf6780ff1e7016d9995f0847e84e96a8e31ab9d5","src/lib.rs":"bf4e93ebd066513001f3d6d77024ae8addf4df4fd89f76549fd1b73df386f3e4"},"package":"03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"}
|
||||
{"files":{"Cargo.toml":"fe0caba7c3959c31f8b7a53d6d077a074e399c7604a2b03dfddcce9c0e56a81e","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/dev.rs":"5890305be2cd3d221d1c2ce295b911cc57017dc341966ba434def4a072f8bf1c","src/digest.rs":"73f564cb8084e61baf850948443bacdea81727dfbff5abeb520c0e5bb690da7a","src/dyn_digest.rs":"2b3151c46d09dae2b7b0d0788d7bcc3517fe638c6a3f6fe43e357494de538049","src/errors.rs":"2584007e98d691160313cc27e6237db9bd886e9774137b59a1289a20054e9375","src/lib.rs":"8b336814939efcb1c1157ccadd52d9e4d6c99a84a799af2fe70cc50d05c45a32"},"package":"05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"}
|
|
@ -12,21 +12,25 @@
|
|||
|
||||
[package]
|
||||
name = "digest"
|
||||
version = "0.7.6"
|
||||
version = "0.8.0"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Traits for cryptographic hash functions"
|
||||
documentation = "https://docs.rs/digest"
|
||||
keywords = ["digest", "crypto", "hash"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/traits"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["std"]
|
||||
[dependencies.blobby]
|
||||
version = "0.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.generic-array]
|
||||
version = "0.9"
|
||||
version = "0.12"
|
||||
|
||||
[features]
|
||||
dev = []
|
||||
dev = ["blobby"]
|
||||
std = []
|
||||
[badges.travis-ci]
|
||||
repository = "RustCrypto/traits"
|
||||
|
|
|
@ -1,146 +1,195 @@
|
|||
use super::{Digest, Input, VariableOutput, ExtendableOutput, XofReader};
|
||||
use super::{Input, VariableOutput, ExtendableOutput, Reset, XofReader};
|
||||
use core::fmt::Debug;
|
||||
|
||||
pub struct Test {
|
||||
pub name: &'static str,
|
||||
pub input: &'static [u8],
|
||||
pub output: &'static [u8],
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! new_tests {
|
||||
( $( $name:expr ),* ) => {
|
||||
[$(
|
||||
Test {
|
||||
name: $name,
|
||||
input: include_bytes!(concat!("data/", $name, ".input.bin")),
|
||||
output: include_bytes!(concat!("data/", $name, ".output.bin")),
|
||||
},
|
||||
)*]
|
||||
};
|
||||
( $( $name:expr ),+, ) => (new_tests!($($name),+))
|
||||
macro_rules! new_test {
|
||||
($name:ident, $test_name:expr, $hasher:ty, $test_func:ident) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
use digest::blobby::Blob2Iterator;
|
||||
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
|
||||
|
||||
for (i, row) in Blob2Iterator::new(data).unwrap().enumerate() {
|
||||
let input = row[0];
|
||||
let output = row[1];
|
||||
if let Some(desc) = $test_func::<$hasher>(input, output) {
|
||||
panic!("\n\
|
||||
Failed test №{}: {}\n\
|
||||
input:\t{:?}\n\
|
||||
output:\t{:?}\n",
|
||||
i, desc, input, output,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main_test<D: Digest + Debug + Clone>(tests: &[Test]) {
|
||||
// module to separate Digest from other traits
|
||||
mod foo {
|
||||
use super::super::Digest;
|
||||
use core::fmt::Debug;
|
||||
|
||||
pub fn digest_test<D>(input: &[u8], output: &[u8]) -> Option<&'static str>
|
||||
where D: Digest + Debug + Clone
|
||||
{
|
||||
let mut hasher = D::new();
|
||||
// Test that it works when accepting the message all at once
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
sh.input(t.input);
|
||||
hasher.input(input);
|
||||
let mut hasher2 = hasher.clone();
|
||||
if hasher.result().as_slice() != output {
|
||||
return Some("whole message");
|
||||
}
|
||||
|
||||
let out = sh.result();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
// Test if reset works correctly
|
||||
hasher2.reset();
|
||||
hasher2.input(input);
|
||||
if hasher2.result().as_slice() != output {
|
||||
return Some("whole message after reset");
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
let len = t.input.len();
|
||||
let mut hasher = D::new();
|
||||
let len = input.len();
|
||||
let mut left = len;
|
||||
while left > 0 {
|
||||
let take = (left + 1) / 2;
|
||||
sh.input(&t.input[len - left..take + len - left]);
|
||||
hasher.input(&input[len - left..take + len - left]);
|
||||
left = left - take;
|
||||
}
|
||||
|
||||
let out = sh.result();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
if hasher.result().as_slice() != output {
|
||||
return Some("message in pieces");
|
||||
}
|
||||
|
||||
pub fn variable_test<D>(tests: &[Test])
|
||||
where D: Input + VariableOutput + Clone + Debug
|
||||
// Test processing byte-by-byte
|
||||
let mut hasher = D::new();
|
||||
for chunk in input.chunks(1) {
|
||||
hasher.input(chunk)
|
||||
}
|
||||
if hasher.result().as_slice() != output {
|
||||
return Some("message byte-by-byte");
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
pub fn one_million_a<D>(expected: &[u8])
|
||||
where D: Digest + Debug + Clone
|
||||
{
|
||||
let mut sh = D::new();
|
||||
for _ in 0..50_000 {
|
||||
sh.input(&[b'a'; 10]);
|
||||
}
|
||||
sh.input(&[b'a'; 500_000][..]);
|
||||
let out = sh.result();
|
||||
assert_eq!(out[..], expected[..]);
|
||||
}
|
||||
}
|
||||
|
||||
pub use self::foo::{digest_test, one_million_a};
|
||||
|
||||
pub fn xof_test<D>(input: &[u8], output: &[u8])
|
||||
-> Option<&'static str>
|
||||
where D: Input + ExtendableOutput + Default + Debug + Reset + Clone
|
||||
{
|
||||
let mut hasher = D::default();
|
||||
let mut buf = [0u8; 1024];
|
||||
// Test that it works when accepting the message all at once
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::new(t.output.len()).unwrap();
|
||||
sh.process(t.input);
|
||||
hasher.input(input);
|
||||
|
||||
let out = sh.variable_result(&mut buf[..t.output.len()]).unwrap();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::new(t.output.len()).unwrap();
|
||||
let len = t.input.len();
|
||||
let mut left = len;
|
||||
while left > 0 {
|
||||
let take = (left + 1) / 2;
|
||||
sh.process(&t.input[len - left..take + len - left]);
|
||||
left = left - take;
|
||||
}
|
||||
|
||||
let out = sh.variable_result(&mut buf[..t.output.len()]).unwrap();
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn xof_test<D>(tests: &[Test])
|
||||
where D: Input + ExtendableOutput + Default + Debug + Clone
|
||||
let mut hasher2 = hasher.clone();
|
||||
{
|
||||
let mut buf = [0u8; 1024];
|
||||
// Test that it works when accepting the message all at once
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
sh.process(t.input);
|
||||
let out = &mut buf[..output.len()];
|
||||
hasher.xof_result().read(out);
|
||||
|
||||
let out = &mut buf[..t.output.len()];
|
||||
sh.xof_result().read(out);
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
if out != output { return Some("whole message"); }
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
let len = t.input.len();
|
||||
// Test if hasher resets correctly
|
||||
hasher2.reset();
|
||||
hasher2.input(input);
|
||||
|
||||
{
|
||||
let out = &mut buf[..output.len()];
|
||||
hasher2.xof_result().read(out);
|
||||
|
||||
if out != output { return Some("whole message after reset"); }
|
||||
}
|
||||
|
||||
// Test if hasher accepts message in pieces correctly
|
||||
let mut hasher = D::default();
|
||||
let len = input.len();
|
||||
let mut left = len;
|
||||
while left > 0 {
|
||||
let take = (left + 1) / 2;
|
||||
sh.process(&t.input[len - left..take + len - left]);
|
||||
hasher.input(&input[len - left..take + len - left]);
|
||||
left = left - take;
|
||||
}
|
||||
|
||||
let out = &mut buf[..t.output.len()];
|
||||
sh.xof_result().read(out);
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
{
|
||||
let out = &mut buf[..output.len()];
|
||||
hasher.xof_result().read(out);
|
||||
if out != output { return Some("message in pieces"); }
|
||||
}
|
||||
|
||||
// Test reeading from reader byte by byte
|
||||
for t in tests.iter() {
|
||||
let mut sh = D::default();
|
||||
sh.process(t.input);
|
||||
// Test reading from reader byte by byte
|
||||
let mut hasher = D::default();
|
||||
hasher.input(input);
|
||||
|
||||
let mut reader = sh.xof_result();
|
||||
let out = &mut buf[..t.output.len()];
|
||||
let mut reader = hasher.xof_result();
|
||||
let out = &mut buf[..output.len()];
|
||||
for chunk in out.chunks_mut(1) {
|
||||
reader.read(chunk);
|
||||
}
|
||||
|
||||
assert_eq!(out[..], t.output[..]);
|
||||
}
|
||||
if out != output { return Some("message in pieces"); }
|
||||
None
|
||||
}
|
||||
|
||||
pub fn one_million_a<D: Digest + Default + Debug + Clone>(expected: &[u8]) {
|
||||
let mut sh = D::default();
|
||||
for _ in 0..50000 {
|
||||
sh.input(&[b'a'; 10]);
|
||||
pub fn variable_test<D>(input: &[u8], output: &[u8])
|
||||
-> Option<&'static str>
|
||||
where D: Input + VariableOutput + Reset + Debug + Clone
|
||||
{
|
||||
let mut hasher = D::new(output.len()).unwrap();
|
||||
let mut buf = [0u8; 128];
|
||||
let buf = &mut buf[..output.len()];
|
||||
// Test that it works when accepting the message all at once
|
||||
hasher.input(input);
|
||||
let mut hasher2 = hasher.clone();
|
||||
hasher.variable_result(|res| buf.copy_from_slice(res));
|
||||
if buf != output { return Some("whole message"); }
|
||||
|
||||
// Test if reset works correctly
|
||||
hasher2.reset();
|
||||
hasher2.input(input);
|
||||
hasher2.variable_result(|res| buf.copy_from_slice(res));
|
||||
if buf != output { return Some("whole message after reset"); }
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
let mut hasher = D::new(output.len()).unwrap();
|
||||
let len = input.len();
|
||||
let mut left = len;
|
||||
while left > 0 {
|
||||
let take = (left + 1) / 2;
|
||||
hasher.input(&input[len - left..take + len - left]);
|
||||
left = left - take;
|
||||
}
|
||||
sh.input(&[b'a'; 500000]);
|
||||
let out = sh.result();
|
||||
assert_eq!(out[..], expected[..]);
|
||||
hasher.variable_result(|res| buf.copy_from_slice(res));
|
||||
if buf != output { return Some("message in pieces"); }
|
||||
|
||||
// Test processing byte-by-byte
|
||||
let mut hasher = D::new(output.len()).unwrap();
|
||||
for chunk in input.chunks(1) {
|
||||
hasher.input(chunk)
|
||||
}
|
||||
hasher.variable_result(|res| buf.copy_from_slice(res));
|
||||
if buf != output { return Some("message byte-by-byte"); }
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bench_digest {
|
||||
macro_rules! bench {
|
||||
($name:ident, $engine:path, $bs:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
|
@ -148,7 +197,7 @@ macro_rules! bench_digest {
|
|||
let data = [0; $bs];
|
||||
|
||||
b.iter(|| {
|
||||
d.input(&data);
|
||||
d.input(&data[..]);
|
||||
});
|
||||
|
||||
b.bytes = $bs;
|
||||
|
@ -161,11 +210,9 @@ macro_rules! bench_digest {
|
|||
use test::Bencher;
|
||||
use digest::Digest;
|
||||
|
||||
bench_digest!(bench1_16, $engine, 1<<4);
|
||||
bench_digest!(bench2_64, $engine, 1<<6);
|
||||
bench_digest!(bench3_256, $engine, 1<<8);
|
||||
bench_digest!(bench4_1k, $engine, 1<<10);
|
||||
bench_digest!(bench5_4k, $engine, 1<<12);
|
||||
bench_digest!(bench6_16k, $engine, 1<<14);
|
||||
bench!(bench1_10, $engine, 10);
|
||||
bench!(bench2_100, $engine, 100);
|
||||
bench!(bench3_1000, $engine, 1000);
|
||||
bench!(bench4_10000, $engine, 10000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,38 @@
|
|||
use super::{Input, BlockInput, FixedOutput};
|
||||
use generic_array::GenericArray;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io;
|
||||
|
||||
type Output<N> = GenericArray<u8, N>;
|
||||
use super::{Input, FixedOutput, Reset};
|
||||
use generic_array::{GenericArray, ArrayLength};
|
||||
use generic_array::typenum::Unsigned;
|
||||
|
||||
/// The `Digest` trait specifies an interface common for digest functions.
|
||||
///
|
||||
/// It's a convinience wrapper around `Input`, `FixedOutput`, `BlockInput` and
|
||||
/// `Default` traits. It also provides additional convenience methods.
|
||||
pub trait Digest: Input + BlockInput + FixedOutput + Default {
|
||||
/// It's a convenience wrapper around `Input`, `FixedOutput`, `Reset`, `Clone`,
|
||||
/// and `Default` traits. It also provides additional convenience methods.
|
||||
pub trait Digest {
|
||||
type OutputSize: ArrayLength<u8>;
|
||||
/// Create new hasher instance
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
fn new() -> Self;
|
||||
|
||||
/// Digest input data. This method can be called repeatedly
|
||||
/// for use with streaming messages.
|
||||
fn input(&mut self, input: &[u8]) {
|
||||
self.process(input);
|
||||
}
|
||||
/// Digest input data.
|
||||
///
|
||||
/// This method can be called repeatedly for use with streaming messages.
|
||||
fn input<B: AsRef<[u8]>>(&mut self, data: B);
|
||||
|
||||
/// Retrieve the digest result. This method consumes digest instance.
|
||||
fn result(self) -> Output<Self::OutputSize> {
|
||||
self.fixed_result()
|
||||
}
|
||||
/// Digest input data in a chained manner.
|
||||
fn chain<B: AsRef<[u8]>>(self, data: B) -> Self where Self: Sized;
|
||||
|
||||
/// Retrieve result and consume hasher instance.
|
||||
fn result(self) -> GenericArray<u8, Self::OutputSize>;
|
||||
|
||||
/// Retrieve result and reset hasher instance.
|
||||
///
|
||||
/// This method sometimes can be more efficient compared to hasher
|
||||
/// re-creation.
|
||||
fn result_reset(&mut self) -> GenericArray<u8, Self::OutputSize>;
|
||||
|
||||
/// Reset hasher instance to its initial state.
|
||||
fn reset(&mut self);
|
||||
|
||||
/// Get output size of the hasher
|
||||
fn output_size() -> usize;
|
||||
|
||||
/// Convenience function to compute hash of the `data`. It will handle
|
||||
/// hasher creation, data feeding and finalization.
|
||||
|
@ -34,53 +42,45 @@ pub trait Digest: Input + BlockInput + FixedOutput + Default {
|
|||
/// ```rust,ignore
|
||||
/// println!("{:x}", sha2::Sha256::digest(b"Hello world"));
|
||||
/// ```
|
||||
#[inline]
|
||||
fn digest(data: &[u8]) -> Output<Self::OutputSize> {
|
||||
fn digest(data: &[u8]) -> GenericArray<u8, Self::OutputSize>;
|
||||
}
|
||||
|
||||
impl<D: Input + FixedOutput + Reset + Clone + Default> Digest for D {
|
||||
type OutputSize = <Self as FixedOutput>::OutputSize;
|
||||
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn input<B: AsRef<[u8]>>(&mut self, data: B) {
|
||||
Input::input(self, data);
|
||||
}
|
||||
|
||||
fn chain<B: AsRef<[u8]>>(self, data: B) -> Self where Self: Sized {
|
||||
Input::chain(self, data)
|
||||
}
|
||||
|
||||
fn result(self) -> GenericArray<u8, Self::OutputSize> {
|
||||
self.fixed_result()
|
||||
}
|
||||
|
||||
fn result_reset(&mut self) -> GenericArray<u8, Self::OutputSize> {
|
||||
let res = self.clone().fixed_result();
|
||||
self.reset();
|
||||
res
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
<Self as Reset>::reset(self)
|
||||
}
|
||||
|
||||
fn output_size() -> usize {
|
||||
Self::OutputSize::to_usize()
|
||||
}
|
||||
|
||||
fn digest(data: &[u8]) -> GenericArray<u8, Self::OutputSize> {
|
||||
let mut hasher = Self::default();
|
||||
hasher.process(data);
|
||||
Input::input(&mut hasher, data);
|
||||
hasher.fixed_result()
|
||||
}
|
||||
|
||||
/// Convenience function to compute hash of the string. It's equivalent to
|
||||
/// `digest(input_string.as_bytes())`.
|
||||
#[inline]
|
||||
fn digest_str(str: &str) -> Output<Self::OutputSize> {
|
||||
Self::digest(str.as_bytes())
|
||||
}
|
||||
|
||||
/// Convenience function which takes `std::io::Read` as a source and computes
|
||||
/// value of digest function `D`, e.g. SHA-2, SHA-3, BLAKE2, etc. using 1 KB
|
||||
/// blocks.
|
||||
///
|
||||
/// Usage example:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use std::fs;
|
||||
/// use sha2::{Sha256, Digest};
|
||||
///
|
||||
/// let mut file = fs::File::open("Cargo.toml")?;
|
||||
/// let result = Sha256::digest_reader(&mut file)?;
|
||||
/// println!("{:x}", result);
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
fn digest_reader(source: &mut io::Read)
|
||||
-> io::Result<Output<Self::OutputSize>>
|
||||
{
|
||||
let mut hasher = Self::default();
|
||||
|
||||
let mut buf = [0u8; 8 * 1024];
|
||||
|
||||
loop {
|
||||
let len = match source.read(&mut buf) {
|
||||
Ok(0) => return Ok(hasher.result()),
|
||||
Ok(len) => len,
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
|
||||
Err(e) => Err(e)?,
|
||||
};
|
||||
hasher.process(&buf[..len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Input + FixedOutput + BlockInput + Default> Digest for D {}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
#![cfg(feature = "std")]
|
||||
use std::boxed::Box;
|
||||
|
||||
use super::{Input, FixedOutput, Reset};
|
||||
use generic_array::typenum::Unsigned;
|
||||
|
||||
/// The `DynDigest` trait is a modification of `Digest` trait suitable
|
||||
/// for trait objects.
|
||||
pub trait DynDigest {
|
||||
/// Digest input data.
|
||||
///
|
||||
/// This method can be called repeatedly for use with streaming messages.
|
||||
fn input(&mut self, data: &[u8]);
|
||||
|
||||
/// Retrieve result and reset hasher instance
|
||||
fn result_reset(&mut self) -> Box<[u8]>;
|
||||
|
||||
/// Retrieve result and consume boxed hasher instance
|
||||
fn result(self: Box<Self>) -> Box<[u8]>;
|
||||
|
||||
/// Reset hasher instance to its initial state.
|
||||
fn reset(&mut self);
|
||||
|
||||
/// Get output size of the hasher
|
||||
fn output_size(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<D: Input + FixedOutput + Reset + Clone> DynDigest for D {
|
||||
/// Digest input data.
|
||||
///
|
||||
/// This method can be called repeatedly for use with streaming messages.
|
||||
fn input(&mut self, data: &[u8]) {
|
||||
Input::input(self, data);
|
||||
}
|
||||
|
||||
/// Retrieve result and reset hasher instance
|
||||
fn result_reset(&mut self) -> Box<[u8]> {
|
||||
let res = self.clone().fixed_result().to_vec().into_boxed_slice();
|
||||
Reset::reset(self);
|
||||
res
|
||||
}
|
||||
|
||||
/// Retrieve result and consume boxed hasher instance
|
||||
fn result(self: Box<Self>) -> Box<[u8]> {
|
||||
self.fixed_result().to_vec().into_boxed_slice()
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
Reset::reset(self);
|
||||
}
|
||||
|
||||
/// Get output size of the hasher
|
||||
fn output_size(&self) -> usize {
|
||||
<Self as FixedOutput>::OutputSize::to_usize()
|
||||
}
|
||||
}
|
|
@ -6,32 +6,15 @@ use std::error;
|
|||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct InvalidOutputSize;
|
||||
|
||||
/// The error type for variable hasher result
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct InvalidBufferLength;
|
||||
|
||||
impl fmt::Display for InvalidOutputSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("invalid output size")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InvalidBufferLength {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("invalid buffer length")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for InvalidOutputSize {
|
||||
fn description(&self) -> &str {
|
||||
"invalid output size"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for InvalidBufferLength {
|
||||
fn description(&self) -> &str {
|
||||
"invalid buffer size"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,59 @@
|
|||
//! This crate provides traits for describing funcionality of cryptographic hash
|
||||
//! This crate provides traits which describe funcionality of cryptographic hash
|
||||
//! functions.
|
||||
//!
|
||||
//! By default std functionality in this crate disabled. (e.g. method for
|
||||
//! hashing `Read`ers) To enable it turn on `std` feature in your `Cargo.toml`
|
||||
//! for this crate.
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
//! Traits in this repository can be separatedin two levels:
|
||||
//! - Low level traits: `Input`, `BlockInput`, `Reset`, `FixedOutput`,
|
||||
//! `VariableOutput`, `ExtendableOutput`. These traits atomically describe
|
||||
//! available functionality of hash function implementations.
|
||||
//! - Convinience trait: `Digest`, `DynDigest`. They are wrappers around
|
||||
//! low level traits for most common hash-function use-cases.
|
||||
//!
|
||||
//! Additionally hash functions implement traits from `std`: `Default`, `Clone`,
|
||||
//! `Write`. (the latter depends on enabled-by-default `std` crate feature)
|
||||
//!
|
||||
//! The `Digest` trait is the most commonly used trait.
|
||||
#![no_std]
|
||||
#![doc(html_logo_url =
|
||||
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
|
||||
pub extern crate generic_array;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std as core;
|
||||
#[macro_use] extern crate std;
|
||||
#[cfg(feature = "dev")]
|
||||
pub extern crate blobby;
|
||||
use generic_array::{GenericArray, ArrayLength};
|
||||
#[cfg(feature = "std")]
|
||||
use std::vec::Vec;
|
||||
|
||||
mod digest;
|
||||
mod dyn_digest;
|
||||
mod errors;
|
||||
#[cfg(feature = "dev")]
|
||||
pub mod dev;
|
||||
|
||||
pub use errors::{InvalidOutputSize, InvalidBufferLength};
|
||||
pub use errors::InvalidOutputSize;
|
||||
pub use digest::Digest;
|
||||
|
||||
// `process` is choosen to not overlap with `input` method in the digest trait
|
||||
// change it on trait alias stabilization
|
||||
#[cfg(feature = "std")]
|
||||
pub use dyn_digest::DynDigest;
|
||||
|
||||
/// Trait for processing input data
|
||||
pub trait Input {
|
||||
/// Digest input data. This method can be called repeatedly
|
||||
/// for use with streaming messages.
|
||||
fn process(&mut self, input: &[u8]);
|
||||
/// Digest input data.
|
||||
///
|
||||
/// This method can be called repeatedly, e.g. for processing streaming
|
||||
/// messages.
|
||||
fn input<B: AsRef<[u8]>>(&mut self, data: B);
|
||||
|
||||
/// Digest input data in a chained manner.
|
||||
fn chain<B: AsRef<[u8]>>(mut self, data: B) -> Self where Self: Sized {
|
||||
self.input(data);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait to indicate that digest function processes data in blocks of size
|
||||
/// `BlockSize`. Main usage of this trait is for implementing HMAC generically.
|
||||
/// `BlockSize`.
|
||||
///
|
||||
/// The main usage of this trait is for implementing HMAC generically.
|
||||
pub trait BlockInput {
|
||||
type BlockSize: ArrayLength<u8>;
|
||||
}
|
||||
|
@ -39,59 +62,79 @@ pub trait BlockInput {
|
|||
pub trait FixedOutput {
|
||||
type OutputSize: ArrayLength<u8>;
|
||||
|
||||
/// Retrieve the digest result. This method consumes digest instance.
|
||||
/// Retrieve result and consume hasher instance.
|
||||
fn fixed_result(self) -> GenericArray<u8, Self::OutputSize>;
|
||||
}
|
||||
|
||||
/// The error type for variable digest output
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct InvalidLength;
|
||||
|
||||
/// Trait for returning digest result with the varaible size
|
||||
pub trait VariableOutput: core::marker::Sized {
|
||||
/// Create new hasher instance with given output size. Will return
|
||||
/// `Err(InvalidLength)` in case if hasher can not work with the given
|
||||
/// output size. Will always return an error if output size equals to zero.
|
||||
fn new(output_size: usize) -> Result<Self, InvalidLength>;
|
||||
/// Create new hasher instance with the given output size.
|
||||
///
|
||||
/// It will return `Err(InvalidOutputSize)` in case if hasher can not return
|
||||
/// specified output size. It will always return an error if output size
|
||||
/// equals to zero.
|
||||
fn new(output_size: usize) -> Result<Self, InvalidOutputSize>;
|
||||
|
||||
/// Get output size of the hasher instance provided to the `new` method
|
||||
fn output_size(&self) -> usize;
|
||||
|
||||
/// Retrieve the digest result into provided buffer. Length of the buffer
|
||||
/// must be equal to output size provided to the `new` method, otherwise
|
||||
/// `Err(InvalidLength)` will be returned
|
||||
fn variable_result(self, buffer: &mut [u8]) -> Result<&[u8], InvalidLength>;
|
||||
/// Retrieve result via closure and consume hasher.
|
||||
///
|
||||
/// Closure is guaranteed to be called, length of the buffer passed to it
|
||||
/// will be equal to `output_size`.
|
||||
fn variable_result<F: FnOnce(&[u8])>(self, f: F);
|
||||
|
||||
/// Retrieve result into vector and consume hasher.
|
||||
#[cfg(feature = "std")]
|
||||
fn vec_result(self) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(self.output_size());
|
||||
self.variable_result(|res| buf.extend_from_slice(res));
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for decribing readers which are used to extract extendable output
|
||||
/// from the resulting state of hash function.
|
||||
/// from XOF (extendable-output function) result.
|
||||
pub trait XofReader {
|
||||
/// Read output into the `buffer`. Can be called unlimited number of times.
|
||||
fn read(&mut self, buffer: &mut [u8]);
|
||||
}
|
||||
|
||||
/// Trait which describes extendable output (XOF) of hash functions. Using this
|
||||
/// trait you first need to get structure which implements `XofReader`, using
|
||||
/// which you can read extendable output.
|
||||
pub trait ExtendableOutput {
|
||||
/// Trait which describes extendable-output functions (XOF).
|
||||
pub trait ExtendableOutput: core::marker::Sized {
|
||||
type Reader: XofReader;
|
||||
|
||||
/// Finalize hash function and return XOF reader
|
||||
/// Retrieve XOF reader and consume hasher instance.
|
||||
fn xof_result(self) -> Self::Reader;
|
||||
|
||||
/// Retrieve result into vector of specified length.
|
||||
#[cfg(feature = "std")]
|
||||
fn vec_result(self, n: usize) -> Vec<u8> {
|
||||
let mut buf = vec![0u8; n];
|
||||
self.xof_result().read(&mut buf);
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for resetting hash instances
|
||||
pub trait Reset {
|
||||
/// Reset hasher instance to its initial state and return current state.
|
||||
fn reset(&mut self);
|
||||
}
|
||||
|
||||
/// Macro for defining opaque `Debug` implementation. It will use the following
|
||||
/// format: "HasherName { ... }". While it's convinient to have it
|
||||
/// (e.g. for including in other structs), it could be undesirable to leak
|
||||
/// internall state, which can happen for example through uncareful logging.
|
||||
#[macro_export]
|
||||
macro_rules! impl_opaque_debug {
|
||||
($state:ty) => {
|
||||
impl ::core::fmt::Debug for $state {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter)
|
||||
-> Result<(), ::core::fmt::Error>
|
||||
{
|
||||
write!(f, concat!(stringify!($state), " {{ ... }}"))
|
||||
/// Implements `std::io::Write` trait for implementator of `Input`
|
||||
macro_rules! impl_write {
|
||||
($hasher:ident) => {
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::io::Write for $hasher {
|
||||
fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
|
||||
Input::input(self, buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> ::std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"87ff65d640c137c26d338f96e21e769af1e1b2e7fa615b40a1bcc755448bb118","LICENSE":"ad4fcfaf8d5b12b97409c137a03d4a4e4b21024c65c54f976cc3b609c1bd5b0f","README.md":"9a1a45416eac57050036b13df6ec84d21d555e820726af3c782896bd9d37d94b","rustfmt.toml":"2a298b4ce1fe6e16b8f281a0035567b8eb15042ed3062729fd28224f29c2f75a","src/arr.rs":"cc1ea0a9ef6a524b90767cc8a89f6b939394a2948a645ed313c0bf5ce5a258a4","src/hex.rs":"bfbf304fb4dea6f7edc0569b38bf2ac7657ce089c5761891321722509e3b5076","src/impl_serde.rs":"805885478728b3c205b842d46deb377b7dd6dd4c4c50254064431f49f0981a2a","src/impls.rs":"8c54e294a82a2bf344bdcb9949b8a84903fb65698d6b1b1e0ab9f5e7847be64f","src/iter.rs":"e52217f04d0dc046f13ef2e3539b90eabd4d55bb85cf40f76ba0bf86d5e55ef0","src/lib.rs":"da93fa505eee94b40fce0fe98e26ed3bb4d2bc4d4869af01598b6e54fc9c0f8d","tests/hex.rs":"e909bc0564e7d52c5fcf172dfc0fac7085010c6a21d38581bf73a54ab2e256e1","tests/import_name.rs":"1235729ecbde47fc9a38b3bf35c750a53ed55e3cf967c9d2b24fd759dc9e9e0c","tests/mod.rs":"f4100c5338906c038636f98f4d2b3d272f59580662afa89d915eafb96d7bbcf9"},"package":"ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"}
|
|
@ -0,0 +1,32 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "generic-array"
|
||||
version = "0.9.0"
|
||||
authors = ["Bartłomiej Kamiński <fizyk20@gmail.com>"]
|
||||
description = "Generic types implementing functionality of arrays"
|
||||
documentation = "http://fizyk20.github.io/generic-array/generic_array/"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/fizyk20/generic-array.git"
|
||||
|
||||
[lib]
|
||||
name = "generic_array"
|
||||
[dependencies.typenum]
|
||||
version = "1.9"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1.0"
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Bartłomiej Kamiński
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,34 @@
|
|||
[![Crates.io](https://img.shields.io/crates/v/generic-array.svg)](https://crates.io/crates/generic-array)
|
||||
[![Build Status](https://travis-ci.org/fizyk20/generic-array.svg?branch=master)](https://travis-ci.org/fizyk20/generic-array)
|
||||
# generic-array
|
||||
|
||||
This crate implements generic array types for Rust.
|
||||
|
||||
[Documentation](http://fizyk20.github.io/generic-array/generic_array/)
|
||||
|
||||
## Usage
|
||||
|
||||
The Rust arrays `[T; N]` are problematic in that they can't be used generically with respect to `N`, so for example this won't work:
|
||||
|
||||
```rust
|
||||
struct Foo<N> {
|
||||
data: [i32; N]
|
||||
}
|
||||
```
|
||||
|
||||
**generic-array** defines a new trait `ArrayLength<T>` and a struct `GenericArray<T, N: ArrayLength<T>>`, which let the above be implemented as:
|
||||
|
||||
```rust
|
||||
struct Foo<N: ArrayLength<i32>> {
|
||||
data: GenericArray<i32, N>
|
||||
}
|
||||
```
|
||||
|
||||
To actually define a type implementing `ArrayLength`, you can use unsigned integer types defined in [typenum](https://github.com/paholg/typenum) crate - for example, `GenericArray<T, U5>` would work almost like `[T; 5]` :)
|
||||
|
||||
In version 0.1.1 an `arr!` macro was introduced, allowing for creation of arrays as shown below:
|
||||
|
||||
```rust
|
||||
let array = arr![u32; 1, 2, 3];
|
||||
assert_eq!(array[2], 3);
|
||||
```
|
|
@ -0,0 +1,3 @@
|
|||
reorder_imports = true
|
||||
reorder_imported_names = true
|
||||
use_try_shorthand = true
|
|
@ -0,0 +1,57 @@
|
|||
//! Implementation for `arr!` macro.
|
||||
|
||||
use super::ArrayLength;
|
||||
use core::ops::Add;
|
||||
use typenum::U1;
|
||||
|
||||
/// Helper trait for `arr!` macro
|
||||
pub trait AddLength<T, N: ArrayLength<T>>: ArrayLength<T> {
|
||||
/// Resulting length
|
||||
type Output: ArrayLength<T>;
|
||||
}
|
||||
|
||||
impl<T, N1, N2> AddLength<T, N2> for N1
|
||||
where
|
||||
N1: ArrayLength<T> + Add<N2>,
|
||||
N2: ArrayLength<T>,
|
||||
<N1 as Add<N2>>::Output: ArrayLength<T>,
|
||||
{
|
||||
type Output = <N1 as Add<N2>>::Output;
|
||||
}
|
||||
|
||||
/// Helper type for `arr!` macro
|
||||
pub type Inc<T, U> = <U as AddLength<T, U1>>::Output;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! arr_impl {
|
||||
($T:ty; $N:ty, [$($x:expr),*], []) => ({
|
||||
unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) }
|
||||
});
|
||||
($T:ty; $N:ty, [], [$x1:expr]) => (
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [])
|
||||
);
|
||||
($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => (
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),*])
|
||||
);
|
||||
($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => (
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),*, $x1 as $T], [])
|
||||
);
|
||||
($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => (
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),*, $x1 as $T], [$($x),*])
|
||||
);
|
||||
}
|
||||
|
||||
/// Macro allowing for easy generation of Generic Arrays.
|
||||
/// Example: `let test = arr![u32; 1, 2, 3];`
|
||||
#[macro_export]
|
||||
macro_rules! arr {
|
||||
($T:ty;) => ({
|
||||
unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) }
|
||||
});
|
||||
($T:ty; $($x:expr),*) => (
|
||||
arr_impl!($T; $crate::typenum::U0, [], [$($x),*])
|
||||
);
|
||||
($($x:expr,)+) => (arr![$($x),*]);
|
||||
() => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`")
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//! Generic array are commonly used as a return value for hash digests, so
|
||||
//! it's a good idea to allow to hexlify them easily. This module implements
|
||||
//! `std::fmt::LowerHex` and `std::fmt::UpperHex` traits.
|
||||
//!
|
||||
//! Example:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #[macro_use]
|
||||
//! # extern crate generic_array;
|
||||
//! # extern crate typenum;
|
||||
//! # fn main() {
|
||||
//! let array = arr![u8; 10, 20, 30];
|
||||
//! assert_eq!(format!("{:x}", array), "0a141e");
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
|
||||
use {ArrayLength, GenericArray};
|
||||
use core::fmt;
|
||||
use core::ops::Add;
|
||||
use core::str;
|
||||
use typenum::*;
|
||||
|
||||
static LOWER_CHARS: &'static [u8] = b"0123456789abcdef";
|
||||
static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF";
|
||||
|
||||
impl<T: ArrayLength<u8>> fmt::LowerHex for GenericArray<u8, T>
|
||||
where
|
||||
T: Add<T>,
|
||||
<T as Add<T>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let max_digits = f.precision().unwrap_or_else(|| self.len());
|
||||
|
||||
if T::to_usize() < 1024 {
|
||||
// For small arrays use a stack allocated
|
||||
// buffer of 2x number of bytes
|
||||
let mut res = GenericArray::<u8, Sum<T, T>>::default();
|
||||
|
||||
for (i, c) in self.iter().take(max_digits).enumerate() {
|
||||
res[i * 2] = LOWER_CHARS[(c >> 4) as usize];
|
||||
res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(
|
||||
unsafe { str::from_utf8_unchecked(&res[..max_digits * 2]) },
|
||||
)?;
|
||||
} else {
|
||||
// For large array use chunks of up to 1024 bytes (2048 hex chars)
|
||||
let mut buf = [0u8; 2048];
|
||||
|
||||
for chunk in self[..max_digits].chunks(1024) {
|
||||
for (i, c) in chunk.iter().enumerate() {
|
||||
buf[i * 2] = LOWER_CHARS[(c >> 4) as usize];
|
||||
buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(unsafe {
|
||||
str::from_utf8_unchecked(&buf[..chunk.len() * 2])
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ArrayLength<u8>> fmt::UpperHex for GenericArray<u8, T>
|
||||
where
|
||||
T: Add<T>,
|
||||
<T as Add<T>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let max_digits = f.precision().unwrap_or_else(|| self.len());
|
||||
|
||||
if T::to_usize() < 1024 {
|
||||
// For small arrays use a stack allocated
|
||||
// buffer of 2x number of bytes
|
||||
let mut res = GenericArray::<u8, Sum<T, T>>::default();
|
||||
|
||||
for (i, c) in self.iter().take(max_digits).enumerate() {
|
||||
res[i * 2] = UPPER_CHARS[(c >> 4) as usize];
|
||||
res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(
|
||||
unsafe { str::from_utf8_unchecked(&res[..max_digits * 2]) },
|
||||
)?;
|
||||
} else {
|
||||
// For large array use chunks of up to 1024 bytes (2048 hex chars)
|
||||
let mut buf = [0u8; 2048];
|
||||
|
||||
for chunk in self[..max_digits].chunks(1024) {
|
||||
for (i, c) in chunk.iter().enumerate() {
|
||||
buf[i * 2] = UPPER_CHARS[(c >> 4) as usize];
|
||||
buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(unsafe {
|
||||
str::from_utf8_unchecked(&buf[..chunk.len() * 2])
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
//! Serde serialization/deserialization implementation
|
||||
|
||||
use {ArrayLength, GenericArray};
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::de::{self, SeqAccess, Visitor};
|
||||
|
||||
impl<T, N> Serialize for GenericArray<T, N>
|
||||
where
|
||||
T: Serialize,
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_seq(self.iter())
|
||||
}
|
||||
}
|
||||
|
||||
struct GAVisitor<T, N> {
|
||||
_t: PhantomData<T>,
|
||||
_n: PhantomData<N>,
|
||||
}
|
||||
|
||||
impl<'de, T, N> Visitor<'de> for GAVisitor<T, N>
|
||||
where
|
||||
T: Deserialize<'de> + Default,
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
type Value = GenericArray<T, N>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("struct GenericArray")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<GenericArray<T, N>, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
let mut result = GenericArray::default();
|
||||
for i in 0..N::to_usize() {
|
||||
result[i] = seq.next_element()?.ok_or_else(
|
||||
|| de::Error::invalid_length(i, &self),
|
||||
)?;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T, N> Deserialize<'de> for GenericArray<T, N>
|
||||
where
|
||||
T: Deserialize<'de> + Default,
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<GenericArray<T, N>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let visitor = GAVisitor {
|
||||
_t: PhantomData,
|
||||
_n: PhantomData,
|
||||
};
|
||||
deserializer.deserialize_seq(visitor)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
use super::{ArrayLength, GenericArray};
|
||||
use core::borrow::{Borrow, BorrowMut};
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
impl<T: Default, N> Default for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::generate(|_| T::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone, N> Clone for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn clone(&self) -> GenericArray<T, N> {
|
||||
self.map_ref(|x| x.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, N> Copy for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
N::ArrayType: Copy,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: PartialEq, N> PartialEq for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
impl<T: Eq, N> Eq for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: PartialOrd, N> PartialOrd for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn partial_cmp(&self, other: &GenericArray<T, N>) -> Option<Ordering> {
|
||||
PartialOrd::partial_cmp(self.as_slice(), other.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord, N> Ord for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn cmp(&self, other: &GenericArray<T, N>) -> Ordering {
|
||||
Ord::cmp(self.as_slice(), other.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug, N> Debug for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
self[..].fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> Borrow<[T]> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn borrow(&self) -> &[T] {
|
||||
&self[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> BorrowMut<[T]> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn borrow_mut(&mut self) -> &mut [T] {
|
||||
&mut self[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> AsRef<[T]> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn as_ref(&self) -> &[T] {
|
||||
&self[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> AsMut<[T]> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut [T] {
|
||||
&mut self[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash, N> Hash for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
Hash::hash(&self[..], state)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from {
|
||||
($($n: expr => $ty: ty),*) => {
|
||||
$(
|
||||
impl<T> From<[T; $n]> for GenericArray<T, $ty> {
|
||||
fn from(arr: [T; $n]) -> Self {
|
||||
use core::mem::{forget, transmute_copy};
|
||||
let x = unsafe { transmute_copy(&arr) };
|
||||
forget(arr);
|
||||
x
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl_from! {
|
||||
1 => ::typenum::U1,
|
||||
2 => ::typenum::U2,
|
||||
3 => ::typenum::U3,
|
||||
4 => ::typenum::U4,
|
||||
5 => ::typenum::U5,
|
||||
6 => ::typenum::U6,
|
||||
7 => ::typenum::U7,
|
||||
8 => ::typenum::U8,
|
||||
9 => ::typenum::U9,
|
||||
10 => ::typenum::U10,
|
||||
11 => ::typenum::U11,
|
||||
12 => ::typenum::U12,
|
||||
13 => ::typenum::U13,
|
||||
14 => ::typenum::U14,
|
||||
15 => ::typenum::U15,
|
||||
16 => ::typenum::U16,
|
||||
17 => ::typenum::U17,
|
||||
18 => ::typenum::U18,
|
||||
19 => ::typenum::U19,
|
||||
20 => ::typenum::U20,
|
||||
21 => ::typenum::U21,
|
||||
22 => ::typenum::U22,
|
||||
23 => ::typenum::U23,
|
||||
24 => ::typenum::U24,
|
||||
25 => ::typenum::U25,
|
||||
26 => ::typenum::U26,
|
||||
27 => ::typenum::U27,
|
||||
28 => ::typenum::U28,
|
||||
29 => ::typenum::U29,
|
||||
30 => ::typenum::U30,
|
||||
31 => ::typenum::U31,
|
||||
32 => ::typenum::U32
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
//! `GenericArray` iterator implementation.
|
||||
|
||||
use super::{ArrayLength, GenericArray};
|
||||
use core::{cmp, ptr};
|
||||
use core::mem::ManuallyDrop;
|
||||
|
||||
/// An iterator that moves out of a `GenericArray`
|
||||
pub struct GenericArrayIter<T, N: ArrayLength<T>> {
|
||||
// Invariants: index <= index_back <= N
|
||||
// Only values in array[index..index_back] are alive at any given time.
|
||||
// Values from array[..index] and array[index_back..] are already moved/dropped.
|
||||
array: ManuallyDrop<GenericArray<T, N>>,
|
||||
index: usize,
|
||||
index_back: usize,
|
||||
}
|
||||
|
||||
impl<T, N> IntoIterator for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
type Item = T;
|
||||
type IntoIter = GenericArrayIter<T, N>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
GenericArrayIter {
|
||||
array: ManuallyDrop::new(self),
|
||||
index: 0,
|
||||
index_back: N::to_usize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> Drop for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
// Drop values that are still alive.
|
||||
for p in &mut self.array[self.index..self.index_back] {
|
||||
unsafe {
|
||||
ptr::drop_in_place(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> Iterator for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if self.len() > 0 {
|
||||
unsafe {
|
||||
let p = self.array.get_unchecked(self.index);
|
||||
self.index += 1;
|
||||
Some(ptr::read(p))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.len();
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn nth(&mut self, n: usize) -> Option<T> {
|
||||
// First consume values prior to the nth.
|
||||
let ndrop = cmp::min(n, self.len());
|
||||
for p in &mut self.array[self.index..self.index + ndrop] {
|
||||
self.index += 1;
|
||||
unsafe {
|
||||
ptr::drop_in_place(p);
|
||||
}
|
||||
}
|
||||
|
||||
self.next()
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<T> {
|
||||
// Note, everything else will correctly drop first as `self` leaves scope.
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
if self.len() > 0 {
|
||||
self.index_back -= 1;
|
||||
unsafe {
|
||||
let p = self.array.get_unchecked(self.index_back);
|
||||
Some(ptr::read(p))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
self.index_back - self.index
|
||||
}
|
||||
}
|
|
@ -0,0 +1,464 @@
|
|||
//! This crate implements a structure that can be used as a generic array type.use
|
||||
//! Core Rust array types `[T; N]` can't be used generically with
|
||||
//! respect to `N`, so for example this:
|
||||
//!
|
||||
//! ```{should_fail}
|
||||
//! struct Foo<T, N> {
|
||||
//! data: [T; N]
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! won't work.
|
||||
//!
|
||||
//! **generic-array** exports a `GenericArray<T,N>` type, which lets
|
||||
//! the above be implemented as:
|
||||
//!
|
||||
//! ```
|
||||
//! # use generic_array::{ArrayLength, GenericArray};
|
||||
//! struct Foo<T, N: ArrayLength<T>> {
|
||||
//! data: GenericArray<T,N>
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The `ArrayLength<T>` trait is implemented by default for
|
||||
//! [unsigned integer types](../typenum/uint/index.html) from
|
||||
//! [typenum](../typenum/index.html).
|
||||
//!
|
||||
//! For ease of use, an `arr!` macro is provided - example below:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use]
|
||||
//! # extern crate generic_array;
|
||||
//! # extern crate typenum;
|
||||
//! # fn main() {
|
||||
//! let array = arr![u32; 1, 2, 3];
|
||||
//! assert_eq!(array[2], 3);
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
//#![deny(missing_docs)]
|
||||
#![no_std]
|
||||
|
||||
pub extern crate typenum;
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
|
||||
mod hex;
|
||||
mod impls;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod impl_serde;
|
||||
|
||||
use core::{mem, ptr, slice};
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::ManuallyDrop;
|
||||
pub use core::mem::transmute;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use typenum::bit::{B0, B1};
|
||||
use typenum::uint::{UInt, UTerm, Unsigned};
|
||||
|
||||
#[cfg_attr(test, macro_use)]
|
||||
pub mod arr;
|
||||
pub mod iter;
|
||||
pub use iter::GenericArrayIter;
|
||||
|
||||
/// Trait making `GenericArray` work, marking types to be used as length of an array
|
||||
pub unsafe trait ArrayLength<T>: Unsigned {
|
||||
/// Associated type representing the array type for the number
|
||||
type ArrayType;
|
||||
}
|
||||
|
||||
unsafe impl<T> ArrayLength<T> for UTerm {
|
||||
#[doc(hidden)]
|
||||
type ArrayType = ();
|
||||
}
|
||||
|
||||
/// Internal type used to generate a struct of appropriate size
|
||||
#[allow(dead_code)]
|
||||
#[repr(C)]
|
||||
#[doc(hidden)]
|
||||
pub struct GenericArrayImplEven<T, U> {
|
||||
parent1: U,
|
||||
parent2: U,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Clone, U: Clone> Clone for GenericArrayImplEven<T, U> {
|
||||
fn clone(&self) -> GenericArrayImplEven<T, U> {
|
||||
GenericArrayImplEven {
|
||||
parent1: self.parent1.clone(),
|
||||
parent2: self.parent2.clone(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U: Copy> Copy for GenericArrayImplEven<T, U> {}
|
||||
|
||||
/// Internal type used to generate a struct of appropriate size
|
||||
#[allow(dead_code)]
|
||||
#[repr(C)]
|
||||
#[doc(hidden)]
|
||||
pub struct GenericArrayImplOdd<T, U> {
|
||||
parent1: U,
|
||||
parent2: U,
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: Clone, U: Clone> Clone for GenericArrayImplOdd<T, U> {
|
||||
fn clone(&self) -> GenericArrayImplOdd<T, U> {
|
||||
GenericArrayImplOdd {
|
||||
parent1: self.parent1.clone(),
|
||||
parent2: self.parent2.clone(),
|
||||
data: self.data.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U: Copy> Copy for GenericArrayImplOdd<T, U> {}
|
||||
|
||||
unsafe impl<T, N: ArrayLength<T>> ArrayLength<T> for UInt<N, B0> {
|
||||
#[doc(hidden)]
|
||||
type ArrayType = GenericArrayImplEven<T, N::ArrayType>;
|
||||
}
|
||||
|
||||
unsafe impl<T, N: ArrayLength<T>> ArrayLength<T> for UInt<N, B1> {
|
||||
#[doc(hidden)]
|
||||
type ArrayType = GenericArrayImplOdd<T, N::ArrayType>;
|
||||
}
|
||||
|
||||
/// Struct representing a generic array - `GenericArray<T, N>` works like [T; N]
|
||||
#[allow(dead_code)]
|
||||
pub struct GenericArray<T, U: ArrayLength<T>> {
|
||||
data: U::ArrayType,
|
||||
}
|
||||
|
||||
impl<T, N> Deref for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &[T] {
|
||||
unsafe { slice::from_raw_parts(self as *const Self as *const T, N::to_usize()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> DerefMut for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, N::to_usize()) }
|
||||
}
|
||||
}
|
||||
|
||||
struct ArrayBuilder<T, N: ArrayLength<T>> {
|
||||
array: ManuallyDrop<GenericArray<T, N>>,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl<T, N: ArrayLength<T>> ArrayBuilder<T, N> {
|
||||
fn new() -> ArrayBuilder<T, N> {
|
||||
ArrayBuilder {
|
||||
array: ManuallyDrop::new(unsafe { mem::uninitialized() }),
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_inner(self) -> GenericArray<T, N> {
|
||||
let array = unsafe { ptr::read(&self.array) };
|
||||
|
||||
mem::forget(self);
|
||||
|
||||
ManuallyDrop::into_inner(array)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N: ArrayLength<T>> Drop for ArrayBuilder<T, N> {
|
||||
fn drop(&mut self) {
|
||||
for value in self.array.iter_mut().take(self.position) {
|
||||
unsafe {
|
||||
ptr::drop_in_place(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ArrayConsumer<T, N: ArrayLength<T>> {
|
||||
array: ManuallyDrop<GenericArray<T, N>>,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl<T, N: ArrayLength<T>> ArrayConsumer<T, N> {
|
||||
fn new(array: GenericArray<T, N>) -> ArrayConsumer<T, N> {
|
||||
ArrayConsumer {
|
||||
array: ManuallyDrop::new(array),
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N: ArrayLength<T>> Drop for ArrayConsumer<T, N> {
|
||||
fn drop(&mut self) {
|
||||
for i in self.position..N::to_usize() {
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.array.get_unchecked_mut(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
/// Initializes a new `GenericArray` instance using the given function.
|
||||
///
|
||||
/// If the generator function panics while initializing the array,
|
||||
/// any already initialized elements will be dropped.
|
||||
pub fn generate<F>(f: F) -> GenericArray<T, N>
|
||||
where
|
||||
F: Fn(usize) -> T,
|
||||
{
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (i, dst) in destination.array.iter_mut().enumerate() {
|
||||
unsafe {
|
||||
ptr::write(dst, f(i));
|
||||
}
|
||||
|
||||
destination.position += 1;
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
|
||||
/// Map a function over a slice to a `GenericArray`.
|
||||
///
|
||||
/// The length of the slice *must* be equal to the length of the array.
|
||||
#[inline]
|
||||
pub fn map_slice<S, F: Fn(&S) -> T>(s: &[S], f: F) -> GenericArray<T, N> {
|
||||
assert_eq!(s.len(), N::to_usize());
|
||||
|
||||
Self::generate(|i| f(unsafe { s.get_unchecked(i) }))
|
||||
}
|
||||
|
||||
/// Maps a `GenericArray` to another `GenericArray`.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements in the new array
|
||||
/// will be dropped, AND any unused elements in the source array will also be dropped.
|
||||
pub fn map<U, F>(self, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(T) -> U,
|
||||
N: ArrayLength<U>,
|
||||
{
|
||||
let mut source = ArrayConsumer::new(self);
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (dst, src) in destination.array.iter_mut().zip(source.array.iter()) {
|
||||
unsafe {
|
||||
ptr::write(dst, f(ptr::read(src)));
|
||||
}
|
||||
|
||||
source.position += 1;
|
||||
destination.position += 1;
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
|
||||
/// Maps a `GenericArray` to another `GenericArray` by reference.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements will be dropped.
|
||||
#[inline]
|
||||
pub fn map_ref<U, F>(&self, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(&T) -> U,
|
||||
N: ArrayLength<U>,
|
||||
{
|
||||
GenericArray::generate(|i| f(unsafe { self.get_unchecked(i) }))
|
||||
}
|
||||
|
||||
/// Combines two `GenericArray` instances and iterates through both of them,
|
||||
/// initializing a new `GenericArray` with the result of the zipped mapping function.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements in the new array
|
||||
/// will be dropped, AND any unused elements in the source arrays will also be dropped.
|
||||
pub fn zip<B, U, F>(self, rhs: GenericArray<B, N>, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(T, B) -> U,
|
||||
N: ArrayLength<B> + ArrayLength<U>,
|
||||
{
|
||||
let mut left = ArrayConsumer::new(self);
|
||||
let mut right = ArrayConsumer::new(rhs);
|
||||
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (dst, (lhs, rhs)) in
|
||||
destination.array.iter_mut().zip(left.array.iter().zip(
|
||||
right.array.iter(),
|
||||
))
|
||||
{
|
||||
unsafe {
|
||||
ptr::write(dst, f(ptr::read(lhs), ptr::read(rhs)));
|
||||
}
|
||||
|
||||
destination.position += 1;
|
||||
left.position += 1;
|
||||
right.position += 1;
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
|
||||
/// Combines two `GenericArray` instances and iterates through both of them by reference,
|
||||
/// initializing a new `GenericArray` with the result of the zipped mapping function.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements will be dropped.
|
||||
pub fn zip_ref<B, U, F>(&self, rhs: &GenericArray<B, N>, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(&T, &B) -> U,
|
||||
N: ArrayLength<B> + ArrayLength<U>,
|
||||
{
|
||||
GenericArray::generate(|i| unsafe {
|
||||
f(self.get_unchecked(i), rhs.get_unchecked(i))
|
||||
})
|
||||
}
|
||||
|
||||
/// Extracts a slice containing the entire array.
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
self.deref()
|
||||
}
|
||||
|
||||
/// Extracts a mutable slice containing the entire array.
|
||||
#[inline]
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
self.deref_mut()
|
||||
}
|
||||
|
||||
/// Converts slice to a generic array reference with inferred length;
|
||||
///
|
||||
/// Length of the slice must be equal to the length of the array.
|
||||
#[inline]
|
||||
pub fn from_slice(slice: &[T]) -> &GenericArray<T, N> {
|
||||
assert_eq!(slice.len(), N::to_usize());
|
||||
|
||||
unsafe { &*(slice.as_ptr() as *const GenericArray<T, N>) }
|
||||
}
|
||||
|
||||
/// Converts mutable slice to a mutable generic array reference
|
||||
///
|
||||
/// Length of the slice must be equal to the length of the array.
|
||||
#[inline]
|
||||
pub fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray<T, N> {
|
||||
assert_eq!(slice.len(), N::to_usize());
|
||||
|
||||
unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray<T, N>) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone, N> GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
/// Construct a `GenericArray` from a slice by cloning its content
|
||||
///
|
||||
/// Length of the slice must be equal to the length of the array
|
||||
#[inline]
|
||||
pub fn clone_from_slice(list: &[T]) -> GenericArray<T, N> {
|
||||
Self::from_exact_iter(list.iter().cloned()).expect(
|
||||
"Slice must be the same length as the array",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
pub fn from_exact_iter<I>(iter: I) -> Option<Self>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
<I as IntoIterator>::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
let iter = iter.into_iter();
|
||||
|
||||
if iter.len() == N::to_usize() {
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (dst, src) in destination.array.iter_mut().zip(iter.into_iter()) {
|
||||
unsafe {
|
||||
ptr::write(dst, src);
|
||||
}
|
||||
|
||||
destination.position += 1;
|
||||
}
|
||||
|
||||
let array = unsafe { ptr::read(&destination.array) };
|
||||
|
||||
mem::forget(destination);
|
||||
|
||||
Some(ManuallyDrop::into_inner(array))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> ::core::iter::FromIterator<T> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
T: Default,
|
||||
{
|
||||
fn from_iter<I>(iter: I) -> GenericArray<T, N>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
let defaults = ::core::iter::repeat(()).map(|_| T::default());
|
||||
|
||||
for (dst, src) in destination.array.iter_mut().zip(
|
||||
iter.into_iter().chain(defaults),
|
||||
)
|
||||
{
|
||||
unsafe {
|
||||
ptr::write(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// Compile with:
|
||||
// cargo rustc --lib --profile test --release --
|
||||
// -C target-cpu=native -C opt-level=3 --emit asm
|
||||
// and view the assembly to make sure test_assembly generates
|
||||
// SIMD instructions instead of a niave loop.
|
||||
|
||||
#[inline(never)]
|
||||
pub fn black_box<T>(val: T) -> T {
|
||||
use core::{mem, ptr};
|
||||
|
||||
let ret = unsafe { ptr::read_volatile(&val) };
|
||||
mem::forget(val);
|
||||
ret
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assembly() {
|
||||
let a = black_box(arr![i32; 1, 3, 5, 7]);
|
||||
let b = black_box(arr![i32; 2, 4, 6, 8]);
|
||||
|
||||
let c = a.zip_ref(&b, |l, r| l + r);
|
||||
|
||||
assert_eq!(c, arr![i32; 3, 7, 11, 15]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#[macro_use]
|
||||
extern crate generic_array;
|
||||
extern crate typenum;
|
||||
|
||||
use generic_array::GenericArray;
|
||||
use std::str::from_utf8;
|
||||
use typenum::U2048;
|
||||
|
||||
|
||||
#[test]
|
||||
fn short_lower_hex() {
|
||||
let ar = arr![u8; 10, 20, 30];
|
||||
assert_eq!(format!("{:x}", ar), "0a141e");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_upper_hex() {
|
||||
let ar = arr![u8; 30, 20, 10];
|
||||
assert_eq!(format!("{:X}", ar), "1E140A");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_lower_hex() {
|
||||
let ar = GenericArray::<u8, U2048>::default();
|
||||
assert_eq!(format!("{:x}", ar), from_utf8(&[b'0'; 4096]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_upper_hex() {
|
||||
let ar = GenericArray::<u8, U2048>::default();
|
||||
assert_eq!(format!("{:X}", ar), from_utf8(&[b'0'; 4096]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truncated_lower_hex() {
|
||||
let ar = arr![u8; 10, 20, 30, 40, 50];
|
||||
assert_eq!(format!("{:.2x}", ar), "0a14");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truncated_upper_hex() {
|
||||
let ar = arr![u8; 30, 20, 10, 17, 0];
|
||||
assert_eq!(format!("{:.4X}", ar), "1E140A11");
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#[macro_use]
|
||||
extern crate generic_array as gen_arr;
|
||||
|
||||
use gen_arr::typenum;
|
||||
|
||||
#[test]
|
||||
fn test_different_crate_name() {
|
||||
let _: gen_arr::GenericArray<u32, typenum::U4> = arr![u32; 0, 1, 2, 3];
|
||||
let _: gen_arr::GenericArray<u32, typenum::U0> = arr![u32;];
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
#![recursion_limit="128"]
|
||||
#![no_std]
|
||||
#[macro_use]
|
||||
extern crate generic_array;
|
||||
use core::cell::Cell;
|
||||
use core::ops::Drop;
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::typenum::{U1, U3, U4, U97};
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut list97 = [0; 97];
|
||||
for i in 0..97 {
|
||||
list97[i] = i as i32;
|
||||
}
|
||||
let l: GenericArray<i32, U97> = GenericArray::clone_from_slice(&list97);
|
||||
assert_eq!(l[0], 0);
|
||||
assert_eq!(l[1], 1);
|
||||
assert_eq!(l[32], 32);
|
||||
assert_eq!(l[56], 56);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop() {
|
||||
#[derive(Clone)]
|
||||
struct TestDrop<'a>(&'a Cell<u32>);
|
||||
|
||||
impl<'a> Drop for TestDrop<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.0.set(self.0.get() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
let drop_counter = Cell::new(0);
|
||||
{
|
||||
let _: GenericArray<TestDrop, U3> =
|
||||
arr![TestDrop; TestDrop(&drop_counter),
|
||||
TestDrop(&drop_counter),
|
||||
TestDrop(&drop_counter)];
|
||||
}
|
||||
assert_eq!(drop_counter.get(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arr() {
|
||||
let test: GenericArray<u32, U3> = arr![u32; 1, 2, 3];
|
||||
assert_eq!(test[1], 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy() {
|
||||
let test = arr![u32; 1, 2, 3];
|
||||
let test2 = test;
|
||||
// if GenericArray is not copy, this should fail as a use of a moved value
|
||||
assert_eq!(test[1], 2);
|
||||
assert_eq!(test2[0], 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iter_flat_map() {
|
||||
assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct NoClone<T>(T);
|
||||
|
||||
#[test]
|
||||
fn test_from_slice() {
|
||||
let arr = [1, 2, 3, 4];
|
||||
let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]);
|
||||
assert_eq!(&arr[..3], gen_arr.as_slice());
|
||||
let arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)];
|
||||
let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]);
|
||||
assert_eq!(&arr[..3], gen_arr.as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_mut_slice() {
|
||||
let mut arr = [1, 2, 3, 4];
|
||||
{
|
||||
let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]);
|
||||
gen_arr[2] = 10;
|
||||
}
|
||||
assert_eq!(arr, [1, 2, 10, 4]);
|
||||
let mut arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)];
|
||||
{
|
||||
let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]);
|
||||
gen_arr[2] = NoClone(10);
|
||||
}
|
||||
assert_eq!(arr, [NoClone(1), NoClone(2), NoClone(10), NoClone(4)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
let arr = GenericArray::<u8, U1>::default();
|
||||
assert_eq!(arr[0], 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from() {
|
||||
let data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)];
|
||||
let garray: GenericArray<(usize, usize, usize), U3> = data.into();
|
||||
assert_eq!(&data, garray.as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unit_macro() {
|
||||
let arr = arr![f32; 3.14];
|
||||
assert_eq!(arr[0], 3.14);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_macro() {
|
||||
let _arr = arr![f32;];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cmp() {
|
||||
arr![u8; 0x00].cmp(&arr![u8; 0x00]);
|
||||
}
|
||||
|
||||
/// This test should cause a helpful compile error if uncommented.
|
||||
// #[test]
|
||||
// fn test_empty_macro2(){
|
||||
// let arr = arr![];
|
||||
// }
|
||||
#[cfg(feature = "serde")]
|
||||
mod impl_serde {
|
||||
extern crate serde_json;
|
||||
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::typenum::U6;
|
||||
|
||||
#[test]
|
||||
fn test_serde_implementation() {
|
||||
let array: GenericArray<f64, U6> = arr![f64; 0.0, 5.0, 3.0, 7.07192, 76.0, -9.0];
|
||||
let string = serde_json::to_string(&array).unwrap();
|
||||
assert_eq!(string, "[0.0,5.0,3.0,7.07192,76.0,-9.0]");
|
||||
|
||||
let test_array: GenericArray<f64, U6> = serde_json::from_str(&string).unwrap();
|
||||
assert_eq!(test_array, array);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_map() {
|
||||
let b: GenericArray<i32, U4> = GenericArray::generate(|i| i as i32 * 4).map(|x| x - 3);
|
||||
|
||||
assert_eq!(b, arr![i32; -3, 1, 5, 9]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zip() {
|
||||
let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1);
|
||||
let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4);
|
||||
|
||||
let c = a.zip(b, |r, l| r as i32 + l);
|
||||
|
||||
assert_eq!(c, arr![i32; 1, 6, 11, 16]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
use core::iter::repeat;
|
||||
|
||||
let a: GenericArray<_, U4> = repeat(11).take(3).collect();
|
||||
|
||||
assert_eq!(a, arr![i32; 11, 11, 11, 0]);
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"87ff65d640c137c26d338f96e21e769af1e1b2e7fa615b40a1bcc755448bb118","LICENSE":"ad4fcfaf8d5b12b97409c137a03d4a4e4b21024c65c54f976cc3b609c1bd5b0f","README.md":"9a1a45416eac57050036b13df6ec84d21d555e820726af3c782896bd9d37d94b","rustfmt.toml":"2a298b4ce1fe6e16b8f281a0035567b8eb15042ed3062729fd28224f29c2f75a","src/arr.rs":"cc1ea0a9ef6a524b90767cc8a89f6b939394a2948a645ed313c0bf5ce5a258a4","src/hex.rs":"bfbf304fb4dea6f7edc0569b38bf2ac7657ce089c5761891321722509e3b5076","src/impl_serde.rs":"805885478728b3c205b842d46deb377b7dd6dd4c4c50254064431f49f0981a2a","src/impls.rs":"8c54e294a82a2bf344bdcb9949b8a84903fb65698d6b1b1e0ab9f5e7847be64f","src/iter.rs":"e52217f04d0dc046f13ef2e3539b90eabd4d55bb85cf40f76ba0bf86d5e55ef0","src/lib.rs":"da93fa505eee94b40fce0fe98e26ed3bb4d2bc4d4869af01598b6e54fc9c0f8d","tests/hex.rs":"e909bc0564e7d52c5fcf172dfc0fac7085010c6a21d38581bf73a54ab2e256e1","tests/import_name.rs":"1235729ecbde47fc9a38b3bf35c750a53ed55e3cf967c9d2b24fd759dc9e9e0c","tests/mod.rs":"f4100c5338906c038636f98f4d2b3d272f59580662afa89d915eafb96d7bbcf9"},"package":"ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"}
|
||||
{"files":{"CHANGELOG.md":"aa938a1a7581e59cbb554b44cc2dcf628cc1af9ddee6dccd53f557ed8d62775e","Cargo.toml":"df66f4832231be648f616c6d5ef1bacf25b40ff5118c7075554a4b41ce1d8ab1","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"aad2a8508f8ae6b009d04d388bffb751875d4cfdcc6f3398212c65cc3c390d03","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"5fee5550800b890383c1dd80e00a0a568475a8599e7678e143740c941e98099d","src/functional.rs":"2437c360c645d8a9816a3b13531f23b005d1aed3ef7b1d9bcc9b2859b1d56826","src/hex.rs":"438288cf41fad3fd40ce60eb893cd038e9a88e450bab0189fe4dba8ce833a686","src/impl_serde.rs":"2cab2f808ba000c214a3ded9f43b4d5363114fe57c2c7abf545345b8b749f0db","src/impls.rs":"a7fbfc134e2d716d3a816c4b7b8aa8376172fb7f2caf91bbb02a52595a45d253","src/iter.rs":"156f798c82bc0d5e2c9a0a7777acc156bfdda793b64295ad7495cc5daa5ecb97","src/lib.rs":"a6e6a869ed40ac944e7817d571b8357eab168b132ad0c2418ab4f3f5cdeede69","src/sequence.rs":"63813c9e305b6642ac29f0ba3dd70d7db86e27fc58b31e7508c68ea52c060e82","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"edf27c43ed13bf8cba2cd01de2fd7b6451c1226c8ad8331880996248e7f14d12","tests/mod.rs":"fca2966183ccd1d1681f91a845773911ab61f618bd412470612fac240ecfe0db"},"package":"3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"}
|
|
@ -0,0 +1,48 @@
|
|||
* **`0.12.0`**
|
||||
* Allow trailing commas in `arr!` macro.
|
||||
* **BREAKING**: Serialize `GenericArray` using `serde` tuples, instead of variable-length sequences. This may not be compatible with old serialized data.
|
||||
|
||||
* **`0.11.0`**
|
||||
* **BREAKING** Redesign `GenericSequence` with an emphasis on use in generic type parameters.
|
||||
* Add `MappedGenericSequence` and `FunctionalSequence`
|
||||
* Implements optimized `map`, `zip` and `fold` for `GenericArray`, `&GenericArray` and `&mut GenericArray`
|
||||
* **BREAKING** Remove `map_ref`, `zip_ref` and `map_slice`
|
||||
* `map_slice` is now equivalent to `GenericArray::from_iter(slice.iter().map(...))`
|
||||
* **`0.10.0`**
|
||||
* Add `GenericSequence`, `Lengthen`, `Shorten`, `Split` and `Concat` traits.
|
||||
* Redefine `transmute` to avert errors.
|
||||
* **`0.9.0`**
|
||||
* Rewrite construction methods to be well-defined in panic situations, correctly dropping elements.
|
||||
* `NoDrop` crate replaced by `ManuallyDrop` as it became stable in Rust core.
|
||||
* Add optimized `map`/`map_ref` and `zip`/`zip_ref` methods to `GenericArray`
|
||||
* **`0.8.0`**
|
||||
* Implement `AsRef`, `AsMut`, `Borrow`, `BorrowMut`, `Hash` for `GenericArray`
|
||||
* Update `serde` to `1.0`
|
||||
* Update `typenum`
|
||||
* Make macro `arr!` non-cloning
|
||||
* Implement `From<[T; N]>` up to `N=32`
|
||||
* Fix #45
|
||||
* **`0.7.0`**
|
||||
* Upgrade `serde` to `0.9`
|
||||
* Make `serde` with `no_std`
|
||||
* Implement `PartialOrd`/`Ord` for `GenericArray`
|
||||
* **`0.6.0`**
|
||||
* Fixed #30
|
||||
* Implement `Default` for `GenericArray`
|
||||
* Implement `LowerHex` and `UpperHex` for `GenericArray<u8, N>`
|
||||
* Use `precision` formatting field in hex representation
|
||||
* Add `as_slice`, `as_mut_slice`
|
||||
* Remove `GenericArray::new` in favor of `Default` trait
|
||||
* Add `from_slice` and `from_mut_slice`
|
||||
* `no_std` and `core` for crate.
|
||||
* **`0.5.0`**
|
||||
* Update `serde`
|
||||
* remove `no_std` feature, fixed #19
|
||||
* **`0.4.0`**
|
||||
* Re-export `typenum`
|
||||
* **`0.3.0`**
|
||||
* Implement `IntoIter` for `GenericArray`
|
||||
* Add `map` method
|
||||
* Add optional `serde` (de)serialization support feature.
|
||||
* **`< 0.3.0`**
|
||||
* Initial implementation in late 2015
|
|
@ -12,21 +12,29 @@
|
|||
|
||||
[package]
|
||||
name = "generic-array"
|
||||
version = "0.9.0"
|
||||
authors = ["Bartłomiej Kamiński <fizyk20@gmail.com>"]
|
||||
version = "0.12.0"
|
||||
authors = ["Bartłomiej Kamiński <fizyk20@gmail.com>", "Aaron Trent <novacrazy@gmail.com>"]
|
||||
description = "Generic types implementing functionality of arrays"
|
||||
documentation = "http://fizyk20.github.io/generic-array/generic_array/"
|
||||
readme = "README.md"
|
||||
keywords = ["generic", "array"]
|
||||
categories = ["data-structures", "no-std"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/fizyk20/generic-array.git"
|
||||
|
||||
[lib]
|
||||
name = "generic_array"
|
||||
[dependencies.typenum]
|
||||
version = "1.9"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.typenum]
|
||||
version = "1.10"
|
||||
[dev-dependencies.bincode]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1.0"
|
||||
[badges.travis-ci]
|
||||
repository = "fizyk20/generic-array"
|
||||
|
|
|
@ -32,13 +32,13 @@ macro_rules! arr_impl {
|
|||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [])
|
||||
);
|
||||
($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => (
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),*])
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+])
|
||||
);
|
||||
($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => (
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),*, $x1 as $T], [])
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [])
|
||||
);
|
||||
($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => (
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),*, $x1 as $T], [$($x),*])
|
||||
arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($x),+])
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -46,10 +46,10 @@ macro_rules! arr_impl {
|
|||
/// Example: `let test = arr![u32; 1, 2, 3];`
|
||||
#[macro_export]
|
||||
macro_rules! arr {
|
||||
($T:ty;) => ({
|
||||
($T:ty; $(,)*) => ({
|
||||
unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) }
|
||||
});
|
||||
($T:ty; $($x:expr),*) => (
|
||||
($T:ty; $($x:expr),* $(,)*) => (
|
||||
arr_impl!($T; $crate::typenum::U0, [], [$($x),*])
|
||||
);
|
||||
($($x:expr,)+) => (arr![$($x),*]);
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
//! Functional programming with generic sequences
|
||||
//!
|
||||
//! Please see `tests/generics.rs` for examples of how to best use these in your generic functions.
|
||||
|
||||
use super::ArrayLength;
|
||||
use core::iter::FromIterator;
|
||||
use sequence::*;
|
||||
|
||||
/// Defines the relationship between one generic sequence and another,
|
||||
/// for operations such as `map` and `zip`.
|
||||
pub unsafe trait MappedGenericSequence<T, U>: GenericSequence<T>
|
||||
where
|
||||
Self::Length: ArrayLength<U>,
|
||||
{
|
||||
/// Mapped sequence type
|
||||
type Mapped: GenericSequence<U, Length = Self::Length>;
|
||||
}
|
||||
|
||||
unsafe impl<'a, T, U, S: MappedGenericSequence<T, U>> MappedGenericSequence<T, U> for &'a S
|
||||
where
|
||||
&'a S: GenericSequence<T>,
|
||||
S: GenericSequence<T, Length = <&'a S as GenericSequence<T>>::Length>,
|
||||
<S as GenericSequence<T>>::Length: ArrayLength<U>,
|
||||
{
|
||||
type Mapped = <S as MappedGenericSequence<T, U>>::Mapped;
|
||||
}
|
||||
|
||||
unsafe impl<'a, T, U, S: MappedGenericSequence<T, U>> MappedGenericSequence<T, U> for &'a mut S
|
||||
where
|
||||
&'a mut S: GenericSequence<T>,
|
||||
S: GenericSequence<T, Length = <&'a mut S as GenericSequence<T>>::Length>,
|
||||
<S as GenericSequence<T>>::Length: ArrayLength<U>,
|
||||
{
|
||||
type Mapped = <S as MappedGenericSequence<T, U>>::Mapped;
|
||||
}
|
||||
|
||||
/// Accessor type for a mapped generic sequence
|
||||
pub type MappedSequence<S, T, U> =
|
||||
<<S as MappedGenericSequence<T, U>>::Mapped as GenericSequence<U>>::Sequence;
|
||||
|
||||
/// Defines functional programming methods for generic sequences
|
||||
pub unsafe trait FunctionalSequence<T>: GenericSequence<T> {
|
||||
/// Maps a `GenericSequence` to another `GenericSequence`.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements in the new sequence
|
||||
/// will be dropped, AND any unused elements in the source sequence will also be dropped.
|
||||
fn map<U, F>(self, f: F) -> MappedSequence<Self, T, U>
|
||||
where
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
Self::Length: ArrayLength<U>,
|
||||
F: FnMut(Self::Item) -> U,
|
||||
{
|
||||
FromIterator::from_iter(self.into_iter().map(f))
|
||||
}
|
||||
|
||||
/// Combines two `GenericSequence` instances and iterates through both of them,
|
||||
/// initializing a new `GenericSequence` with the result of the zipped mapping function.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements in the new sequence
|
||||
/// will be dropped, AND any unused elements in the source sequences will also be dropped.
|
||||
#[inline]
|
||||
fn zip<B, Rhs, U, F>(self, rhs: Rhs, f: F) -> MappedSequence<Self, T, U>
|
||||
where
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
Rhs: MappedGenericSequence<B, U, Mapped = MappedSequence<Self, T, U>>,
|
||||
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
||||
Rhs: GenericSequence<B, Length = Self::Length>,
|
||||
F: FnMut(Self::Item, Rhs::Item) -> U,
|
||||
{
|
||||
rhs.inverted_zip2(self, f)
|
||||
}
|
||||
|
||||
/// Folds (or reduces) a sequence of data into a single value.
|
||||
///
|
||||
/// If the fold function panics, any unused elements will be dropped.
|
||||
fn fold<U, F>(self, init: U, f: F) -> U
|
||||
where
|
||||
F: FnMut(U, Self::Item) -> U,
|
||||
{
|
||||
self.into_iter().fold(init, f)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, T, S: GenericSequence<T>> FunctionalSequence<T> for &'a S
|
||||
where
|
||||
&'a S: GenericSequence<T>,
|
||||
{
|
||||
}
|
||||
|
||||
unsafe impl<'a, T, S: GenericSequence<T>> FunctionalSequence<T> for &'a mut S
|
||||
where
|
||||
&'a mut S: GenericSequence<T>,
|
||||
{
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
//!
|
||||
|
||||
use {ArrayLength, GenericArray};
|
||||
use core::cmp::min;
|
||||
use core::fmt;
|
||||
use core::ops::Add;
|
||||
use core::str;
|
||||
|
@ -30,32 +31,32 @@ where
|
|||
<T as Add<T>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let max_digits = f.precision().unwrap_or_else(|| self.len());
|
||||
let max_digits = f.precision().unwrap_or_else(|| self.len() * 2);
|
||||
let max_hex = (max_digits >> 1) + (max_digits & 1);
|
||||
|
||||
if T::to_usize() < 1024 {
|
||||
// For small arrays use a stack allocated
|
||||
// buffer of 2x number of bytes
|
||||
let mut res = GenericArray::<u8, Sum<T, T>>::default();
|
||||
|
||||
for (i, c) in self.iter().take(max_digits).enumerate() {
|
||||
for (i, c) in self.iter().take(max_hex).enumerate() {
|
||||
res[i * 2] = LOWER_CHARS[(c >> 4) as usize];
|
||||
res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(
|
||||
unsafe { str::from_utf8_unchecked(&res[..max_digits * 2]) },
|
||||
)?;
|
||||
f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?;
|
||||
} else {
|
||||
// For large array use chunks of up to 1024 bytes (2048 hex chars)
|
||||
let mut buf = [0u8; 2048];
|
||||
let mut digits_left = max_digits;
|
||||
|
||||
for chunk in self[..max_digits].chunks(1024) {
|
||||
for chunk in self[..max_hex].chunks(1024) {
|
||||
for (i, c) in chunk.iter().enumerate() {
|
||||
buf[i * 2] = LOWER_CHARS[(c >> 4) as usize];
|
||||
buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(unsafe {
|
||||
str::from_utf8_unchecked(&buf[..chunk.len() * 2])
|
||||
})?;
|
||||
let n = min(chunk.len() * 2, digits_left);
|
||||
f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?;
|
||||
digits_left -= n;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -68,32 +69,32 @@ where
|
|||
<T as Add<T>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let max_digits = f.precision().unwrap_or_else(|| self.len());
|
||||
let max_digits = f.precision().unwrap_or_else(|| self.len() * 2);
|
||||
let max_hex = (max_digits >> 1) + (max_digits & 1);
|
||||
|
||||
if T::to_usize() < 1024 {
|
||||
// For small arrays use a stack allocated
|
||||
// buffer of 2x number of bytes
|
||||
let mut res = GenericArray::<u8, Sum<T, T>>::default();
|
||||
|
||||
for (i, c) in self.iter().take(max_digits).enumerate() {
|
||||
for (i, c) in self.iter().take(max_hex).enumerate() {
|
||||
res[i * 2] = UPPER_CHARS[(c >> 4) as usize];
|
||||
res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(
|
||||
unsafe { str::from_utf8_unchecked(&res[..max_digits * 2]) },
|
||||
)?;
|
||||
f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?;
|
||||
} else {
|
||||
// For large array use chunks of up to 1024 bytes (2048 hex chars)
|
||||
let mut buf = [0u8; 2048];
|
||||
let mut digits_left = max_digits;
|
||||
|
||||
for chunk in self[..max_digits].chunks(1024) {
|
||||
for chunk in self[..max_hex].chunks(1024) {
|
||||
for (i, c) in chunk.iter().enumerate() {
|
||||
buf[i * 2] = UPPER_CHARS[(c >> 4) as usize];
|
||||
buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
|
||||
}
|
||||
f.write_str(unsafe {
|
||||
str::from_utf8_unchecked(&buf[..chunk.len() * 2])
|
||||
})?;
|
||||
let n = min(chunk.len() * 2, digits_left);
|
||||
f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?;
|
||||
digits_left -= n;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Serde serialization/deserialization implementation
|
||||
|
||||
use {ArrayLength, GenericArray};
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::de::{self, SeqAccess, Visitor};
|
||||
use serde::{ser::SerializeTuple, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use {ArrayLength, GenericArray};
|
||||
|
||||
impl<T, N> Serialize for GenericArray<T, N>
|
||||
where
|
||||
|
@ -16,7 +16,12 @@ where
|
|||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_seq(self.iter())
|
||||
let mut tup = serializer.serialize_tuple(N::to_usize())?;
|
||||
for el in self {
|
||||
tup.serialize_element(el)?;
|
||||
}
|
||||
|
||||
tup.end()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,9 +47,9 @@ where
|
|||
{
|
||||
let mut result = GenericArray::default();
|
||||
for i in 0..N::to_usize() {
|
||||
result[i] = seq.next_element()?.ok_or_else(
|
||||
|| de::Error::invalid_length(i, &self),
|
||||
)?;
|
||||
result[i] = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(i, &self))?;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -63,6 +68,41 @@ where
|
|||
_t: PhantomData,
|
||||
_n: PhantomData,
|
||||
};
|
||||
deserializer.deserialize_seq(visitor)
|
||||
deserializer.deserialize_tuple(N::to_usize(), visitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bincode;
|
||||
use typenum;
|
||||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
let array = GenericArray::<u8, typenum::U2>::default();
|
||||
let serialized = bincode::serialize(&array);
|
||||
assert!(serialized.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize() {
|
||||
let mut array = GenericArray::<u8, typenum::U2>::default();
|
||||
array[0] = 1;
|
||||
array[1] = 2;
|
||||
let serialized = bincode::serialize(&array).unwrap();
|
||||
let deserialized = bincode::deserialize::<GenericArray<u8, typenum::U2>>(&array);
|
||||
assert!(deserialized.is_ok());
|
||||
let array = deserialized.unwrap();
|
||||
assert_eq!(array[0], 1);
|
||||
assert_eq!(array[1], 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialized_size() {
|
||||
let array = GenericArray::<u8, typenum::U1>::default();
|
||||
let size = bincode::serialized_size(&array).unwrap();
|
||||
assert_eq!(size, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ use core::borrow::{Borrow, BorrowMut};
|
|||
use core::cmp::Ordering;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use functional::*;
|
||||
use sequence::*;
|
||||
|
||||
impl<T: Default, N> Default for GenericArray<T, N>
|
||||
where
|
||||
|
@ -19,7 +21,7 @@ where
|
|||
N: ArrayLength<T>,
|
||||
{
|
||||
fn clone(&self) -> GenericArray<T, N> {
|
||||
self.map_ref(|x| x.clone())
|
||||
self.map(|x| x.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! `GenericArray` iterator implementation.
|
||||
|
||||
use super::{ArrayLength, GenericArray};
|
||||
use core::{cmp, ptr};
|
||||
use core::{cmp, ptr, fmt, mem};
|
||||
use core::mem::ManuallyDrop;
|
||||
|
||||
/// An iterator that moves out of a `GenericArray`
|
||||
|
@ -14,6 +14,35 @@ pub struct GenericArrayIter<T, N: ArrayLength<T>> {
|
|||
index_back: usize,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
fn send<I: Send>(_iter: I) {}
|
||||
|
||||
#[test]
|
||||
fn test_send_iter() {
|
||||
send(GenericArray::from([1, 2, 3, 4]).into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
/// Returns the remaining items of this iterator as a slice
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
&self.array.as_slice()[self.index..self.index_back]
|
||||
}
|
||||
|
||||
/// Returns the remaining items of this iterator as a mutable slice
|
||||
#[inline]
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
&mut self.array.as_mut_slice()[self.index..self.index_back]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> IntoIterator for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
|
@ -30,13 +59,26 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// Based on work in rust-lang/rust#49000
|
||||
impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("GenericArrayIter")
|
||||
.field(&self.as_slice())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> Drop for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
// Drop values that are still alive.
|
||||
for p in &mut self.array[self.index..self.index_back] {
|
||||
for p in self.as_mut_slice() {
|
||||
unsafe {
|
||||
ptr::drop_in_place(p);
|
||||
}
|
||||
|
@ -44,29 +86,58 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// Based on work in rust-lang/rust#49000
|
||||
impl<T: Clone, N> Clone for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
// This places all cloned elements at the start of the new array iterator,
|
||||
// not at their original indices.
|
||||
unsafe {
|
||||
let mut iter = GenericArrayIter {
|
||||
array: ManuallyDrop::new(mem::uninitialized()),
|
||||
index: 0,
|
||||
index_back: 0,
|
||||
};
|
||||
|
||||
for (dst, src) in iter.array.iter_mut().zip(self.as_slice()) {
|
||||
ptr::write(dst, src.clone());
|
||||
|
||||
iter.index_back += 1;
|
||||
}
|
||||
|
||||
iter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> Iterator for GenericArrayIter<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if self.len() > 0 {
|
||||
unsafe {
|
||||
let p = self.array.get_unchecked(self.index);
|
||||
if self.index < self.index_back {
|
||||
let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };
|
||||
|
||||
self.index += 1;
|
||||
Some(ptr::read(p))
|
||||
}
|
||||
|
||||
p
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.len();
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
@ -74,8 +145,10 @@ where
|
|||
fn nth(&mut self, n: usize) -> Option<T> {
|
||||
// First consume values prior to the nth.
|
||||
let ndrop = cmp::min(n, self.len());
|
||||
|
||||
for p in &mut self.array[self.index..self.index + ndrop] {
|
||||
self.index += 1;
|
||||
|
||||
unsafe {
|
||||
ptr::drop_in_place(p);
|
||||
}
|
||||
|
@ -95,12 +168,10 @@ where
|
|||
N: ArrayLength<T>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
if self.len() > 0 {
|
||||
if self.index < self.index_back {
|
||||
self.index_back -= 1;
|
||||
unsafe {
|
||||
let p = self.array.get_unchecked(self.index_back);
|
||||
Some(ptr::read(p))
|
||||
}
|
||||
|
||||
unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -115,3 +186,5 @@ where
|
|||
self.index_back - self.index
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement `FusedIterator` and `TrustedLen` when stabilized
|
|
@ -36,33 +36,40 @@
|
|||
//! # }
|
||||
//! ```
|
||||
|
||||
//#![deny(missing_docs)]
|
||||
#![deny(missing_docs)]
|
||||
#![no_std]
|
||||
|
||||
pub extern crate typenum;
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate bincode;
|
||||
|
||||
pub extern crate typenum;
|
||||
|
||||
mod hex;
|
||||
mod impls;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod impl_serde;
|
||||
|
||||
use core::{mem, ptr, slice};
|
||||
|
||||
use core::iter::FromIterator;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::ManuallyDrop;
|
||||
pub use core::mem::transmute;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use core::{mem, ptr, slice};
|
||||
use typenum::bit::{B0, B1};
|
||||
use typenum::uint::{UInt, UTerm, Unsigned};
|
||||
|
||||
#[cfg_attr(test, macro_use)]
|
||||
pub mod arr;
|
||||
pub mod functional;
|
||||
pub mod iter;
|
||||
pub mod sequence;
|
||||
|
||||
use functional::*;
|
||||
pub use iter::GenericArrayIter;
|
||||
use sequence::*;
|
||||
|
||||
/// Trait making `GenericArray` work, marking types to be used as length of an array
|
||||
pub unsafe trait ArrayLength<T>: Unsigned {
|
||||
|
@ -135,6 +142,9 @@ pub struct GenericArray<T, U: ArrayLength<T>> {
|
|||
data: U::ArrayType,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send, N: ArrayLength<T>> Send for GenericArray<T, N> {}
|
||||
unsafe impl<T: Sync, N: ArrayLength<T>> Sync for GenericArray<T, N> {}
|
||||
|
||||
impl<T, N> Deref for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
|
@ -155,21 +165,43 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
struct ArrayBuilder<T, N: ArrayLength<T>> {
|
||||
/// Creates an array one element at a time using a mutable iterator
|
||||
/// you can write to with `ptr::write`.
|
||||
///
|
||||
/// Incremenent the position while iterating to mark off created elements,
|
||||
/// which will be dropped if `into_inner` is not called.
|
||||
#[doc(hidden)]
|
||||
pub struct ArrayBuilder<T, N: ArrayLength<T>> {
|
||||
array: ManuallyDrop<GenericArray<T, N>>,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl<T, N: ArrayLength<T>> ArrayBuilder<T, N> {
|
||||
fn new() -> ArrayBuilder<T, N> {
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub unsafe fn new() -> ArrayBuilder<T, N> {
|
||||
ArrayBuilder {
|
||||
array: ManuallyDrop::new(unsafe { mem::uninitialized() }),
|
||||
array: ManuallyDrop::new(mem::uninitialized()),
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_inner(self) -> GenericArray<T, N> {
|
||||
let array = unsafe { ptr::read(&self.array) };
|
||||
/// Creates a mutable iterator for writing to the array using `ptr::write`.
|
||||
///
|
||||
/// Increment the position value given as a mutable reference as you iterate
|
||||
/// to mark how many elements have been created.
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub unsafe fn iter_position(&mut self) -> (slice::IterMut<T>, &mut usize) {
|
||||
(self.array.iter_mut(), &mut self.position)
|
||||
}
|
||||
|
||||
/// When done writing (assuming all elements have been written to),
|
||||
/// get the inner array.
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub unsafe fn into_inner(self) -> GenericArray<T, N> {
|
||||
let array = ptr::read(&self.array);
|
||||
|
||||
mem::forget(self);
|
||||
|
||||
|
@ -179,7 +211,7 @@ impl<T, N: ArrayLength<T>> ArrayBuilder<T, N> {
|
|||
|
||||
impl<T, N: ArrayLength<T>> Drop for ArrayBuilder<T, N> {
|
||||
fn drop(&mut self) {
|
||||
for value in self.array.iter_mut().take(self.position) {
|
||||
for value in &mut self.array[..self.position] {
|
||||
unsafe {
|
||||
ptr::drop_in_place(value);
|
||||
}
|
||||
|
@ -187,147 +219,269 @@ impl<T, N: ArrayLength<T>> Drop for ArrayBuilder<T, N> {
|
|||
}
|
||||
}
|
||||
|
||||
struct ArrayConsumer<T, N: ArrayLength<T>> {
|
||||
/// Consumes an array.
|
||||
///
|
||||
/// Increment the position while iterating and any leftover elements
|
||||
/// will be dropped if position does not go to N
|
||||
#[doc(hidden)]
|
||||
pub struct ArrayConsumer<T, N: ArrayLength<T>> {
|
||||
array: ManuallyDrop<GenericArray<T, N>>,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl<T, N: ArrayLength<T>> ArrayConsumer<T, N> {
|
||||
fn new(array: GenericArray<T, N>) -> ArrayConsumer<T, N> {
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub unsafe fn new(array: GenericArray<T, N>) -> ArrayConsumer<T, N> {
|
||||
ArrayConsumer {
|
||||
array: ManuallyDrop::new(array),
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an iterator and mutable reference to the internal position
|
||||
/// to keep track of consumed elements.
|
||||
///
|
||||
/// Increment the position as you iterate to mark off consumed elements
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub unsafe fn iter_position(&mut self) -> (slice::Iter<T>, &mut usize) {
|
||||
(self.array.iter(), &mut self.position)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N: ArrayLength<T>> Drop for ArrayConsumer<T, N> {
|
||||
fn drop(&mut self) {
|
||||
for i in self.position..N::to_usize() {
|
||||
for value in &mut self.array[self.position..N::to_usize()] {
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.array.get_unchecked_mut(i));
|
||||
ptr::drop_in_place(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, N> IntoIterator for &'a GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
type IntoIter = slice::Iter<'a, T>;
|
||||
type Item = &'a T;
|
||||
|
||||
fn into_iter(self: &'a GenericArray<T, N>) -> Self::IntoIter {
|
||||
self.as_slice().iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, N> IntoIterator for &'a mut GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
type IntoIter = slice::IterMut<'a, T>;
|
||||
type Item = &'a mut T;
|
||||
|
||||
fn into_iter(self: &'a mut GenericArray<T, N>) -> Self::IntoIter {
|
||||
self.as_mut_slice().iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> FromIterator<T> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
fn from_iter<I>(iter: I) -> GenericArray<T, N>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
unsafe {
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
{
|
||||
let (destination_iter, position) = destination.iter_position();
|
||||
|
||||
for (src, dst) in iter.into_iter().zip(destination_iter) {
|
||||
ptr::write(dst, src);
|
||||
|
||||
*position += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if destination.position < N::to_usize() {
|
||||
from_iter_length_fail(destination.position, N::to_usize());
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn from_iter_length_fail(length: usize, expected: usize) -> ! {
|
||||
panic!(
|
||||
"GenericArray::from_iter received {} elements but expected {}",
|
||||
length, expected
|
||||
);
|
||||
}
|
||||
|
||||
unsafe impl<T, N> GenericSequence<T> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
Self: IntoIterator<Item = T>,
|
||||
{
|
||||
type Length = N;
|
||||
type Sequence = Self;
|
||||
|
||||
fn generate<F>(mut f: F) -> GenericArray<T, N>
|
||||
where
|
||||
F: FnMut(usize) -> T,
|
||||
{
|
||||
unsafe {
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
{
|
||||
let (destination_iter, position) = destination.iter_position();
|
||||
|
||||
for (i, dst) in destination_iter.enumerate() {
|
||||
ptr::write(dst, f(i));
|
||||
|
||||
*position += 1;
|
||||
}
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
fn inverted_zip<B, U, F>(
|
||||
self,
|
||||
lhs: GenericArray<B, Self::Length>,
|
||||
mut f: F,
|
||||
) -> MappedSequence<GenericArray<B, Self::Length>, B, U>
|
||||
where
|
||||
GenericArray<B, Self::Length>:
|
||||
GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
||||
F: FnMut(B, Self::Item) -> U,
|
||||
{
|
||||
unsafe {
|
||||
let mut left = ArrayConsumer::new(lhs);
|
||||
let mut right = ArrayConsumer::new(self);
|
||||
|
||||
let (left_array_iter, left_position) = left.iter_position();
|
||||
let (right_array_iter, right_position) = right.iter_position();
|
||||
|
||||
FromIterator::from_iter(left_array_iter.zip(right_array_iter).map(|(l, r)| {
|
||||
let left_value = ptr::read(l);
|
||||
let right_value = ptr::read(r);
|
||||
|
||||
*left_position += 1;
|
||||
*right_position += 1;
|
||||
|
||||
f(left_value, right_value)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
fn inverted_zip2<B, Lhs, U, F>(self, lhs: Lhs, mut f: F) -> MappedSequence<Lhs, B, U>
|
||||
where
|
||||
Lhs: GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
||||
F: FnMut(Lhs::Item, Self::Item) -> U,
|
||||
{
|
||||
unsafe {
|
||||
let mut right = ArrayConsumer::new(self);
|
||||
|
||||
let (right_array_iter, right_position) = right.iter_position();
|
||||
|
||||
FromIterator::from_iter(
|
||||
lhs.into_iter()
|
||||
.zip(right_array_iter)
|
||||
.map(|(left_value, r)| {
|
||||
let right_value = ptr::read(r);
|
||||
|
||||
*right_position += 1;
|
||||
|
||||
f(left_value, right_value)
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T, U, N> MappedGenericSequence<T, U> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T> + ArrayLength<U>,
|
||||
GenericArray<U, N>: GenericSequence<U, Length = N>,
|
||||
{
|
||||
type Mapped = GenericArray<U, N>;
|
||||
}
|
||||
|
||||
unsafe impl<T, N> FunctionalSequence<T> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
Self: GenericSequence<T, Item = T, Length = N>,
|
||||
{
|
||||
fn map<U, F>(self, mut f: F) -> MappedSequence<Self, T, U>
|
||||
where
|
||||
Self::Length: ArrayLength<U>,
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
F: FnMut(T) -> U,
|
||||
{
|
||||
unsafe {
|
||||
let mut source = ArrayConsumer::new(self);
|
||||
|
||||
let (array_iter, position) = source.iter_position();
|
||||
|
||||
FromIterator::from_iter(array_iter.map(|src| {
|
||||
let value = ptr::read(src);
|
||||
|
||||
*position += 1;
|
||||
|
||||
f(value)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn zip<B, Rhs, U, F>(self, rhs: Rhs, f: F) -> MappedSequence<Self, T, U>
|
||||
where
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
Rhs: MappedGenericSequence<B, U, Mapped = MappedSequence<Self, T, U>>,
|
||||
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
||||
Rhs: GenericSequence<B, Length = Self::Length>,
|
||||
F: FnMut(T, Rhs::Item) -> U,
|
||||
{
|
||||
rhs.inverted_zip(self, f)
|
||||
}
|
||||
|
||||
fn fold<U, F>(self, init: U, mut f: F) -> U
|
||||
where
|
||||
F: FnMut(U, T) -> U,
|
||||
{
|
||||
unsafe {
|
||||
let mut source = ArrayConsumer::new(self);
|
||||
|
||||
let (array_iter, position) = source.iter_position();
|
||||
|
||||
array_iter.fold(init, |acc, src| {
|
||||
let value = ptr::read(src);
|
||||
|
||||
*position += 1;
|
||||
|
||||
f(acc, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
/// Initializes a new `GenericArray` instance using the given function.
|
||||
///
|
||||
/// If the generator function panics while initializing the array,
|
||||
/// any already initialized elements will be dropped.
|
||||
pub fn generate<F>(f: F) -> GenericArray<T, N>
|
||||
where
|
||||
F: Fn(usize) -> T,
|
||||
{
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (i, dst) in destination.array.iter_mut().enumerate() {
|
||||
unsafe {
|
||||
ptr::write(dst, f(i));
|
||||
}
|
||||
|
||||
destination.position += 1;
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
|
||||
/// Map a function over a slice to a `GenericArray`.
|
||||
///
|
||||
/// The length of the slice *must* be equal to the length of the array.
|
||||
#[inline]
|
||||
pub fn map_slice<S, F: Fn(&S) -> T>(s: &[S], f: F) -> GenericArray<T, N> {
|
||||
assert_eq!(s.len(), N::to_usize());
|
||||
|
||||
Self::generate(|i| f(unsafe { s.get_unchecked(i) }))
|
||||
}
|
||||
|
||||
/// Maps a `GenericArray` to another `GenericArray`.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements in the new array
|
||||
/// will be dropped, AND any unused elements in the source array will also be dropped.
|
||||
pub fn map<U, F>(self, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(T) -> U,
|
||||
N: ArrayLength<U>,
|
||||
{
|
||||
let mut source = ArrayConsumer::new(self);
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (dst, src) in destination.array.iter_mut().zip(source.array.iter()) {
|
||||
unsafe {
|
||||
ptr::write(dst, f(ptr::read(src)));
|
||||
}
|
||||
|
||||
source.position += 1;
|
||||
destination.position += 1;
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
|
||||
/// Maps a `GenericArray` to another `GenericArray` by reference.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements will be dropped.
|
||||
#[inline]
|
||||
pub fn map_ref<U, F>(&self, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(&T) -> U,
|
||||
N: ArrayLength<U>,
|
||||
{
|
||||
GenericArray::generate(|i| f(unsafe { self.get_unchecked(i) }))
|
||||
}
|
||||
|
||||
/// Combines two `GenericArray` instances and iterates through both of them,
|
||||
/// initializing a new `GenericArray` with the result of the zipped mapping function.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements in the new array
|
||||
/// will be dropped, AND any unused elements in the source arrays will also be dropped.
|
||||
pub fn zip<B, U, F>(self, rhs: GenericArray<B, N>, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(T, B) -> U,
|
||||
N: ArrayLength<B> + ArrayLength<U>,
|
||||
{
|
||||
let mut left = ArrayConsumer::new(self);
|
||||
let mut right = ArrayConsumer::new(rhs);
|
||||
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (dst, (lhs, rhs)) in
|
||||
destination.array.iter_mut().zip(left.array.iter().zip(
|
||||
right.array.iter(),
|
||||
))
|
||||
{
|
||||
unsafe {
|
||||
ptr::write(dst, f(ptr::read(lhs), ptr::read(rhs)));
|
||||
}
|
||||
|
||||
destination.position += 1;
|
||||
left.position += 1;
|
||||
right.position += 1;
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
|
||||
/// Combines two `GenericArray` instances and iterates through both of them by reference,
|
||||
/// initializing a new `GenericArray` with the result of the zipped mapping function.
|
||||
///
|
||||
/// If the mapping function panics, any already initialized elements will be dropped.
|
||||
pub fn zip_ref<B, U, F>(&self, rhs: &GenericArray<B, N>, f: F) -> GenericArray<U, N>
|
||||
where
|
||||
F: Fn(&T, &B) -> U,
|
||||
N: ArrayLength<B> + ArrayLength<U>,
|
||||
{
|
||||
GenericArray::generate(|i| unsafe {
|
||||
f(self.get_unchecked(i), rhs.get_unchecked(i))
|
||||
})
|
||||
}
|
||||
|
||||
/// Extracts a slice containing the entire array.
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
|
@ -345,9 +499,7 @@ where
|
|||
/// Length of the slice must be equal to the length of the array.
|
||||
#[inline]
|
||||
pub fn from_slice(slice: &[T]) -> &GenericArray<T, N> {
|
||||
assert_eq!(slice.len(), N::to_usize());
|
||||
|
||||
unsafe { &*(slice.as_ptr() as *const GenericArray<T, N>) }
|
||||
slice.into()
|
||||
}
|
||||
|
||||
/// Converts mutable slice to a mutable generic array reference
|
||||
|
@ -355,6 +507,28 @@ where
|
|||
/// Length of the slice must be equal to the length of the array.
|
||||
#[inline]
|
||||
pub fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray<T, N> {
|
||||
slice.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, N: ArrayLength<T>> From<&'a [T]> for &'a GenericArray<T, N> {
|
||||
/// Converts slice to a generic array reference with inferred length;
|
||||
///
|
||||
/// Length of the slice must be equal to the length of the array.
|
||||
#[inline]
|
||||
fn from(slice: &[T]) -> &GenericArray<T, N> {
|
||||
assert_eq!(slice.len(), N::to_usize());
|
||||
|
||||
unsafe { &*(slice.as_ptr() as *const GenericArray<T, N>) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, N: ArrayLength<T>> From<&'a mut [T]> for &'a mut GenericArray<T, N> {
|
||||
/// Converts mutable slice to a mutable generic array reference
|
||||
///
|
||||
/// Length of the slice must be equal to the length of the array.
|
||||
#[inline]
|
||||
fn from(slice: &mut [T]) -> &mut GenericArray<T, N> {
|
||||
assert_eq!(slice.len(), N::to_usize());
|
||||
|
||||
unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray<T, N>) }
|
||||
|
@ -370,9 +544,8 @@ where
|
|||
/// Length of the slice must be equal to the length of the array
|
||||
#[inline]
|
||||
pub fn clone_from_slice(list: &[T]) -> GenericArray<T, N> {
|
||||
Self::from_exact_iter(list.iter().cloned()).expect(
|
||||
"Slice must be the same length as the array",
|
||||
)
|
||||
Self::from_exact_iter(list.iter().cloned())
|
||||
.expect("Slice must be the same length as the array")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,6 +553,9 @@ impl<T, N> GenericArray<T, N>
|
|||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
/// Creates a new `GenericArray` instance from an iterator with a known exact size.
|
||||
///
|
||||
/// Returns `None` if the size is not equal to the number of elements in the `GenericArray`.
|
||||
pub fn from_exact_iter<I>(iter: I) -> Option<Self>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
|
@ -388,51 +564,35 @@ where
|
|||
let iter = iter.into_iter();
|
||||
|
||||
if iter.len() == N::to_usize() {
|
||||
unsafe {
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
for (dst, src) in destination.array.iter_mut().zip(iter.into_iter()) {
|
||||
unsafe {
|
||||
{
|
||||
let (destination_iter, position) = destination.iter_position();
|
||||
|
||||
for (dst, src) in destination_iter.zip(iter.into_iter()) {
|
||||
ptr::write(dst, src);
|
||||
|
||||
*position += 1;
|
||||
}
|
||||
}
|
||||
|
||||
destination.position += 1;
|
||||
Some(destination.into_inner())
|
||||
}
|
||||
|
||||
let array = unsafe { ptr::read(&destination.array) };
|
||||
|
||||
mem::forget(destination);
|
||||
|
||||
Some(ManuallyDrop::into_inner(array))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N> ::core::iter::FromIterator<T> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
T: Default,
|
||||
{
|
||||
fn from_iter<I>(iter: I) -> GenericArray<T, N>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut destination = ArrayBuilder::new();
|
||||
|
||||
let defaults = ::core::iter::repeat(()).map(|_| T::default());
|
||||
|
||||
for (dst, src) in destination.array.iter_mut().zip(
|
||||
iter.into_iter().chain(defaults),
|
||||
)
|
||||
{
|
||||
unsafe {
|
||||
ptr::write(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
destination.into_inner()
|
||||
}
|
||||
/// A reimplementation of the `transmute` function, avoiding problems
|
||||
/// when the compiler can't prove equal sizes.
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn transmute<A, B>(a: A) -> B {
|
||||
let b = ::core::ptr::read(&a as *const A as *const B);
|
||||
::core::mem::forget(a);
|
||||
b
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -454,11 +614,17 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_assembly() {
|
||||
use functional::*;
|
||||
|
||||
let a = black_box(arr![i32; 1, 3, 5, 7]);
|
||||
let b = black_box(arr![i32; 2, 4, 6, 8]);
|
||||
|
||||
let c = a.zip_ref(&b, |l, r| l + r);
|
||||
let c = (&a).zip(b, |l, r| l + r);
|
||||
|
||||
let d = a.fold(0, |a, x| a + x);
|
||||
|
||||
assert_eq!(c, arr![i32; 3, 7, 11, 15]);
|
||||
|
||||
assert_eq!(d, 16);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,320 @@
|
|||
//! Useful traits for manipulating sequences of data stored in `GenericArray`s
|
||||
|
||||
use super::*;
|
||||
use core::{mem, ptr};
|
||||
use core::ops::{Add, Sub};
|
||||
use typenum::operator_aliases::*;
|
||||
|
||||
/// Defines some sequence with an associated length and iteration capabilities.
|
||||
///
|
||||
/// This is useful for passing N-length generic arrays as generics.
|
||||
pub unsafe trait GenericSequence<T>: Sized + IntoIterator {
|
||||
/// `GenericArray` associated length
|
||||
type Length: ArrayLength<T>;
|
||||
|
||||
/// Concrete sequence type used in conjuction with reference implementations of `GenericSequence`
|
||||
type Sequence: GenericSequence<T, Length = Self::Length> + FromIterator<T>;
|
||||
|
||||
/// Initializes a new sequence instance using the given function.
|
||||
///
|
||||
/// If the generator function panics while initializing the sequence,
|
||||
/// any already initialized elements will be dropped.
|
||||
fn generate<F>(f: F) -> Self::Sequence
|
||||
where
|
||||
F: FnMut(usize) -> T;
|
||||
|
||||
#[doc(hidden)]
|
||||
fn inverted_zip<B, U, F>(
|
||||
self,
|
||||
lhs: GenericArray<B, Self::Length>,
|
||||
mut f: F,
|
||||
) -> MappedSequence<GenericArray<B, Self::Length>, B, U>
|
||||
where
|
||||
GenericArray<B, Self::Length>: GenericSequence<B, Length = Self::Length>
|
||||
+ MappedGenericSequence<B, U>,
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
||||
F: FnMut(B, Self::Item) -> U,
|
||||
{
|
||||
unsafe {
|
||||
let mut left = ArrayConsumer::new(lhs);
|
||||
|
||||
let (left_array_iter, left_position) = left.iter_position();
|
||||
|
||||
FromIterator::from_iter(
|
||||
left_array_iter
|
||||
.zip(self.into_iter())
|
||||
.map(|(l, right_value)| {
|
||||
let left_value = ptr::read(l);
|
||||
|
||||
*left_position += 1;
|
||||
|
||||
f(left_value, right_value)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
fn inverted_zip2<B, Lhs, U, F>(self, lhs: Lhs, mut f: F) -> MappedSequence<Lhs, B, U>
|
||||
where
|
||||
Lhs: GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
|
||||
Self: MappedGenericSequence<T, U>,
|
||||
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
||||
F: FnMut(Lhs::Item, Self::Item) -> U,
|
||||
{
|
||||
FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Accessor for `GenericSequence` item type, which is really `IntoIterator::Item`
|
||||
///
|
||||
/// For deeply nested generic mapped sequence types, like shown in `tests/generics.rs`,
|
||||
/// this can be useful for keeping things organized.
|
||||
pub type SequenceItem<T> = <T as IntoIterator>::Item;
|
||||
|
||||
unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a S
|
||||
where
|
||||
&'a S: IntoIterator,
|
||||
{
|
||||
type Length = S::Length;
|
||||
type Sequence = S::Sequence;
|
||||
|
||||
#[inline]
|
||||
fn generate<F>(f: F) -> Self::Sequence
|
||||
where
|
||||
F: FnMut(usize) -> T,
|
||||
{
|
||||
S::generate(f)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a mut S
|
||||
where
|
||||
&'a mut S: IntoIterator,
|
||||
{
|
||||
type Length = S::Length;
|
||||
type Sequence = S::Sequence;
|
||||
|
||||
#[inline]
|
||||
fn generate<F>(f: F) -> Self::Sequence
|
||||
where
|
||||
F: FnMut(usize) -> T,
|
||||
{
|
||||
S::generate(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines any `GenericSequence` which can be lengthened or extended by appending
|
||||
/// or prepending an element to it.
|
||||
///
|
||||
/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back`
|
||||
pub unsafe trait Lengthen<T>: Sized + GenericSequence<T> {
|
||||
/// `GenericSequence` that has one more element than `Self`
|
||||
type Longer: Shorten<T, Shorter = Self>;
|
||||
|
||||
/// Returns a new array with the given element appended to the end of it.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let a = arr![i32; 1, 2, 3];
|
||||
///
|
||||
/// let b = a.append(4);
|
||||
///
|
||||
/// assert_eq!(b, arr![i32; 1, 2, 3, 4]);
|
||||
/// ```
|
||||
fn append(self, last: T) -> Self::Longer;
|
||||
|
||||
/// Returns a new array with the given element prepended to the front of it.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let a = arr![i32; 1, 2, 3];
|
||||
///
|
||||
/// let b = a.prepend(4);
|
||||
///
|
||||
/// assert_eq!(b, arr![i32; 4, 1, 2, 3]);
|
||||
/// ```
|
||||
fn prepend(self, first: T) -> Self::Longer;
|
||||
}
|
||||
|
||||
/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it.
|
||||
///
|
||||
/// Additionally, any shortened sequence can be lengthened by
|
||||
/// appending or prepending an element to it.
|
||||
pub unsafe trait Shorten<T>: Sized + GenericSequence<T> {
|
||||
/// `GenericSequence` that has one less element than `Self`
|
||||
type Shorter: Lengthen<T, Longer = Self>;
|
||||
|
||||
/// Returns a new array without the last element, and the last element.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let a = arr![i32; 1, 2, 3, 4];
|
||||
///
|
||||
/// let (init, last) = a.pop_back();
|
||||
///
|
||||
/// assert_eq!(init, arr![i32; 1, 2, 3]);
|
||||
/// assert_eq!(last, 4);
|
||||
/// ```
|
||||
fn pop_back(self) -> (Self::Shorter, T);
|
||||
|
||||
/// Returns a new array without the first element, and the first element.
|
||||
/// Example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let a = arr![i32; 1, 2, 3, 4];
|
||||
///
|
||||
/// let (head, tail) = a.pop_front();
|
||||
///
|
||||
/// assert_eq!(head, 1);
|
||||
/// assert_eq!(tail, arr![i32; 2, 3, 4]);
|
||||
/// ```
|
||||
fn pop_front(self) -> (T, Self::Shorter);
|
||||
}
|
||||
|
||||
unsafe impl<T, N: ArrayLength<T>> Lengthen<T> for GenericArray<T, N>
|
||||
where
|
||||
N: Add<B1>,
|
||||
Add1<N>: ArrayLength<T>,
|
||||
Add1<N>: Sub<B1, Output = N>,
|
||||
Sub1<Add1<N>>: ArrayLength<T>,
|
||||
{
|
||||
type Longer = GenericArray<T, Add1<N>>;
|
||||
|
||||
fn append(self, last: T) -> Self::Longer {
|
||||
let mut longer: Self::Longer = unsafe { mem::uninitialized() };
|
||||
|
||||
unsafe {
|
||||
ptr::write(longer.as_mut_ptr() as *mut _, self);
|
||||
ptr::write(&mut longer[N::to_usize()], last);
|
||||
}
|
||||
|
||||
longer
|
||||
}
|
||||
|
||||
fn prepend(self, first: T) -> Self::Longer {
|
||||
let mut longer: Self::Longer = unsafe { mem::uninitialized() };
|
||||
|
||||
let longer_ptr = longer.as_mut_ptr();
|
||||
|
||||
unsafe {
|
||||
ptr::write(longer_ptr as *mut _, first);
|
||||
ptr::write(longer_ptr.offset(1) as *mut _, self);
|
||||
}
|
||||
|
||||
longer
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T, N: ArrayLength<T>> Shorten<T> for GenericArray<T, N>
|
||||
where
|
||||
N: Sub<B1>,
|
||||
Sub1<N>: ArrayLength<T>,
|
||||
Sub1<N>: Add<B1, Output = N>,
|
||||
Add1<Sub1<N>>: ArrayLength<T>,
|
||||
{
|
||||
type Shorter = GenericArray<T, Sub1<N>>;
|
||||
|
||||
fn pop_back(self) -> (Self::Shorter, T) {
|
||||
let init_ptr = self.as_ptr();
|
||||
let last_ptr = unsafe { init_ptr.offset(Sub1::<N>::to_usize() as isize) };
|
||||
|
||||
let init = unsafe { ptr::read(init_ptr as _) };
|
||||
let last = unsafe { ptr::read(last_ptr as _) };
|
||||
|
||||
mem::forget(self);
|
||||
|
||||
(init, last)
|
||||
}
|
||||
|
||||
fn pop_front(self) -> (T, Self::Shorter) {
|
||||
let head_ptr = self.as_ptr();
|
||||
let tail_ptr = unsafe { head_ptr.offset(1) };
|
||||
|
||||
let head = unsafe { ptr::read(head_ptr as _) };
|
||||
let tail = unsafe { ptr::read(tail_ptr as _) };
|
||||
|
||||
mem::forget(self);
|
||||
|
||||
(head, tail)
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a `GenericSequence` that can be split into two parts at a given pivot index.
|
||||
pub unsafe trait Split<T, K>: GenericSequence<T>
|
||||
where
|
||||
K: ArrayLength<T>,
|
||||
{
|
||||
/// First part of the resulting split array
|
||||
type First: GenericSequence<T>;
|
||||
/// Second part of the resulting split array
|
||||
type Second: GenericSequence<T>;
|
||||
|
||||
/// Splits an array at the given index, returning the separate parts of the array.
|
||||
fn split(self) -> (Self::First, Self::Second);
|
||||
}
|
||||
|
||||
unsafe impl<T, N, K> Split<T, K> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
K: ArrayLength<T>,
|
||||
N: Sub<K>,
|
||||
Diff<N, K>: ArrayLength<T>,
|
||||
{
|
||||
type First = GenericArray<T, K>;
|
||||
type Second = GenericArray<T, Diff<N, K>>;
|
||||
|
||||
fn split(self) -> (Self::First, Self::Second) {
|
||||
let head_ptr = self.as_ptr();
|
||||
let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) };
|
||||
|
||||
let head = unsafe { ptr::read(head_ptr as _) };
|
||||
let tail = unsafe { ptr::read(tail_ptr as _) };
|
||||
|
||||
mem::forget(self);
|
||||
|
||||
(head, tail)
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines `GenericSequence`s which can be joined together, forming a larger array.
|
||||
pub unsafe trait Concat<T, M>: GenericSequence<T>
|
||||
where
|
||||
M: ArrayLength<T>,
|
||||
{
|
||||
/// Sequence to be concatenated with `self`
|
||||
type Rest: GenericSequence<T, Length = M>;
|
||||
|
||||
/// Resulting sequence formed by the concatenation.
|
||||
type Output: GenericSequence<T>;
|
||||
|
||||
/// Concatenate, or join, two sequences.
|
||||
fn concat(self, rest: Self::Rest) -> Self::Output;
|
||||
}
|
||||
|
||||
unsafe impl<T, N, M> Concat<T, M> for GenericArray<T, N>
|
||||
where
|
||||
N: ArrayLength<T> + Add<M>,
|
||||
M: ArrayLength<T>,
|
||||
Sum<N, M>: ArrayLength<T>,
|
||||
{
|
||||
type Rest = GenericArray<T, M>;
|
||||
type Output = GenericArray<T, Sum<N, M>>;
|
||||
|
||||
fn concat(self, rest: Self::Rest) -> Self::Output {
|
||||
let mut output: Self::Output = unsafe { mem::uninitialized() };
|
||||
|
||||
let output_ptr = output.as_mut_ptr();
|
||||
|
||||
unsafe {
|
||||
ptr::write(output_ptr as *mut _, self);
|
||||
ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest);
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#[macro_use]
|
||||
extern crate generic_array;
|
||||
extern crate typenum;
|
||||
|
||||
#[test]
|
||||
fn empty_without_trailing_comma() {
|
||||
let ar = arr![u8; ];
|
||||
assert_eq!(format!("{:x}", ar), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_with_trailing_comma() {
|
||||
let ar = arr![u8; , ];
|
||||
assert_eq!(format!("{:x}", ar), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn without_trailing_comma() {
|
||||
let ar = arr![u8; 10, 20, 30];
|
||||
assert_eq!(format!("{:x}", ar), "0a141e");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_trailing_comma() {
|
||||
let ar = arr![u8; 10, 20, 30, ];
|
||||
assert_eq!(format!("{:x}", ar), "0a141e");
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
#![recursion_limit = "128"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate generic_array;
|
||||
|
||||
use generic_array::typenum::consts::U4;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Add;
|
||||
|
||||
use generic_array::{GenericArray, ArrayLength};
|
||||
use generic_array::sequence::*;
|
||||
use generic_array::functional::*;
|
||||
|
||||
/// Example function using generics to pass N-length sequences and map them
|
||||
pub fn generic_map<S>(s: S)
|
||||
where
|
||||
S: FunctionalSequence<i32>, // `.map`
|
||||
S::Item: Add<i32, Output = i32>, // `x + 1`
|
||||
S: MappedGenericSequence<i32, i32>, // `i32` -> `i32`
|
||||
MappedSequence<S, i32, i32>: Debug, // println!
|
||||
{
|
||||
let a = s.map(|x| x + 1);
|
||||
|
||||
println!("{:?}", a);
|
||||
}
|
||||
|
||||
/// Complex example function using generics to pass N-length sequences, zip them, and then map that result.
|
||||
///
|
||||
/// If used with `GenericArray` specifically this isn't necessary
|
||||
pub fn generic_sequence_zip_sum<A, B>(a: A, b: B) -> i32
|
||||
where
|
||||
A: FunctionalSequence<i32>, // `.zip`
|
||||
B: FunctionalSequence<i32, Length = A::Length>, // `.zip`
|
||||
A: MappedGenericSequence<i32, i32>, // `i32` -> `i32`
|
||||
B: MappedGenericSequence<i32, i32, Mapped = MappedSequence<A, i32, i32>>, // `i32` -> `i32`, prove A and B can map to the same output
|
||||
A::Item: Add<B::Item, Output = i32>, // `l + r`
|
||||
MappedSequence<A, i32, i32>: MappedGenericSequence<i32, i32> + FunctionalSequence<i32>, // `.map`
|
||||
SequenceItem<MappedSequence<A, i32, i32>>: Add<i32, Output=i32>, // `x + 1`
|
||||
MappedSequence<MappedSequence<A, i32, i32>, i32, i32>: Debug, // `println!`
|
||||
MappedSequence<MappedSequence<A, i32, i32>, i32, i32>: FunctionalSequence<i32>, // `.fold`
|
||||
SequenceItem<MappedSequence<MappedSequence<A, i32, i32>, i32, i32>>: Add<i32, Output=i32> // `x + a`, note the order
|
||||
{
|
||||
let c = a.zip(b, |l, r| l + r).map(|x| x + 1);
|
||||
|
||||
println!("{:?}", c);
|
||||
|
||||
c.fold(0, |a, x| x + a)
|
||||
}
|
||||
|
||||
/// Super-simple fixed-length i32 `GenericArray`s
|
||||
pub fn generic_array_plain_zip_sum(a: GenericArray<i32, U4>, b: GenericArray<i32, U4>) -> i32 {
|
||||
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
|
||||
}
|
||||
|
||||
pub fn generic_array_variable_length_zip_sum<N>(a: GenericArray<i32, N>, b: GenericArray<i32, N>) -> i32
|
||||
where
|
||||
N: ArrayLength<i32>,
|
||||
{
|
||||
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
|
||||
}
|
||||
|
||||
pub fn generic_array_same_type_variable_length_zip_sum<T, N>(a: GenericArray<T, N>, b: GenericArray<T, N>) -> i32
|
||||
where
|
||||
N: ArrayLength<T> + ArrayLength<<T as Add<T>>::Output>,
|
||||
T: Add<T, Output=i32>,
|
||||
{
|
||||
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
|
||||
}
|
||||
|
||||
/// Complex example using fully generic `GenericArray`s with the same length.
|
||||
///
|
||||
/// It's mostly just the repeated `Add` traits, which would be present in other systems anyway.
|
||||
pub fn generic_array_zip_sum<A, B, N: ArrayLength<A> + ArrayLength<B>>(a: GenericArray<A, N>, b: GenericArray<B, N>) -> i32
|
||||
where
|
||||
A: Add<B>,
|
||||
N: ArrayLength<<A as Add<B>>::Output> +
|
||||
ArrayLength<<<A as Add<B>>::Output as Add<i32>>::Output>,
|
||||
<A as Add<B>>::Output: Add<i32>,
|
||||
<<A as Add<B>>::Output as Add<i32>>::Output: Add<i32, Output=i32>,
|
||||
{
|
||||
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generics() {
|
||||
generic_map(arr![i32; 1, 2, 3, 4]);
|
||||
|
||||
assert_eq!(generic_sequence_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
|
||||
|
||||
assert_eq!(generic_array_plain_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
|
||||
|
||||
assert_eq!(generic_array_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
|
||||
|
||||
assert_eq!(generic_array_same_type_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
|
||||
|
||||
assert_eq!(generic_array_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
|
||||
}
|
|
@ -6,7 +6,6 @@ use generic_array::GenericArray;
|
|||
use std::str::from_utf8;
|
||||
use typenum::U2048;
|
||||
|
||||
|
||||
#[test]
|
||||
fn short_lower_hex() {
|
||||
let ar = arr![u8; 10, 20, 30];
|
||||
|
@ -25,20 +24,38 @@ fn long_lower_hex() {
|
|||
assert_eq!(format!("{:x}", ar), from_utf8(&[b'0'; 4096]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_lower_hex_truncated() {
|
||||
let ar = GenericArray::<u8, U2048>::default();
|
||||
assert_eq!(format!("{:.3001x}", ar), from_utf8(&[b'0'; 3001]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_upper_hex() {
|
||||
let ar = GenericArray::<u8, U2048>::default();
|
||||
assert_eq!(format!("{:X}", ar), from_utf8(&[b'0'; 4096]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_upper_hex_truncated() {
|
||||
let ar = GenericArray::<u8, U2048>::default();
|
||||
assert_eq!(format!("{:.2777X}", ar), from_utf8(&[b'0'; 2777]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truncated_lower_hex() {
|
||||
let ar = arr![u8; 10, 20, 30, 40, 50];
|
||||
assert_eq!(format!("{:.2x}", ar), "0a14");
|
||||
assert_eq!(format!("{:.2x}", ar), "0a");
|
||||
assert_eq!(format!("{:.3x}", ar), "0a1");
|
||||
assert_eq!(format!("{:.4x}", ar), "0a14");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truncated_upper_hex() {
|
||||
let ar = arr![u8; 30, 20, 10, 17, 0];
|
||||
assert_eq!(format!("{:.4X}", ar), "1E140A11");
|
||||
assert_eq!(format!("{:.4X}", ar), "1E14");
|
||||
assert_eq!(format!("{:.5X}", ar), "1E140");
|
||||
assert_eq!(format!("{:.6X}", ar), "1E140A");
|
||||
assert_eq!(format!("{:.7X}", ar), "1E140A1");
|
||||
assert_eq!(format!("{:.8X}", ar), "1E140A11");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
#[macro_use]
|
||||
extern crate generic_array;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::ops::Drop;
|
||||
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::typenum::consts::U5;
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_as_slice() {
|
||||
let array = arr![char; 'a', 'b', 'c'];
|
||||
let mut into_iter = array.into_iter();
|
||||
assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
|
||||
let _ = into_iter.next().unwrap();
|
||||
assert_eq!(into_iter.as_slice(), &['b', 'c']);
|
||||
let _ = into_iter.next().unwrap();
|
||||
let _ = into_iter.next().unwrap();
|
||||
assert_eq!(into_iter.as_slice(), &[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_as_mut_slice() {
|
||||
let array = arr![char; 'a', 'b', 'c'];
|
||||
let mut into_iter = array.into_iter();
|
||||
assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
|
||||
into_iter.as_mut_slice()[0] = 'x';
|
||||
into_iter.as_mut_slice()[1] = 'y';
|
||||
assert_eq!(into_iter.next().unwrap(), 'x');
|
||||
assert_eq!(into_iter.as_slice(), &['y', 'c']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_debug() {
|
||||
let array = arr![char; 'a', 'b', 'c'];
|
||||
let into_iter = array.into_iter();
|
||||
let debug = format!("{:?}", into_iter);
|
||||
assert_eq!(debug, "GenericArrayIter(['a', 'b', 'c'])");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_clone() {
|
||||
fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
|
||||
let v: Vec<i32> = it.collect();
|
||||
assert_eq!(&v[..], slice);
|
||||
}
|
||||
let mut it = arr![i32; 1, 2, 3].into_iter();
|
||||
iter_equal(it.clone(), &[1, 2, 3]);
|
||||
assert_eq!(it.next(), Some(1));
|
||||
let mut it = it.rev();
|
||||
iter_equal(it.clone(), &[3, 2]);
|
||||
assert_eq!(it.next(), Some(3));
|
||||
iter_equal(it.clone(), &[2]);
|
||||
assert_eq!(it.next(), Some(2));
|
||||
iter_equal(it.clone(), &[]);
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_nth() {
|
||||
let v = arr![i32; 0, 1, 2, 3, 4];
|
||||
for i in 0..v.len() {
|
||||
assert_eq!(v.clone().into_iter().nth(i).unwrap(), v[i]);
|
||||
}
|
||||
assert_eq!(v.clone().into_iter().nth(v.len()), None);
|
||||
|
||||
let mut iter = v.into_iter();
|
||||
assert_eq!(iter.nth(2).unwrap(), v[2]);
|
||||
assert_eq!(iter.nth(1).unwrap(), v[4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_last() {
|
||||
let v = arr![i32; 0, 1, 2, 3, 4];
|
||||
assert_eq!(v.into_iter().last().unwrap(), 4);
|
||||
assert_eq!(arr![i32; 0].into_iter().last().unwrap(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_count() {
|
||||
let v = arr![i32; 0, 1, 2, 3, 4];
|
||||
assert_eq!(v.clone().into_iter().count(), 5);
|
||||
|
||||
let mut iter2 = v.into_iter();
|
||||
iter2.next();
|
||||
iter2.next();
|
||||
assert_eq!(iter2.count(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_flat_map() {
|
||||
assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_drops() {
|
||||
struct R<'a> {
|
||||
i: &'a Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for R<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.i.set(self.i.get() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn r(i: &Cell<usize>) -> R {
|
||||
R {
|
||||
i: i
|
||||
}
|
||||
}
|
||||
|
||||
fn v(i: &Cell<usize>) -> GenericArray<R, U5> {
|
||||
arr![R; r(i), r(i), r(i), r(i), r(i)]
|
||||
}
|
||||
|
||||
let i = Cell::new(0);
|
||||
{
|
||||
v(&i).into_iter();
|
||||
}
|
||||
assert_eq!(i.get(), 5);
|
||||
|
||||
let i = Cell::new(0);
|
||||
{
|
||||
let mut iter = v(&i).into_iter();
|
||||
let _x = iter.next();
|
||||
assert_eq!(i.get(), 0);
|
||||
assert_eq!(iter.count(), 4);
|
||||
assert_eq!(i.get(), 4);
|
||||
}
|
||||
assert_eq!(i.get(), 5);
|
||||
|
||||
let i = Cell::new(0);
|
||||
{
|
||||
let mut iter = v(&i).into_iter();
|
||||
let _x = iter.nth(2);
|
||||
assert_eq!(i.get(), 2);
|
||||
let _y = iter.last();
|
||||
assert_eq!(i.get(), 3);
|
||||
}
|
||||
assert_eq!(i.get(), 5);
|
||||
|
||||
let i = Cell::new(0);
|
||||
for (index, _x) in v(&i).into_iter().enumerate() {
|
||||
assert_eq!(i.get(), index);
|
||||
}
|
||||
assert_eq!(i.get(), 5);
|
||||
|
||||
let i = Cell::new(0);
|
||||
for (index, _x) in v(&i).into_iter().rev().enumerate() {
|
||||
assert_eq!(i.get(), index);
|
||||
}
|
||||
assert_eq!(i.get(), 5);
|
||||
}
|
||||
|
||||
/*
|
||||
//TODO: Cover this
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn into_iter<'new>(i: GenericArrayIter<&'static str, U10>) -> GenericArrayIter<&'new str, U10> {
|
||||
i
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -3,8 +3,10 @@
|
|||
#[macro_use]
|
||||
extern crate generic_array;
|
||||
use core::cell::Cell;
|
||||
use core::ops::Drop;
|
||||
use core::ops::{Add, Drop};
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::functional::*;
|
||||
use generic_array::sequence::*;
|
||||
use generic_array::typenum::{U1, U3, U4, U97};
|
||||
|
||||
#[test]
|
||||
|
@ -33,8 +35,7 @@ fn test_drop() {
|
|||
|
||||
let drop_counter = Cell::new(0);
|
||||
{
|
||||
let _: GenericArray<TestDrop, U3> =
|
||||
arr![TestDrop; TestDrop(&drop_counter),
|
||||
let _: GenericArray<TestDrop, U3> = arr![TestDrop; TestDrop(&drop_counter),
|
||||
TestDrop(&drop_counter),
|
||||
TestDrop(&drop_counter)];
|
||||
}
|
||||
|
@ -56,11 +57,6 @@ fn test_copy() {
|
|||
assert_eq!(test2[0], 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iter_flat_map() {
|
||||
assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct NoClone<T>(T);
|
||||
|
||||
|
@ -154,16 +150,138 @@ fn test_zip() {
|
|||
let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1);
|
||||
let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4);
|
||||
|
||||
let c = a.zip(b, |r, l| r as i32 + l);
|
||||
// Uses reference and non-reference arguments
|
||||
let c = (&a).zip(b, |r, l| *r as i32 + l);
|
||||
|
||||
assert_eq!(c, arr![i32; 1, 6, 11, 16]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
#[should_panic]
|
||||
fn test_from_iter_short() {
|
||||
use core::iter::repeat;
|
||||
|
||||
let a: GenericArray<_, U4> = repeat(11).take(3).collect();
|
||||
|
||||
assert_eq!(a, arr![i32; 11, 11, 11, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
use core::iter::{once, repeat};
|
||||
|
||||
let a: GenericArray<_, U4> = repeat(11).take(3).chain(once(0)).collect();
|
||||
|
||||
assert_eq!(a, arr![i32; 11, 11, 11, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sizes() {
|
||||
#![allow(dead_code)]
|
||||
use core::mem::{size_of, size_of_val};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
#[repr(packed)]
|
||||
struct Test {
|
||||
t: u16,
|
||||
s: u32,
|
||||
r: u16,
|
||||
f: u16,
|
||||
o: u32,
|
||||
}
|
||||
|
||||
assert_eq!(size_of::<Test>(), 14);
|
||||
|
||||
assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::<u8>() * 3);
|
||||
assert_eq!(size_of_val(&arr![u32; 1]), size_of::<u32>() * 1);
|
||||
assert_eq!(size_of_val(&arr![u64; 1, 2, 3, 4]), size_of::<u64>() * 4);
|
||||
|
||||
assert_eq!(size_of::<GenericArray<Test, U97>>(), size_of::<Test>() * 97);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_append() {
|
||||
let a = arr![i32; 1, 2, 3];
|
||||
|
||||
let b = a.append(4);
|
||||
|
||||
assert_eq!(b, arr![i32; 1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prepend() {
|
||||
let a = arr![i32; 1, 2, 3];
|
||||
|
||||
let b = a.prepend(4);
|
||||
|
||||
assert_eq!(b, arr![i32; 4, 1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pop() {
|
||||
let a = arr![i32; 1, 2, 3, 4];
|
||||
|
||||
let (init, last) = a.pop_back();
|
||||
|
||||
assert_eq!(init, arr![i32; 1, 2, 3]);
|
||||
assert_eq!(last, 4);
|
||||
|
||||
let (head, tail) = a.pop_front();
|
||||
|
||||
assert_eq!(head, 1);
|
||||
assert_eq!(tail, arr![i32; 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split() {
|
||||
let a = arr![i32; 1, 2, 3, 4];
|
||||
|
||||
let (b, c) = a.split();
|
||||
|
||||
assert_eq!(b, arr![i32; 1]);
|
||||
assert_eq!(c, arr![i32; 2, 3, 4]);
|
||||
|
||||
let (e, f) = a.split();
|
||||
|
||||
assert_eq!(e, arr![i32; 1, 2]);
|
||||
assert_eq!(f, arr![i32; 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_concat() {
|
||||
let a = arr![i32; 1, 2];
|
||||
let b = arr![i32; 3, 4];
|
||||
|
||||
let c = a.concat(b);
|
||||
|
||||
assert_eq!(c, arr![i32; 1, 2, 3, 4]);
|
||||
|
||||
let (d, e) = c.split();
|
||||
|
||||
assert_eq!(d, arr![i32; 1]);
|
||||
assert_eq!(e, arr![i32; 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold() {
|
||||
let a = arr![i32; 1, 2, 3, 4];
|
||||
|
||||
assert_eq!(10, a.fold(0, |a, x| a + x));
|
||||
}
|
||||
|
||||
fn sum_generic<S>(s: S) -> i32
|
||||
where
|
||||
S: FunctionalSequence<i32>,
|
||||
S::Item: Add<i32, Output = i32>, // `+`
|
||||
i32: Add<S::Item, Output = i32>, // reflexive
|
||||
{
|
||||
s.fold(0, |a, x| a + x)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum() {
|
||||
let a = sum_generic(arr![i32; 1, 2, 3, 4]);
|
||||
|
||||
assert_eq!(a, 10);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"14c835bd1efdb7293220cb4d4ed2d332f2e7512a46e9a185bdb68d66f390fbc2","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/lib.rs":"e4730f0693ba6e8a4e481bea655ede96775f8eb4c0f94f1af740acb2a11240be"},"package":"51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682"}
|
|
@ -0,0 +1,22 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.1"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Macro for opaque Debug trait implementation"
|
||||
documentation = "https://docs.rs/opaque-debug"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/utils"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2017 Artyom Pavlov
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,31 @@
|
|||
//! Macro for opaque `Debug` trait implementation.
|
||||
#![no_std]
|
||||
|
||||
/// Macro for defining opaque `Debug` implementation.
|
||||
///
|
||||
/// It will use the following format: "StructName { ... }". While it's
|
||||
/// convinient to have it (e.g. for including into other structs), it could be
|
||||
/// undesirable to leak internall state, which can happen for example through
|
||||
/// uncareful logging.
|
||||
#[macro_export]
|
||||
macro_rules! impl_opaque_debug {
|
||||
($struct:ty) => {
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Debug for $struct {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter)
|
||||
-> Result<(), ::std::fmt::Error>
|
||||
{
|
||||
write!(f, concat!(stringify!($struct), " {{ ... }}"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl ::core::fmt::Debug for $struct {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter)
|
||||
-> Result<(), ::core::fmt::Error>
|
||||
{
|
||||
write!(f, concat!(stringify!($struct), " {{ ... }}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,45 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "sha2"
|
||||
version = "0.7.1"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "SHA-2 hash functions"
|
||||
documentation = "https://docs.rs/sha2"
|
||||
keywords = ["crypto", "sha2", "hash", "digest"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/hashes"
|
||||
[dependencies.block-buffer]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.byte-tools]
|
||||
version = "0.2"
|
||||
|
||||
[dependencies.digest]
|
||||
version = "0.7"
|
||||
|
||||
[dependencies.fake-simd]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.sha2-asm]
|
||||
version = "0.5"
|
||||
optional = true
|
||||
[dev-dependencies.digest]
|
||||
version = "^0.7.1"
|
||||
features = ["dev"]
|
||||
|
||||
[features]
|
||||
asm = ["sha2-asm"]
|
||||
[badges.travis-ci]
|
||||
repository = "RustCrypto/hashes"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2006-2009 Graydon Hoare
|
||||
Copyright (c) 2009-2013 Mozilla Foundation
|
||||
Copyright (c) 2016 Artyom Pavlov
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
|||
#![no_std]
|
||||
#![feature(test)]
|
||||
#[macro_use]
|
||||
extern crate digest;
|
||||
extern crate sha2;
|
||||
|
||||
bench_digest!(sha2::Sha256);
|
|
@ -0,0 +1,7 @@
|
|||
#![no_std]
|
||||
#![feature(test)]
|
||||
#[macro_use]
|
||||
extern crate digest;
|
||||
extern crate sha2;
|
||||
|
||||
bench_digest!(sha2::Sha512);
|
|
@ -0,0 +1,49 @@
|
|||
extern crate sha2;
|
||||
|
||||
use sha2::{Sha256, Digest};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
|
||||
const BUFFER_SIZE: usize = 1024;
|
||||
|
||||
/// Print digest result as hex string and name pair
|
||||
fn print_result(sum: &[u8], name: &str) {
|
||||
for byte in sum {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!("\t{}", name);
|
||||
}
|
||||
|
||||
/// Compute digest value for given `Reader` and print it
|
||||
/// On any error simply return without doing anything
|
||||
fn process<D: Digest + Default, R: Read>(reader: &mut R, name: &str) {
|
||||
let mut sh = D::default();
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
loop {
|
||||
let n = match reader.read(&mut buffer) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return,
|
||||
};
|
||||
sh.input(&buffer[..n]);
|
||||
if n == 0 || n < BUFFER_SIZE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
print_result(&sh.result(), name);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
// Process files listed in command line arguments one by one
|
||||
// If no files provided process input from stdin
|
||||
if args.len() > 1 {
|
||||
for path in args.skip(1) {
|
||||
if let Ok(mut file) = fs::File::open(&path) {
|
||||
process::<Sha256, _>(&mut file, &path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process::<Sha256, _>(&mut io::stdin(), "-");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
extern crate sha2;
|
||||
|
||||
use sha2::{Sha512, Digest};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
|
||||
const BUFFER_SIZE: usize = 1024;
|
||||
|
||||
/// Print digest result as hex string and name pair
|
||||
fn print_result(sum: &[u8], name: &str) {
|
||||
for byte in sum {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!("\t{}", name);
|
||||
}
|
||||
|
||||
/// Compute digest value for given `Reader` and print it
|
||||
/// On any error simply return without doing anything
|
||||
fn process<D: Digest + Default, R: Read>(reader: &mut R, name: &str) {
|
||||
let mut sh = D::default();
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
loop {
|
||||
let n = match reader.read(&mut buffer) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return,
|
||||
};
|
||||
sh.input(&buffer[..n]);
|
||||
if n == 0 || n < BUFFER_SIZE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
print_result(&sh.result(), name);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
// Process files listed in command line arguments one by one
|
||||
// If no files provided process input from stdin
|
||||
if args.len() > 1 {
|
||||
for path in args.skip(1) {
|
||||
if let Ok(mut file) = fs::File::open(&path) {
|
||||
process::<Sha512, _>(&mut file, &path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process::<Sha512, _>(&mut io::stdin(), "-");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
#![allow(dead_code)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
|
||||
|
||||
use simd::u64x2;
|
||||
use simd::u32x4;
|
||||
|
||||
pub const STATE_LEN: usize = 8;
|
||||
pub const BLOCK_LEN: usize = 16;
|
||||
|
||||
/// Constants necessary for SHA-256 family of digests.
|
||||
pub const K32: [u32; 64] =
|
||||
[0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
|
||||
|
||||
/// Constants necessary for SHA-256 family of digests.
|
||||
pub const K32X4: [u32x4; 16] = [u32x4(K32[3], K32[2], K32[1], K32[0]),
|
||||
u32x4(K32[7], K32[6], K32[5], K32[4]),
|
||||
u32x4(K32[11], K32[10], K32[9], K32[8]),
|
||||
u32x4(K32[15], K32[14], K32[13], K32[12]),
|
||||
u32x4(K32[19], K32[18], K32[17], K32[16]),
|
||||
u32x4(K32[23], K32[22], K32[21], K32[20]),
|
||||
u32x4(K32[27], K32[26], K32[25], K32[24]),
|
||||
u32x4(K32[31], K32[30], K32[29], K32[28]),
|
||||
u32x4(K32[35], K32[34], K32[33], K32[32]),
|
||||
u32x4(K32[39], K32[38], K32[37], K32[36]),
|
||||
u32x4(K32[43], K32[42], K32[41], K32[40]),
|
||||
u32x4(K32[47], K32[46], K32[45], K32[44]),
|
||||
u32x4(K32[51], K32[50], K32[49], K32[48]),
|
||||
u32x4(K32[55], K32[54], K32[53], K32[52]),
|
||||
u32x4(K32[59], K32[58], K32[57], K32[56]),
|
||||
u32x4(K32[63], K32[62], K32[61], K32[60])];
|
||||
|
||||
/// Constants necessary for SHA-512 family of digests.
|
||||
pub const K64: [u64; 80] = [0x428a2f98d728ae22,
|
||||
0x7137449123ef65cd,
|
||||
0xb5c0fbcfec4d3b2f,
|
||||
0xe9b5dba58189dbbc,
|
||||
0x3956c25bf348b538,
|
||||
0x59f111f1b605d019,
|
||||
0x923f82a4af194f9b,
|
||||
0xab1c5ed5da6d8118,
|
||||
0xd807aa98a3030242,
|
||||
0x12835b0145706fbe,
|
||||
0x243185be4ee4b28c,
|
||||
0x550c7dc3d5ffb4e2,
|
||||
0x72be5d74f27b896f,
|
||||
0x80deb1fe3b1696b1,
|
||||
0x9bdc06a725c71235,
|
||||
0xc19bf174cf692694,
|
||||
0xe49b69c19ef14ad2,
|
||||
0xefbe4786384f25e3,
|
||||
0x0fc19dc68b8cd5b5,
|
||||
0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275,
|
||||
0x4a7484aa6ea6e483,
|
||||
0x5cb0a9dcbd41fbd4,
|
||||
0x76f988da831153b5,
|
||||
0x983e5152ee66dfab,
|
||||
0xa831c66d2db43210,
|
||||
0xb00327c898fb213f,
|
||||
0xbf597fc7beef0ee4,
|
||||
0xc6e00bf33da88fc2,
|
||||
0xd5a79147930aa725,
|
||||
0x06ca6351e003826f,
|
||||
0x142929670a0e6e70,
|
||||
0x27b70a8546d22ffc,
|
||||
0x2e1b21385c26c926,
|
||||
0x4d2c6dfc5ac42aed,
|
||||
0x53380d139d95b3df,
|
||||
0x650a73548baf63de,
|
||||
0x766a0abb3c77b2a8,
|
||||
0x81c2c92e47edaee6,
|
||||
0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364,
|
||||
0xa81a664bbc423001,
|
||||
0xc24b8b70d0f89791,
|
||||
0xc76c51a30654be30,
|
||||
0xd192e819d6ef5218,
|
||||
0xd69906245565a910,
|
||||
0xf40e35855771202a,
|
||||
0x106aa07032bbd1b8,
|
||||
0x19a4c116b8d2d0c8,
|
||||
0x1e376c085141ab53,
|
||||
0x2748774cdf8eeb99,
|
||||
0x34b0bcb5e19b48a8,
|
||||
0x391c0cb3c5c95a63,
|
||||
0x4ed8aa4ae3418acb,
|
||||
0x5b9cca4f7763e373,
|
||||
0x682e6ff3d6b2b8a3,
|
||||
0x748f82ee5defb2fc,
|
||||
0x78a5636f43172f60,
|
||||
0x84c87814a1f0ab72,
|
||||
0x8cc702081a6439ec,
|
||||
0x90befffa23631e28,
|
||||
0xa4506cebde82bde9,
|
||||
0xbef9a3f7b2c67915,
|
||||
0xc67178f2e372532b,
|
||||
0xca273eceea26619c,
|
||||
0xd186b8c721c0c207,
|
||||
0xeada7dd6cde0eb1e,
|
||||
0xf57d4f7fee6ed178,
|
||||
0x06f067aa72176fba,
|
||||
0x0a637dc5a2c898a6,
|
||||
0x113f9804bef90dae,
|
||||
0x1b710b35131c471b,
|
||||
0x28db77f523047d84,
|
||||
0x32caab7b40c72493,
|
||||
0x3c9ebe0a15c9bebc,
|
||||
0x431d67c49c100d4c,
|
||||
0x4cc5d4becb3e42b6,
|
||||
0x597f299cfc657e2a,
|
||||
0x5fcb6fab3ad6faec,
|
||||
0x6c44198c4a475817];
|
||||
|
||||
/// Constants necessary for SHA-512 family of digests.
|
||||
pub const K64X2: [u64x2; 40] = [u64x2(K64[1], K64[0]),
|
||||
u64x2(K64[3], K64[2]),
|
||||
u64x2(K64[5], K64[4]),
|
||||
u64x2(K64[7], K64[6]),
|
||||
u64x2(K64[9], K64[8]),
|
||||
u64x2(K64[11], K64[10]),
|
||||
u64x2(K64[13], K64[12]),
|
||||
u64x2(K64[15], K64[14]),
|
||||
u64x2(K64[17], K64[16]),
|
||||
u64x2(K64[19], K64[18]),
|
||||
u64x2(K64[21], K64[20]),
|
||||
u64x2(K64[23], K64[22]),
|
||||
u64x2(K64[25], K64[24]),
|
||||
u64x2(K64[27], K64[26]),
|
||||
u64x2(K64[29], K64[28]),
|
||||
u64x2(K64[31], K64[30]),
|
||||
u64x2(K64[33], K64[32]),
|
||||
u64x2(K64[35], K64[34]),
|
||||
u64x2(K64[37], K64[36]),
|
||||
u64x2(K64[39], K64[38]),
|
||||
u64x2(K64[41], K64[40]),
|
||||
u64x2(K64[43], K64[42]),
|
||||
u64x2(K64[45], K64[44]),
|
||||
u64x2(K64[47], K64[46]),
|
||||
u64x2(K64[49], K64[48]),
|
||||
u64x2(K64[51], K64[50]),
|
||||
u64x2(K64[53], K64[52]),
|
||||
u64x2(K64[55], K64[54]),
|
||||
u64x2(K64[57], K64[56]),
|
||||
u64x2(K64[59], K64[58]),
|
||||
u64x2(K64[61], K64[60]),
|
||||
u64x2(K64[63], K64[62]),
|
||||
u64x2(K64[65], K64[64]),
|
||||
u64x2(K64[67], K64[66]),
|
||||
u64x2(K64[69], K64[68]),
|
||||
u64x2(K64[71], K64[70]),
|
||||
u64x2(K64[73], K64[72]),
|
||||
u64x2(K64[75], K64[74]),
|
||||
u64x2(K64[77], K64[76]),
|
||||
u64x2(K64[79], K64[78])];
|
||||
|
||||
pub static H224: [u32; STATE_LEN] = [0xc1059ed8, 0x367cd507, 0x3070dd17,
|
||||
0xf70e5939, 0xffc00b31, 0x68581511,
|
||||
0x64f98fa7, 0xbefa4fa4];
|
||||
|
||||
pub static H256: [u32; STATE_LEN] = [0x6a09e667, 0xbb67ae85, 0x3c6ef372,
|
||||
0xa54ff53a, 0x510e527f, 0x9b05688c,
|
||||
0x1f83d9ab, 0x5be0cd19];
|
||||
|
||||
pub static H384: [u64; STATE_LEN] = [0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
|
||||
0x9159015a3070dd17, 0x152fecd8f70e5939,
|
||||
0x67332667ffc00b31, 0x8eb44a8768581511,
|
||||
0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4];
|
||||
|
||||
pub static H512: [u64; STATE_LEN] = [0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
|
||||
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179];
|
||||
|
||||
pub static H512_TRUNC_224: [u64; STATE_LEN] = [0x8c3d37c819544da2,
|
||||
0x73e1996689dcd4d6,
|
||||
0x1dfab7ae32ff9c82,
|
||||
0x679dd514582f9fcf,
|
||||
0x0f6d2b697bd44da8,
|
||||
0x77e36f7304c48942,
|
||||
0x3f9d85a86a1d36c8,
|
||||
0x1112e6ad91d692a1];
|
||||
|
||||
pub static H512_TRUNC_256: [u64; STATE_LEN] = [0x22312194fc2bf72c,
|
||||
0x9f555fa3c84c64c2,
|
||||
0x2393b86b6f53b151,
|
||||
0x963877195940eabd,
|
||||
0x96283ee2a88effe3,
|
||||
0xbe5e1e2553863992,
|
||||
0x2b0199fc2c85b8aa,
|
||||
0x0eb72ddc81c52ca2];
|
|
@ -0,0 +1,85 @@
|
|||
//! An implementation of the SHA-2 cryptographic hash algorithms.
|
||||
//!
|
||||
//! There are 6 standard algorithms specified in the SHA-2 standard:
|
||||
//!
|
||||
//! * `Sha224`, which is the 32-bit `Sha256` algorithm with the result truncated
|
||||
//! to 224 bits.
|
||||
//! * `Sha256`, which is the 32-bit `Sha256` algorithm.
|
||||
//! * `Sha384`, which is the 64-bit `Sha512` algorithm with the result truncated
|
||||
//! to 384 bits.
|
||||
//! * `Sha512`, which is the 64-bit `Sha512` algorithm.
|
||||
//! * `Sha512Trunc224`, which is the 64-bit `Sha512` algorithm with the result
|
||||
//! truncated to 224 bits.
|
||||
//! * `Sha512Trunc256`, which is the 64-bit `Sha512` algorithm with the result
|
||||
//! truncated to 256 bits.
|
||||
//!
|
||||
//! Algorithmically, there are only 2 core algorithms: `Sha256` and `Sha512`.
|
||||
//! All other algorithms are just applications of these with different initial
|
||||
//! hash values, and truncated to different digest bit lengths.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! An example of using `Sha256` is:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use sha2::{Sha256, Digest};
|
||||
//!
|
||||
//! // create a Sha256 object
|
||||
//! let mut hasher = Sha256::default();
|
||||
//!
|
||||
//! // write input message
|
||||
//! hasher.input(b"hello world");
|
||||
//!
|
||||
//! // read hash digest and consume hasher
|
||||
//! let output = hasher.result();
|
||||
//!
|
||||
//! assert_eq!(output[..], [0xb9, 0x4d, 0x27, 0xb9, 0x93, 0x4d, 0x3e, 0x08,
|
||||
//! 0xa5, 0x2e, 0x52, 0xd7, 0xda, 0x7d, 0xab, 0xfa,
|
||||
//! 0xc4, 0x84, 0xef, 0xe3, 0x7a, 0x53, 0x80, 0xee,
|
||||
//! 0x90, 0x88, 0xf7, 0xac, 0xe2, 0xef, 0xcd, 0xe9]);
|
||||
//! ```
|
||||
//!
|
||||
//! An example of using `Sha512` is:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use sha2::{Sha512, Digest};
|
||||
//!
|
||||
//! // create a Sha512 object
|
||||
//! let mut hasher = Sha512::default();
|
||||
//!
|
||||
//! // write input message
|
||||
//! hasher.input(b"hello world");
|
||||
//!
|
||||
//! // read hash digest and consume hasher
|
||||
//! let output = hasher.result();
|
||||
//!
|
||||
//! assert_eq!(output[..], [0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb,
|
||||
//! 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02, 0xf2, 0xb4,
|
||||
//! 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a,
|
||||
//! 0x9b, 0xcd, 0x3c, 0xa8, 0x6d, 0x4c, 0xd8, 0x6f,
|
||||
//! 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96,
|
||||
//! 0x70, 0xda, 0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf,
|
||||
//! 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
|
||||
//! 0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f][..]);
|
||||
//! ```
|
||||
|
||||
#![no_std]
|
||||
extern crate byte_tools;
|
||||
#[macro_use]
|
||||
extern crate digest;
|
||||
extern crate block_buffer;
|
||||
extern crate fake_simd as simd;
|
||||
#[cfg(feature = "asm")]
|
||||
extern crate sha2_asm;
|
||||
|
||||
mod consts;
|
||||
#[cfg(not(feature = "asm"))]
|
||||
mod sha256_utils;
|
||||
#[cfg(not(feature = "asm"))]
|
||||
mod sha512_utils;
|
||||
mod sha256;
|
||||
mod sha512;
|
||||
|
||||
pub use digest::Digest;
|
||||
pub use sha256::{Sha256, Sha224};
|
||||
pub use sha512::{Sha512, Sha384, Sha512Trunc224, Sha512Trunc256};
|
|
@ -0,0 +1,127 @@
|
|||
use digest;
|
||||
use digest::generic_array::GenericArray;
|
||||
use digest::generic_array::typenum::{U28, U32, U64};
|
||||
use block_buffer::BlockBuffer512;
|
||||
use byte_tools::write_u32v_be;
|
||||
|
||||
use consts::{STATE_LEN, H224, H256};
|
||||
|
||||
#[cfg(not(feature = "asm"))]
|
||||
use sha256_utils::compress256;
|
||||
#[cfg(feature = "asm")]
|
||||
use sha2_asm::compress256;
|
||||
|
||||
type BlockSize = U64;
|
||||
pub type Block = [u8; 64];
|
||||
|
||||
/// A structure that represents that state of a digest computation for the
|
||||
/// SHA-2 512 family of digest functions
|
||||
#[derive(Clone)]
|
||||
struct Engine256State {
|
||||
h: [u32; 8],
|
||||
}
|
||||
|
||||
impl Engine256State {
|
||||
fn new(h: &[u32; STATE_LEN]) -> Engine256State { Engine256State { h: *h } }
|
||||
|
||||
pub fn process_block(&mut self, data: &Block) {
|
||||
compress256(&mut self.h, data);
|
||||
}
|
||||
}
|
||||
|
||||
/// A structure that keeps track of the state of the Sha-256 operation and
|
||||
/// contains the logic necessary to perform the final calculations.
|
||||
#[derive(Clone)]
|
||||
struct Engine256 {
|
||||
len: u64,
|
||||
buffer: BlockBuffer512,
|
||||
state: Engine256State,
|
||||
}
|
||||
|
||||
impl Engine256 {
|
||||
fn new(h: &[u32; STATE_LEN]) -> Engine256 {
|
||||
Engine256 {
|
||||
len: 0,
|
||||
buffer: Default::default(),
|
||||
state: Engine256State::new(h),
|
||||
}
|
||||
}
|
||||
|
||||
fn input(&mut self, input: &[u8]) {
|
||||
// Assumes that input.len() can be converted to u64 without overflow
|
||||
self.len += (input.len() as u64) << 3;
|
||||
let self_state = &mut self.state;
|
||||
self.buffer.input(input, |input| self_state.process_block(input));
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
let self_state = &mut self.state;
|
||||
let l = self.len;
|
||||
// TODO: replace with `len_padding_be` method
|
||||
let l = if cfg!(target_endian = "little") { l.to_be() } else { l.to_le() };
|
||||
self.buffer.len_padding(l, |input| self_state.process_block(input));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The SHA-256 hash algorithm with the SHA-256 initial hash value.
|
||||
#[derive(Clone)]
|
||||
pub struct Sha256 {
|
||||
engine: Engine256,
|
||||
}
|
||||
|
||||
impl Default for Sha256 {
|
||||
fn default() -> Self { Sha256 { engine: Engine256::new(&H256) } }
|
||||
}
|
||||
|
||||
impl digest::BlockInput for Sha256 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
impl digest::Input for Sha256 {
|
||||
fn process(&mut self, msg: &[u8]) { self.engine.input(msg); }
|
||||
}
|
||||
|
||||
impl digest::FixedOutput for Sha256 {
|
||||
type OutputSize = U32;
|
||||
|
||||
fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
|
||||
self.engine.finish();
|
||||
let mut out = GenericArray::default();
|
||||
write_u32v_be(out.as_mut_slice(), &self.engine.state.h);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA-256 hash algorithm with the SHA-224 initial hash value. The result
|
||||
/// is truncated to 224 bits.
|
||||
#[derive(Clone)]
|
||||
pub struct Sha224 {
|
||||
engine: Engine256,
|
||||
}
|
||||
|
||||
impl Default for Sha224 {
|
||||
fn default() -> Self { Sha224 { engine: Engine256::new(&H224) } }
|
||||
}
|
||||
|
||||
impl digest::BlockInput for Sha224 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
impl digest::Input for Sha224 {
|
||||
fn process(&mut self, msg: &[u8]) { self.engine.input(msg); }
|
||||
}
|
||||
|
||||
impl digest::FixedOutput for Sha224 {
|
||||
type OutputSize = U28;
|
||||
|
||||
fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
|
||||
self.engine.finish();
|
||||
let mut out = GenericArray::default();
|
||||
write_u32v_be(out.as_mut_slice(), &self.engine.state.h[..7]);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
impl_opaque_debug!(Sha224);
|
||||
impl_opaque_debug!(Sha256);
|
|
@ -0,0 +1,267 @@
|
|||
#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))]
|
||||
|
||||
use simd::u32x4;
|
||||
use consts::{BLOCK_LEN, K32X4};
|
||||
use byte_tools::{read_u32v_be};
|
||||
use sha256::Block;
|
||||
|
||||
/// Not an intrinsic, but works like an unaligned load.
|
||||
#[inline]
|
||||
fn sha256load(v2: u32x4, v3: u32x4) -> u32x4 {
|
||||
u32x4(v3.3, v2.0, v2.1, v2.2)
|
||||
}
|
||||
|
||||
/// Not an intrinsic, but useful for swapping vectors.
|
||||
#[inline]
|
||||
fn sha256swap(v0: u32x4) -> u32x4 {
|
||||
u32x4(v0.2, v0.3, v0.0, v0.1)
|
||||
}
|
||||
|
||||
/// Emulates `llvm.x86.sha256msg1` intrinsic.
|
||||
// #[inline]
|
||||
fn sha256msg1(v0: u32x4, v1: u32x4) -> u32x4 {
|
||||
|
||||
// sigma 0 on vectors
|
||||
#[inline]
|
||||
fn sigma0x4(x: u32x4) -> u32x4 {
|
||||
((x >> u32x4( 7, 7, 7, 7)) | (x << u32x4(25, 25, 25, 25))) ^
|
||||
((x >> u32x4(18, 18, 18, 18)) | (x << u32x4(14, 14, 14, 14))) ^
|
||||
(x >> u32x4( 3, 3, 3, 3))
|
||||
}
|
||||
|
||||
v0 + sigma0x4(sha256load(v0, v1))
|
||||
}
|
||||
|
||||
/// Emulates `llvm.x86.sha256msg2` intrinsic.
|
||||
// #[inline]
|
||||
fn sha256msg2(v4: u32x4, v3: u32x4) -> u32x4 {
|
||||
|
||||
macro_rules! sigma1 {
|
||||
($a:expr) => ($a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10))
|
||||
}
|
||||
|
||||
let u32x4(x3, x2, x1, x0) = v4;
|
||||
let u32x4(w15, w14, _, _) = v3;
|
||||
|
||||
let w16 = x0.wrapping_add(sigma1!(w14));
|
||||
let w17 = x1.wrapping_add(sigma1!(w15));
|
||||
let w18 = x2.wrapping_add(sigma1!(w16));
|
||||
let w19 = x3.wrapping_add(sigma1!(w17));
|
||||
|
||||
u32x4(w19, w18, w17, w16)
|
||||
}
|
||||
|
||||
/*
|
||||
/// Performs 4 rounds of the SHA-256 message schedule update.
|
||||
fn sha256_schedule_x4(v0: u32x4, v1: u32x4, v2: u32x4, v3: u32x4) -> u32x4 {
|
||||
sha256msg2(sha256msg1(v0, v1) + sha256load(v2, v3), v3)
|
||||
}*/
|
||||
|
||||
/// Emulates `llvm.x86.sha256rnds2` intrinsic.
|
||||
// #[inline]
|
||||
fn sha256_digest_round_x2(cdgh: u32x4, abef: u32x4, wk: u32x4) -> u32x4 {
|
||||
|
||||
macro_rules! big_sigma0 {
|
||||
($a:expr) => (($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22)))
|
||||
}
|
||||
macro_rules! big_sigma1 {
|
||||
($a:expr) => (($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25)))
|
||||
}
|
||||
macro_rules! bool3ary_202 {
|
||||
($a:expr, $b:expr, $c:expr) => ($c ^ ($a & ($b ^ $c)))
|
||||
} // Choose, MD5F, SHA1C
|
||||
macro_rules! bool3ary_232 {
|
||||
($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
|
||||
} // Majority, SHA1M
|
||||
|
||||
let u32x4(_, _, wk1, wk0) = wk;
|
||||
let u32x4(a0, b0, e0, f0) = abef;
|
||||
let u32x4(c0, d0, g0, h0) = cdgh;
|
||||
|
||||
// a round
|
||||
let x0 = big_sigma1!(e0)
|
||||
.wrapping_add(bool3ary_202!(e0, f0, g0))
|
||||
.wrapping_add(wk0)
|
||||
.wrapping_add(h0);
|
||||
let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
|
||||
let (a1, b1, c1, d1, e1, f1, g1, h1) =
|
||||
(x0.wrapping_add(y0), a0, b0, c0, x0.wrapping_add(d0), e0, f0, g0);
|
||||
|
||||
// a round
|
||||
let x1 = big_sigma1!(e1)
|
||||
.wrapping_add(bool3ary_202!(e1, f1, g1))
|
||||
.wrapping_add(wk1)
|
||||
.wrapping_add(h1);
|
||||
let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1));
|
||||
let (a2, b2, _, _, e2, f2, _, _) =
|
||||
(x1.wrapping_add(y1), a1, b1, c1, x1.wrapping_add(d1), e1, f1, g1);
|
||||
|
||||
u32x4(a2, b2, e2, f2)
|
||||
}
|
||||
|
||||
/// Process a block with the SHA-256 algorithm.
|
||||
fn sha256_digest_block_u32(state: &mut [u32; 8], block: &[u32; 16]) {
|
||||
let k = &K32X4;
|
||||
|
||||
macro_rules! schedule {
|
||||
($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
|
||||
sha256msg2(sha256msg1($v0, $v1) + sha256load($v2, $v3), $v3)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! rounds4 {
|
||||
($abef:ident, $cdgh:ident, $rest:expr) => {
|
||||
{
|
||||
$cdgh = sha256_digest_round_x2($cdgh, $abef, $rest);
|
||||
$abef = sha256_digest_round_x2($abef, $cdgh, sha256swap($rest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut abef = u32x4(state[0], state[1], state[4], state[5]);
|
||||
let mut cdgh = u32x4(state[2], state[3], state[6], state[7]);
|
||||
|
||||
// Rounds 0..64
|
||||
let mut w0 = u32x4(block[3], block[2], block[1], block[0]);
|
||||
rounds4!(abef, cdgh, k[0] + w0);
|
||||
let mut w1 = u32x4(block[7], block[6], block[5], block[4]);
|
||||
rounds4!(abef, cdgh, k[1] + w1);
|
||||
let mut w2 = u32x4(block[11], block[10], block[9], block[8]);
|
||||
rounds4!(abef, cdgh, k[2] + w2);
|
||||
let mut w3 = u32x4(block[15], block[14], block[13], block[12]);
|
||||
rounds4!(abef, cdgh, k[3] + w3);
|
||||
let mut w4 = schedule!(w0, w1, w2, w3);
|
||||
rounds4!(abef, cdgh, k[4] + w4);
|
||||
w0 = schedule!(w1, w2, w3, w4);
|
||||
rounds4!(abef, cdgh, k[5] + w0);
|
||||
w1 = schedule!(w2, w3, w4, w0);
|
||||
rounds4!(abef, cdgh, k[6] + w1);
|
||||
w2 = schedule!(w3, w4, w0, w1);
|
||||
rounds4!(abef, cdgh, k[7] + w2);
|
||||
w3 = schedule!(w4, w0, w1, w2);
|
||||
rounds4!(abef, cdgh, k[8] + w3);
|
||||
w4 = schedule!(w0, w1, w2, w3);
|
||||
rounds4!(abef, cdgh, k[9] + w4);
|
||||
w0 = schedule!(w1, w2, w3, w4);
|
||||
rounds4!(abef, cdgh, k[10] + w0);
|
||||
w1 = schedule!(w2, w3, w4, w0);
|
||||
rounds4!(abef, cdgh, k[11] + w1);
|
||||
w2 = schedule!(w3, w4, w0, w1);
|
||||
rounds4!(abef, cdgh, k[12] + w2);
|
||||
w3 = schedule!(w4, w0, w1, w2);
|
||||
rounds4!(abef, cdgh, k[13] + w3);
|
||||
w4 = schedule!(w0, w1, w2, w3);
|
||||
rounds4!(abef, cdgh, k[14] + w4);
|
||||
w0 = schedule!(w1, w2, w3, w4);
|
||||
rounds4!(abef, cdgh, k[15] + w0);
|
||||
|
||||
let u32x4(a, b, e, f) = abef;
|
||||
let u32x4(c, d, g, h) = cdgh;
|
||||
|
||||
state[0] = state[0].wrapping_add(a);
|
||||
state[1] = state[1].wrapping_add(b);
|
||||
state[2] = state[2].wrapping_add(c);
|
||||
state[3] = state[3].wrapping_add(d);
|
||||
state[4] = state[4].wrapping_add(e);
|
||||
state[5] = state[5].wrapping_add(f);
|
||||
state[6] = state[6].wrapping_add(g);
|
||||
state[7] = state[7].wrapping_add(h);
|
||||
}
|
||||
|
||||
/// Process a block with the SHA-256 algorithm. (See more...)
|
||||
///
|
||||
/// Internally, this uses functions which resemble the new Intel SHA instruction
|
||||
/// sets, and so it's data locality properties may improve performance. However,
|
||||
/// to benefit the most from this implementation, replace these functions with
|
||||
/// x86 intrinsics to get a possible speed boost.
|
||||
///
|
||||
/// # Implementation
|
||||
///
|
||||
/// The `Sha256` algorithm is implemented with functions that resemble the new
|
||||
/// Intel SHA instruction set extensions. These intructions fall into two
|
||||
/// categories: message schedule calculation, and the message block 64-round
|
||||
/// digest calculation. The schedule-related instructions allow 4 rounds to be
|
||||
/// calculated as:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use std::simd::u32x4;
|
||||
/// use self::crypto::sha2::{
|
||||
/// sha256msg1,
|
||||
/// sha256msg2,
|
||||
/// sha256load
|
||||
/// };
|
||||
///
|
||||
/// fn schedule4_data(work: &mut [u32x4], w: &[u32]) {
|
||||
///
|
||||
/// // this is to illustrate the data order
|
||||
/// work[0] = u32x4(w[3], w[2], w[1], w[0]);
|
||||
/// work[1] = u32x4(w[7], w[6], w[5], w[4]);
|
||||
/// work[2] = u32x4(w[11], w[10], w[9], w[8]);
|
||||
/// work[3] = u32x4(w[15], w[14], w[13], w[12]);
|
||||
/// }
|
||||
///
|
||||
/// fn schedule4_work(work: &mut [u32x4], t: usize) {
|
||||
///
|
||||
/// // this is the core expression
|
||||
/// work[t] = sha256msg2(sha256msg1(work[t - 4], work[t - 3]) +
|
||||
/// sha256load(work[t - 2], work[t - 1]),
|
||||
/// work[t - 1])
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// instead of 4 rounds of:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn schedule_work(w: &mut [u32], t: usize) {
|
||||
/// w[t] = sigma1!(w[t - 2]) + w[t - 7] + sigma0!(w[t - 15]) + w[t - 16];
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// and the digest-related instructions allow 4 rounds to be calculated as:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use std::simd::u32x4;
|
||||
/// use self::crypto::sha2::{K32X4,
|
||||
/// sha256rnds2,
|
||||
/// sha256swap
|
||||
/// };
|
||||
///
|
||||
/// fn rounds4(state: &mut [u32; 8], work: &mut [u32x4], t: usize) {
|
||||
/// let [a, b, c, d, e, f, g, h]: [u32; 8] = *state;
|
||||
///
|
||||
/// // this is to illustrate the data order
|
||||
/// let mut abef = u32x4(a, b, e, f);
|
||||
/// let mut cdgh = u32x4(c, d, g, h);
|
||||
/// let temp = K32X4[t] + work[t];
|
||||
///
|
||||
/// // this is the core expression
|
||||
/// cdgh = sha256rnds2(cdgh, abef, temp);
|
||||
/// abef = sha256rnds2(abef, cdgh, sha256swap(temp));
|
||||
///
|
||||
/// *state = [abef.0, abef.1, cdgh.0, cdgh.1,
|
||||
/// abef.2, abef.3, cdgh.2, cdgh.3];
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// instead of 4 rounds of:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn round(state: &mut [u32; 8], w: &mut [u32], t: usize) {
|
||||
/// let [a, b, c, mut d, e, f, g, mut h]: [u32; 8] = *state;
|
||||
///
|
||||
/// h += big_sigma1!(e) + choose!(e, f, g) + K32[t] + w[t]; d += h;
|
||||
/// h += big_sigma0!(a) + majority!(a, b, c);
|
||||
///
|
||||
/// *state = [h, a, b, c, d, e, f, g];
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// **NOTE**: It is important to note, however, that these instructions are not
|
||||
/// implemented by any CPU (at the time of this writing), and so they are
|
||||
/// emulated in this library until the instructions become more common, and gain
|
||||
/// support in LLVM (and GCC, etc.).
|
||||
pub fn compress256(state: &mut [u32; 8], block: &Block) {
|
||||
let mut block_u32 = [0u32; BLOCK_LEN];
|
||||
read_u32v_be(&mut block_u32[..], block);
|
||||
sha256_digest_block_u32(state, &block_u32);
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
use digest;
|
||||
use digest::generic_array::GenericArray;
|
||||
use digest::generic_array::typenum::{U28, U32, U48, U64, U128};
|
||||
use block_buffer::BlockBuffer1024;
|
||||
use byte_tools::{write_u64v_be, write_u32_be};
|
||||
|
||||
use consts::{STATE_LEN, H384, H512, H512_TRUNC_224, H512_TRUNC_256};
|
||||
|
||||
#[cfg(not(feature = "asm"))]
|
||||
use sha512_utils::compress512;
|
||||
#[cfg(feature = "asm")]
|
||||
use sha2_asm::compress512;
|
||||
|
||||
type BlockSize = U128;
|
||||
pub type Block = [u8; 128];
|
||||
|
||||
/// A structure that represents that state of a digest computation for the
|
||||
/// SHA-2 512 family of digest functions
|
||||
#[derive(Clone)]
|
||||
struct Engine512State {
|
||||
h: [u64; 8],
|
||||
}
|
||||
|
||||
impl Engine512State {
|
||||
fn new(h: &[u64; 8]) -> Engine512State { Engine512State { h: *h } }
|
||||
|
||||
pub fn process_block(&mut self, data: &Block) {
|
||||
compress512(&mut self.h, data);
|
||||
}
|
||||
}
|
||||
|
||||
/// A structure that keeps track of the state of the Sha-512 operation and
|
||||
/// contains the logic necessary to perform the final calculations.
|
||||
#[derive(Clone)]
|
||||
struct Engine512 {
|
||||
len: (u64, u64), // TODO: replace with u128 on stabilization
|
||||
buffer: BlockBuffer1024,
|
||||
state: Engine512State,
|
||||
}
|
||||
|
||||
impl Engine512 {
|
||||
fn new(h: &[u64; STATE_LEN]) -> Engine512 {
|
||||
Engine512 {
|
||||
len: (0, 0),
|
||||
buffer: Default::default(),
|
||||
state: Engine512State::new(h),
|
||||
}
|
||||
}
|
||||
|
||||
fn input(&mut self, input: &[u8]) {
|
||||
let (res, over) = self.len.1.overflowing_add((input.len() as u64) << 3);
|
||||
self.len.1 = res;
|
||||
if over { self.len.0 += 1; }
|
||||
let self_state = &mut self.state;
|
||||
self.buffer.input(input, |d| self_state.process_block(d));
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
let self_state = &mut self.state;
|
||||
let (mut hi, mut lo) = self.len;
|
||||
// TODO: change `len_padding_u128` to use BE
|
||||
if cfg!(target_endian = "little") {
|
||||
hi = hi.to_be();
|
||||
lo = lo.to_be();
|
||||
} else {
|
||||
hi = hi.to_le();
|
||||
lo = lo.to_le();
|
||||
};
|
||||
self.buffer.len_padding_u128(hi, lo, |d| self_state.process_block(d));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The SHA-512 hash algorithm with the SHA-512 initial hash value.
|
||||
#[derive(Clone)]
|
||||
pub struct Sha512 {
|
||||
engine: Engine512,
|
||||
}
|
||||
|
||||
impl Default for Sha512 {
|
||||
fn default() -> Self { Sha512 { engine: Engine512::new(&H512) } }
|
||||
}
|
||||
|
||||
impl digest::BlockInput for Sha512 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
impl digest::Input for Sha512 {
|
||||
fn process(&mut self, msg: &[u8]) { self.engine.input(msg); }
|
||||
}
|
||||
|
||||
impl digest::FixedOutput for Sha512 {
|
||||
type OutputSize = U64;
|
||||
|
||||
fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
|
||||
self.engine.finish();
|
||||
|
||||
let mut out = GenericArray::default();
|
||||
write_u64v_be(out.as_mut_slice(), &self.engine.state.h[..]);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// The SHA-512 hash algorithm with the SHA-384 initial hash value. The result
|
||||
/// is truncated to 384 bits.
|
||||
#[derive(Clone)]
|
||||
pub struct Sha384 {
|
||||
engine: Engine512,
|
||||
}
|
||||
|
||||
impl Default for Sha384 {
|
||||
fn default() -> Self { Sha384 { engine: Engine512::new(&H384) } }
|
||||
}
|
||||
|
||||
impl digest::BlockInput for Sha384 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
impl digest::Input for Sha384 {
|
||||
fn process(&mut self, msg: &[u8]) { self.engine.input(msg); }
|
||||
}
|
||||
|
||||
impl digest::FixedOutput for Sha384 {
|
||||
type OutputSize = U48;
|
||||
|
||||
fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
|
||||
self.engine.finish();
|
||||
|
||||
let mut out = GenericArray::default();
|
||||
write_u64v_be(out.as_mut_slice(), &self.engine.state.h[..6]);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// The SHA-512 hash algorithm with the SHA-512/256 initial hash value. The
|
||||
/// result is truncated to 256 bits.
|
||||
#[derive(Clone)]
|
||||
pub struct Sha512Trunc256 {
|
||||
engine: Engine512,
|
||||
}
|
||||
|
||||
impl Default for Sha512Trunc256 {
|
||||
fn default() -> Self {
|
||||
Sha512Trunc256 { engine: Engine512::new(&H512_TRUNC_256) }
|
||||
}
|
||||
}
|
||||
|
||||
impl digest::BlockInput for Sha512Trunc256 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
impl digest::Input for Sha512Trunc256 {
|
||||
fn process(&mut self, msg: &[u8]) { self.engine.input(msg); }
|
||||
}
|
||||
|
||||
impl digest::FixedOutput for Sha512Trunc256 {
|
||||
type OutputSize = U32;
|
||||
|
||||
fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
|
||||
self.engine.finish();
|
||||
|
||||
let mut out = GenericArray::default();
|
||||
write_u64v_be(out.as_mut_slice(), &self.engine.state.h[..4]);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA-512 hash algorithm with the SHA-512/224 initial hash value.
|
||||
/// The result is truncated to 224 bits.
|
||||
#[derive(Clone)]
|
||||
pub struct Sha512Trunc224 {
|
||||
engine: Engine512,
|
||||
}
|
||||
|
||||
impl Default for Sha512Trunc224 {
|
||||
fn default() -> Self {
|
||||
Sha512Trunc224 { engine: Engine512::new(&H512_TRUNC_224) }
|
||||
}
|
||||
}
|
||||
|
||||
impl digest::BlockInput for Sha512Trunc224 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
impl digest::Input for Sha512Trunc224 {
|
||||
fn process(&mut self, msg: &[u8]) { self.engine.input(msg); }
|
||||
}
|
||||
|
||||
impl digest::FixedOutput for Sha512Trunc224 {
|
||||
type OutputSize = U28;
|
||||
|
||||
fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
|
||||
self.engine.finish();
|
||||
|
||||
let mut out = GenericArray::default();
|
||||
write_u64v_be(&mut out[..24], &self.engine.state.h[..3]);
|
||||
write_u32_be(&mut out[24..28], (self.engine.state.h[3] >> 32) as u32);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
impl_opaque_debug!(Sha384);
|
||||
impl_opaque_debug!(Sha512);
|
||||
impl_opaque_debug!(Sha512Trunc224);
|
||||
impl_opaque_debug!(Sha512Trunc256);
|
|
@ -0,0 +1,287 @@
|
|||
#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))]
|
||||
|
||||
use simd::u64x2;
|
||||
use consts::{BLOCK_LEN, K64X2};
|
||||
use byte_tools::{read_u64v_be};
|
||||
use sha512::Block;
|
||||
|
||||
/// Not an intrinsic, but works like an unaligned load.
|
||||
#[inline]
|
||||
fn sha512load(v0: u64x2, v1: u64x2) -> u64x2 {
|
||||
u64x2(v1.1, v0.0)
|
||||
}
|
||||
|
||||
/// Performs 2 rounds of the SHA-512 message schedule update.
|
||||
pub fn sha512_schedule_x2(v0: u64x2, v1: u64x2, v4to5: u64x2, v7: u64x2)
|
||||
-> u64x2 {
|
||||
|
||||
// sigma 0
|
||||
fn sigma0(x: u64) -> u64 {
|
||||
((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7)
|
||||
}
|
||||
|
||||
// sigma 1
|
||||
fn sigma1(x: u64) -> u64 {
|
||||
((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6)
|
||||
}
|
||||
|
||||
let u64x2(w1, w0) = v0;
|
||||
let u64x2(_, w2) = v1;
|
||||
let u64x2(w10, w9) = v4to5;
|
||||
let u64x2(w15, w14) = v7;
|
||||
|
||||
let w16 =
|
||||
sigma1(w14).wrapping_add(w9).wrapping_add(sigma0(w1)).wrapping_add(w0);
|
||||
let w17 =
|
||||
sigma1(w15).wrapping_add(w10).wrapping_add(sigma0(w2)).wrapping_add(w1);
|
||||
|
||||
u64x2(w17, w16)
|
||||
}
|
||||
|
||||
/// Performs one round of the SHA-512 message block digest.
|
||||
pub fn sha512_digest_round(ae: u64x2, bf: u64x2, cg: u64x2, dh: u64x2,
|
||||
wk0: u64)
|
||||
-> u64x2 {
|
||||
|
||||
macro_rules! big_sigma0 {
|
||||
($a:expr) => (($a.rotate_right(28) ^ $a.rotate_right(34) ^ $a.rotate_right(39)))
|
||||
}
|
||||
macro_rules! big_sigma1 {
|
||||
($a:expr) => (($a.rotate_right(14) ^ $a.rotate_right(18) ^ $a.rotate_right(41)))
|
||||
}
|
||||
macro_rules! bool3ary_202 {
|
||||
($a:expr, $b:expr, $c:expr) => ($c ^ ($a & ($b ^ $c)))
|
||||
} // Choose, MD5F, SHA1C
|
||||
macro_rules! bool3ary_232 {
|
||||
($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
|
||||
} // Majority, SHA1M
|
||||
|
||||
let u64x2(a0, e0) = ae;
|
||||
let u64x2(b0, f0) = bf;
|
||||
let u64x2(c0, g0) = cg;
|
||||
let u64x2(d0, h0) = dh;
|
||||
|
||||
// a round
|
||||
let x0 = big_sigma1!(e0)
|
||||
.wrapping_add(bool3ary_202!(e0, f0, g0))
|
||||
.wrapping_add(wk0)
|
||||
.wrapping_add(h0);
|
||||
let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
|
||||
let (a1, _, _, _, e1, _, _, _) =
|
||||
(x0.wrapping_add(y0), a0, b0, c0, x0.wrapping_add(d0), e0, f0, g0);
|
||||
|
||||
u64x2(a1, e1)
|
||||
}
|
||||
|
||||
/// Process a block with the SHA-512 algorithm.
|
||||
pub fn sha512_digest_block_u64(state: &mut [u64; 8], block: &[u64; 16]) {
|
||||
let k = &K64X2;
|
||||
|
||||
macro_rules! schedule {
|
||||
($v0:expr, $v1:expr, $v4:expr, $v5:expr, $v7:expr) => (
|
||||
sha512_schedule_x2($v0, $v1, sha512load($v4, $v5), $v7)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! rounds4 {
|
||||
($ae:ident, $bf:ident, $cg:ident, $dh:ident, $wk0:expr, $wk1:expr) => {
|
||||
{
|
||||
let u64x2(u, t) = $wk0;
|
||||
let u64x2(w, v) = $wk1;
|
||||
|
||||
$dh = sha512_digest_round($ae, $bf, $cg, $dh, t);
|
||||
$cg = sha512_digest_round($dh, $ae, $bf, $cg, u);
|
||||
$bf = sha512_digest_round($cg, $dh, $ae, $bf, v);
|
||||
$ae = sha512_digest_round($bf, $cg, $dh, $ae, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut ae = u64x2(state[0], state[4]);
|
||||
let mut bf = u64x2(state[1], state[5]);
|
||||
let mut cg = u64x2(state[2], state[6]);
|
||||
let mut dh = u64x2(state[3], state[7]);
|
||||
|
||||
// Rounds 0..20
|
||||
let (mut w1, mut w0) = (u64x2(block[3], block[2]),
|
||||
u64x2(block[1], block[0]));
|
||||
rounds4!(ae, bf, cg, dh, k[0] + w0, k[1] + w1);
|
||||
let (mut w3, mut w2) = (u64x2(block[7], block[6]),
|
||||
u64x2(block[5], block[4]));
|
||||
rounds4!(ae, bf, cg, dh, k[2] + w2, k[3] + w3);
|
||||
let (mut w5, mut w4) = (u64x2(block[11], block[10]),
|
||||
u64x2(block[9], block[8]));
|
||||
rounds4!(ae, bf, cg, dh, k[4] + w4, k[5] + w5);
|
||||
let (mut w7, mut w6) = (u64x2(block[15], block[14]),
|
||||
u64x2(block[13], block[12]));
|
||||
rounds4!(ae, bf, cg, dh, k[6] + w6, k[7] + w7);
|
||||
let mut w8 = schedule!(w0, w1, w4, w5, w7);
|
||||
let mut w9 = schedule!(w1, w2, w5, w6, w8);
|
||||
rounds4!(ae, bf, cg, dh, k[8] + w8, k[9] + w9);
|
||||
|
||||
// Rounds 20..40
|
||||
w0 = schedule!(w2, w3, w6, w7, w9);
|
||||
w1 = schedule!(w3, w4, w7, w8, w0);
|
||||
rounds4!(ae, bf, cg, dh, k[10] + w0, k[11] + w1);
|
||||
w2 = schedule!(w4, w5, w8, w9, w1);
|
||||
w3 = schedule!(w5, w6, w9, w0, w2);
|
||||
rounds4!(ae, bf, cg, dh, k[12] + w2, k[13] + w3);
|
||||
w4 = schedule!(w6, w7, w0, w1, w3);
|
||||
w5 = schedule!(w7, w8, w1, w2, w4);
|
||||
rounds4!(ae, bf, cg, dh, k[14] + w4, k[15] + w5);
|
||||
w6 = schedule!(w8, w9, w2, w3, w5);
|
||||
w7 = schedule!(w9, w0, w3, w4, w6);
|
||||
rounds4!(ae, bf, cg, dh, k[16] + w6, k[17] + w7);
|
||||
w8 = schedule!(w0, w1, w4, w5, w7);
|
||||
w9 = schedule!(w1, w2, w5, w6, w8);
|
||||
rounds4!(ae, bf, cg, dh, k[18] + w8, k[19] + w9);
|
||||
|
||||
// Rounds 40..60
|
||||
w0 = schedule!(w2, w3, w6, w7, w9);
|
||||
w1 = schedule!(w3, w4, w7, w8, w0);
|
||||
rounds4!(ae, bf, cg, dh, k[20] + w0, k[21] + w1);
|
||||
w2 = schedule!(w4, w5, w8, w9, w1);
|
||||
w3 = schedule!(w5, w6, w9, w0, w2);
|
||||
rounds4!(ae, bf, cg, dh, k[22] + w2, k[23] + w3);
|
||||
w4 = schedule!(w6, w7, w0, w1, w3);
|
||||
w5 = schedule!(w7, w8, w1, w2, w4);
|
||||
rounds4!(ae, bf, cg, dh, k[24] + w4, k[25] + w5);
|
||||
w6 = schedule!(w8, w9, w2, w3, w5);
|
||||
w7 = schedule!(w9, w0, w3, w4, w6);
|
||||
rounds4!(ae, bf, cg, dh, k[26] + w6, k[27] + w7);
|
||||
w8 = schedule!(w0, w1, w4, w5, w7);
|
||||
w9 = schedule!(w1, w2, w5, w6, w8);
|
||||
rounds4!(ae, bf, cg, dh, k[28] + w8, k[29] + w9);
|
||||
|
||||
// Rounds 60..80
|
||||
w0 = schedule!(w2, w3, w6, w7, w9);
|
||||
w1 = schedule!(w3, w4, w7, w8, w0);
|
||||
rounds4!(ae, bf, cg, dh, k[30] + w0, k[31] + w1);
|
||||
w2 = schedule!(w4, w5, w8, w9, w1);
|
||||
w3 = schedule!(w5, w6, w9, w0, w2);
|
||||
rounds4!(ae, bf, cg, dh, k[32] + w2, k[33] + w3);
|
||||
w4 = schedule!(w6, w7, w0, w1, w3);
|
||||
w5 = schedule!(w7, w8, w1, w2, w4);
|
||||
rounds4!(ae, bf, cg, dh, k[34] + w4, k[35] + w5);
|
||||
w6 = schedule!(w8, w9, w2, w3, w5);
|
||||
w7 = schedule!(w9, w0, w3, w4, w6);
|
||||
rounds4!(ae, bf, cg, dh, k[36] + w6, k[37] + w7);
|
||||
w8 = schedule!(w0, w1, w4, w5, w7);
|
||||
w9 = schedule!(w1, w2, w5, w6, w8);
|
||||
rounds4!(ae, bf, cg, dh, k[38] + w8, k[39] + w9);
|
||||
|
||||
let u64x2(a, e) = ae;
|
||||
let u64x2(b, f) = bf;
|
||||
let u64x2(c, g) = cg;
|
||||
let u64x2(d, h) = dh;
|
||||
|
||||
state[0] = state[0].wrapping_add(a);
|
||||
state[1] = state[1].wrapping_add(b);
|
||||
state[2] = state[2].wrapping_add(c);
|
||||
state[3] = state[3].wrapping_add(d);
|
||||
state[4] = state[4].wrapping_add(e);
|
||||
state[5] = state[5].wrapping_add(f);
|
||||
state[6] = state[6].wrapping_add(g);
|
||||
state[7] = state[7].wrapping_add(h);
|
||||
}
|
||||
|
||||
/// Process a block with the SHA-512 algorithm. (See more...)
|
||||
///
|
||||
/// Internally, this uses functions that resemble the new Intel SHA
|
||||
/// instruction set extensions, but since no architecture seems to
|
||||
/// have any designs, these may not be the final designs if and/or when
|
||||
/// there are instruction set extensions with SHA-512. So to summarize:
|
||||
/// SHA-1 and SHA-256 are being implemented in hardware soon (at the time
|
||||
/// of this writing), but it doesn't look like SHA-512 will be hardware
|
||||
/// accelerated any time soon.
|
||||
///
|
||||
/// # Implementation
|
||||
///
|
||||
/// These functions fall into two categories: message schedule calculation, and
|
||||
/// the message block 64-round digest calculation. The schedule-related
|
||||
/// functions allow 4 rounds to be calculated as:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use std::simd::u64x2;
|
||||
/// use self::crypto::sha2::{
|
||||
/// sha512msg,
|
||||
/// sha512load
|
||||
/// };
|
||||
///
|
||||
/// fn schedule4_data(work: &mut [u64x2], w: &[u64]) {
|
||||
///
|
||||
/// // this is to illustrate the data order
|
||||
/// work[0] = u64x2(w[1], w[0]);
|
||||
/// work[1] = u64x2(w[3], w[2]);
|
||||
/// work[2] = u64x2(w[5], w[4]);
|
||||
/// work[3] = u64x2(w[7], w[6]);
|
||||
/// work[4] = u64x2(w[9], w[8]);
|
||||
/// work[5] = u64x2(w[11], w[10]);
|
||||
/// work[6] = u64x2(w[13], w[12]);
|
||||
/// work[7] = u64x2(w[15], w[14]);
|
||||
/// }
|
||||
///
|
||||
/// fn schedule4_work(work: &mut [u64x2], t: usize) {
|
||||
///
|
||||
/// // this is the core expression
|
||||
/// work[t] = sha512msg(work[t - 8],
|
||||
/// work[t - 7],
|
||||
/// sha512load(work[t - 4], work[t - 3]),
|
||||
/// work[t - 1]);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// instead of 4 rounds of:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn schedule_work(w: &mut [u64], t: usize) {
|
||||
/// w[t] = sigma1!(w[t - 2]) + w[t - 7] + sigma0!(w[t - 15]) + w[t - 16];
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// and the digest-related functions allow 4 rounds to be calculated as:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use std::simd::u64x2;
|
||||
/// use self::crypto::sha2::{K64X2, sha512rnd};
|
||||
///
|
||||
/// fn rounds4(state: &mut [u64; 8], work: &mut [u64x2], t: usize) {
|
||||
/// let [a, b, c, d, e, f, g, h]: [u64; 8] = *state;
|
||||
///
|
||||
/// // this is to illustrate the data order
|
||||
/// let mut ae = u64x2(a, e);
|
||||
/// let mut bf = u64x2(b, f);
|
||||
/// let mut cg = u64x2(c, g);
|
||||
/// let mut dh = u64x2(d, h);
|
||||
/// let u64x2(w1, w0) = K64X2[2*t] + work[2*t];
|
||||
/// let u64x2(w3, w2) = K64X2[2*t + 1] + work[2*t + 1];
|
||||
///
|
||||
/// // this is the core expression
|
||||
/// dh = sha512rnd(ae, bf, cg, dh, w0);
|
||||
/// cg = sha512rnd(dh, ae, bf, cg, w1);
|
||||
/// bf = sha512rnd(cg, dh, ae, bf, w2);
|
||||
/// ae = sha512rnd(bf, cg, dh, ae, w3);
|
||||
///
|
||||
/// *state = [ae.0, bf.0, cg.0, dh.0,
|
||||
/// ae.1, bf.1, cg.1, dh.1];
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// instead of 4 rounds of:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn round(state: &mut [u64; 8], w: &mut [u64], t: usize) {
|
||||
/// let [a, b, c, mut d, e, f, g, mut h]: [u64; 8] = *state;
|
||||
///
|
||||
/// h += big_sigma1!(e) + choose!(e, f, g) + K64[t] + w[t]; d += h;
|
||||
/// h += big_sigma0!(a) + majority!(a, b, c);
|
||||
///
|
||||
/// *state = [h, a, b, c, d, e, f, g];
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn compress512(state: &mut [u64; 8], block: &Block) {
|
||||
let mut block_u64 = [0u64; BLOCK_LEN];
|
||||
read_u64v_be(&mut block_u64[..], block);
|
||||
sha512_digest_block_u64(state, &block_u64);
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче