[rust] Add rust-tuf dependencies

This is necessary to support building rust-tuf with GN, implemented
in https://fuchsia-review.googlesource.com/c/garnet/+/239484. The
dependencies are:

* data-encoding 2.1.2
* derp 0.0.11
* ring 0.13.5
* untrusted 0.6.2

This was approved by OSRB-109.

OSRB-109 #comment import the crates
PKG-404 #comment add rust-tuf dependencies

Change-Id: I4fd4b972d0e1ef6ce2eb5a227442f37af39d316b
diff --git a/rustc_deps/Cargo.lock b/rustc_deps/Cargo.lock
index 2f9b5f7..88de16a 100644
--- a/rustc_deps/Cargo.lock
+++ b/rustc_deps/Cargo.lock
@@ -347,6 +347,11 @@
 ]
 
 [[package]]
+name = "data-encoding"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "deflate"
 version = "0.7.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -357,6 +362,14 @@
 ]
 
 [[package]]
+name = "derp"
+version = "0.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "difference"
 version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -464,6 +477,8 @@
  "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "crossbeam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derp 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "font-rs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -472,11 +487,14 @@
  "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.12.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -492,6 +510,7 @@
  "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "rouille 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rust-crypto 0.2.36",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -511,6 +530,7 @@
  "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "valico 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1367,6 +1387,17 @@
 ]
 
 [[package]]
+name = "ring"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "rouille"
 version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1827,6 +1858,11 @@
 ]
 
 [[package]]
+name = "untrusted"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "url"
 version = "1.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2057,7 +2093,9 @@
 "checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8"
 "checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c"
 "checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a"
+"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97"
 "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86"
+"checksum derp 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8e686cf031aae7161f6169912b1b38049b128dff51a94789f26d54a067634bb1"
 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
@@ -2162,6 +2200,7 @@
 "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
 "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
 "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
+"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
 "checksum rouille 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0845b9c39ba772da769fe2aaa4d81bfd10695a7ea051d0510702260ff4159841"
 "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
@@ -2218,6 +2257,7 @@
 "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
 "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
+"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
 "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
 "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
 "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
diff --git a/rustc_deps/Cargo.toml b/rustc_deps/Cargo.toml
index ebcdf3c..188b944 100644
--- a/rustc_deps/Cargo.toml
+++ b/rustc_deps/Cargo.toml
@@ -19,6 +19,8 @@
 chrono = "0.4.2"
 clap = "2.29"
 crossbeam = "0.5"
+data-encoding = "2.1.2"
+derp = "0.0.11"
 euclid = "0.19"
 failure = "0.1.1"
 font-rs = "0.1.3"
@@ -27,11 +29,14 @@
 getopts = "0.2"
 heck = "0.3.1"
 hex = "0.3.2"
+http = "0.1"
 hyper = { version = "0.12.13", default-features = false }
 itertools = "0.7"
+itoa = "0.4"
 lazy_static = "1"
 libc = "0.2"
 log = { version = "0.4.4", features = ["std"] }
+maplit = "1.0"
 memchr = "2.0"
 net2 = "0.2"
 nom = "3.2"
@@ -44,6 +49,7 @@
 pest_derive = "2.1"
 proptest = "0.8.7"
 rand = "0.5"
+ring = { version = "0.13", features = [ "rsa_signing" ] }
 regex = "1.0.6"
 rouille = "2.1.0"
 rust-crypto = "0.2"
@@ -63,6 +69,7 @@
 unicode-normalization = "0.1"
 unicode-segmentation = "1.0"
 unicode-width = "0.1.3"
+untrusted = "0.6.2"
 utf8parse = "0.1"
 url = "1.7.0"
 valico = "2.3.1"
diff --git a/rustc_deps/vendor/data-encoding/.cargo-checksum.json b/rustc_deps/vendor/data-encoding/.cargo-checksum.json
new file mode 100644
index 0000000..e95f1c9
--- /dev/null
+++ b/rustc_deps/vendor/data-encoding/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"5e27ea783f56eb9aec94534ac72b49daf47b46afca4ad80514f2ac8f20f34e8f","LICENSE":"d9ae65b8784809f801d67a1805ba55e5c911978aae6173c85f4ce9bccfaa7373","README.md":"d7b8beca949688c8065bb17343ce6c629e95c802d8be05282587ba3ea189f87c","src/lib.rs":"95b08422ec57bb11549c47e67cadc82b52d6752fcff0e42f511d51cb78890ffe"},"package":"f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97"}
\ No newline at end of file
diff --git a/rustc_deps/vendor/data-encoding/Cargo.toml b/rustc_deps/vendor/data-encoding/Cargo.toml
new file mode 100644
index 0000000..cf08fa1
--- /dev/null
+++ b/rustc_deps/vendor/data-encoding/Cargo.toml
@@ -0,0 +1,42 @@
+# 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]
+edition = "2018"
+name = "data-encoding"
+version = "2.1.2"
+authors = ["Julien Cretin <git@ia0.eu>"]
+include = ["Cargo.toml", "LICENSE", "README.md", "src/lib.rs"]
+description = "Efficient and customizable data-encoding functions"
+documentation = "https://docs.rs/data-encoding"
+readme = "README.md"
+keywords = ["base-conversion", "encoding", "base64", "base32", "hex"]
+categories = ["encoding"]
+license = "MIT"
+repository = "https://github.com/ia0/data-encoding"
+[badges.appveyor]
+repository = "ia0/data-encoding"
+
+[badges.coveralls]
+repository = "ia0/data-encoding"
+
+[badges.is-it-maintained-issue-resolution]
+repository = "ia0/data-encoding"
+
+[badges.is-it-maintained-open-issues]
+repository = "ia0/data-encoding"
+
+[badges.maintenance]
+status = "passively-maintained"
+
+[badges.travis-ci]
+repository = "ia0/data-encoding"
diff --git a/rustc_deps/vendor/data-encoding/LICENSE b/rustc_deps/vendor/data-encoding/LICENSE
new file mode 100644
index 0000000..8e376eb
--- /dev/null
+++ b/rustc_deps/vendor/data-encoding/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2017 Julien Cretin
+Copyright (c) 2017 Google Inc.
+
+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.
diff --git a/rustc_deps/vendor/data-encoding/README.md b/rustc_deps/vendor/data-encoding/README.md
new file mode 100644
index 0000000..6786797
--- /dev/null
+++ b/rustc_deps/vendor/data-encoding/README.md
@@ -0,0 +1,101 @@
+## Common use-cases
+
+This library provides the following common encodings:
+
+- `HEXLOWER`: lowercase hexadecimal
+- `HEXLOWER_PERMISSIVE`: lowercase hexadecimal with case-insensitive decoding
+- `HEXUPPER`: uppercase hexadecimal
+- `HEXUPPER_PERMISSIVE`: uppercase hexadecimal with case-insensitive decoding
+- `BASE32`: RFC4648 base32
+- `BASE32_NOPAD`: RFC4648 base32 without padding
+- `BASE32_DNSSEC`: RFC5155 base32
+- `BASE32_DNSCURVE`: DNSCurve base32
+- `BASE32HEX`: RFC4648 base32hex
+- `BASE32HEX_NOPAD`: RFC4648 base32hex without padding
+- `BASE64`: RFC4648 base64
+- `BASE64_NOPAD`: RFC4648 base64 without padding
+- `BASE64_MIME`: RFC2045-like base64
+- `BASE64URL`: RFC4648 base64url
+- `BASE64URL_NOPAD`: RFC4648 base64url without padding
+
+Typical usage looks like:
+
+```rust
+// allocating functions
+BASE64.encode(&input_to_encode)
+HEXLOWER.decode(&input_to_decode)
+// in-place functions
+BASE32.encode_mut(&input_to_encode, &mut encoded_output)
+BASE64_URL.decode_mut(&input_to_decode, &mut decoded_output)
+```
+
+See the [documentation] or the [changelog] for more details.
+
+## Custom use-cases
+
+This library also provides the possibility to define custom little-endian ASCII
+base-conversion encodings for bases of size 2, 4, 8, 16, 32, and 64 (for which
+all above use-cases are particular instances). It supports:
+
+- padded and unpadded encodings
+- canonical encodings (e.g. trailing bits are checked)
+- in-place encoding and decoding functions
+- partial decoding functions (e.g. for error recovery)
+- character translation (e.g. for case-insensitivity)
+- most and least significant bit-order
+- ignoring characters when decoding (e.g. for skipping newlines)
+- wrapping the output when encoding
+
+The typical definition of a custom encoding looks like:
+
+```rust
+lazy_static! {
+    static ref HEX: Encoding = {
+        let mut spec = Specification::new();
+        spec.symbols.push_str("0123456789abcdef");
+        spec.translate.from.push_str("ABCDEF");
+        spec.translate.to.push_str("abcdef");
+        spec.encoding().unwrap()
+    };
+    static ref BASE64: Encoding = {
+        let mut spec = Specification::new();
+        spec.symbols.push_str(
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+        spec.padding = Some('=');
+        spec.encoding().unwrap()
+    };
+}
+```
+
+You may also use the [macro] library to define a compile-time custom encoding:
+
+```rust
+const HEX: Encoding = new_encoding!{
+    symbols: "0123456789abcdef",
+    translate_from: "ABCDEF",
+    translate_to: "abcdef",
+};
+const BASE64: Encoding = new_encoding!{
+    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+    padding: '=',
+};
+```
+
+See the [documentation] or the [changelog] for more details.
+
+## Performance
+
+The performance of the encoding and decoding functions (for both common and
+custom encodings) are similar to existing implementations in C, Rust, and other
+high-performance languages (see how to run the benchmarks on [github]).
+
+## Swiss-knife binary
+
+This crate is a library. If you are looking for the [binary] using this library,
+see the installation instructions on [github].
+
+[binary]: https://crates.io/crates/data-encoding-bin
+[changelog]: https://github.com/ia0/data-encoding/blob/master/lib/CHANGELOG.md
+[documentation]: https://docs.rs/data-encoding
+[github]: https://github.com/ia0/data-encoding
+[macro]: https://crates.io/crates/data-encoding-macro
diff --git a/rustc_deps/vendor/data-encoding/src/lib.rs b/rustc_deps/vendor/data-encoding/src/lib.rs
new file mode 100644
index 0000000..350f7b7
--- /dev/null
+++ b/rustc_deps/vendor/data-encoding/src/lib.rs
@@ -0,0 +1,2307 @@
+//! Efficient and customizable data-encoding functions
+//!
+//! This [crate] provides little-endian ASCII base-conversion encodings for
+//! bases of size 2, 4, 8, 16, 32, and 64. It supports:
+//!
+//! - padded and unpadded encodings
+//! - canonical encodings (e.g. trailing bits are checked)
+//! - in-place encoding and decoding functions
+//! - partial decoding functions (e.g. for error recovery)
+//! - character translation (e.g. for case-insensitivity)
+//! - most and least significant bit-order
+//! - ignoring characters when decoding (e.g. for skipping newlines)
+//! - wrapping the output when encoding
+//!
+//! The performance of the encoding and decoding functions are similar to
+//! existing implementations (see how to run the benchmarks on [github]).
+//!
+//! This is the library documentation. If you are looking for the [binary], see
+//! the installation instructions on [github].
+//!
+//! # Examples
+//!
+//! This crate provides predefined encodings as [constants]. These constants are
+//! of type [`Encoding`]. This type provides encoding and decoding functions
+//! with in-place or allocating variants. Here is an example using the
+//! allocating encoding function of [base64]:
+//!
+//! ```rust
+//! use data_encoding::BASE64;
+//! assert_eq!(BASE64.encode(b"Hello world"), "SGVsbG8gd29ybGQ=");
+//! ```
+//!
+//! Here is an example using the in-place decoding function of [base32]:
+//!
+//! ```rust
+//! use data_encoding::BASE32;
+//! let input = b"JBSWY3DPEB3W64TMMQ======";
+//! let mut output = vec![0; BASE32.decode_len(input.len()).unwrap()];
+//! let len = BASE32.decode_mut(input, &mut output).unwrap();
+//! assert_eq!(&output[0 .. len], b"Hello world");
+//! ```
+//!
+//! You are not limited to the predefined encodings. You may define your own
+//! encodings (with the same correctness and performance properties as the
+//! predefined ones) using the [`Specification`] type:
+//!
+//! ```rust
+//! use data_encoding::Specification;
+//! let hex = {
+//!     let mut spec = Specification::new();
+//!     spec.symbols.push_str("0123456789abcdef");
+//!     spec.encoding().unwrap()
+//! };
+//! assert_eq!(hex.encode(b"hello"), "68656c6c6f");
+//! ```
+//!
+//! If you use the [`lazy_static`] crate, you can define a global encoding:
+//!
+//! ```rust,ignore
+//! lazy_static! {
+//!     static ref HEX: Encoding = {
+//!         let mut spec = Specification::new();
+//!         spec.symbols.push_str("0123456789abcdef");
+//!         spec.translate.from.push_str("ABCDEF");
+//!         spec.translate.to.push_str("abcdef");
+//!         spec.encoding().unwrap()
+//!     };
+//! }
+//! ```
+//!
+//! You may also use the [macro] library to define a compile-time custom encoding:
+//!
+//! ```rust,ignore
+//! const HEX: Encoding = new_encoding!{
+//!     symbols: "0123456789abcdef",
+//!     translate_from: "ABCDEF",
+//!     translate_to: "abcdef",
+//! };
+//! const BASE64: Encoding = new_encoding!{
+//!     symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+//!     padding: '=',
+//! };
+//! ```
+//!
+//! # Properties
+//!
+//! The [base16], [base32], [base32hex], [base64], and [base64url] predefined
+//! encodings are conform to [RFC4648].
+//!
+//! In general, the encoding and decoding functions satisfy the following
+//! properties:
+//!
+//! - They are deterministic: their output only depends on their input
+//! - They have no side-effects: they do not modify a hidden mutable state
+//! - They are correct: encoding then decoding gives the initial data
+//! - They are canonical (unless [`is_canonical`] returns false): decoding then
+//! encoding gives the initial data
+//!
+//! This last property is usually not satisfied by common base64 implementations
+//! (like the `rustc-serialize` crate, the `base64` crate, or the `base64` GNU
+//! program). This is a matter of choice and this crate has made the choice to
+//! let the user choose. Support for canonical encoding as described by the
+//! [RFC][canonical] is provided. But it is also possible to disable checking
+//! trailing bits, to add characters translation, to decode concatenated padded
+//! inputs, and to ignore some characters.
+//!
+//! Since the RFC specifies the encoding function on all inputs and the decoding
+//! function on all possible encoded outputs, the differences between
+//! implementations come from the decoding function which may be more or less
+//! permissive. In this crate, the decoding function of canonical encodings
+//! rejects all inputs that are not a possible output of the encoding function.
+//! Here are some concrete examples of decoding differences between this crate,
+//! the `rustc-serialize` crate, the `base64` crate, and the `base64` GNU
+//! program:
+//!
+//! | Input      | `data-encoding` | `rustc`  | `base64` | GNU `base64`  |
+//! | ---------- | --------------- | -------- | -------- | ------------- |
+//! | `AAB=`     | `Trailing(2)`   | `[0, 0]` | `[0, 0]` | `\x00\x00`    |
+//! | `AA\nB=`   | `Length(4)`     | `[0, 0]` | `Length` | `\x00\x00`    |
+//! | `AAB`      | `Length(0)`     | `[0, 0]` | `[0, 0]` | Invalid input |
+//! | `A\rA\nB=` | `Length(4)`     | `[0, 0]` | `Err(1)` | Invalid input |
+//! | `-_\r\n`   | `Symbol(0)`     | `[251]`  | `Err(0)` | Invalid input |
+//! | `AA==AA==` | `[0, 0]`        | `Err`    | `Err(2)` | `\x00\x00`    |
+//!
+//! We can summarize these discrepancies as follows:
+//!
+//! | Discrepancy | `data-encoding` | `rustc` | `base64` | GNU `base64` |
+//! | ----------- | --------------- | ------- | -------- | ------------ |
+//! | Check trailing bits | Yes | No | No | No |
+//! | Ignored characters | None | `\r` and `\n` | None | `\n` |
+//! | Translated characters | None | `-_` mapped to `+/` | None | None |
+//! | Check padding | Yes | No | No | Yes |
+//! | Support concatenated input | Yes | No | No | Yes |
+//!
+//! This crate permits to disable checking trailing bits. It permits to ignore
+//! some characters. It permits to translate characters. It permits to use
+//! unpadded encodings. However, for padded encodings, support for concatenated
+//! inputs cannot be disabled. This is simply because it doesn't make sense to
+//! use padding if it is not to support concatenated inputs.
+//!
+//! # Migration
+//!
+//! The [changelog] describes the changes between v1 and v2. Here are the
+//! migration steps for common usage:
+//!
+//! | v1                          | v2                          |
+//! | --------------------------- | --------------------------- |
+//! | `use data_encoding::baseNN` | `use data_encoding::BASENN` |
+//! | `baseNN::function`          | `BASENN.method`             |
+//! | `baseNN::function_nopad`    | `BASENN_NOPAD.method`       |
+//!
+//! [`Encoding`]: struct.Encoding.html
+//! [`Specification`]: struct.Specification.html
+//! [`is_canonical`]: struct.Encoding.html#method.is_canonical
+//! [`lazy_static`]: https://crates.io/crates/lazy_static
+//! [RFC4648]: https://tools.ietf.org/html/rfc4648
+//! [base16]: constant.HEXUPPER.html
+//! [base32]: constant.BASE32.html
+//! [base32hex]: constant.BASE32HEX.html
+//! [base64]: constant.BASE64.html
+//! [base64url]: constant.BASE64URL.html
+//! [binary]: https://crates.io/crates/data-encoding-bin
+//! [canonical]: https://tools.ietf.org/html/rfc4648#section-3.5
+//! [changelog]:
+//!     https://github.com/ia0/data-encoding/blob/master/lib/CHANGELOG.md
+//! [constants]: index.html#constants
+//! [crate]: https://crates.io/crates/data-encoding
+//! [github]: https://github.com/ia0/data-encoding
+//! [macro]: https://crates.io/crates/data-encoding-macro
+
+#![warn(unused_results, missing_docs)]
+
+macro_rules! check {
+    ($e: expr, $c: expr) => {
+        if !$c {
+            return Err($e);
+        }
+    };
+}
+
+trait Static<T: Copy>: Copy {
+    fn val(self) -> T;
+}
+
+macro_rules! define {
+    ($name: ident: $type: ty = $val: expr) => {
+        #[derive(Copy, Clone)]
+        struct $name;
+        impl Static<$type> for $name {
+            fn val(self) -> $type {
+                $val
+            }
+        }
+    };
+}
+
+define!(Bf: bool = false);
+define!(Bt: bool = true);
+define!(N1: usize = 1);
+define!(N2: usize = 2);
+define!(N3: usize = 3);
+define!(N4: usize = 4);
+define!(N5: usize = 5);
+define!(N6: usize = 6);
+
+#[derive(Copy, Clone)]
+struct On;
+impl<T: Copy> Static<Option<T>> for On {
+    fn val(self) -> Option<T> {
+        None
+    }
+}
+
+#[derive(Copy, Clone)]
+struct Os<T>(T);
+impl<T: Copy> Static<Option<T>> for Os<T> {
+    fn val(self) -> Option<T> {
+        Some(self.0)
+    }
+}
+
+macro_rules! dispatch {
+    (let $var: ident: bool = $val: expr; $($body: tt)*) => {
+        match $val {
+            false => { let $var = Bf; dispatch!($($body)*) },
+            true => { let $var = Bt; dispatch!($($body)*) },
+        }
+    };
+    (let $var: ident: usize = $val: expr; $($body: tt)*) => {
+        match $val {
+            1 => { let $var = N1; dispatch!($($body)*) },
+            2 => { let $var = N2; dispatch!($($body)*) },
+            3 => { let $var = N3; dispatch!($($body)*) },
+            4 => { let $var = N4; dispatch!($($body)*) },
+            5 => { let $var = N5; dispatch!($($body)*) },
+            6 => { let $var = N6; dispatch!($($body)*) },
+            _ => panic!(),
+        }
+    };
+    (let $var: ident: Option<$type: ty> = $val: expr; $($body: tt)*) => {
+        match $val {
+            None => { let $var = On; dispatch!($($body)*) },
+            Some(x) => { let $var = Os(x); dispatch!($($body)*) },
+        }
+    };
+    ($body: expr) => { $body };
+}
+
+unsafe fn chunk_unchecked(x: &[u8], n: usize, i: usize) -> &[u8] {
+    debug_assert!((i + 1) * n <= x.len());
+    let ptr = x.as_ptr().offset((n * i) as isize);
+    std::slice::from_raw_parts(ptr, n)
+}
+unsafe fn chunk_mut_unchecked(x: &mut [u8], n: usize, i: usize) -> &mut [u8] {
+    debug_assert!((i + 1) * n <= x.len());
+    let ptr = x.as_mut_ptr().offset((n * i) as isize);
+    std::slice::from_raw_parts_mut(ptr, n)
+}
+unsafe fn as_array(x: &[u8]) -> &[u8; 256] {
+    debug_assert_eq!(x.len(), 256);
+    &*(x.as_ptr() as *const [u8; 256])
+}
+fn div_ceil(x: usize, m: usize) -> usize {
+    (x + m - 1) / m
+}
+fn floor(x: usize, m: usize) -> usize {
+    x / m * m
+}
+
+fn vectorize<F: FnMut(usize)>(n: usize, bs: usize, mut f: F) {
+    for k in 0 .. n / bs {
+        for i in k * bs .. (k + 1) * bs {
+            f(i);
+        }
+    }
+    for i in floor(n, bs) .. n {
+        f(i);
+    }
+}
+
+/// Decoding error kind
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum DecodeKind {
+    /// Invalid length
+    Length,
+    /// Invalid symbol
+    Symbol,
+    /// Non-zero trailing bits
+    Trailing,
+    /// Invalid padding length
+    Padding,
+}
+
+/// Decoding error
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct DecodeError {
+    /// Error position
+    ///
+    /// This position is always a valid input position and represents the first
+    /// encountered error.
+    pub position: usize,
+    /// Error kind
+    pub kind: DecodeKind,
+}
+impl std::error::Error for DecodeError {
+    fn description(&self) -> &str {
+        match self.kind {
+            DecodeKind::Length => "invalid length",
+            DecodeKind::Symbol => "invalid symbol",
+            DecodeKind::Trailing => "non-zero trailing bits",
+            DecodeKind::Padding => "invalid padding length",
+        }
+    }
+}
+impl std::fmt::Display for DecodeError {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        use std::error::Error;
+        write!(f, "{} at {}", self.description(), self.position)
+    }
+}
+
+/// Decoding error with partial result
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct DecodePartial {
+    /// Number of bytes read from input
+    ///
+    /// This number does not exceed the error position: `read <=
+    /// error.position`.
+    pub read: usize,
+
+    /// Number of bytes written to output
+    ///
+    /// This number does not exceed the decoded length: `written <=
+    /// decode_len(read)`.
+    pub written: usize,
+
+    /// Decoding error
+    pub error: DecodeError,
+}
+
+const INVALID: u8 = 128;
+const IGNORE: u8 = 129;
+const PADDING: u8 = 130;
+
+fn order(msb: bool, n: usize, i: usize) -> usize {
+    if msb {
+        n - 1 - i
+    } else {
+        i
+    }
+}
+fn enc(bit: usize) -> usize {
+    debug_assert!(1 <= bit && bit <= 6);
+    match bit {
+        1 | 2 | 4 => 1,
+        3 | 6 => 3,
+        5 => 5,
+        _ => unreachable!(),
+    }
+}
+fn dec(bit: usize) -> usize {
+    enc(bit) * 8 / bit
+}
+
+fn encode_len<B: Static<usize>>(bit: B, len: usize) -> usize {
+    div_ceil(8 * len, bit.val())
+}
+fn encode_block<B: Static<usize>, M: Static<bool>>(
+    bit: B, msb: M, symbols: &[u8; 256], input: &[u8], output: &mut [u8],
+) {
+    debug_assert!(input.len() <= enc(bit.val()));
+    debug_assert_eq!(output.len(), encode_len(bit, input.len()));
+    let bit = bit.val();
+    let msb = msb.val();
+    let mut x = 0u64;
+    for i in 0 .. input.len() {
+        x |= (input[i] as u64) << 8 * order(msb, enc(bit), i);
+    }
+    for i in 0 .. output.len() {
+        let y = x >> bit * order(msb, dec(bit), i);
+        output[i] = symbols[y as usize % 256];
+    }
+}
+fn encode_mut<B: Static<usize>, M: Static<bool>>(
+    bit: B, msb: M, symbols: &[u8; 256], input: &[u8], output: &mut [u8],
+) {
+    debug_assert_eq!(output.len(), encode_len(bit, input.len()));
+    let enc = enc(bit.val());
+    let dec = dec(bit.val());
+    let n = input.len() / enc;
+    let bs = match bit.val() {
+        5 => 2,
+        6 => 4,
+        _ => 1,
+    };
+    vectorize(n, bs, |i| {
+        let input = unsafe { chunk_unchecked(input, enc, i) };
+        let output = unsafe { chunk_mut_unchecked(output, dec, i) };
+        encode_block(bit, msb, symbols, input, output);
+    });
+    encode_block(bit, msb, symbols, &input[enc * n ..], &mut output[dec * n ..]);
+}
+
+// Fails if an input character does not translate to a symbol. The error is the
+// lowest index of such character. The output is not written to.
+fn decode_block<B: Static<usize>, M: Static<bool>>(
+    bit: B, msb: M, values: &[u8; 256], input: &[u8], output: &mut [u8],
+) -> Result<(), usize> {
+    debug_assert!(output.len() <= enc(bit.val()));
+    debug_assert_eq!(input.len(), encode_len(bit, output.len()));
+    let bit = bit.val();
+    let msb = msb.val();
+    let mut x = 0u64;
+    for j in 0 .. input.len() {
+        let y = values[input[j] as usize];
+        check!(j, y < 1 << bit);
+        x |= (y as u64) << bit * order(msb, dec(bit), j);
+    }
+    for j in 0 .. output.len() {
+        output[j] = (x >> 8 * order(msb, enc(bit), j)) as u8;
+    }
+    Ok(())
+}
+// Fails if an input character does not translate to a symbol. The error `pos`
+// is the lowest index of such character. The output is valid up to `pos / dec *
+// enc` excluded.
+fn decode_mut<B: Static<usize>, M: Static<bool>>(
+    bit: B, msb: M, values: &[u8; 256], input: &[u8], output: &mut [u8],
+) -> Result<(), usize> {
+    debug_assert_eq!(input.len(), encode_len(bit, output.len()));
+    let enc = enc(bit.val());
+    let dec = dec(bit.val());
+    let n = input.len() / dec;
+    for i in 0 .. n {
+        let input = unsafe { chunk_unchecked(input, dec, i) };
+        let output = unsafe { chunk_mut_unchecked(output, enc, i) };
+        decode_block(bit, msb, values, input, output).map_err(|e| dec * i + e)?;
+    }
+    decode_block(bit, msb, values, &input[dec * n ..], &mut output[enc * n ..])
+        .map_err(|e| dec * n + e)
+}
+// Fails if there are non-zero trailing bits.
+fn check_trail<B: Static<usize>, M: Static<bool>>(
+    bit: B, msb: M, ctb: bool, values: &[u8; 256], input: &[u8],
+) -> Result<(), ()> {
+    if 8 % bit.val() == 0 || !ctb {
+        return Ok(());
+    }
+    let trail = bit.val() * input.len() % 8;
+    if trail == 0 {
+        return Ok(());
+    }
+    let mut mask = (1 << trail) - 1;
+    if !msb.val() {
+        mask <<= bit.val() - trail;
+    }
+    check!((), values[input[input.len() - 1] as usize] & mask == 0);
+    Ok(())
+}
+// Fails if the padding length is invalid. The error is the index of the first
+// padding character.
+fn check_pad<B: Static<usize>>(bit: B, values: &[u8; 256], input: &[u8]) -> Result<usize, usize> {
+    let bit = bit.val();
+    debug_assert_eq!(input.len(), dec(bit));
+    let is_pad = |x: &&u8| values[**x as usize] == PADDING;
+    let count = input.iter().rev().take_while(is_pad).count();
+    let len = input.len() - count;
+    check!(len, len > 0 && bit * len % 8 < bit);
+    Ok(len)
+}
+
+fn encode_base_len<B: Static<usize>>(bit: B, len: usize) -> usize {
+    encode_len(bit, len)
+}
+fn encode_base<B: Static<usize>, M: Static<bool>>(
+    bit: B, msb: M, symbols: &[u8; 256], input: &[u8], output: &mut [u8],
+) {
+    debug_assert_eq!(output.len(), encode_base_len(bit, input.len()));
+    encode_mut(bit, msb, symbols, input, output);
+}
+
+fn encode_pad_len<B: Static<usize>, P: Static<Option<u8>>>(bit: B, pad: P, len: usize) -> usize {
+    match pad.val() {
+        None => encode_base_len(bit, len),
+        Some(_) => div_ceil(len, enc(bit.val())) * dec(bit.val()),
+    }
+}
+fn encode_pad<B: Static<usize>, M: Static<bool>, P: Static<Option<u8>>>(
+    bit: B, msb: M, symbols: &[u8; 256], spad: P, input: &[u8], output: &mut [u8],
+) {
+    let pad = match spad.val() {
+        None => return encode_base(bit, msb, symbols, input, output),
+        Some(pad) => pad,
+    };
+    debug_assert_eq!(output.len(), encode_pad_len(bit, spad, input.len()));
+    let olen = encode_base_len(bit, input.len());
+    encode_base(bit, msb, symbols, input, &mut output[.. olen]);
+    for i in olen .. output.len() {
+        output[i] = pad;
+    }
+}
+
+fn encode_wrap_len<
+    'a,
+    B: Static<usize>,
+    P: Static<Option<u8>>,
+    W: Static<Option<(usize, &'a [u8])>>,
+>(
+    bit: B, pad: P, wrap: W, ilen: usize,
+) -> usize {
+    let olen = encode_pad_len(bit, pad, ilen);
+    match wrap.val() {
+        None => olen,
+        Some((col, end)) => olen + end.len() * div_ceil(olen, col),
+    }
+}
+fn encode_wrap_mut<
+    'a,
+    B: Static<usize>,
+    M: Static<bool>,
+    P: Static<Option<u8>>,
+    W: Static<Option<(usize, &'a [u8])>>,
+>(
+    bit: B, msb: M, symbols: &[u8; 256], pad: P, wrap: W, input: &[u8], output: &mut [u8],
+) {
+    let (col, end) = match wrap.val() {
+        None => return encode_pad(bit, msb, symbols, pad, input, output),
+        Some((col, end)) => (col, end),
+    };
+    debug_assert_eq!(output.len(), encode_wrap_len(bit, pad, wrap, input.len()));
+    debug_assert_eq!(col % dec(bit.val()), 0);
+    let col = col / dec(bit.val());
+    let enc = col * enc(bit.val());
+    let dec = col * dec(bit.val()) + end.len();
+    let olen = dec - end.len();
+    let n = input.len() / enc;
+    for i in 0 .. n {
+        let input = unsafe { chunk_unchecked(input, enc, i) };
+        let output = unsafe { chunk_mut_unchecked(output, dec, i) };
+        encode_base(bit, msb, symbols, input, &mut output[.. olen]);
+        output[olen ..].copy_from_slice(end);
+    }
+    if input.len() > enc * n {
+        let olen = dec * n + encode_pad_len(bit, pad, input.len() - enc * n);
+        encode_pad(bit, msb, symbols, pad, &input[enc * n ..], &mut output[dec * n .. olen]);
+        output[olen ..].copy_from_slice(end);
+    }
+}
+
+// Returns the longest valid input length and associated output length.
+fn decode_wrap_len<B: Static<usize>, P: Static<bool>>(
+    bit: B, pad: P, len: usize,
+) -> (usize, usize) {
+    let bit = bit.val();
+    if pad.val() {
+        (floor(len, dec(bit)), len / dec(bit) * enc(bit))
+    } else {
+        let trail = bit * len % 8;
+        (len - trail / bit, bit * len / 8)
+    }
+}
+
+// Fails with Length if length is invalid. The error is the largest valid
+// length.
+fn decode_pad_len<B: Static<usize>, P: Static<bool>>(
+    bit: B, pad: P, len: usize,
+) -> Result<usize, DecodeError> {
+    let (ilen, olen) = decode_wrap_len(bit, pad, len);
+    check!(DecodeError { position: ilen, kind: DecodeKind::Length }, ilen == len);
+    Ok(olen)
+}
+
+// Fails with Length if length is invalid. The error is the largest valid
+// length.
+fn decode_base_len<B: Static<usize>>(bit: B, len: usize) -> Result<usize, DecodeError> {
+    decode_pad_len(bit, Bf, len)
+}
+// Fails with Symbol if an input character does not translate to a symbol. The
+// error is the lowest index of such character.
+// Fails with Trailing if there are non-zero trailing bits.
+fn decode_base_mut<B: Static<usize>, M: Static<bool>>(
+    bit: B, msb: M, ctb: bool, values: &[u8; 256], input: &[u8], output: &mut [u8],
+) -> Result<usize, DecodePartial> {
+    debug_assert_eq!(Ok(output.len()), decode_base_len(bit, input.len()));
+    let fail = |pos, kind| DecodePartial {
+        read: pos / dec(bit.val()) * dec(bit.val()),
+        written: pos / dec(bit.val()) * enc(bit.val()),
+        error: DecodeError { position: pos, kind },
+    };
+    decode_mut(bit, msb, values, input, output).map_err(|pos| fail(pos, DecodeKind::Symbol))?;
+    check_trail(bit, msb, ctb, values, input)
+        .map_err(|()| fail(input.len() - 1, DecodeKind::Trailing))?;
+    Ok(output.len())
+}
+
+// Fails with Symbol if an input character does not translate to a symbol. The
+// error is the lowest index of such character.
+// Fails with Padding if some padding length is invalid. The error is the index
+// of the first padding character of the invalid padding.
+// Fails with Trailing if there are non-zero trailing bits.
+fn decode_pad_mut<B: Static<usize>, M: Static<bool>, P: Static<bool>>(
+    bit: B, msb: M, ctb: bool, values: &[u8; 256], pad: P, input: &[u8], output: &mut [u8],
+) -> Result<usize, DecodePartial> {
+    if !pad.val() {
+        return decode_base_mut(bit, msb, ctb, values, input, output);
+    }
+    debug_assert_eq!(Ok(output.len()), decode_pad_len(bit, pad, input.len()));
+    let enc = enc(bit.val());
+    let dec = dec(bit.val());
+    let mut inpos = 0;
+    let mut outpos = 0;
+    let mut outend = output.len();
+    while inpos < input.len() {
+        match decode_base_mut(
+            bit,
+            msb,
+            ctb,
+            values,
+            &input[inpos ..],
+            &mut output[outpos .. outend],
+        ) {
+            Ok(written) => {
+                if cfg!(debug_assertions) {
+                    inpos = input.len();
+                }
+                outpos += written;
+                break;
+            }
+            Err(partial) => {
+                inpos += partial.read;
+                outpos += partial.written;
+            }
+        }
+        let inlen =
+            check_pad(bit, values, &input[inpos .. inpos + dec]).map_err(|pos| DecodePartial {
+                read: inpos,
+                written: outpos,
+                error: DecodeError { position: inpos + pos, kind: DecodeKind::Padding },
+            })?;
+        let outlen = decode_base_len(bit, inlen).unwrap();
+        let written = decode_base_mut(
+            bit,
+            msb,
+            ctb,
+            values,
+            &input[inpos .. inpos + inlen],
+            &mut output[outpos .. outpos + outlen],
+        )
+        .map_err(|partial| {
+            debug_assert_eq!(partial.read, 0);
+            debug_assert_eq!(partial.written, 0);
+            DecodePartial {
+                read: inpos,
+                written: outpos,
+                error: DecodeError {
+                    position: inpos + partial.error.position,
+                    kind: partial.error.kind,
+                },
+            }
+        })?;
+        debug_assert_eq!(written, outlen);
+        inpos += dec;
+        outpos += outlen;
+        outend -= enc - outlen;
+    }
+    debug_assert_eq!(inpos, input.len());
+    debug_assert_eq!(outpos, outend);
+    Ok(outend)
+}
+
+fn skip_ignore(values: &[u8; 256], input: &[u8], mut inpos: usize) -> usize {
+    while inpos < input.len() && values[input[inpos] as usize] == IGNORE {
+        inpos += 1;
+    }
+    inpos
+}
+// Returns next input and output position.
+// Fails with Symbol if an input character does not translate to a symbol. The
+// error is the lowest index of such character.
+// Fails with Padding if some padding length is invalid. The error is the index
+// of the first padding character of the invalid padding.
+// Fails with Trailing if there are non-zero trailing bits.
+fn decode_wrap_block<B: Static<usize>, M: Static<bool>, P: Static<bool>>(
+    bit: B, msb: M, ctb: bool, values: &[u8; 256], pad: P, input: &[u8], output: &mut [u8],
+) -> Result<(usize, usize), DecodeError> {
+    let dec = dec(bit.val());
+    let mut buf = [0u8; 8];
+    let mut shift = [0usize; 8];
+    let mut bufpos = 0;
+    let mut inpos = 0;
+    while bufpos < dec {
+        inpos = skip_ignore(values, input, inpos);
+        if inpos == input.len() {
+            break;
+        }
+        shift[bufpos] = inpos;
+        buf[bufpos] = input[inpos];
+        bufpos += 1;
+        inpos += 1;
+    }
+    let olen = decode_pad_len(bit, pad, bufpos).map_err(|mut e| {
+        e.position = shift[e.position];
+        e
+    })?;
+    let written = decode_pad_mut(bit, msb, ctb, values, pad, &buf[.. bufpos], &mut output[.. olen])
+        .map_err(|partial| {
+            debug_assert_eq!(partial.read, 0);
+            debug_assert_eq!(partial.written, 0);
+            DecodeError { position: shift[partial.error.position], kind: partial.error.kind }
+        })?;
+    Ok((inpos, written))
+}
+// Fails with Symbol if an input character does not translate to a symbol. The
+// error is the lowest index of such character.
+// Fails with Padding if some padding length is invalid. The error is the index
+// of the first padding character of the invalid padding.
+// Fails with Trailing if there are non-zero trailing bits.
+// Fails with Length if input length (without ignored characters) is invalid.
+fn decode_wrap_mut<B: Static<usize>, M: Static<bool>, P: Static<bool>, I: Static<bool>>(
+    bit: B, msb: M, ctb: bool, values: &[u8; 256], pad: P, has_ignore: I, input: &[u8],
+    output: &mut [u8],
+) -> Result<usize, DecodePartial> {
+    if !has_ignore.val() {
+        return decode_pad_mut(bit, msb, ctb, values, pad, input, output);
+    }
+    debug_assert_eq!(output.len(), decode_wrap_len(bit, pad, input.len()).1);
+    let mut inpos = 0;
+    let mut outpos = 0;
+    while inpos < input.len() {
+        let (inlen, outlen) = decode_wrap_len(bit, pad, input.len() - inpos);
+        match decode_pad_mut(
+            bit,
+            msb,
+            ctb,
+            values,
+            pad,
+            &input[inpos .. inpos + inlen],
+            &mut output[outpos .. outpos + outlen],
+        ) {
+            Ok(written) => {
+                inpos += inlen;
+                outpos += written;
+                break;
+            }
+            Err(partial) => {
+                inpos += partial.read;
+                outpos += partial.written;
+            }
+        }
+        let (ipos, opos) =
+            decode_wrap_block(bit, msb, ctb, values, pad, &input[inpos ..], &mut output[outpos ..])
+                .map_err(|mut error| {
+                    error.position += inpos;
+                    DecodePartial { read: inpos, written: outpos, error }
+                })?;
+        inpos += ipos;
+        outpos += opos;
+    }
+    let inpos = skip_ignore(values, input, inpos);
+    if inpos == input.len() {
+        Ok(outpos)
+    } else {
+        Err(DecodePartial {
+            read: inpos,
+            written: outpos,
+            error: DecodeError { position: inpos, kind: DecodeKind::Length },
+        })
+    }
+}
+
+/// Order in which bits are read from a byte
+///
+/// The base-conversion encoding is always little-endian. This means that the
+/// least significant *byte* is always first. However, we can still choose
+/// whether, within a byte, this is the most significant or the least
+/// significant *bit* that is first. If the terminology is confusing, testing on
+/// an asymmetrical example should be enough to choose the correct value.
+///
+/// # Examples
+///
+/// In the following example, we can see that a base with the
+/// `MostSignificantFirst` bit-order has the most significant bit first in the
+/// encoded output. In particular, the output is in the same order as the bits
+/// in the byte. The opposite happens with the `LeastSignificantFirst`
+/// bit-order. The least significant bit is first and the output is in the
+/// reverse order.
+///
+/// ```rust
+/// use data_encoding::{BitOrder, Specification};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("01");
+/// // spec.bit_order = BitOrder::MostSignificantFirst;  // default
+/// let msb = spec.encoding().unwrap();
+/// spec.bit_order = BitOrder::LeastSignificantFirst;
+/// let lsb = spec.encoding().unwrap();
+/// assert_eq!(msb.encode(&[0b01010011]), "01010011");
+/// assert_eq!(lsb.encode(&[0b01010011]), "11001010");
+/// ```
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum BitOrder {
+    /// Most significant bit first
+    ///
+    /// This is the most common and most intuitive bit-order. In particular,
+    /// this is the bit-order used by [RFC4648] and thus the usual hexadecimal,
+    /// base64, base32, base64url, and base32hex encodings. This is the default
+    /// bit-order when [specifying](struct.Specification.html) a base.
+    ///
+    /// [RFC4648]: https://tools.ietf.org/html/rfc4648
+    MostSignificantFirst,
+
+    /// Least significant bit first
+    ///
+    /// # Examples
+    ///
+    /// DNSCurve [base32] uses least significant bit first:
+    ///
+    /// ```rust
+    /// use data_encoding::BASE32_DNSCURVE;
+    /// assert_eq!(BASE32_DNSCURVE.encode(&[0x64, 0x88]), "4321");
+    /// assert_eq!(BASE32_DNSCURVE.decode(b"4321").unwrap(), vec![0x64, 0x88]);
+    /// ```
+    ///
+    /// [base32]: constant.BASE32_DNSCURVE.html
+    LeastSignificantFirst,
+}
+use crate::BitOrder::*;
+
+#[doc(hidden)]
+pub type InternalEncoding = std::borrow::Cow<'static, [u8]>;
+
+/// Base-conversion encoding
+///
+/// See [Specification](struct.Specification.html) for technical details or how
+/// to define a new one.
+// Required fields:
+//   0 - 256 (256) symbols
+// 256 - 512 (256) values
+// 512 - 513 (  1) padding
+// 513 - 514 (  1) reserved(3),ctb(1),msb(1),bit(3)
+// Optional fields:
+// 514 - 515 (  1) width
+// 515 -   * (  N) separator
+// Invariants:
+// - symbols is 2^bit unique characters repeated 2^(8-bit) times
+// - values[128 ..] are INVALID
+// - values[0 .. 128] are either INVALID, IGNORE, PADDING, or < 2^bit
+// - padding is either < 128 or INVALID
+// - values[padding] is PADDING if padding < 128
+// - values and symbols are inverse
+// - ctb is true if 8 % bit == 0
+// - width is present if there is x such that values[x] is IGNORE
+// - width % dec(bit) == 0
+// - for all x in separator values[x] is IGNORE
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Encoding(pub InternalEncoding);
+
+/// How to translate characters when decoding
+///
+/// The order matters. The first character of the `from` field is translated to
+/// the first character of the `to` field. The second to the second. Etc.
+///
+/// See [Specification](struct.Specification.html) for more information.
+#[derive(Debug, Clone)]
+pub struct Translate {
+    /// Characters to translate from
+    pub from: String,
+    /// Characters to translate to
+    pub to: String,
+}
+
+/// How to wrap the output when encoding
+///
+/// See [Specification](struct.Specification.html) for more information.
+#[derive(Debug, Clone)]
+pub struct Wrap {
+    /// Wrapping width
+    ///
+    /// Must be a multiple of:
+    ///
+    /// - 8 for a bit-width of 1 (binary), 3 (octal), and 5 (base32)
+    /// - 4 for a bit-width of 2 (base4) and 6 (base64)
+    /// - 2 for a bit-width of 4 (hexadecimal)
+    ///
+    /// Wrapping is disabled if null.
+    pub width: usize,
+
+    /// Wrapping characters
+    ///
+    /// Wrapping is disabled if empty.
+    pub separator: String,
+}
+
+/// Base-conversion specification
+///
+/// It is possible to define custom encodings given a specification. To do so,
+/// it is important to understand the theory first.
+///
+/// # Theory
+///
+/// Each subsection has an equivalent subsection in the [Practice](#practice)
+/// section.
+///
+/// ## Basics
+///
+/// The main idea of a [base-conversion] encoding is to see `[u8]` as numbers
+/// written in little-endian base256 and convert them in another little-endian
+/// base. For performance reasons, this crate restricts this other base to be of
+/// size 2 (binary), 4 (base4), 8 (octal), 16 (hexadecimal), 32 (base32), or 64
+/// (base64). The converted number is written as `[u8]` although it doesn't use
+/// all the 256 possible values of `u8`. This crate encodes to ASCII, so only
+/// values smaller than 128 are allowed.
+///
+/// More precisely, we need the following elements:
+///
+/// - The bit-width N: 1 for binary, 2 for base4, 3 for octal, 4 for
+/// hexadecimal, 5 for base32, and 6 for base64
+/// - The [bit-order](enum.BitOrder.html): most or least significant bit first
+/// - The symbols function S from [0, 2<sup>N</sup>) (called values and written
+/// `uN`) to symbols (represented as `u8` although only ASCII symbols are
+/// allowed, i.e. smaller than 128)
+/// - The values partial function V from ASCII to [0, 2<sup>N</sup>), i.e. from
+/// `u8` to `uN`
+/// - Whether trailing bits are checked: trailing bits are leading zeros in
+/// theory, but since numbers are little-endian they come last
+///
+/// For the encoding to be correct (i.e. encoding then decoding gives back the
+/// initial input), V(S(i)) must be defined and equal to i for all i in [0,
+/// 2<sup>N</sup>). For the encoding to be [canonical][canonical] (i.e.
+/// different inputs decode to different outputs, or equivalently, decoding then
+/// encoding gives back the initial input), trailing bits must be checked and if
+/// V(i) is defined then S(V(i)) is equal to i for all i.
+///
+/// Encoding and decoding are given by the following pipeline:
+///
+/// ```text
+/// [u8] <--1--> [[bit; 8]] <--2--> [[bit; N]] <--3--> [uN] <--4--> [u8]
+/// 1: Map bit-order between each u8 and [bit; 8]
+/// 2: Base conversion between base 2^8 and base 2^N (check trailing bits)
+/// 3: Map bit-order between each [bit; N] and uN
+/// 4: Map symbols/values between each uN and u8 (values must be defined)
+/// ```
+///
+/// ## Extensions
+///
+/// All these extensions make the encoding not canonical.
+///
+/// ### Padding
+///
+/// Padding is useful if the following conditions are met:
+///
+/// - the bit-width is 3 (octal), 5 (base32), or 6 (base64)
+/// - the length of the data to encode is not known in advance
+///
+/// Bases for which the bit-width N does not divide 8 may not concatenate
+/// encoded data. This comes from the fact that it is not possible to make the
+/// difference between trailing bits and encoding bits. Padding solves this
+/// issue by adding a new character (which is not a symbol) to discriminate
+/// between trailing bits and encoding bits. The idea is to work by blocks of
+/// lcm(8, N) bits, where lcm(8, N) is the least common multiple of 8 and N.
+/// When such block is not complete, it is padded.
+///
+/// To preserve correctness, the padding character must not be a symbol.
+///
+/// ### Ignore characters when decoding
+///
+/// Ignoring characters when decoding is useful if after encoding some
+/// characters are added for convenience or any other reason (like wrapping). In
+/// that case we want to first ignore thoses characters before decoding.
+///
+/// To preserve correctness, ignored characters must not contain symbols or the
+/// padding character.
+///
+/// ### Wrap output when encoding
+///
+/// Wrapping output when encoding is useful if the output is meant to be printed
+/// in a document where width is limited (typically 80-columns documents). In
+/// that case, the wrapping width and the wrapping separator have to be defined.
+///
+/// To preserve correctness, the wrapping separator characters must be ignored
+/// (see previous subsection). As such, wrapping separator characters must also
+/// not contain symbols or the padding character.
+///
+/// ### Translate characters when decoding
+///
+/// Translating characters when decoding is useful when encoded data may be
+/// copied by a humain instead of a machine. Humans tend to confuse some
+/// characters for others. In that case we want to translate those characters
+/// before decoding.
+///
+/// To preserve correctness, the characters we translate from must not contain
+/// symbols or the padding character, and the characters we translate to must
+/// only contain symbols or the padding character.
+///
+/// # Practice
+///
+/// ## Basics
+///
+/// ```rust
+/// use data_encoding::{Encoding, Specification};
+/// fn make_encoding(symbols: &str) -> Encoding {
+///     let mut spec = Specification::new();
+///     spec.symbols.push_str(symbols);
+///     spec.encoding().unwrap()
+/// }
+/// let binary = make_encoding("01");
+/// let octal = make_encoding("01234567");
+/// let hexadecimal = make_encoding("0123456789abcdef");
+/// assert_eq!(binary.encode(b"Bit"), "010000100110100101110100");
+/// assert_eq!(octal.encode(b"Bit"), "20464564");
+/// assert_eq!(hexadecimal.encode(b"Bit"), "426974");
+/// ```
+///
+/// The `binary` base has 2 symbols `0` and `1` with value 0 and 1 respectively.
+/// The `octal` base has 8 symbols `0` to `7` with value 0 to 7. The
+/// `hexadecimal` base has 16 symbols `0` to `9` and `a` to `f` with value 0 to
+/// 15. The following diagram gives the idea of how encoding works in the
+/// previous example (note that we can actually write such diagram only because
+/// the bit-order is most significant first):
+///
+/// ```text
+/// [      octal] |  2  :  0  :  4  :  6  :  4  :  5  :  6  :  4  |
+/// [     binary] |0 1 0 0 0 0 1 0|0 1 1 0 1 0 0 1|0 1 1 1 0 1 0 0|
+/// [hexadecimal] |   4   :   2   |   6   :   9   |   7   :   4   |
+///                ^-- LSB                                       ^-- MSB
+/// ```
+///
+/// Note that in theory, these little-endian numbers are read from right to left
+/// (the most significant bit is at the right). Since leading zeros are
+/// meaningless (in our usual decimal notation 0123 is the same as 123), it
+/// explains why trailing bits must be zero. Trailing bits may occur when the
+/// bit-width of a base does not divide 8. Only binary, base4, and hexadecimal
+/// don't have trailing bits issues. So let's consider octal and base64, which
+/// have trailing bits in similar circumstances:
+///
+/// ```rust
+/// use data_encoding::{Specification, BASE64_NOPAD};
+/// let octal = {
+///     let mut spec = Specification::new();
+///     spec.symbols.push_str("01234567");
+///     spec.encoding().unwrap()
+/// };
+/// assert_eq!(BASE64_NOPAD.encode(b"B"), "Qg");
+/// assert_eq!(octal.encode(b"B"), "204");
+/// ```
+///
+/// We have the following diagram, where the base64 values are written between
+/// parentheses:
+///
+/// ```text
+/// [base64] |   Q(16)   :   g(32)   : [has 4 zero trailing bits]
+/// [ octal] |  2  :  0  :  4  :       [has 1 zero trailing bit ]
+///          |0 1 0 0 0 0 1 0|0 0 0 0
+/// [ ascii] |       B       |
+///                           ^-^-^-^-- leading zeros / trailing bits
+/// ```
+///
+/// ## Extensions
+///
+/// ### Padding
+///
+/// For octal and base64, lcm(8, 3) == lcm(8, 6) == 24 bits or 3 bytes. For
+/// base32, lcm(8, 5) is 40 bits or 5 bytes. Let's consider octal and base64:
+///
+/// ```rust
+/// use data_encoding::{Specification, BASE64};
+/// let octal = {
+///     let mut spec = Specification::new();
+///     spec.symbols.push_str("01234567");
+///     spec.padding = Some('=');
+///     spec.encoding().unwrap()
+/// };
+/// // We start encoding but we only have "B" for now.
+/// assert_eq!(BASE64.encode(b"B"), "Qg==");
+/// assert_eq!(octal.encode(b"B"), "204=====");
+/// // Now we have "it".
+/// assert_eq!(BASE64.encode(b"it"), "aXQ=");
+/// assert_eq!(octal.encode(b"it"), "322720==");
+/// // By concatenating everything, we may decode the original data.
+/// assert_eq!(BASE64.decode(b"Qg==aXQ=").unwrap(), b"Bit");
+/// assert_eq!(octal.decode(b"204=====322720==").unwrap(), b"Bit");
+/// ```
+///
+/// We have the following diagrams:
+///
+/// ```text
+/// [base64] |   Q(16)   :   g(32)   :     =     :     =     |
+/// [ octal] |  2  :  0  :  4  :  =  :  =  :  =  :  =  :  =  |
+///          |0 1 0 0 0 0 1 0|. . . . . . . .|. . . . . . . .|
+/// [ ascii] |       B       |        end of block aligned --^
+///          ^-- beginning of block aligned
+///
+/// [base64] |   a(26)   :   X(23)   :   Q(16)   :     =     |
+/// [ octal] |  3  :  2  :  2  :  7  :  2  :  0  :  =  :  =  |
+///          |0 1 1 0 1 0 0 1|0 1 1 1 0 1 0 0|. . . . . . . .|
+/// [ ascii] |       i       |       t       |
+/// ```
+///
+/// ### Ignore characters when decoding
+///
+/// The typical use-case is to ignore newlines (`\r` and `\n`). But to keep the
+/// example small, we will ignore spaces.
+///
+/// ```rust
+/// let mut spec = data_encoding::HEXLOWER.specification();
+/// spec.ignore.push_str(" \t");
+/// let base = spec.encoding().unwrap();
+/// assert_eq!(base.decode(b"42 69 74"), base.decode(b"426974"));
+/// ```
+///
+/// ### Wrap output when encoding
+///
+/// The typical use-case is to wrap after 64 or 76 characters with a newline
+/// (`\r\n` or `\n`). But to keep the example small, we will wrap after 8
+/// characters with a space.
+///
+/// ```rust
+/// let mut spec = data_encoding::BASE64.specification();
+/// spec.wrap.width = 8;
+/// spec.wrap.separator.push_str(" ");
+/// let base64 = spec.encoding().unwrap();
+/// assert_eq!(base64.encode(b"Hey you"), "SGV5IHlv dQ== ");
+/// ```
+///
+/// Note that the output always ends with the separator.
+///
+/// ### Translate characters when decoding
+///
+/// The typical use-case is to translate lowercase to uppercase or reciprocally,
+/// but it is also used for letters that look alike, like `O0` or `Il1`. Let's
+/// illustrate both examples.
+///
+/// ```rust
+/// let mut spec = data_encoding::HEXLOWER.specification();
+/// spec.translate.from.push_str("ABCDEFOIl");
+/// spec.translate.to.push_str("abcdef011");
+/// let base = spec.encoding().unwrap();
+/// assert_eq!(base.decode(b"BOIl"), base.decode(b"b011"));
+/// ```
+///
+/// [base-conversion]:
+///     https://en.wikipedia.org/wiki/Positional_notation#Base_conversion
+/// [canonical]: https://tools.ietf.org/html/rfc4648#section-3.5
+#[derive(Debug, Clone)]
+pub struct Specification {
+    /// Symbols
+    ///
+    /// The number of symbols must be 2, 4, 8, 16, 32, or 64. Symbols must be
+    /// ASCII characters (smaller than 128) and they must be unique.
+    pub symbols: String,
+
+    /// Bit-order
+    ///
+    /// The default is to use most significant bit first since it is the most
+    /// common.
+    pub bit_order: BitOrder,
+
+    /// Check trailing bits
+    ///
+    /// The default is to check trailing bits. This field is ignored when
+    /// unnecessary (i.e. for base2, base4, and base16).
+    pub check_trailing_bits: bool,
+
+    /// Padding
+    ///
+    /// The default is to not use padding. The padding character must be ASCII
+    /// and must not be a symbol.
+    pub padding: Option<char>,
+
+    /// Characters to ignore when decoding
+    ///
+    /// The default is to not ignore characters when decoding. The characters to
+    /// ignore must be ASCII and must not be symbols or the padding character.
+    pub ignore: String,
+
+    /// How to wrap the output when encoding
+    ///
+    /// The default is to not wrap the output when encoding. The wrapping
+    /// characters must be ASCII and must not be symbols or the padding
+    /// character.
+    pub wrap: Wrap,
+
+    /// How to translate characters when decoding
+    ///
+    /// The default is to not translate characters when decoding. The characters
+    /// to translate from must be ASCII and must not have already been assigned
+    /// a semantics. The characters to translate to must be ASCII and must have
+    /// been assigned a semantics (symbol, padding character, or ignored
+    /// character).
+    pub translate: Translate,
+}
+
+impl Specification {
+    /// Returns a default specification
+    pub fn new() -> Specification {
+        Specification {
+            symbols: String::new(),
+            bit_order: MostSignificantFirst,
+            check_trailing_bits: true,
+            padding: None,
+            ignore: String::new(),
+            wrap: Wrap { width: 0, separator: String::new() },
+            translate: Translate { from: String::new(), to: String::new() },
+        }
+    }
+}
+
+impl Encoding {
+    fn sym(&self) -> &[u8; 256] {
+        unsafe { as_array(&self.0[0 .. 256]) }
+    }
+    fn val(&self) -> &[u8; 256] {
+        unsafe { as_array(&self.0[256 .. 512]) }
+    }
+    fn pad(&self) -> Option<u8> {
+        if self.0[512] < 128 {
+            Some(self.0[512])
+        } else {
+            None
+        }
+    }
+    fn ctb(&self) -> bool {
+        self.0[513] & 0x10 != 0
+    }
+    fn msb(&self) -> bool {
+        self.0[513] & 0x8 != 0
+    }
+    fn bit(&self) -> usize {
+        (self.0[513] & 0x7) as usize
+    }
+    fn wrap(&self) -> Option<(usize, &[u8])> {
+        if self.0.len() <= 515 {
+            return None;
+        }
+        Some((self.0[514] as usize, &self.0[515 ..]))
+    }
+    fn has_ignore(&self) -> bool {
+        self.0.len() >= 515
+    }
+
+    /// Returns the encoded length of an input of length `len`
+    ///
+    /// See [`encode_mut`] for when to use it.
+    ///
+    /// [`encode_mut`]: struct.Encoding.html#method.encode_mut
+    pub fn encode_len(&self, len: usize) -> usize {
+        dispatch! {
+            let bit: usize = self.bit();
+            let pad: Option<u8> = self.pad();
+            let wrap: Option<(usize, &[u8])> = self.wrap();
+            encode_wrap_len(bit, pad, wrap, len)
+        }
+    }
+
+    /// Encodes `input` in `output`
+    ///
+    /// # Panics
+    ///
+    /// Panics if the `output` length does not match the result of
+    /// [`encode_len`] for the `input` length.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use data_encoding::BASE64;
+    /// # let mut buffer = vec![0; 100];
+    /// let input = b"Hello world";
+    /// let output = &mut buffer[0 .. BASE64.encode_len(input.len())];
+    /// BASE64.encode_mut(input, output);
+    /// assert_eq!(output, b"SGVsbG8gd29ybGQ=");
+    /// ```
+    ///
+    /// [`encode_len`]: struct.Encoding.html#method.encode_len
+    pub fn encode_mut(&self, input: &[u8], output: &mut [u8]) {
+        assert_eq!(output.len(), self.encode_len(input.len()));
+        dispatch! {
+            let bit: usize = self.bit();
+            let msb: bool = self.msb();
+            let pad: Option<u8> = self.pad();
+            let wrap: Option<(usize, &[u8])> = self.wrap();
+            encode_wrap_mut(bit, msb, self.sym(), pad, wrap, input, output)
+        }
+    }
+
+    /// Returns encoded `input`
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use data_encoding::BASE64;
+    /// assert_eq!(BASE64.encode(b"Hello world"), "SGVsbG8gd29ybGQ=");
+    /// ```
+    pub fn encode(&self, input: &[u8]) -> String {
+        let mut output = vec![0u8; self.encode_len(input.len())];
+        self.encode_mut(input, &mut output);
+        unsafe { String::from_utf8_unchecked(output) }
+    }
+
+    /// Returns the decoded length of an input of length `len`
+    ///
+    /// See [`decode_mut`] for when to use it.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if `len` is invalid. The error kind is [`Length`] and
+    /// the [position] is the greatest valid input length.
+    ///
+    /// [`decode_mut`]: struct.Encoding.html#method.decode_mut
+    /// [`Length`]: enum.DecodeKind.html#variant.Length
+    /// [position]: struct.DecodeError.html#structfield.position
+    pub fn decode_len(&self, len: usize) -> Result<usize, DecodeError> {
+        let (ilen, olen) = dispatch! {
+            let bit: usize = self.bit();
+            let pad: bool = self.pad().is_some();
+            decode_wrap_len(bit, pad, len)
+        };
+        check!(
+            DecodeError { position: ilen, kind: DecodeKind::Length },
+            self.has_ignore() || len == ilen
+        );
+        Ok(olen)
+    }
+
+    /// Decodes `input` in `output`
+    ///
+    /// Returns the length of the decoded output. This length may be smaller
+    /// than the output length if the input contained padding or ignored
+    /// characters. The output bytes after the returned length are not
+    /// initialized and should not be read.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the `output` length does not match the result of
+    /// [`decode_len`] for the `input` length. Also panics if `decode_len` fails
+    /// for the `input` length.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if `input` is invalid. See [`decode`] for more details.
+    /// The are two differences though:
+    ///
+    /// - [`Length`] may be returned only if the encoding allows ignored
+    /// characters, because otherwise this is already checked by [`decode_len`].
+    /// - The [`read`] first bytes of the input have been successfully decoded
+    /// to the [`written`] first bytes of the output.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use data_encoding::BASE64;
+    /// # let mut buffer = vec![0; 100];
+    /// let input = b"SGVsbA==byB3b3JsZA==";
+    /// let output = &mut buffer[0 .. BASE64.decode_len(input.len()).unwrap()];
+    /// let len = BASE64.decode_mut(input, output).unwrap();
+    /// assert_eq!(&output[0 .. len], b"Hello world");
+    /// ```
+    ///
+    /// [`decode_len`]: struct.Encoding.html#method.decode_len
+    /// [`decode`]: struct.Encoding.html#method.decode
+    /// [`Length`]: enum.DecodeKind.html#variant.Length
+    /// [`read`]: struct.DecodePartial.html#structfield.read
+    /// [`written`]: struct.DecodePartial.html#structfield.written
+    pub fn decode_mut(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodePartial> {
+        assert_eq!(Ok(output.len()), self.decode_len(input.len()));
+        dispatch! {
+            let bit: usize = self.bit();
+            let msb: bool = self.msb();
+            let pad: bool = self.pad().is_some();
+            let has_ignore: bool = self.has_ignore();
+            decode_wrap_mut(bit, msb, self.ctb(), self.val(), pad, has_ignore,
+                            input, output)
+        }
+    }
+
+    /// Returns decoded `input`
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if `input` is invalid. The error kind can be:
+    ///
+    /// - [`Length`] if the input length is invalid. The [position] is the
+    /// greatest valid input length.
+    /// - [`Symbol`] if the input contains an invalid character. The [position]
+    /// is the first invalid character.
+    /// - [`Trailing`] if the input has non-zero trailing bits. This is only
+    /// possible if the encoding checks trailing bits. The [position] is the
+    /// first character containing non-zero trailing bits.
+    /// - [`Padding`] if the input has an invalid padding length. This is only
+    /// possible if the encoding uses padding. The [position] is the first
+    /// padding character of the first padding of invalid length.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use data_encoding::BASE64;
+    /// assert_eq!(BASE64.decode(b"SGVsbA==byB3b3JsZA==").unwrap(), b"Hello world");
+    /// ```
+    ///
+    /// [`Length`]: enum.DecodeKind.html#variant.Length
+    /// [`Symbol`]: enum.DecodeKind.html#variant.Symbol
+    /// [`Trailing`]: enum.DecodeKind.html#variant.Trailing
+    /// [`Padding`]: enum.DecodeKind.html#variant.Padding
+    /// [position]: struct.DecodeError.html#structfield.position
+    pub fn decode(&self, input: &[u8]) -> Result<Vec<u8>, DecodeError> {
+        let mut output = vec![0u8; self.decode_len(input.len())?];
+        let len = self.decode_mut(input, &mut output).map_err(|partial| partial.error)?;
+        output.truncate(len);
+        Ok(output)
+    }
+
+    /// Returns the bit-width
+    pub fn bit_width(&self) -> usize {
+        self.bit()
+    }
+
+    /// Returns whether the encoding is canonical
+    ///
+    /// An encoding is not canonical if one of the following conditions holds:
+    ///
+    /// - trailing bits are not checked
+    /// - padding is used
+    /// - characters are ignored
+    /// - characters are translated
+    pub fn is_canonical(&self) -> bool {
+        if !self.ctb() {
+            return false;
+        }
+        let bit = self.bit();
+        let sym = self.sym();
+        let val = self.val();
+        for i in 0 .. 256 {
+            if val[i] == INVALID {
+                continue;
+            }
+            if val[i] >= 1 << bit {
+                return false;
+            }
+            if sym[val[i] as usize] != i as u8 {
+                return false;
+            }
+        }
+        true
+    }
+
+    /// Returns the encoding specification
+    pub fn specification(&self) -> Specification {
+        let mut specification = Specification::new();
+        specification
+            .symbols
+            .push_str(std::str::from_utf8(&self.sym()[0 .. 1 << self.bit()]).unwrap());
+        specification.bit_order =
+            if self.msb() { MostSignificantFirst } else { LeastSignificantFirst };
+        specification.check_trailing_bits = self.ctb();
+        if let Some(pad) = self.pad() {
+            specification.padding = Some(pad as char);
+        }
+        for i in 0 .. 128u8 {
+            if self.val()[i as usize] != IGNORE {
+                continue;
+            }
+            specification.ignore.push(i as char);
+        }
+        if let Some((col, end)) = self.wrap() {
+            specification.wrap.width = col;
+            specification.wrap.separator = std::str::from_utf8(end).unwrap().to_owned();
+        }
+        for i in 0 .. 128u8 {
+            let canonical = if self.val()[i as usize] < 1 << self.bit() {
+                self.sym()[self.val()[i as usize] as usize]
+            } else if self.val()[i as usize] == PADDING {
+                self.pad().unwrap()
+            } else {
+                continue;
+            };
+            if i == canonical {
+                continue;
+            }
+            specification.translate.from.push(i as char);
+            specification.translate.to.push(canonical as char);
+        }
+        specification
+    }
+
+    #[doc(hidden)]
+    pub fn internal_new(implementation: &'static [u8]) -> Encoding {
+        Encoding(std::borrow::Cow::Borrowed(implementation))
+    }
+
+    #[doc(hidden)]
+    pub fn internal_implementation(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+enum SpecificationErrorImpl {
+    BadSize,
+    NotAscii,
+    Duplicate(u8),
+    ExtraPadding,
+    WrapLength,
+    WrapWidth(u8),
+    FromTo,
+    Undefined(u8),
+}
+use crate::SpecificationErrorImpl::*;
+
+/// Specification error
+#[derive(Debug, Copy, Clone)]
+pub struct SpecificationError(SpecificationErrorImpl);
+
+impl std::fmt::Display for SpecificationError {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match self.0 {
+            BadSize => write!(f, "invalid number of symbols"),
+            NotAscii => write!(f, "non-ascii character"),
+            Duplicate(c) => write!(f, "{:?} has conflicting definitions", c as char),
+            ExtraPadding => write!(f, "unnecessary padding"),
+            WrapLength => write!(f, "invalid wrap width or separator length"),
+            WrapWidth(x) => write!(f, "wrap width not a multiple of {}", x),
+            FromTo => write!(f, "translate from/to length mismatch"),
+            Undefined(c) => write!(f, "{:?} is undefined", c as char),
+        }
+    }
+}
+
+impl std::error::Error for SpecificationError {
+    fn description(&self) -> &str {
+        match self.0 {
+            BadSize => "invalid number of symbols",
+            NotAscii => "non-ascii character",
+            Duplicate(_) => "conflicting definitions",
+            ExtraPadding => "unnecessary padding",
+            WrapLength => "invalid wrap width or separator length",
+            WrapWidth(_) => "wrap width not a multiple",
+            FromTo => "translate from/to length mismatch",
+            Undefined(_) => "undefined character",
+        }
+    }
+}
+
+impl Specification {
+    /// Returns the specified encoding
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the specification is invalid.
+    pub fn encoding(&self) -> Result<Encoding, SpecificationError> {
+        let symbols = self.symbols.as_bytes();
+        let bit: usize = match symbols.len() {
+            2 => 1,
+            4 => 2,
+            8 => 3,
+            16 => 4,
+            32 => 5,
+            64 => 6,
+            _ => return Err(SpecificationError(BadSize)),
+        };
+        let mut values = [INVALID; 128];
+        let set = |v: &mut [u8; 128], i: u8, x: u8| {
+            check!(SpecificationError(NotAscii), i < 128);
+            if v[i as usize] == x {
+                return Ok(());
+            }
+            check!(SpecificationError(Duplicate(i)), v[i as usize] == INVALID);
+            Ok(v[i as usize] = x)
+        };
+        for v in 0 .. symbols.len() {
+            set(&mut values, symbols[v], v as u8)?;
+        }
+        let msb = self.bit_order == MostSignificantFirst;
+        let ctb = self.check_trailing_bits || 8 % bit == 0;
+        let pad = match self.padding {
+            None => None,
+            Some(pad) => {
+                check!(SpecificationError(ExtraPadding), 8 % bit != 0);
+                check!(SpecificationError(NotAscii), pad.len_utf8() == 1);
+                set(&mut values, pad as u8, PADDING)?;
+                Some(pad as u8)
+            }
+        };
+        for i in self.ignore.bytes() {
+            set(&mut values, i, IGNORE)?;
+        }
+        let wrap = if self.wrap.separator.is_empty() || self.wrap.width == 0 {
+            None
+        } else {
+            Some((self.wrap.width, self.wrap.separator.as_bytes()))
+        };
+        if let Some((col, end)) = wrap {
+            check!(SpecificationError(WrapLength), col < 256 && end.len() < 256);
+            check!(SpecificationError(WrapWidth(dec(bit) as u8)), col % dec(bit) == 0);
+            for i in end.iter() {
+                set(&mut values, *i, IGNORE)?;
+            }
+        }
+        let from = self.translate.from.as_bytes();
+        let to = self.translate.to.as_bytes();
+        check!(SpecificationError(FromTo), from.len() == to.len());
+        for i in 0 .. from.len() {
+            check!(SpecificationError(NotAscii), to[i] < 128);
+            let v = values[to[i] as usize];
+            check!(SpecificationError(Undefined(to[i])), v != INVALID);
+            set(&mut values, from[i], v)?;
+        }
+        let mut encoding = Vec::new();
+        for _ in 0 .. 256 / symbols.len() {
+            encoding.extend_from_slice(symbols);
+        }
+        encoding.extend_from_slice(&values);
+        encoding.extend_from_slice(&[INVALID; 128]);
+        match pad {
+            None => encoding.push(INVALID),
+            Some(pad) => encoding.push(pad),
+        }
+        encoding.push(bit as u8);
+        if msb {
+            encoding[513] |= 0x08;
+        }
+        if ctb {
+            encoding[513] |= 0x10;
+        }
+        if let Some((col, end)) = wrap {
+            encoding.push(col as u8);
+            encoding.extend_from_slice(end);
+        } else if values.contains(&IGNORE) {
+            encoding.push(0);
+        }
+        Ok(Encoding(std::borrow::Cow::Owned(encoding)))
+    }
+}
+
+/// Lowercase hexadecimal encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, HEXLOWER};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789abcdef");
+/// assert_eq!(HEXLOWER, spec.encoding().unwrap());
+/// ```
+///
+/// # Examples
+///
+/// ```rust
+/// use data_encoding::HEXLOWER;
+/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
+/// assert_eq!(HEXLOWER.decode(b"deadbeef").unwrap(), deadbeef);
+/// assert_eq!(HEXLOWER.encode(&deadbeef), "deadbeef");
+/// ```
+pub const HEXLOWER: Encoding = HEXLOWER_IMPL;
+const HEXLOWER_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54,
+    55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
+    101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
+    52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
+    98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
+    49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
+    101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
+    52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
+    98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
+    49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 97, 98, 99, 100, 101, 102, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 1, 2,
+    3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
+]));
+
+/// Lowercase hexadecimal encoding with case-insensitive decoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, HEXLOWER_PERMISSIVE};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789abcdef");
+/// spec.translate.from.push_str("ABCDEF");
+/// spec.translate.to.push_str("abcdef");
+/// assert_eq!(HEXLOWER_PERMISSIVE, spec.encoding().unwrap());
+/// ```
+///
+/// # Examples
+///
+/// ```rust
+/// use data_encoding::HEXLOWER_PERMISSIVE;
+/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
+/// assert_eq!(HEXLOWER_PERMISSIVE.decode(b"DeadBeef").unwrap(), deadbeef);
+/// assert_eq!(HEXLOWER_PERMISSIVE.encode(&deadbeef), "deadbeef");
+/// ```
+///
+/// You can also define a shorter name:
+///
+/// ```rust
+/// use data_encoding::{Encoding, HEXLOWER_PERMISSIVE};
+/// const HEX: Encoding = HEXLOWER_PERMISSIVE;
+/// ```
+pub const HEXLOWER_PERMISSIVE: Encoding = HEXLOWER_PERMISSIVE_IMPL;
+const HEXLOWER_PERMISSIVE_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54,
+    55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
+    101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
+    52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
+    98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
+    49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
+    101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
+    52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
+    98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
+    49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 97, 98, 99, 100, 101, 102, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 1, 2,
+    3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
+]));
+
+/// Uppercase hexadecimal encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, HEXUPPER};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789ABCDEF");
+/// assert_eq!(HEXUPPER, spec.encoding().unwrap());
+/// ```
+///
+/// It is compliant with [RFC4648] and known as "base16" or "hex".
+///
+/// # Examples
+///
+/// ```rust
+/// use data_encoding::HEXUPPER;
+/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
+/// assert_eq!(HEXUPPER.decode(b"DEADBEEF").unwrap(), deadbeef);
+/// assert_eq!(HEXUPPER.encode(&deadbeef), "DEADBEEF");
+/// ```
+///
+/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-8
+pub const HEXUPPER: Encoding = HEXUPPER_IMPL;
+const HEXUPPER_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11,
+    12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
+]));
+
+/// Uppercase hexadecimal encoding with case-insensitive decoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, HEXUPPER_PERMISSIVE};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789ABCDEF");
+/// spec.translate.from.push_str("abcdef");
+/// spec.translate.to.push_str("ABCDEF");
+/// assert_eq!(HEXUPPER_PERMISSIVE, spec.encoding().unwrap());
+/// ```
+///
+/// # Examples
+///
+/// ```rust
+/// use data_encoding::HEXUPPER_PERMISSIVE;
+/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
+/// assert_eq!(HEXUPPER_PERMISSIVE.decode(b"DeadBeef").unwrap(), deadbeef);
+/// assert_eq!(HEXUPPER_PERMISSIVE.encode(&deadbeef), "DEADBEEF");
+/// ```
+pub const HEXUPPER_PERMISSIVE: Encoding = HEXUPPER_PERMISSIVE_IMPL;
+const HEXUPPER_PERMISSIVE_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11,
+    12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
+]));
+
+/// Padded base32 encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE32};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
+/// spec.padding = Some('=');
+/// assert_eq!(BASE32, spec.encoding().unwrap());
+/// ```
+///
+/// It is conform to [RFC4648].
+///
+/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-6
+pub const BASE32: Encoding = BASE32_IMPL;
+const BASE32_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+    81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+    81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+    81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 26, 27, 28, 29, 30, 31, 128, 128, 128, 128, 128, 130, 128, 128,
+    128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61, 29,
+]));
+
+/// Unpadded base32 encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE32_NOPAD};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
+/// assert_eq!(BASE32_NOPAD, spec.encoding().unwrap());
+/// ```
+pub const BASE32_NOPAD: Encoding = BASE32_NOPAD_IMPL;
+const BASE32_NOPAD_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+    81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+    81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+    81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 26, 27, 28, 29, 30, 31, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 29,
+]));
+
+/// Padded base32hex encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE32HEX};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789ABCDEFGHIJKLMNOPQRSTUV");
+/// spec.padding = Some('=');
+/// assert_eq!(BASE32HEX, spec.encoding().unwrap());
+/// ```
+///
+/// It is conform to [RFC4648].
+///
+/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-7
+pub const BASE32HEX: Encoding = BASE32HEX_IMPL;
+const BASE32HEX_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 130, 128, 128, 128, 10, 11,
+    12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61, 29,
+]));
+
+/// Unpadded base32hex encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE32HEX_NOPAD};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789ABCDEFGHIJKLMNOPQRSTUV");
+/// assert_eq!(BASE32HEX_NOPAD, spec.encoding().unwrap());
+/// ```
+pub const BASE32HEX_NOPAD: Encoding = BASE32HEX_NOPAD_IMPL;
+const BASE32HEX_NOPAD_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
+    71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11,
+    12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 29,
+]));
+
+/// DNSSEC base32 encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE32_DNSSEC};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789abcdefghijklmnopqrstuv");
+/// spec.translate.from.push_str("ABCDEFGHIJKLMNOPQRSTUV");
+/// spec.translate.to.push_str("abcdefghijklmnopqrstuv");
+/// assert_eq!(BASE32_DNSSEC, spec.encoding().unwrap());
+/// ```
+///
+/// It is conform to [RFC5155]:
+///
+/// - It uses a base32 extended hex alphabet.
+/// - It is case-insensitive when decoding and uses lowercase when encoding.
+/// - It does not use padding.
+///
+/// [RFC5155]: https://tools.ietf.org/html/rfc5155
+pub const BASE32_DNSSEC: Encoding = BASE32_DNSSEC_IMPL;
+const BASE32_DNSSEC_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+    108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104,
+    105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 48, 49, 50, 51, 52, 53,
+    54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+    113, 114, 115, 116, 117, 118, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101,
+    102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 48, 49,
+    50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+    110, 111, 112, 113, 114, 115, 116, 117, 118, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98,
+    99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+    118, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
+    107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11, 12, 13,
+    14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+    26, 27, 28, 29, 30, 31, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 29,
+]));
+
+/// DNSCurve base32 encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{BitOrder, Specification, BASE32_DNSCURVE};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("0123456789bcdfghjklmnpqrstuvwxyz");
+/// spec.bit_order = BitOrder::LeastSignificantFirst;
+/// spec.translate.from.push_str("BCDFGHJKLMNPQRSTUVWXYZ");
+/// spec.translate.to.push_str("bcdfghjklmnpqrstuvwxyz");
+/// assert_eq!(BASE32_DNSCURVE, spec.encoding().unwrap());
+/// ```
+///
+/// It is conform to [DNSCurve].
+///
+/// [DNSCurve]: https://dnscurve.org/in-implement.html
+pub const BASE32_DNSCURVE: Encoding = BASE32_DNSCURVE_IMPL;
+const BASE32_DNSCURVE_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 98, 99, 100, 102, 103, 104, 106, 107, 108, 109, 110,
+    112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+    98, 99, 100, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119,
+    120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 98, 99, 100, 102, 103, 104, 106, 107,
+    108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53,
+    54, 55, 56, 57, 98, 99, 100, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116,
+    117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 98, 99, 100, 102, 103,
+    104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49,
+    50, 51, 52, 53, 54, 55, 56, 57, 98, 99, 100, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113,
+    114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 98, 99,
+    100, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+    122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 98, 99, 100, 102, 103, 104, 106, 107, 108, 109,
+    110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 128, 10, 11,
+    12, 128, 13, 14, 15, 128, 16, 17, 18, 19, 20, 128, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+    128, 128, 128, 128, 128, 128, 128, 10, 11, 12, 128, 13, 14, 15, 128, 16, 17, 18, 19, 20, 128,
+    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 21,
+]));
+
+/// Padded base64 encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE64};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+/// spec.padding = Some('=');
+/// assert_eq!(BASE64, spec.encoding().unwrap());
+/// ```
+///
+/// It is conform to [RFC4648].
+///
+/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-4
+pub const BASE64: Encoding = BASE64_IMPL;
+const BASE64_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+    115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66,
+    67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66, 67,
+    68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97,
+    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+    117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66, 67, 68,
+    69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98,
+    99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+    118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 62, 128, 128, 128, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 130, 128,
+    128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 128, 128, 128, 128, 128, 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61, 30,
+]));
+
+/// Unpadded base64 encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE64_NOPAD};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+/// assert_eq!(BASE64_NOPAD, spec.encoding().unwrap());
+/// ```
+pub const BASE64_NOPAD: Encoding = BASE64_NOPAD_IMPL;
+const BASE64_NOPAD_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+    115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66,
+    67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66, 67,
+    68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97,
+    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+    117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66, 67, 68,
+    69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98,
+    99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+    118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 62, 128, 128, 128, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 128, 128,
+    128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 128, 128, 128, 128, 128, 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 30,
+]));
+
+/// MIME base64 encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, Wrap, BASE64_MIME};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+/// spec.padding = Some('=');
+/// spec.wrap.width = 76;
+/// spec.wrap.separator.push_str("\r\n");
+/// assert_eq!(BASE64_MIME, spec.encoding().unwrap());
+/// ```
+///
+/// It is not exactly conform to [RFC2045] because it does not print the header
+/// and does not ignore all characters.
+///
+/// [RFC2045]: https://tools.ietf.org/html/rfc2045
+pub const BASE64_MIME: Encoding = BASE64_MIME_IMPL;
+const BASE64_MIME_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+    115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66,
+    67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66, 67,
+    68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97,
+    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+    117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 65, 66, 67, 68,
+    69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98,
+    99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+    118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 129, 128, 128, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 62, 128, 128, 128, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 130, 128,
+    128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 128, 128, 128, 128, 128, 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61, 30, 76, 13, 10,
+]));
+
+/// Padded base64url encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE64URL};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
+/// spec.padding = Some('=');
+/// assert_eq!(BASE64URL, spec.encoding().unwrap());
+/// ```
+///
+/// It is conform to [RFC4648].
+///
+/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-5
+pub const BASE64URL: Encoding = BASE64URL_IMPL;
+const BASE64URL_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+    115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 65, 66,
+    67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 65, 66, 67,
+    68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97,
+    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+    117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 65, 66, 67, 68,
+    69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98,
+    99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+    118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 62, 128, 128, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 130, 128,
+    128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 128, 128, 128, 128, 63, 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61, 30,
+]));
+
+/// Unpadded base64url encoding
+///
+/// This encoding is a static version of:
+///
+/// ```rust
+/// # use data_encoding::{Specification, BASE64URL_NOPAD};
+/// let mut spec = Specification::new();
+/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
+/// assert_eq!(BASE64URL_NOPAD, spec.encoding().unwrap());
+/// ```
+pub const BASE64URL_NOPAD: Encoding = BASE64URL_NOPAD_IMPL;
+const BASE64URL_NOPAD_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+    115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 65, 66,
+    67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 65, 66, 67,
+    68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97,
+    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+    117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 65, 66, 67, 68,
+    69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98,
+    99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+    118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 62, 128, 128, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 128, 128,
+    128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 128, 128, 128, 128, 63, 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 30,
+]));
diff --git a/rustc_deps/vendor/derp/.cargo-checksum.json b/rustc_deps/vendor/derp/.cargo-checksum.json
new file mode 100644
index 0000000..da9aace
--- /dev/null
+++ b/rustc_deps/vendor/derp/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"e5f1e66c0771e40d5d7bef7805825f571a48c85633bdebbe09641d2d7e61639e","LICENSE":"32fc3c69682d24616aa4ad3a3a74578e3f668e1c8031dd302200dd78ee810f40","README.md":"2aaefc159463e821e0e2469b39586e068002f39c31a32b32a8ffafe6c13e5069","src/bin/derp.rs":"766396c1297ec94a0732c807c78f87e1fdec4d63e6f676a5297bf6c7b17516ba","src/der.rs":"641919733d7a3c88b991dcc5413d51fc5173e0c5d5b79ba4fa274e1e1006c592","src/lib.rs":"79d31ad3181a1f5cafe88f13ef284ade27c6ba4da40363fa592da5c7cdcbb9d0","src/writer.rs":"89815109eb4e307b1e04e32bc9efadaf2c7ffa73f7bafff22d75a999e64debcf","tests/ed25519.pk8":"8db9bbc5ac4480f3cc645e610f7ed1d7ab69f5718cd12e275eaaeb107d704799","tests/rsa-2048.pkcs1.der":"b3aecb01a4c4e98dc42c0f1cb9de31329a29c2391d4958175d7dedc3cd1ae783"},"package":"8e686cf031aae7161f6169912b1b38049b128dff51a94789f26d54a067634bb1"}
\ No newline at end of file
diff --git a/rustc_deps/vendor/derp/Cargo.toml b/rustc_deps/vendor/derp/Cargo.toml
new file mode 100644
index 0000000..34ba379
--- /dev/null
+++ b/rustc_deps/vendor/derp/Cargo.toml
@@ -0,0 +1,46 @@
+# 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 = "derp"
+version = "0.0.11"
+authors = ["heartsucker <heartsucker@autistici.org>"]
+description = "DER Parser (and Writer)"
+homepage = "https://github.com/heartsucker/derp"
+documentation = "https://docs.rs/derp"
+readme = "README.md"
+keywords = ["der", "parser"]
+license = "ISC"
+repository = "https://github.com/heartsucker/derp"
+
+[[bin]]
+name = "derp"
+path = "./src/bin/derp.rs"
+doc = false
+required-features = ["cli"]
+[dependencies.clap]
+version = "2.23"
+optional = true
+
+[dependencies.data-encoding]
+version = "2.0.0-rc.1"
+optional = true
+
+[dependencies.pem]
+version = "0.5"
+optional = true
+
+[dependencies.untrusted]
+version = "0.6"
+
+[features]
+cli = ["clap", "data-encoding", "pem"]
diff --git a/rustc_deps/vendor/derp/LICENSE b/rustc_deps/vendor/derp/LICENSE
new file mode 100644
index 0000000..cfd0cb5
--- /dev/null
+++ b/rustc_deps/vendor/derp/LICENSE
@@ -0,0 +1,16 @@
+ISC License (ISC)
+
+Copyright 2015-2016 Brian Smith.
+Copyright 2017 heartsucker
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/rustc_deps/vendor/derp/README.md b/rustc_deps/vendor/derp/README.md
new file mode 100644
index 0000000..1f17eee
--- /dev/null
+++ b/rustc_deps/vendor/derp/README.md
@@ -0,0 +1,14 @@
+# derp
+
+`derp` is **DER P**arser.
+
+`derp` doesn't panic. `derp` is minimal.
+
+## Credit
+
+A significant portion of `derp` was pulled from the crypto library `ring` by **@briansmith**.
+If you like this lib, thank him.
+
+## License
+
+This work is licensed under the ISC license. See [LICENSE](./LICENSE).
diff --git a/rustc_deps/vendor/derp/src/bin/derp.rs b/rustc_deps/vendor/derp/src/bin/derp.rs
new file mode 100644
index 0000000..6624db3
--- /dev/null
+++ b/rustc_deps/vendor/derp/src/bin/derp.rs
@@ -0,0 +1,121 @@
+extern crate clap;
+extern crate data_encoding;
+extern crate derp;
+extern crate pem;
+extern crate untrusted;
+
+use clap::{App, Arg, ArgMatches};
+use derp::{Result, Error, Tag};
+use std::fs::File;
+use std::io::Read;
+use untrusted::{Input, Reader};
+
+fn main() {
+    let matches = parser().get_matches();
+    match run_main(matches) {
+        Ok(s) => {
+            println!("{}", s.trim());
+            std::process::exit(0)
+        }
+        Err(e) => {
+            println!("Error: {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run_main(matches: ArgMatches) -> Result<String> {
+    let mut file = File::open(matches.value_of("path").unwrap())?;
+    let mut buf = Vec::new();
+    file.read_to_end(&mut buf)?;
+    let buf = parse_to_bytes(&buf);
+    let input = Input::from(&buf);
+    Ok(input.read_all(Error::Read, make_printable_string)?)
+}
+
+fn parser<'a, 'b>() -> App<'a, 'b> {
+    App::new("derp")
+        .version(env!("CARGO_PKG_VERSION"))
+        .about("CLI tool for parsing and displaying DER")
+        .arg(
+            Arg::with_name("path")
+                .takes_value(true)
+                .required(true)
+                .help("The path to the file")
+        )
+}
+
+fn parse_to_bytes(bytes: &[u8]) -> Vec<u8> {
+    data_encoding::BASE64.decode(bytes)
+        .map_err(|_| ())
+        .or_else(|_| {
+            data_encoding::HEXUPPER.decode(bytes)
+                .map_err(|_| ())
+        })
+        .or_else(|_| {
+            data_encoding::HEXLOWER.decode(bytes)
+                .map_err(|_| ())
+        })
+        .or_else(|_| {
+            pem::parse(bytes)
+                .map(|p| p.contents)
+                .map_err(|_| ())
+        })
+        .unwrap_or_else(|_| bytes.to_vec())
+}
+
+fn make_printable_string<'a>(input: &mut Reader<'a>) -> Result<String> {
+    if input.at_end() {
+        return Ok("".into())
+    }
+
+    if input.peek(Tag::Sequence as u8) {
+        let out = derp::nested(input, Tag::Sequence, make_printable_string)?
+            .lines()
+            .map(|l| format!("  {}\n", l))
+            .collect::<String>();
+        return Ok(format!("{}\n{}", Tag::Sequence, out))
+    }
+
+    if input.peek(Tag::BitString as u8) {
+        let out = derp::nested(input, Tag::BitString, make_printable_string)
+            .map(|s| {
+                s.lines()
+                    .map(|l| format!("  {}\n", l))
+                    .collect::<String>()
+            })
+            .unwrap_or_else(|_| "".into());
+        return Ok(format!("{}\n{}", Tag::BitString, out))
+    }
+
+    if input.peek(Tag::OctetString as u8) {
+        let out = derp::nested(input, Tag::OctetString, make_printable_string)
+            .map(|s| {
+                s.lines()
+                    .map(|l| format!("  {}\n", l))
+                    .collect::<String>()
+            })
+            .unwrap_or_else(|_| "".into());
+        return Ok(format!("{}\n{}", Tag::OctetString, out))
+    }
+
+    let mut out = String::new();
+    while let Ok((tag, _)) = derp::read_tag_and_get_value(input) {
+        out.push_str(&format!("{}\n", Tag::from_byte(tag).map(|t| format!("{}", t)).unwrap_or_else(|_| format!("0x{:x}", tag))))
+    }
+    Ok(out)
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    const ED25519_PK8: &[u8] = include_bytes!("../../tests/ed25519.pk8");
+
+    #[test]
+    fn parse_ed25519_pk8() {
+        let input = parse_to_bytes(ED25519_PK8);
+        let input = Input::from(&input);
+        input.read_all(Error::Read, make_printable_string).unwrap();
+    }
+}
diff --git a/rustc_deps/vendor/derp/src/der.rs b/rustc_deps/vendor/derp/src/der.rs
new file mode 100644
index 0000000..ee4b87a
--- /dev/null
+++ b/rustc_deps/vendor/derp/src/der.rs
@@ -0,0 +1,430 @@
+// Copyright 2015 Brian Smith.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+//! Building blocks for parsing DER-encoded ASN.1 structures.
+//!
+//! This module contains the foundational parts of an ASN.1 DER parser.
+
+#[cfg(feature = "cli")]
+use std::fmt::{self, Display, Formatter};
+use untrusted::{Reader, Input};
+
+use {Error, Result};
+
+const CONSTRUCTED: u8 = 1 << 5;
+const CONTEXT_SPECIFIC: u8 = 2 << 6;
+
+/// ASN.1 Tags
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[repr(u8)]
+pub enum Tag {
+    Eoc = 0x00,
+    Boolean = 0x01,
+    Integer = 0x02,
+    BitString = 0x03,
+    OctetString = 0x04,
+    Null = 0x05,
+    Oid = 0x06,
+    Sequence = CONSTRUCTED | 0x10, // 0x30
+    UtcTime = 0x17,
+    GeneralizedTime = 0x18,
+    ContextSpecificConstructed0 = CONTEXT_SPECIFIC | CONSTRUCTED | 0,
+    ContextSpecificConstructed1 = CONTEXT_SPECIFIC | CONSTRUCTED | 1,
+    ContextSpecificConstructed2 = CONTEXT_SPECIFIC | CONSTRUCTED | 2,
+    ContextSpecificConstructed3 = CONTEXT_SPECIFIC | CONSTRUCTED | 3,
+}
+
+#[cfg(feature = "cli")]
+impl Display for Tag {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        let s = match *self {
+            Tag::Eoc => "EOC",
+            Tag::Boolean => "BOOLEAN",
+            Tag::Integer => "INTEGER",
+            Tag::BitString => "BIT STRING",
+            Tag::OctetString => "OCTET STRING",
+            Tag::Null => "NULL",
+            Tag::Oid => "OBJECT IDENTIFIER",
+            Tag::Sequence => "SEQUENCE",
+            Tag::UtcTime => "UTC TIME",
+            Tag::GeneralizedTime => "GENERALIZED TIME",
+            Tag::ContextSpecificConstructed0 => "CONTEXT SPECIFIC CONSTRUCTED 0",
+            Tag::ContextSpecificConstructed1 => "CONTEXT SPECIFIC CONSTRUCTED 1",
+            Tag::ContextSpecificConstructed2 => "CONTEXT SPECIFIC CONSTRUCTED 2",
+            Tag::ContextSpecificConstructed3 => "CONTEXT SPECIFIC CONSTRUCTED 3",
+        };
+        write!(f, "{}", s)
+    }
+}
+
+#[cfg(feature = "cli")]
+impl Tag {
+    pub fn from_byte(byte: u8) -> Result<Self> {
+        match byte {
+            x if x == Tag::Eoc as u8 => Ok(Tag::Eoc),
+            x if x == Tag::Boolean as u8 => Ok(Tag::Boolean),
+            x if x == Tag::Integer as u8 => Ok(Tag::Integer),
+            x if x == Tag::BitString as u8 => Ok(Tag::BitString),
+            x if x == Tag::OctetString as u8 => Ok(Tag::OctetString),
+            x if x == Tag::Null as u8 => Ok(Tag::Null),
+            x if x == Tag::Oid as u8 => Ok(Tag::Oid),
+            x if x == Tag::Sequence as u8 => Ok(Tag::Sequence),
+            x if x == Tag::UtcTime as u8 => Ok(Tag::UtcTime),
+            x if x == Tag::GeneralizedTime as u8 => Ok(Tag::GeneralizedTime),
+            x if x == Tag::ContextSpecificConstructed0 as u8 => Ok(Tag::ContextSpecificConstructed0),
+            x if x == Tag::ContextSpecificConstructed1 as u8 => Ok(Tag::ContextSpecificConstructed1),
+            x if x == Tag::ContextSpecificConstructed2 as u8 => Ok(Tag::ContextSpecificConstructed2),
+            x if x == Tag::ContextSpecificConstructed3 as u8 => Ok(Tag::ContextSpecificConstructed3),
+            _ => Err(Error::UnknownTag)
+        }
+    }
+}
+
+
+/// Read a tag and return it's value. Errors when the expect and actual tag do not match.
+pub fn expect_tag_and_get_value<'a>(
+    input: &mut Reader<'a>,
+    tag: Tag,
+) -> Result<Input<'a>> {
+    let (actual_tag, inner) = read_tag_and_get_value(input)?;
+    if tag as u8 != actual_tag {
+        return Err(Error::WrongTag);
+    }
+    Ok(inner)
+}
+
+/// Read the next tag, and return it and its value.
+pub fn read_tag_and_get_value<'a>(
+    input: &mut Reader<'a>,
+) -> Result<(u8, Input<'a>)> {
+    let tag = input.read_byte()?;
+    if (tag & 0x1F) == 0x1F {
+        return Err(Error::HighTagNumberForm);
+    }
+
+    // If the high order bit of the first byte is set to zero then the length
+    // is encoded in the seven remaining bits of that byte. Otherwise, those
+    // seven bits represent the number of bytes used to encode the length.
+    let length = match input.read_byte()? {
+        n if (n & 0x80) == 0 => n as usize,
+        0x81 => {
+            let second_byte = input.read_byte()?;
+            if second_byte < 128 {
+                return Err(Error::NonCanonical);
+            }
+            second_byte as usize
+        }
+        0x82 => {
+            let second_byte = input.read_byte()? as usize;
+            let third_byte = input.read_byte()? as usize;
+            let combined = (second_byte << 8) | third_byte;
+            if combined < 256 {
+                return Err(Error::NonCanonical);
+            }
+            combined
+        }
+        _ => return Err(Error::LongLengthNotSupported),
+    };
+
+    let inner = input.skip_and_get_input(length)?;
+    Ok((tag, inner))
+}
+
+pub fn read_null<'a>(input: &mut Reader<'a>) -> Result<()> {
+    expect_tag_and_get_value(input, Tag::Null)
+        .map(|_| ())
+}
+
+/// Read a `BIT STRING` with leading byte `0x00` signifying no unused bits.
+///
+/// ```
+/// extern crate derp;
+/// extern crate untrusted;
+///
+/// use untrusted::Input;
+///
+/// const BIT_STRING: &'static [u8] = &[0x03, 0x04, 0x00, 0x01, 0x02, 0x03];
+///
+/// fn main() {
+///     let input = Input::from(BIT_STRING);
+///     let bits = input.read_all(derp::Error::Read, |input| {
+///         derp::bit_string_with_no_unused_bits(input)
+///     }).unwrap();
+///     assert_eq!(bits, Input::from(&[0x01, 0x02, 0x03]));
+/// }
+/// ```
+pub fn bit_string_with_no_unused_bits<'a>(
+    input: &mut Reader<'a>,
+) -> Result<Input<'a>> {
+    nested(input, Tag::BitString, |value| {
+        let unused_bits_at_end = value.read_byte()?;
+        if unused_bits_at_end != 0 {
+            return Err(Error::NonZeroUnusedBits);
+        }
+        Ok(value.skip_to_end())
+    })
+}
+
+/// Return the value of the given tag and apply a decoding function to it.
+///
+/// ```
+/// extern crate derp;
+/// extern crate untrusted;
+///
+/// use derp::Tag;
+/// use untrusted::Input;
+///
+/// const NESTED: &'static [u8] = &[
+///     0x30, 0x14,                                 // seq
+///         0x30, 0x0c,                             // seq
+///             0x02, 0x04, 0x0a, 0x0b, 0x0c, 0x0d, // x
+///             0x02, 0x04, 0x1a, 0x1b, 0x1c, 0x1d, // y
+///         0x02, 0x04, 0x01, 0x02, 0x03, 0x04,     // z
+/// ];
+/// fn main () {
+///     let input = Input::from(NESTED);
+///     let (x, y, z) = input.read_all(derp::Error::Read, |input| {
+///         derp::nested(input, Tag::Sequence, |input| {
+///             let (x, y) = derp::nested(input, Tag::Sequence, |input| {
+///                 let x = derp::positive_integer(input)?;
+///                 let y = derp::positive_integer(input)?;
+///                 Ok((x, y))
+///             })?;
+///             let z = derp::positive_integer(input)?;
+///             Ok((x, y, z))
+///         })
+///     }).unwrap();
+///
+///     assert_eq!(x, Input::from(&[0x0a, 0x0b, 0x0c, 0x0d]));
+///     assert_eq!(y, Input::from(&[0x1a, 0x1b, 0x1c, 0x1d]));
+///     assert_eq!(z, Input::from(&[0x01, 0x02, 0x03, 0x04]));
+/// }
+/// ```
+// TODO: investigate taking decoder as a reference to reduce generated code
+// size.
+pub fn nested<'a, F, R>(input: &mut Reader<'a>, tag: Tag, decoder: F) -> Result<R>
+where
+    F: FnOnce(&mut Reader<'a>) -> Result<R>,
+{
+    let inner = expect_tag_and_get_value(input, tag)?;
+    inner.read_all(Error::Read, decoder)
+}
+
+/// Return a non-negative integer.
+pub fn nonnegative_integer<'a>(
+    input: &mut Reader<'a>,
+    min_value: u8,
+) -> Result<Input<'a>> {
+    // Verify that |input|, which has had any leading zero stripped off, is the
+    // encoding of a value of at least |min_value|.
+    fn check_minimum(input: Input, min_value: u8) -> Result<()> {
+        input.read_all(Error::Read, |input| {
+            let first_byte = input.read_byte()?;
+            if input.at_end() && first_byte < min_value {
+                return Err(Error::LessThanMinimum);
+            }
+            let _ = input.skip_to_end();
+            Ok(())
+        })
+    }
+
+    let value = expect_tag_and_get_value(input, Tag::Integer)?;
+
+    value.read_all(Error::Read, |input| {
+        // Empty encodings are not allowed.
+        let first_byte = input.read_byte()?;
+
+        if first_byte == 0 {
+            if input.at_end() {
+                // |value| is the legal encoding of zero.
+                if min_value > 0 {
+                    return Err(Error::LessThanMinimum);
+                }
+                return Ok(value);
+            }
+
+            let r = input.skip_to_end();
+            r.read_all(Error::Read, |input| {
+                let second_byte = input.read_byte()?;
+                if (second_byte & 0x80) == 0 {
+                    // A leading zero is only allowed when the value's high bit
+                    // is set.
+                    return Err(Error::LeadingZero);
+                }
+                let _ = input.skip_to_end();
+                Ok(())
+            })?;
+            check_minimum(r, min_value)?;
+            return Ok(r);
+        }
+
+        // Negative values are not allowed.
+        if (first_byte & 0x80) != 0 {
+            return Err(Error::NegativeValue);
+        }
+
+        let _ = input.skip_to_end();
+        check_minimum(value, min_value)?;
+        Ok(value)
+    })
+}
+
+/// Parse as integer with a value in the in the range [0, 255], returning its
+/// numeric value. This is typically used for parsing version numbers.
+#[inline]
+pub fn small_nonnegative_integer(input: &mut Reader) -> Result<u8> {
+    let value = nonnegative_integer(input, 0)?;
+    value.read_all(Error::Read, |input| {
+        let r = input.read_byte()?;
+        Ok(r)
+    })
+}
+
+/// Parses a positive DER integer, returning the big-endian-encoded value, sans
+/// any leading zero byte.
+#[inline]
+pub fn positive_integer<'a>(input: &mut Reader<'a>) -> Result<Input<'a>> {
+    nonnegative_integer(input, 1)
+}
+
+/// Parse a boolean value.
+#[inline]
+pub fn boolean<'a>(input: &mut Reader<'a>) -> Result<bool> {
+    let value = expect_tag_and_get_value(input, Tag::Boolean)?;
+    match value.as_slice_less_safe() {
+        x if x == &[0x00] => Ok(false),
+        x if x == &[0x01] => Ok(true),
+        _ => Err(Error::BadBooleanValue),
+    }
+}
+
+/// For a given length, how many bytes are required to represent it in DER form.
+pub fn length_of_length(len: usize) -> u8 {
+    let mut i = len;
+    let mut num_bytes = 1;
+
+    while i > 255 {
+        num_bytes += 1;
+        i >>= 8;
+    }
+
+    num_bytes
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn with_good_i<F, R>(value: &[u8], f: F)
+    where
+        F: FnOnce(&mut Reader) -> Result<R>,
+    {
+        let r = Input::from(value).read_all(Error::Read, f);
+        assert!(r.is_ok());
+    }
+
+    fn with_bad_i<F, R>(value: &[u8], f: F)
+    where
+        F: FnOnce(&mut Reader) -> Result<R>,
+    {
+        let r = Input::from(value).read_all(Error::Read, f);
+        assert!(r.is_err());
+    }
+
+    static ZERO_INTEGER: &'static [u8] = &[0x02, 0x01, 0x00];
+
+    static GOOD_POSITIVE_INTEGERS: &'static [(&'static [u8], u8)] =
+        &[
+            (&[0x02, 0x01, 0x01], 0x01),
+            (&[0x02, 0x01, 0x02], 0x02),
+            (&[0x02, 0x01, 0x7e], 0x7e),
+            (&[0x02, 0x01, 0x7f], 0x7f),
+
+            // Values that need to have an 0x00 prefix to disambiguate them from
+            // them from negative values.
+            (&[0x02, 0x02, 0x00, 0x80], 0x80),
+            (&[0x02, 0x02, 0x00, 0x81], 0x81),
+            (&[0x02, 0x02, 0x00, 0xfe], 0xfe),
+            (&[0x02, 0x02, 0x00, 0xff], 0xff),
+        ];
+
+    static BAD_NONNEGATIVE_INTEGERS: &'static [&'static [u8]] = &[
+        &[], // At end of input
+        &[0x02], // Tag only
+        &[0x02, 0x00], // Empty value
+
+        // Length mismatch
+        &[0x02, 0x00, 0x01],
+        &[0x02, 0x01],
+        &[0x02, 0x01, 0x00, 0x01],
+        &[0x02, 0x01, 0x01, 0x00], // Would be valid if last byte is ignored.
+        &[0x02, 0x02, 0x01],
+
+        // Negative values
+        &[0x02, 0x01, 0x80],
+        &[0x02, 0x01, 0xfe],
+        &[0x02, 0x01, 0xff],
+
+        // Values that have an unnecessary leading 0x00
+        &[0x02, 0x02, 0x00, 0x00],
+        &[0x02, 0x02, 0x00, 0x01],
+        &[0x02, 0x02, 0x00, 0x02],
+        &[0x02, 0x02, 0x00, 0x7e],
+        &[0x02, 0x02, 0x00, 0x7f],
+    ];
+
+    #[test]
+    fn test_small_nonnegative_integer() {
+        with_good_i(ZERO_INTEGER, |input| {
+            assert_eq!(small_nonnegative_integer(input)?, 0x00);
+            Ok(())
+        });
+        for &(ref test_in, test_out) in GOOD_POSITIVE_INTEGERS.iter() {
+            with_good_i(test_in, |input| {
+                assert_eq!(small_nonnegative_integer(input)?, test_out);
+                Ok(())
+            });
+        }
+        for &test_in in BAD_NONNEGATIVE_INTEGERS.iter() {
+            with_bad_i(test_in, |input| {
+                let _ = small_nonnegative_integer(input)?;
+                Ok(())
+            });
+        }
+    }
+
+    #[test]
+    fn test_positive_integer() {
+        with_bad_i(ZERO_INTEGER, |input| {
+            let _ = positive_integer(input)?;
+            Ok(())
+        });
+        for &(ref test_in, test_out) in GOOD_POSITIVE_INTEGERS.iter() {
+            with_good_i(test_in, |input| {
+                let test_out = [test_out];
+                assert_eq!(
+                    positive_integer(input)?,
+                    Input::from(&test_out[..])
+                );
+                Ok(())
+            });
+        }
+        for &test_in in BAD_NONNEGATIVE_INTEGERS.iter() {
+            with_bad_i(test_in, |input| {
+                let _ = positive_integer(input)?;
+                Ok(())
+            });
+        }
+    }
+}
diff --git a/rustc_deps/vendor/derp/src/lib.rs b/rustc_deps/vendor/derp/src/lib.rs
new file mode 100644
index 0000000..9d5e70b
--- /dev/null
+++ b/rustc_deps/vendor/derp/src/lib.rs
@@ -0,0 +1,137 @@
+//! DER Parser (and Writer)
+//!
+//! ```
+//! extern crate derp;
+//! extern crate untrusted;
+//!
+//! use derp::{Tag, Der};
+//! use untrusted::Input;
+//!
+//! const MY_DATA: &'static [u8] = &[
+//!     0x30, 0x18,                                             // sequence
+//!         0x05, 0x00,                                         // null
+//!         0x30, 0x0e,                                         // sequence
+//!             0x02, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // x
+//!             0x02, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,             // y
+//!         0x03, 0x04, 0x00, 0xff, 0xff, 0xff,                 // bits
+//! ];
+//!
+//! fn main() {
+//!     let input = Input::from(MY_DATA);
+//!     let (x, y, bits) = input.read_all(derp::Error::Read, |input| {
+//!         derp::nested(input, Tag::Sequence, |input| {
+//!             derp::read_null(input)?;
+//!             let (x, y) = derp::nested(input, Tag::Sequence, |input| {
+//!                 let x = derp::positive_integer(input)?;
+//!                 let y = derp::positive_integer(input)?;
+//!                 Ok((x.as_slice_less_safe(), y.as_slice_less_safe()))
+//!             })?;
+//!             let bits = derp::bit_string_with_no_unused_bits(input)?;
+//!             Ok((x, y, bits.as_slice_less_safe()))
+//!         })
+//!     }).unwrap();
+//!
+//!     assert_eq!(x, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
+//!     assert_eq!(y, &[0x0a, 0x0b, 0x0c, 0x0d]);
+//!     assert_eq!(bits, &[0xff, 0xff, 0xff]);
+//!
+//!     let mut buf = Vec::new();
+//!     {
+//!         let mut der = Der::new(&mut buf);
+//!         der.sequence(|der| {
+//!             der.null()?;
+//!             der.sequence(|der| {
+//!                 der.integer(x)?;
+//!                 der.integer(y)
+//!             })?;
+//!             der.bit_string(0, bits)
+//!         }).unwrap();
+//!     }
+//!
+//!     assert_eq!(buf.as_slice(), MY_DATA);
+//! }
+//! ```
+extern crate untrusted;
+
+use std::fmt::{self, Display};
+
+mod der;
+mod writer;
+
+pub use der::*;
+pub use writer::*;
+
+#[derive(Debug, PartialEq, Clone, Copy)]
+pub enum Error {
+    BadBooleanValue,
+    LeadingZero,
+    LessThanMinimum,
+    LongLengthNotSupported,
+    HighTagNumberForm,
+    Io,
+    NegativeValue,
+    NonCanonical,
+    NonZeroUnusedBits,
+    Read,
+    UnexpectedEnd,
+    UnknownTag,
+    WrongTag,
+    WrongValue,
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let s = match *self {
+            Error::BadBooleanValue => "bad boolean value",
+            Error::LeadingZero => "leading zero",
+            Error::LessThanMinimum => "less than minimum",
+            Error::LongLengthNotSupported => "long length not supported",
+            Error::HighTagNumberForm => "high tag number form",
+            Error::Io => "I/O",
+            Error::NegativeValue => "negative value",
+            Error::NonCanonical => "non-canonical",
+            Error::NonZeroUnusedBits => "non-zero unused bits",
+            Error::Read => "read",
+            Error::UnexpectedEnd => "unexpected end",
+            Error::UnknownTag => "unknown tag",
+            Error::WrongTag => "wrong tag",
+            Error::WrongValue => "wrong value",
+        };
+        s.fmt(f)
+    }
+}
+impl ::std::error::Error for Error {
+    fn description(&self) -> &str {
+        match *self {
+            Error::BadBooleanValue => "bad boolean value",
+            Error::LeadingZero => "leading zero",
+            Error::LessThanMinimum => "less than minimum",
+            Error::LongLengthNotSupported => "long length not supported",
+            Error::HighTagNumberForm => "high tag number form",
+            Error::Io => "I/O",
+            Error::NegativeValue => "negative value",
+            Error::NonCanonical => "non-canonical",
+            Error::NonZeroUnusedBits => "non-zero unused bits",
+            Error::Read => "read",
+            Error::UnexpectedEnd => "unexpected end",
+            Error::UnknownTag => "unknown tag",
+            Error::WrongTag => "wrong tag",
+            Error::WrongValue => "wrong value",
+        }
+    }
+}
+
+impl From<untrusted::EndOfInput> for Error {
+    fn from(_: untrusted::EndOfInput) -> Error {
+        Error::UnexpectedEnd
+    }
+}
+
+impl From<::std::io::Error> for Error {
+    fn from(_: ::std::io::Error) -> Error {
+        Error::Io
+    }
+}
+
+/// Alias for `Result<T, Error>`
+pub type Result<T> = ::std::result::Result<T, Error>;
diff --git a/rustc_deps/vendor/derp/src/writer.rs b/rustc_deps/vendor/derp/src/writer.rs
new file mode 100644
index 0000000..f004b59
--- /dev/null
+++ b/rustc_deps/vendor/derp/src/writer.rs
@@ -0,0 +1,189 @@
+use std::io::Write;
+
+use Result;
+use der::{self, Tag};
+
+/// Helper for writing DER that automattically encoes tags and content lengths.
+pub struct Der<'a, W: Write + 'a> {
+    writer: &'a mut W,
+}
+
+impl<'a, W: Write> Der<'a, W> {
+    /// Create a new `Der` structure that writes values to the given writer.
+    pub fn new(writer: &'a mut W) -> Self {
+        Der { writer: writer }
+    }
+
+    fn write_len(&mut self, len: usize) -> Result<()> {
+        if len >= 128 {
+            let n = der::length_of_length(len);
+            self.writer.write_all(&[0x80 | n])?;
+
+            for i in (1..n + 1).rev() {
+                self.writer.write_all(&[(len >> ((i - 1) * 8)) as u8])?;
+            }
+        } else {
+            self.writer.write_all(&[len as u8])?;
+        }
+
+        Ok(())
+    }
+
+    /// Write a `NULL` tag.
+    pub fn null(&mut self) -> Result<()> {
+        Ok(self.writer.write_all(&[Tag::Null as u8, 0])?)
+    }
+
+    /// Write an arbitrary element.
+    pub fn element(&mut self, tag: Tag, input: &[u8]) -> Result<()> {
+        self.writer.write_all(&[tag as u8])?;
+        self.write_len(input.len())?;
+        self.writer.write_all(input)?;
+        Ok(())
+    }
+
+    /// Write the given input as an integer.
+    pub fn integer(&mut self, input: &[u8]) -> Result<()> {
+        self.writer.write_all(&[Tag::Integer as u8])?;
+        self.write_len(input.len())?;
+        self.writer.write_all(input)?;
+        Ok(())
+    }
+
+    /// Write the given input as a positive integer.
+    pub fn positive_integer(&mut self, input: &[u8]) -> Result<()> {
+        self.writer.write_all(&[Tag::Integer as u8])?;
+
+        let push_zero = if input.len() > 0 {
+            input[0] & 0x80 == 0x80
+        } else {
+            false
+        };
+
+        self.write_len(input.len() + push_zero as usize)?;
+        
+        if push_zero {
+            self.writer.write_all(&[0x00])?;
+        }
+
+        self.writer.write_all(input)?;
+        Ok(())
+    }
+
+    /// Write a nested structure by passing in a handling function that writes to an intermediate
+    /// `Vec` before writing the whole sequence to `self`.
+    pub fn nested<F: FnOnce(&mut Der<Vec<u8>>) -> Result<()>>(
+        &mut self,
+        tag: Tag,
+        func: F,
+    ) -> Result<()> {
+        let mut buf = Vec::new();
+
+        {
+            let mut inner = Der::new(&mut buf);
+            func(&mut inner)?;
+        }
+
+        self.writer.write_all(&[tag as u8])?;
+        self.write_len(buf.len())?;
+        Ok(self.writer.write_all(&buf)?)
+    }
+
+    /// Write a `SEQUENCE` by passing in a handling function that writes to an intermediate `Vec`
+    /// before writing the whole sequence to `self`.
+    pub fn sequence<F: FnOnce(&mut Der<Vec<u8>>) -> Result<()>>(
+        &mut self,
+        func: F,
+    ) -> Result<()> {
+        self.nested(Tag::Sequence, func)
+    }
+
+    /// Write an `OBJECT IDENTIFIER`.
+    pub fn oid(&mut self, input: &[u8]) -> Result<()> {
+        self.writer.write_all(&[Tag::Oid as u8])?;
+        self.write_len(input.len())?;
+        self.writer.write_all(&input)?;
+        Ok(())
+    }
+
+    /// Write raw bytes to `self`. This does not calculate length or apply. This should only be used
+    /// when you know you are dealing with bytes that are already DER encoded.
+    pub fn raw(&mut self, input: &[u8]) -> Result<()> {
+        Ok(self.writer.write_all(input)?)
+    }
+
+    /// Write a `BIT STRING`.
+    pub fn bit_string(
+        &mut self,
+        unused_bits: u8,
+        bit_string: &[u8],
+    ) -> Result<()> {
+        self.writer.write_all(&[Tag::BitString as u8])?;
+        self.write_len(bit_string.len() + 1)?;
+        self.writer.write_all(&[unused_bits])?;
+        self.writer.write_all(&bit_string)?;
+        Ok(())
+    }
+
+    /// Write an `OCTET STRING`.
+    pub fn octet_string(
+        &mut self,
+        octet_string: &[u8],
+    ) -> Result<()> {
+        self.writer.write_all(&[Tag::OctetString as u8])?;
+        self.write_len(octet_string.len())?;
+        self.writer.write_all(&octet_string)?;
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use Error;
+    use untrusted::Input;
+    
+    static RSA_2048_PKCS1: &'static [u8] = include_bytes!("../tests/rsa-2048.pkcs1.der");
+
+    #[test]
+    fn write_pkcs1() {
+        let input = Input::from(RSA_2048_PKCS1);
+        let (n, e) = input.read_all(Error::Read, |input| {
+            der::nested(input, Tag::Sequence, |input| {
+                let n = der::positive_integer(input)?;
+                let e = der::positive_integer(input)?;
+                Ok((n.as_slice_less_safe(), e.as_slice_less_safe()))
+            })
+        }).unwrap();
+
+        let mut buf = Vec::new();
+        {
+            let mut der = Der::new(&mut buf);
+            der.sequence(|der| {
+                der.positive_integer(n)?;
+                der.positive_integer(e)
+            }).unwrap();
+        }
+
+        assert_eq!(buf.as_slice(), RSA_2048_PKCS1);
+    }
+
+    #[test]
+    fn write_octet_string() {
+        let mut buf = Vec::new();
+        {
+            let mut der = Der::new(&mut buf);
+            der.octet_string(&[]).unwrap();
+        }
+
+        assert_eq!(&buf, &[0x04, 0x00]);
+
+        let mut buf = Vec::new();
+        {
+            let mut der = Der::new(&mut buf);
+            der.octet_string(&[0x0a, 0x0b, 0x0c]).unwrap();
+        }
+
+        assert_eq!(&buf, &[0x04, 0x03, 0x0a, 0x0b, 0x0c]);
+    }
+}
diff --git a/rustc_deps/vendor/derp/tests/ed25519.pk8 b/rustc_deps/vendor/derp/tests/ed25519.pk8
new file mode 100644
index 0000000..ea5dda6
--- /dev/null
+++ b/rustc_deps/vendor/derp/tests/ed25519.pk8
Binary files differ
diff --git a/rustc_deps/vendor/derp/tests/rsa-2048.pkcs1.der b/rustc_deps/vendor/derp/tests/rsa-2048.pkcs1.der
new file mode 100644
index 0000000..d647532
--- /dev/null
+++ b/rustc_deps/vendor/derp/tests/rsa-2048.pkcs1.der
Binary files differ
diff --git a/rustc_deps/vendor/ring/.cargo-checksum.json b/rustc_deps/vendor/ring/.cargo-checksum.json
new file mode 100644
index 0000000..80e89fc
--- /dev/null
+++ b/rustc_deps/vendor/ring/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"fd9b24803d45fe5855ac134e760b868f48ca21564ea86a29e90d2906009efaa1","LICENSE":"76b39f9b371688eac9d8323f96ee80b3aef5ecbc2217f25377bd4e4a615296a9","build.rs":"302d913c2fb91aa000d4ef903273caaed192a74eba277d797c2988397999053b","crypto/chacha/asm/chacha-armv4.pl":"4dabdd766dd25711ee6276f7415c3fd654635687aa536617eceb75a8a3ad1189","crypto/chacha/asm/chacha-armv8.pl":"7ca420290e179dc4b348d5a3bfcf78d27e374fa10c16b2533dd5339245690305","crypto/chacha/asm/chacha-x86.pl":"abbcf8181bd629d8003322dbf2592bf4631abb7895861d7021c451043e39be34","crypto/chacha/asm/chacha-x86_64.pl":"7f38c54bae872a6f6cde85cd13bf061ebcd9372a4d126f66bbe018fb7231d6a4","crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl":"c0ae9169db7e1bd9244074e9d221aea3ef56930b54925a369b66c8782e602e64","crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt":"1a0b201dd8f4aa2106db0de3c26eb0d9623394ec80247867371c20103718b1c0","crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt":"514a978594261e0520b30aac455c8a29c3280cc15701a928a0e8ad7bacfc2c79","crypto/constant_time_test.c":"a9e6346e829c35310fcbf8da8d820da1d66a2d7957704f7c020cd29898079191","crypto/cpu-aarch64-linux.c":"61cb9b03431d543488ca045b9f70d04b6a1d1fc876ab7e3613ec9b3b237baa0b","crypto/cpu-arm-linux.c":"c60eb2cf858814842624cfe7adf9f080cae99dba9decb25e35b91affbfbbe7f3","crypto/cpu-arm.c":"e7b6be5862e1f7f83568991ef2c46f05df9d6517f8ad5ce0a12fe8c8bab788c7","crypto/cpu-intel.c":"bfe154d6fe0670181634d58df0a9810e2482677e795b8780390c341d17b2bd2d","crypto/crypto.c":"bc59868b8d99ab744dda129f2d01c5150e9f0872c6d6f9b992f4a6b6b19f986a","crypto/curve25519/asm/x25519-asm-arm.S":"a6784f13e24bc8db7b3f2088722b04fd6a3382c02eaaa0d652a3ae931a465be9","crypto/fipsmodule/aes/aes.c":"a83349c801cd7145b110fa4ae52db2f3cf8f009f6124a3968c721e7b7bed97a4","crypto/fipsmodule/aes/asm/aes-586.pl":"49ad826191e7f1bda45bbaac10027343cabf56443c5e3bec869c6e1c37e105fa","crypto/fipsmodule/aes/asm/aes-armv4.pl":"4e845e40ef5e1cf7153c9b1d0a6e75b192f9255ddfa53f4aadee3362700d954b","crypto/fipsmodule/aes/asm/aes-x86_64.pl":"52e0ce0725f41ddf9ba4220d5ef3f4c5ef9c835c90d9e998bd5f7e957d7f025b","crypto/fipsmodule/aes/asm/aesni-x86.pl":"5c1ae42c253f05b8d76af696ecced2a6bce6750e66bdd0e4cfa3cc1102dd5c25","crypto/fipsmodule/aes/asm/aesni-x86_64.pl":"97b0a0d9ddac8b972b5fb98e0fd564eb68b3b50dc31180d1af1d6599685d004c","crypto/fipsmodule/aes/asm/aesv8-armx.pl":"6794d9fb90b3fe183e457a425596d7e57600f937d7435d5075894cfb7fc3bd77","crypto/fipsmodule/aes/asm/bsaes-armv7.pl":"8a569dfcc42bc4dd2252de088793a3b55c020d5166459df8f4eb779f1e414db7","crypto/fipsmodule/aes/asm/vpaes-x86.pl":"7672ae209b0eb33d0d6856f46c46066a07db4c6534cb678cc2bf329b040575b9","crypto/fipsmodule/aes/asm/vpaes-x86_64.pl":"383e964a9188bfbbdb5f0b53d74c5493ef234194c1eb1b7e2f63504bb3974c9e","crypto/fipsmodule/aes/internal.h":"5091399344bf1fa3ef1f5c94aa8629e04820070b4fd1713ecfcdc4db63f62a52","crypto/fipsmodule/bn/asm/armv4-mont.pl":"0e6b793c5628ff2d1172969a56a508735150409e4a520bdc7226a0dd1f104240","crypto/fipsmodule/bn/asm/armv8-mont.pl":"a0f9368bcce4d56ec72ebf04a0664c8514a0fa9299aa2d27eec07fc63dcf4d0a","crypto/fipsmodule/bn/asm/x86-mont.pl":"eff867e854ba35bdbe2f884b35e1c6cabb7f4e6b5ffc62d13e3d795285479138","crypto/fipsmodule/bn/asm/x86_64-mont.pl":"240d70d03b632727c71afe0de20478104768290dfbd15023cda2d440de99e3df","crypto/fipsmodule/bn/asm/x86_64-mont5.pl":"acad1c261477c1e028d3d429be6f5c709aac95e8e87eefd6b1ce1057e5e316fe","crypto/fipsmodule/bn/exponentiation.c":"a4db6ae8f9756204656db37ba4d0cd1eb21ec13d27c189eb7808d5c809ae582d","crypto/fipsmodule/bn/generic.c":"3c910c750af5e39fa5fdbe02266a192a8a4a5c6f2058a6da4911dd39a561eb90","crypto/fipsmodule/bn/internal.h":"f71a90792d124fa35531cfd17aa9085c6f7ba60e6dc1361bc151cd4553f61bf2","crypto/fipsmodule/bn/montgomery.c":"c1518fac73f378cd7514cf5a5ab2c3c29d95ef44817141e06cff45a3c9bf9a3b","crypto/fipsmodule/bn/montgomery_inv.c":"189e42169abb7aa166dcd67084e82169c5eb2a9edd22099147c1859f687198d4","crypto/fipsmodule/bn/shift.c":"c440ff1d7164ed3f6acfe169ac4735df5df8a73ea38c9b872ce15471e9b9b2f9","crypto/fipsmodule/cipher/e_aes.c":"380e23cd4673e247811076b21b17bc79a714e05ab8a5c19239d87100244421d5","crypto/fipsmodule/cipher/internal.h":"ddb38c0d1315d6d68a7c8a6d771aab2b8414c514575478ee5315a6a3fd287445","crypto/fipsmodule/ec/asm/ecp_nistz256-armv4.pl":"f92e6f293af43e439cf41f603ca1c016227912e3ea16d221edc56a467c5ab1e5","crypto/fipsmodule/ec/asm/ecp_nistz256-armv8.pl":"2338e60bd7a868850ec681fc66e313c92c90727de8f723e83ad72a0d7c553c3f","crypto/fipsmodule/ec/asm/ecp_nistz256-x86.pl":"51be61331792fc0c971eed9d70f15b89a79a0bcc3211f65401d343f5bf794091","crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl":"ee22f9cc1f108be12dc71d9751330cd8289cf67645a3ab9eb71a217427f4a5d9","crypto/fipsmodule/ec/ecp_nistz.c":"0aa030bae6375beda98471759d367fd43df7a2d8ef7a0bb917a4638cf6f07429","crypto/fipsmodule/ec/ecp_nistz.h":"47640aa28ddde8bcc6ef015cb9f77cfef6b0d9849a106bd1307158b7d7f0773a","crypto/fipsmodule/ec/ecp_nistz256.c":"db52545e6614512de7bb2ce72d4c616526113baf6f093f4f2361164fb7219cde","crypto/fipsmodule/ec/ecp_nistz256.h":"0032b44c8a61c6478f8c2c36c1dbbf9789418f509f428419c7a7f6d148674872","crypto/fipsmodule/ec/ecp_nistz256_table.inl":"ccc4126030480c8898832cc7f0ae6c62bf5e16de51a32d16f667fae016699579","crypto/fipsmodule/ec/ecp_nistz384.h":"9fbd1b8a9fdb0514110b441f47618ee781d531e67fc54c38a89671a5160a44b1","crypto/fipsmodule/ec/ecp_nistz384.inl":"db02c8713824572c6b3b75c8c43b59f8aaa0e91ebc757b183598984b1b3c584f","crypto/fipsmodule/ec/gfp_p256.c":"b2d9d6523d02d0adb2ae8230e70a7618e100e6026a82b1dceebda955d4922d0e","crypto/fipsmodule/ec/gfp_p384.c":"ae7c91d6dfc69dd7c47c80169450abce2c5452b6273fea10864c938bd1bad47e","crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl":"5b0a694058161ef6536d798acfc2bf268a5a9cb0615fa16bdac04e2873f44639","crypto/fipsmodule/modes/asm/ghash-armv4.pl":"77408b681c42324691044d98d4ff7f8160a4193cb286ade366279ebf3c581ac2","crypto/fipsmodule/modes/asm/ghash-x86.pl":"16c8c02399a7513430b8d88fe10a94e19a016acd72801bffd29c1c14705bd367","crypto/fipsmodule/modes/asm/ghash-x86_64.pl":"2ad656e0b03246db0f30b2a8ad5a76d20528a643d36802a633fe8ad87dcf697a","crypto/fipsmodule/modes/asm/ghashv8-armx.pl":"e210dcf14cad06e593481e30db0f06355582f53bb2419eeb78c7bb3bbb393091","crypto/fipsmodule/modes/gcm.c":"8db9fb57ba6a0d83b13b10243051fd05e3b1152bd3190d4a5f83aa97e9d61018","crypto/fipsmodule/modes/internal.h":"799277554a552f83e5cb9f69ed1ac89414b1364c99280b1d7d15e93a2879f36c","crypto/fipsmodule/sha/asm/sha256-586.pl":"7d28f78ef27b17a7ac6a62337ae5a75d2ef1c2bf08c8154189652e4d93e9ab65","crypto/fipsmodule/sha/asm/sha256-armv4.pl":"673523183c7ac34ade7becc78f077e6bbda6a2d1f6d33644207c725be2dc16c8","crypto/fipsmodule/sha/asm/sha512-586.pl":"b536e80fcc7cf77e5945fa7af1c43b18d2e1df438e601262429065b0b622682b","crypto/fipsmodule/sha/asm/sha512-armv4.pl":"7352a2ced5b722e37023e27afdfdcd5eddebbe067ba8f5da4c421a8709ee8955","crypto/fipsmodule/sha/asm/sha512-armv8.pl":"a2dfbb71da796eb45d75776ef65192bfedd70b1a106d2e067c4be9c7af79c761","crypto/fipsmodule/sha/asm/sha512-x86_64.pl":"50393117d19a47dc99387fb0a353cd29cbc3276a339e138d1d7edc4ba273a386","crypto/internal.h":"15db12031a8df201e12bb8dc411268d6cd2fe18188336856bafbbb9fbe46468e","crypto/limbs/limbs.c":"c9a13bbdae2a11a5d3b06b0a37095fb7030ae4104ae2f675dc6f4e30a176f03a","crypto/limbs/limbs.h":"25b3b6a396642ee69e5056c3ce2a4bdc5c83cfa963af7db5924c257081196ca3","crypto/limbs/limbs.inl":"82511bcb44106f579e023adb67c7ae07093c0f36078a2c4bc6ca107773ce5eed","crypto/mem.c":"18e2844c6205fab613031e671dac3b65ceeb18bb5125f2a11e4df7ec0c09ec0f","crypto/perlasm/arm-xlate.pl":"3089f10d2d1dd355b4ccbd4dc39d807c0623ba47f68b0cb4ef7bfdd269194c62","crypto/perlasm/x86_64-xlate.pl":"67d5a38865d5a5b9e00926d867454553afc5c4cf2e4fd5ebe122162996e66bc1","crypto/perlasm/x86asm.pl":"8a25f4ecff890d0f6f9d6f66481f080b7cf80ce722d916351cb0ef19782fbe70","crypto/perlasm/x86gas.pl":"183d2642ab2e4c76b46bcb97a92fd16c539d9c07331c7204b0564d78c9413817","crypto/perlasm/x86nasm.pl":"7d3b50f58cfd1da94a10f17e1129770d744edf03d4029417ea53bf8771a99b97","crypto/poly1305/asm/poly1305-armv4.pl":"2092a6f1b330972fb050da99b7a63d3c70dfd5f99db98ed1f679018d89e839c2","crypto/poly1305/asm/poly1305-armv8.pl":"c717d87739909c95e0dd1e2d95e6a5d9f693677e68ca1bcf2dc619c93c777185","crypto/poly1305/asm/poly1305-x86.pl":"060b3689cac73fb7a32e16daa799573e6c52dda47fa3ddba9cc235763d6834fc","crypto/poly1305/asm/poly1305-x86_64.pl":"ee69a0717f931d7c336898cce017946a56196a90d6fb44a02989b855ce136bf7","include/GFp/aes.h":"e48438db50d49f708d56b55db0f8a783bca20f237c79c7aff7336e08b6c78883","include/GFp/arm_arch.h":"7b2d7945fc47ba8d8534ffb03a62d9b891e727d3a14fe32f1608f07dd0021f5d","include/GFp/base.h":"d35bf7b59e1b3e98e7b9bd5c5a6fc226c63fd95bedf80c5337daf2f89d090640","include/GFp/cpu.h":"fd8bb798fb6ea1b1afa4cd11717c970d7591ad8ef207be5188a552798bf7615f","include/GFp/mem.h":"8cdf71bb6bd7ba1d1625a88c055a57f4e1529884b93498b495efd62cb582d0c7","include/GFp/type_check.h":"0071b1f6a42e5f0185561443600800a02dae4f355db6895b6c3df63aa40a5bc8","pregenerated/aes-586-elf.S":"bace0bf299d6830f564ff1f6b71dfeb08a97142f924ca77b722f66dc74520067","pregenerated/aes-586-macosx.S":"ed1529ea2b001e54e12cfd247b72bd1f68c7c915b8d5bf0846e00e2b24239043","pregenerated/aes-586-win32n.obj":"08ee97af66fdca8902776e3b8c9acf3c6d2a3ddfd79da9942f2b6b5dd2954162","pregenerated/aes-armv4-ios32.S":"bd592c0302d9ac88f96af8c29fa9c28d76470c19d25b52f1dfc4ed8a9278ddb4","pregenerated/aes-armv4-linux32.S":"7434ac4faf6e4c6fb166aa1393d20fc5b5814f18a44180d7a5a5bf159810f747","pregenerated/aes-x86_64-elf.S":"4670fa16e3ebbec6332e6f906a1aba2bd60cb07c6d7775c4a802bf37e127bf52","pregenerated/aes-x86_64-macosx.S":"fc8d58ed35da1be37294c895979bfacf697e518cfc2d2d6cb983d89780bcccdf","pregenerated/aes-x86_64-nasm.obj":"4e4945c594e09f3264921a163a1d16b5c800b508687e1a995db37f7a31cfd25a","pregenerated/aesni-gcm-x86_64-elf.S":"53dfea5b51c8236904fcab378ecf198b852056ff6a3b98716c75acc5af32d1db","pregenerated/aesni-gcm-x86_64-macosx.S":"29c5de7f4f0682036331551206d32df8f1df0f872dae2c341bf883f526931e00","pregenerated/aesni-gcm-x86_64-nasm.obj":"61f5ddb2f07bea9b1655a1d1d450361a7c4006ab2efa80f8ebbe95976d22e1a0","pregenerated/aesni-x86-elf.S":"3e17c6dea1430e75740e885731d422f70cba21f3699cb753ac7aa157224da886","pregenerated/aesni-x86-macosx.S":"36633ebff6c930b5d827073257e0c9fad745356ac3aeb607d516946e12466b75","pregenerated/aesni-x86-win32n.obj":"873a3c82e91b3e327487da22d451e18509932bfae82064eb258ae1509200349a","pregenerated/aesni-x86_64-elf.S":"3094c086f75504128e8fd130c8ab70666329f422107e209564b4ceab3724143a","pregenerated/aesni-x86_64-macosx.S":"5c00ba24973a34cd6b2155882b3ca987d66d81a1c9a70cb64e48dc18cdd6c96e","pregenerated/aesni-x86_64-nasm.obj":"e44ce85e7955f9dc17ea6ba9ca847138c6382d9df77d17a452b035bad9f65cb5","pregenerated/aesv8-armx-ios32.S":"e211ab361d174af69fac02d0fb8d5985ba642ddae45d0eafb74dee7a5aafaeb1","pregenerated/aesv8-armx-ios64.S":"b6f27a22653e31497788de7c4c936dde0c727280dba39064144a6f1a7ae84539","pregenerated/aesv8-armx-linux32.S":"5e9c84abdedd92d8977414b537f3939ae1dc9e9506900bac169be35fbe7708f7","pregenerated/aesv8-armx-linux64.S":"e70652666e535c57ff5871ea84b1acef339cbf9b1231e87c28ba7d2834e7b1a0","pregenerated/armv4-mont-ios32.S":"2f9926339db35652ce582d131bcb2de6981cd23fed979f0b35252bab03fb38bc","pregenerated/armv4-mont-linux32.S":"93bf9b6db03f63f1c3e013d9590ac7b7f6bad34188584f15d800b0e28e8c3f51","pregenerated/armv8-mont-ios64.S":"10a193c3eb405f93fa3d714a9c31b835f2c156625a2ab8ac22b6fc45b9724e80","pregenerated/armv8-mont-linux64.S":"a4f643237edd317afd3c70cf2c0e5b8c9c3fc55f5c16ba6175d66991ca81bf77","pregenerated/bsaes-armv7-ios32.S":"5d79110f25c887c61c973489c28cb539414b884ed3f5ab75f80ef9c56ccc49c3","pregenerated/bsaes-armv7-linux32.S":"965c4c95239527b33c4c53a7135b39471548e30c42fc469a2e0cac918edcbd27","pregenerated/chacha-armv4-ios32.S":"d5097696c4e08359a4c707c1a219adc359f03754ea2427de02abf892165336dc","pregenerated/chacha-armv4-linux32.S":"1b1afa5bbd819683bd96ed60b6d329a1dbe79aaa90ecd5ea83e52fd2934b957c","pregenerated/chacha-armv8-ios64.S":"209e0b2874a69bedf6aa92c8793eba323b0b44894804f916f7050c67b6f0540f","pregenerated/chacha-armv8-linux64.S":"b6c8b24c11fba499cfd4905e33526e19592240a1e35bb673d568ff9b55067156","pregenerated/chacha-x86-elf.S":"4c2add447dadec5c1531fa77e63de71f5c07bd11db0eb36adfcfa26664f2813d","pregenerated/chacha-x86-macosx.S":"5f75f029943ce4752307c3fcd8fd3f409d0d2bfc8e6e182dc6855d1fc4ff28f9","pregenerated/chacha-x86-win32n.obj":"567f434cf1dd6713340f7cc04fa214db7cb8f78e94c7271ca2374bfa8edd516b","pregenerated/chacha-x86_64-elf.S":"ef6b6948c031e112678758670f51eb5a077fcfcd3d1ca5229a1cfd62749892eb","pregenerated/chacha-x86_64-macosx.S":"4ec99e102952ea66a3f6bb3ff4fea2302df01c2b13fd87b2a0916ff9c698d062","pregenerated/chacha-x86_64-nasm.obj":"cd5eaf1ca437fc8ae049479632ab384a9ce178d312fac45f01440215d7e9ae33","pregenerated/ecp_nistz256-armv4-ios32.S":"094232c4428647397123c507662cf2610b42e5e368ac845fe62fdccfd8a54e62","pregenerated/ecp_nistz256-armv4-linux32.S":"24f74c3114acc6a40172fae0ac3143dd81cd150680cdf0add76203ed19a3d0f8","pregenerated/ecp_nistz256-armv8-ios64.S":"16409f691fe1adfd30d0bc11d4918e336f77e86618be2489f64a3b14f7cfa9d4","pregenerated/ecp_nistz256-armv8-linux64.S":"9d14df832a8c41b0569fc1374b944b72076f031d14f937eb976474ce97203b49","pregenerated/ecp_nistz256-x86-elf.S":"ae3770aee96b96226c96b07a9ff9bcdf5b411dff83adef5a970952c3d8bb7ad5","pregenerated/ecp_nistz256-x86-macosx.S":"0ac9c2c1ac8e0ce2d44559b18c215cee8ce308d1570636f19aa980afb94cdfdd","pregenerated/ecp_nistz256-x86-win32n.obj":"d6a6693840a6c7478775e2ca67c513653856503b42dc1cdf7921773296753988","pregenerated/ghash-armv4-ios32.S":"2aa696368c007d065a227d46f2c760d26141dc326543d6fd92d084eeed63ff18","pregenerated/ghash-armv4-linux32.S":"6679d36bd2a8c482085f33abed0b5ff77157a011d054932b53d3a0938ea6d686","pregenerated/ghash-x86-elf.S":"22ea8f199210f5dea6afee4a58f6a04fbb977a1cbd5a7819e2421833cd5182d5","pregenerated/ghash-x86-macosx.S":"a484fe8deafd7e216a3c7924209882f2c67fa7e56ae8843c094acad9868ccc88","pregenerated/ghash-x86-win32n.obj":"3e4474492360d7d4970ab92cce237cba95ef3af251e1359c0ddc635f3982563b","pregenerated/ghash-x86_64-elf.S":"127e5996c745d8f221a58f5da1af94347ff97ca578640c07e9ee4dcb538e8d29","pregenerated/ghash-x86_64-macosx.S":"1183022494af6d13fa77fa30752977f19152f4aa28931ca3c0951f8503eea000","pregenerated/ghash-x86_64-nasm.obj":"4fde8c6b1c3274df3543f08aa032defb7cb06722f325b5740a37f1ff7b5d9876","pregenerated/ghashv8-armx-ios32.S":"72cb523ff6176952ebcfac359a47f037405ed3911169c48ef0176ab2917a1088","pregenerated/ghashv8-armx-ios64.S":"f3f66f47d0daa285098c1485991c8599416904b7107fe68e5c6b1ff1dcd76a96","pregenerated/ghashv8-armx-linux32.S":"26e10ec3e2480bb4266cca7008de4bbc1b434250b45224cc2d6807daa9bd54ea","pregenerated/ghashv8-armx-linux64.S":"6c82cec3c0d2147a0b9a251e1c870caa311158171acfd21dd5b428fd9a28e37b","pregenerated/p256-x86_64-asm-elf.S":"d65eb4365b9470247d3d7e48b2b71e814dfc2ca9c29b2319df013b5723585007","pregenerated/p256-x86_64-asm-macosx.S":"251984dfb1620b19fb470f9cf6dc30c681f12ef8aafb34d1db50f10d1d103c6f","pregenerated/p256-x86_64-asm-nasm.obj":"67bcc411568b43b73399b02b7610645575633d81e5a24a4900fda4eb4c9296e0","pregenerated/poly1305-armv4-ios32.S":"05e1002ce1eafba66534856b2d0904294a04197185ad26c4002c0ae336f6d321","pregenerated/poly1305-armv4-linux32.S":"e750ff85fddee95ac48289c47158cb9019912bf2d93710f541b3be4e6bcbc6e1","pregenerated/poly1305-armv8-ios64.S":"0a260a41312bba9a823ec0f6036c01713fd04f7cdf91970c979862fc5b16aa75","pregenerated/poly1305-armv8-linux64.S":"7033faf43fe02ee9bb37f58c87c74852ddefe296d5b5d3d26589a3acd628e371","pregenerated/poly1305-x86-elf.S":"77e2b31e6dce365adebbdc4e9efd1e74381d24c1bf17c8edacd64a842dc0895d","pregenerated/poly1305-x86-macosx.S":"c8db55e562fb5b067d130badacd90b4e2b47522a03851e7cc59c2c5b281a22be","pregenerated/poly1305-x86-win32n.obj":"3eb2b419b3ddc0408ad98143855aa21b30e33b9350bb971aa62bbd2027c8779b","pregenerated/poly1305-x86_64-elf.S":"950d09f0dc5c333c2efd72f252eccbc5f3f392bff503ef11c0c32560ac565d02","pregenerated/poly1305-x86_64-macosx.S":"89cc9c0ad2e6421cd89fb341cfc1422d842ac7a3d0555218fb549dfad14dddd1","pregenerated/poly1305-x86_64-nasm.obj":"a4f72316097966f37409e60f3d1ec1a62a11913ad4d0c1515b9bf63248549849","pregenerated/sha256-586-elf.S":"c2666a6fe1ebcaf8e906b16fbcbda35941df5cfb28c9d5afbba2b31d32120e33","pregenerated/sha256-586-macosx.S":"0cd5007b8ad2fdd07f2f97c857ddd8bd066098aed3ac7060cc3b6e0db2b3cb43","pregenerated/sha256-586-win32n.obj":"42e65c791d92225e54de4d5acdf5d9c91a64f8b1fd4eb90e8f7bb486935e4aae","pregenerated/sha256-armv4-ios32.S":"8c8b07fe80ea742de1b113c8fe820293a8e584c935bb17efbce74221fb6865a4","pregenerated/sha256-armv4-linux32.S":"512f3fcc9bab4988e3f36f8bde6018c957f15e526d26b63770fb00533560f7d7","pregenerated/sha256-armv8-ios64.S":"df7f441e8687e5f2e05b27327c19f1d76e2f67817886d464d729c976572dd80f","pregenerated/sha256-armv8-linux64.S":"2d9fb077b296ee97c5a7738def3ac093d6173945861419ab4c640a1696d78e10","pregenerated/sha256-x86_64-elf.S":"8e475f6c5f3787c10c71513b0d611c24684ac4277dd29810d7a271a0230e4071","pregenerated/sha256-x86_64-macosx.S":"b352aa748664533d595b30030e03dd07ee04300d8f7dedb7a962e95428582830","pregenerated/sha256-x86_64-nasm.obj":"15dea95dedb29855669dc8a7b426b07e1291e4750bc14e9530b1406d7c7d2e5d","pregenerated/sha512-586-elf.S":"e785f2903296490ebd77a58cac011b86e27bd08006b41dbba7d8d25617a031ee","pregenerated/sha512-586-macosx.S":"8507b01795ce1b6db3683a609fdbf82673bc83170a3aea6f09d41c148419aed4","pregenerated/sha512-586-win32n.obj":"977174b643357d5fa5d9f350b61c67f435d329bcaa5a77ad692af4566726b12b","pregenerated/sha512-armv4-ios32.S":"588ba52839ac62a67e671bcd46dbd038eae49039e29a691bb219f5b21b84f9ed","pregenerated/sha512-armv4-linux32.S":"01432363bdb1de88f551b021c4a3f8f95e2e164b7a474360a5609df61ac1210e","pregenerated/sha512-armv8-ios64.S":"85a754750ae044677650fb5e888194f7c655040dc8bf6229c868bd72b6dae9d8","pregenerated/sha512-armv8-linux64.S":"d0542bf1e2e7aa4535404932d5f10afecd16df7b0b40606fdea6ea09a09a6d4c","pregenerated/sha512-x86_64-elf.S":"cfa50a0164c2b722610898680d0c1fd2b0a1c298697d96563158ddf92859d95f","pregenerated/sha512-x86_64-macosx.S":"8264ca5e2c717d6e65d53f80c715c54b5debd78ce4701b4b055b729973dfbf31","pregenerated/sha512-x86_64-nasm.obj":"a81977f62ebf5b07e0aa20d8083d185ba45a7cac01b6ca3c4d117abdb6d8b7ea","pregenerated/tmp/aes-586-win32n.asm":"da525d7cb54408984e806c6c33a9064d363b70e81d9b29c1d6b66069dc072f0e","pregenerated/tmp/aes-x86_64-nasm.asm":"4a0ed0baaa2cef67a862ae5cc77e5cb41a22a339e692a6d3df7f9157b1918d6a","pregenerated/tmp/aesni-gcm-x86_64-nasm.asm":"8eb7d4f4608392545156d187ebff40778fb88eed4191ae1e86d92d71025ae4f7","pregenerated/tmp/aesni-x86-win32n.asm":"1146ea29b0189531e25715320e3a35f6c6c07bfb940649cc4d7efedd07ca49d2","pregenerated/tmp/aesni-x86_64-nasm.asm":"8f80e63b42c61dd6a65fe0952558fcc22153995cd87a7409882380b39781a368","pregenerated/tmp/chacha-x86-win32n.asm":"4249a0825b7c75bc31005f49e78c3c4aeb50cece4b27abbbbf40cdc6ba3e2106","pregenerated/tmp/chacha-x86_64-nasm.asm":"1556daf278153ba33ba8eb5b1271dd663562b22f44794cd126ad9be73eb200e5","pregenerated/tmp/ecp_nistz256-x86-win32n.asm":"77c2a6d166912a2aa84f0e14290e9560add3cd40287e575636f78c09185cb214","pregenerated/tmp/ghash-x86-win32n.asm":"9fdc5bc9524240cf62a58f95a357106082fb1ef5e00677877519cc728df74d28","pregenerated/tmp/ghash-x86_64-nasm.asm":"494576f0ff30589cb66eeb5f45a8c552f03bab4ec2517934e79a929b2f37e06d","pregenerated/tmp/p256-x86_64-asm-nasm.asm":"71060ebfe9e47b4458d1240dd038b3f9341ce83a229d63d3cfb763524b9806f6","pregenerated/tmp/poly1305-x86-win32n.asm":"eadefc208a7f260fb44e38577ab584479e2d289dbdbe524cabef996f81b78de2","pregenerated/tmp/poly1305-x86_64-nasm.asm":"66b27a9152114f1a0a614318b645a9cfc22a00c0bd2c9ffdb8774a74effb36a2","pregenerated/tmp/sha256-586-win32n.asm":"71a5f45df90f6ce35d3657ca83b5b80b3864de6f63ba045594785fb21cdf8e59","pregenerated/tmp/sha256-x86_64-nasm.asm":"498b2471bfacc12df4aa9233c81f5b86d6e56773e60e28f24088cde6454a11cb","pregenerated/tmp/sha512-586-win32n.asm":"fa32423c613e30cb6dbd8fad6e2ffe2e450da321a960381498609b1ebb5d8e1a","pregenerated/tmp/sha512-x86_64-nasm.asm":"233604a1bb54a541585a711d430f7e99623069bcc61e674eee76590268afb1fb","pregenerated/tmp/vpaes-x86-win32n.asm":"e4d9f5c86c207b67fc6a246fcb07e3a192ed6c929cdec18d60a384fb33b7f9b0","pregenerated/tmp/vpaes-x86_64-nasm.asm":"4cd63141bdf1e3b80768a9c532f65094e4fd800409f3901cfdb1a97bd9ae9c36","pregenerated/tmp/x86-mont-win32n.asm":"0cf31818e21a33d865f3a24ab9d38292e059338d28b295009fc3013dc45046fb","pregenerated/tmp/x86_64-mont-nasm.asm":"6f6544745dd9d181472ff0f0a53a9651794b7835ddfbc1f382976767a78712b3","pregenerated/tmp/x86_64-mont5-nasm.asm":"cd7a8e378e8c430e9f3b755f690f61a800332f830ad34b667cfde63c30c6d8b7","pregenerated/vpaes-x86-elf.S":"f0730662912db49c4f500c7074070f0d1d9b423e4b9e4e8ee0abdcfd6f097b3d","pregenerated/vpaes-x86-macosx.S":"f4e1f9846776ed68a83513e44cc3aca4da6124d71f87ddc5e4b4de5bd8bf75fa","pregenerated/vpaes-x86-win32n.obj":"46ed84d51fc35618dc394124ec715e6e593dd8e67f25c973f63d06cf10c518ef","pregenerated/vpaes-x86_64-elf.S":"ebaf462c4dbb7d79899aba8b50752af8466febae32d1ac9f9325464e41b733eb","pregenerated/vpaes-x86_64-macosx.S":"19392ab0203adea52781382df124e874c5c95dbbdd024e970af2589f0378b865","pregenerated/vpaes-x86_64-nasm.obj":"2b2b41b75eeaab47310c3ed24a570b0b74208b54639f78c7177b633b691b70f7","pregenerated/x86-mont-elf.S":"7f71ebc9188f3ae1bd366f5ba0e97c3ff97d204d84f774cc0c4b57907223d825","pregenerated/x86-mont-macosx.S":"7382660774ac0cee55c33e816200efcacca726d9b8744f07a0cd655b20764e36","pregenerated/x86-mont-win32n.obj":"5fc0e1b6e21d4f877cd53164717d983cb0f1f4c3c59cd80c5310bc6519d10e7f","pregenerated/x86_64-mont-elf.S":"1170f36b95b463f0e168ae48d37ee2df7c904331b1d2be5004f65a818d1653ab","pregenerated/x86_64-mont-macosx.S":"79a8d422fe0dc5826c440b74149ab241430b2d0ea025dc5de6474dc5b40069ff","pregenerated/x86_64-mont-nasm.obj":"6a89cf1056351aaf42546ebe63cfa3c75567585d7da2f3767fca974c6d86feba","pregenerated/x86_64-mont5-elf.S":"05420ae9e406e229a6cdefb38b398ea836bc64c61ce75840ecef75dee2252796","pregenerated/x86_64-mont5-macosx.S":"ef81d6d9d221b5ccd493e0540e85fa1cf1db065249bd34dfa19a6398f8200460","pregenerated/x86_64-mont5-nasm.obj":"22ce3087c8c06791a5999aa48d48af71431069078a9fb3dd14d4addc3267086a","src/aead/aes_gcm.rs":"c3c8aa005c9d1c04cb3ac066fd091e7cf355e2e9964013edd96966cf952127cd","src/aead/aes_tests.txt":"4ae334ed8c34c0cef24c22b73568faec906a39e26a428e4cd6fe4f810cc51fb0","src/aead/chacha20_poly1305.rs":"fc2abd81f9e5d60bfe9baf31613990530713b24860e2d317162aabe2a4f97d24","src/aead/chacha20_poly1305_openssh.rs":"3226b02291d257768a5f38d5a264268167ca94d418fcb5616913e21ee59f7670","src/aead/mod.rs":"bbeb66d0711010cde30aa9252ffd417556804fe1dd47f041c1c8f3995c3a228d","src/agreement.rs":"3f84faa61b3f7463584fa00b8f559cf9879631504972629bb6d75ec5268c6d64","src/arithmetic/mod.rs":"4154c5a049a6bc602985170a292f6f16c1728abffcbaf0cf461da228022f1f2d","src/arithmetic/montgomery.rs":"adb7d8e3bb058fcbab6911967d62cf2e2b2ffc9fa165cc8da0de984fe6eab5d2","src/bits.rs":"16c7640e8e7c093883050c44b704d29c772bffb612bf501d1962e0f4eb7a86bd","src/bssl.rs":"b94eda108e6e8bc53e1635e0dd46c21ad208dedb2331fe5cc91eb5ccc788d3af","src/c.rs":"37b7038f9c7f04f44670678ea2ff5a115b3b24f699d0e3480e1de121478e1cd2","src/chacha.rs":"74946cf5dbf1a074667c74d7b7680e2c4a8b677b54251096470a9343394534cf","src/chacha_tests.txt":"6ed1303cef7a0ffa30cc76f9933509a2d952a334b80c731d52d32c6ef3b37042","src/constant_time.rs":"2d76e72ad06e65de8ae060607759b7b618ccdd0b4b1a94c227c9af2b402008ff","src/data/alg-rsa-encryption.der":"7bc023427767a2f2e156f8ae030d06d19f862e326b952116649b423c3ff7110e","src/debug.rs":"692fc36bd8bb6f416fcc3aed93c4fc8809a2ec6614ddf825bc6974a954347b22","src/der.rs":"98afa28694de2b56a3198d23932b2538326b512f97401c86c5fa5b6ba04fc90f","src/digest/mod.rs":"d17f80d215b0e725034bd21160b8524497b3015caf59028611f59b96b731a232","src/digest/sha1.rs":"d744a71eeb1edce3e37d22c571c0c5cc492b98ec09a53066e64e770c11cac467","src/ec/curve25519/ed25519/digest.rs":"6bf6c446b145d0caaf45398c4fe8574df7e974e89a9155d87d4a0798716f79a2","src/ec/curve25519/ed25519/ed25519_pkcs8_v2_template.der":"1bd2db034b5160de343688ff570db3da6a5bbfc66f9f2dd015f0902e2d2b7e34","src/ec/curve25519/ed25519/mod.rs":"5dcee3ebc59b65d444b162b6832a51f501c37bef8f16945c220ec7e0e157b8d5","src/ec/curve25519/ed25519/signing.rs":"324eba85aad558260360dd8c3af883b5a7c07fba9e75e72394770517057161d2","src/ec/curve25519/ed25519/verification.rs":"7fd0d0e7264e1aea1ad9319f62ef8aff7c4fc1fe09b488c37a05dd10100bf124","src/ec/curve25519/mod.rs":"9758e50247f0f325332ccf70245ce7745cbc21a01de39590e2babd6dd185451c","src/ec/curve25519/ops.rs":"71c04dbd2788a59abdcf6d17d1ef5ec0f97de32a94a1345da07f698eb0ebc0ed","src/ec/curve25519/x25519.rs":"d275c9fae49c86c42d5671e9118c84aa8d34f5f7e67d286c189358b4fc49b055","src/ec/mod.rs":"e0724f2b55aee8c68dc4338da6a8f1491dffbd54a5a30ba1b763e5d4e98316ab","src/ec/suite_b/curve.rs":"278b9b54fbe56ce092e441bebaca60cbc8d2f327e84c551b857c2b80562ed896","src/ec/suite_b/ecdh.rs":"d02b0753708246dd2cb03199865f778417cfa87d8c9eb40c0a4feb97f51bc019","src/ec/suite_b/ecdsa/digest_scalar.rs":"d08e48bb1bb7ba694021f11972f9c0a66acec4f2cea746796298dccf1df1c05f","src/ec/suite_b/ecdsa/ecPublicKey_p256_pkcs8_v1_template.der":"5a2207da0199ebe3e2a80e15e7692b21f215f855ed3bd2c51f466c7969e11990","src/ec/suite_b/ecdsa/ecPublicKey_p384_pkcs8_v1_template.der":"5ec14cd6aac17cec849382ee5e2077497f98ce435d7aee2116cd092bf84f5556","src/ec/suite_b/ecdsa/ecdsa_digest_scalar_tests.txt":"7f38872c3acbd5d156783de92f3671062101af3cc496c1b261165971b3eea2ee","src/ec/suite_b/ecdsa/ecdsa_sign_asn1_tests.txt":"ab92cd110846b42d7738374d25734cff6459467f40121c4e7fda5b31bee651e2","src/ec/suite_b/ecdsa/ecdsa_sign_fixed_tests.txt":"c471d314f18270c79141062d5964d84fbe38c1bb9559ca217f3511d34fc4af25","src/ec/suite_b/ecdsa/mod.rs":"013e0d2d2a21eb437253b03a1f6a1a4ba8c45eb1c2ea1396696bdd04a8ed2932","src/ec/suite_b/ecdsa/signing.rs":"481b5cab7364a84e73e60aa778403ea6ef8a800b2afe76fc604b68f4cd991e89","src/ec/suite_b/ecdsa/verification.rs":"5df172396718db719ff3e618ec6e326c14d67bcf08b978b684a272c2600e74bb","src/ec/suite_b/mod.rs":"5c16c4a4f722a5fe85233a5b4877752373ba7623cdd610f0ad6db9dff78371d0","src/ec/suite_b/ops/elem.rs":"7f81e636ed526dcb9fb12f4e4fd642d3a848b5da10ddff6f97b873d6016d52fb","src/ec/suite_b/ops/mod.rs":"90e88ed071e8fa3578ddf9d1635cc3dd7e049fbf00de95f9fd4a98451f11a3b2","src/ec/suite_b/ops/p256.rs":"99bc56042b70278a1e5e3bab43afa15183d48313a569140c1a9f74ab921e3dcb","src/ec/suite_b/ops/p256_elem_mul_tests.txt":"02e7a991d6643a81229f462d21ea72f0503c038d783583c83ad7f118952ecf0b","src/ec/suite_b/ops/p256_elem_neg_tests.txt":"b61eb959dd473bd8edbc4566f18be0ac9f483be9e7d0900f48eb764454475807","src/ec/suite_b/ops/p256_elem_sum_tests.txt":"2fbbc13100065539bce71e83d642878a90103b5ca3d9b8d3c321db15a0c05c9e","src/ec/suite_b/ops/p256_point_double_tests.txt":"34a5968bb40320c6cc0f7d248951376823d46c0aab1fc7ba59311bc1cfd34417","src/ec/suite_b/ops/p256_point_mul_base_tests.txt":"f207084da07de3f63b7563b07994915dc770e2b7d5dfe41881b2ffe875ad69d7","src/ec/suite_b/ops/p256_point_mul_serialized_tests.txt":"f3c8061e0f891441de35e80869c253c65fea2ed1dd4f9be7a444c956211d32ae","src/ec/suite_b/ops/p256_point_mul_tests.txt":"894e02359b562f3d74757f4d8fdd20c5fc5528634f5922ce01d9546910e0b0b9","src/ec/suite_b/ops/p256_point_sum_mixed_tests.txt":"c2a178ad0371ff7dcf15364edbbb5cd0e82478d7e1037a6d3b2243204465f918","src/ec/suite_b/ops/p256_point_sum_tests.txt":"1ede1f508c673890e2f48ba53309397a17a02f13370aac114f34ea0c3c4f4617","src/ec/suite_b/ops/p256_scalar_mul_tests.txt":"6fa09fc69c9962c31f090ffc747d4cafe184429b8e0acad3adda7b14ac26a4ef","src/ec/suite_b/ops/p256_scalar_square_tests.txt":"19633fcefdf8af6685fa9750a96c17478e282972ee7ffbf4c4303229f7938db3","src/ec/suite_b/ops/p384.rs":"6e1237710c247c7097687549d9b2e9db6f38d9bb64d620a81de2cad3c0bdf33d","src/ec/suite_b/ops/p384_elem_div_by_2_tests.txt":"8c4d02994577c8b6ec3a83158fe20ce92366052ddff349b02bad4595847be8cc","src/ec/suite_b/ops/p384_elem_mul_tests.txt":"acf37680470a3574acfe64cb3629186d1f29bc8e905c5d9c1e40a2c2bde2701d","src/ec/suite_b/ops/p384_elem_neg_tests.txt":"08986c5fb0b8adfd3be6ba217ee68308c5e452dba086d92793e0ce3383c1acaa","src/ec/suite_b/ops/p384_elem_sum_tests.txt":"48850b24fca0487a875379b6de77879f97578f50111c11a12e8d789f6c8f0ab4","src/ec/suite_b/ops/p384_point_double_tests.txt":"6d25547058f40d98ef3c2a1957fb72a57f4fb19623c28dda92b42b7adc93bc9a","src/ec/suite_b/ops/p384_point_mul_base_tests.txt":"4995baf7080a6a4d72de1d262300c4ee49d0449034e1250f87bb15fadb78408f","src/ec/suite_b/ops/p384_point_mul_tests.txt":"2fa85969ab080e6f977ed92abbe29f6f5f0658e5ee126834769673ff557efbd0","src/ec/suite_b/ops/p384_point_sum_tests.txt":"5cbdf15ce4a56a952b85046e49cd0fc4ee22d516d914ab48c19b7801864bd352","src/ec/suite_b/ops/p384_scalar_mul_tests.txt":"f88e82363d7a1eb4fd687bd54dec6cb05e2796e751f39b5c774c11af0569bea5","src/ec/suite_b/private_key.rs":"a2c63d29a99b635848a693399c06e25f4ff6f35832377a2c69a55b4f5f05fc92","src/ec/suite_b/public_key.rs":"20997859ba83ce8b9fd0d0d6934b3d48d036c944962bb102fd1dac8e2b019ac3","src/ec/suite_b/suite_b_public_key_tests.txt":"392bcb543cf69cbab5252792a8dfe09ffa3421cb27d65cdafe9771bd68d49a5d","src/error.rs":"ce9845ba2da202dac97d2c4a9539d3b8483cecdac589984a65449cb4c5efe02a","src/hkdf.rs":"4f15ecd47d2031225e5f14b02245b3635489516a82ff13be8bf9959ab8c77c60","src/hmac.rs":"ee8555f302e0bfc7bb1f2b905ba1dcc78c12cd13592e1a680e68733e8c58ff24","src/hmac_generate_serializable_tests.txt":"d9fad4aa957496eb05dd67d97699631bd428de8a5be6e29aeb82b732eae97a59","src/init.rs":"fb8b2031e0341387b2583c39a0be48922a1292dc6bbd9a80de40e283c5249db6","src/lib.rs":"ab2ce04b421460116baffb6c9fd4d05b263ace73d570e46c0f36728d856c97b8","src/limb.rs":"068e271eb91b3b701db7bd6ae23089dd7c436243918fd4f17a4b208c2bf0018b","src/pbkdf2.rs":"190713bfe17a273442b737dad836f5020c377bc800eba7d6866a4f4c848ce8d0","src/pkcs8.rs":"cda6d79cb18dc83a4e3ce9ef087df7eece0fbb935a02029b7584441c2eac6b35","src/poly1305.rs":"23af607e1c79812139bd25b26e641d747310a65b2b34a9d2557f0787fc1d4786","src/poly1305_test.txt":"89be1be8e403e5a17845f0603e19337604f1f278c7b283de2c7227ef6041491f","src/polyfill.rs":"797682ba9f781abecc6efc11477802a058148f3822557750a74df6db303113c7","src/rand.rs":"19e1807425d7bde230df350fe30aa7c680f0ba3b191b756a1b754464895978a3","src/rsa/bigint.rs":"ecc414a276c4d777af2b199d62ce8c8f2917c81f9207d78db2226ca4ca88e264","src/rsa/bigint_elem_exp_consttime_tests.txt":"5f84de732433df1e0db3b3eb690bdb0cc1a735bdc7e60a8218d5910e9d9ac436","src/rsa/bigint_elem_exp_vartime_tests.txt":"6501c58fa66083ceb7dffe14a0191cd6a2d74a96aafeb72d828841844a37f409","src/rsa/bigint_elem_mul_tests.txt":"0de8d667f4bae0648607cff2c53df81a6b2ccddb8ee620593350255b36de0e91","src/rsa/bigint_elem_reduced_once_tests.txt":"7b4aea41259ffa329d669843d6dbf29a5ba56d845210bbf4b0a2ccafbe8d8c01","src/rsa/bigint_elem_reduced_tests.txt":"7c5dd25b495b89bab09e8f09cbbecf34aa28ee7eb2ed592bad50ab63e5b17ebe","src/rsa/bigint_elem_squared_tests.txt":"0517a5446667fd49d198a89fd93f19d9870fd3fddad3371ad9aa8075b6020e22","src/rsa/convert_nist_rsa_test_vectors.py":"c670a7d9761667c46a9b204848c74ed8cb5ba723e3f5b92b081e94e4601c55fa","src/rsa/mod.rs":"0edd512f8636bd0f50927ed7bbcf4b90adf067511f0acb8617540e8933b7c44d","src/rsa/padding.rs":"6c7fc38bc021a3c2ede033e83e8ee45b476b4730f937ab5271bcd89ec15b2e7b","src/rsa/rsa_pss_padding_tests.txt":"1b68a294521e983a4a35fd7ad4e5823d6173641ad63d736b3b8e6e867f748ea8","src/rsa/signature_rsa_example_private_key.der":"5344d57f719a98c4464aed1d1c2fa569f0a9de8621c6fdec7d28923a0e1c662c","src/rsa/signature_rsa_example_public_key.der":"28b0a357936485bd2a7776321cccfe17c2347f2bb75751ddf9dfc6429cacb6f1","src/rsa/signing.rs":"ca953aa66b43367d94059c2a5fd61d4ae404866e223bf60dbed57694c0ef5d02","src/rsa/verification.rs":"65b382531d6af89c841a33778d313737b81ad42a7b9a4670f76dc44df17e20ef","src/signature.rs":"8c76db30b50e9b342c402cd54390d4e2cda522a4b0e7de670ca846140e07142e","src/signature_impl.rs":"15c07c7d916c19f1e6cc8afc89c0c9ba602bbd6186888f2210254ecd8268b594","src/test.rs":"befd5a72ec39b58208ec081248e22a6f57c28864ea41c45474dc65d5a6c7977d","src/test_1_syntax_error_tests.txt":"c6e72aaee3817e145fea114020193c5b3acbbd2f3a97614f1c2670822f1ac6f1","src/test_1_tests.txt":"1014aec056f9a06eb23983e61eb6dae8384ee982f4eb0c5be002fb5d6ce10f99","src/test_3_tests.txt":"e489a2da5f486e75cd6e2cf7089f09d6ddf61a8765fd58c47bc79ad32be77e13","tests/aead_aes_128_gcm_tests.txt":"2e88612cf3d767626f62d59d81652fef5611f4418bf56016c12ac0bc26a12a20","tests/aead_aes_256_gcm_tests.txt":"c21fab30c0098cddef658908ca2820d656c4717d24d79ef3dd68251695972040","tests/aead_chacha20_poly1305_tests.txt":"3688abbd7b1d87c9200b627c289a2bebf763f512baadf536cd72cc8f3ce80fe5","tests/aead_tests.rs":"791b311be75d72a2e302443345d994179c219ba1963c84b188fb423fa39c52a3","tests/agreement_tests.rs":"4693499fa201cad7709030818dcd59d6738d31a342781f21516437d22e818038","tests/agreement_tests.txt":"4b784d203e87f9de0678df00ac1b2a28db169f680a3333e9d773656fcebceea9","tests/digest_tests.rs":"6ac88c9673b3c03fa772c4493a9aeb226e7fa548097439591151dcdb746b9fec","tests/digest_tests.txt":"dd817794e2ba72ed637805e225240a295ae7b4cbea956dcd23c4752da67a394c","tests/ecdsa_from_pkcs8_tests.txt":"c277b11b3efd6598269257a5aab14896214c611bf22b89fef9a2e6ddf1ed913c","tests/ecdsa_tests.rs":"5866e997da7642e45c75aec507a7db0bdd50a5983a4c0af971b94dc70e14fa3d","tests/ecdsa_verify_asn1_tests.txt":"4ae6325e0a1fdf4cd6fd2f299a7fb7a60927d0775b63aa9b027676fa76f3ee6d","tests/ecdsa_verify_fixed_tests.txt":"837f116fca066cb181677e389cf92b684d15ed883189b4544538cb5387e6b742","tests/ed25519_from_pkcs8_tests.txt":"0eac04f0e0ef3bab0e3ce2f2005d230e173333ac85fa363d560dc351dbcb09b7","tests/ed25519_from_pkcs8_unchecked_tests.txt":"dcb114c04bedcf720da313f93b79ce81ec805e5291b366a770010568f405ae08","tests/ed25519_test_private_key.bin":"644d50ab64864c20a12b3c4656d46b4a48f69ef7c47ecdc8415cd28316b22ef5","tests/ed25519_test_public_key.bin":"21fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9","tests/ed25519_tests.rs":"ad473116a57c61fce3a71844a1710b283a34afd5198e9e5bf64f1276372fbeac","tests/ed25519_tests.txt":"f99c7e7bf7cbbd7df936ca883ca0cb293c31ad37c03597890fdb07dc1c923d36","tests/hkdf_tests.rs":"7d57171a547d5e0e87235426aed97f258603d645629eba8590101823fbfbdfee","tests/hkdf_tests.txt":"516a19799fa940c72dca68d8cc92ec605b46aa71590cf1b827468a58a01da574","tests/hmac_tests.rs":"44757854526929bb7643cebc00d424e6dcf596db23f38053854e2e7ed569efd7","tests/hmac_tests.txt":"272c143921789a66d39396843c2fa0aadbdfe26d061bd2b7836ec40dfc76e09e","tests/pbkdf2_tests.rs":"f5b23675a2335961919b5b75d4626fddd4df5322ff597306a8d74ead9121cefe","tests/pbkdf2_tests.txt":"db65f42fb72cec9ca89c8c071d11c341f67c4df5e0c66a70735da5d1d370cee3","tests/rsa_from_pkcs8_tests.txt":"3140defc47180e283e59d4fb457061f041c9e724491849d3ff8eca3af3fcc387","tests/rsa_pkcs1_sign_tests.txt":"cb202666f2ed100a0ba8ebf818dab1bece055bd9ac9d5533d3f20fdad7b4c509","tests/rsa_pkcs1_verify_tests.txt":"ed8a330181e8a47cc707238e80377a8bd4002f6f8f6d06106c78aa9b59da98cb","tests/rsa_primitive_verify_tests.txt":"68c90857490543bcfb836f3b8644445acfe90a2e4c5189310914ce5484927418","tests/rsa_pss_sign_tests.txt":"aca70cfc877b055c0a29da2a457563cd1b5afe6e932b011e8b9a15d57dbe10d0","tests/rsa_pss_verify_tests.txt":"afcde20cea975ea235d9828bbb9b083f77584a7cb8c5c955e40c4bd305573f4a","tests/rsa_tests.rs":"57f43dbe11ce75285a92f0cbdce0df593210c4ea6bd28abe4917adbd8177aa17","tests/signature_tests.rs":"b71d9ba0580a27e1f3c7da01de19cb3a8b12c07e417b6951b74db63abcbb0143","third_party/NIST/SHAVS/SHA1LongMsg.rsp":"c765dbc1609e9046b12f60a5285a88128dab4315080c94ce9f2a57a7b0b980be","third_party/NIST/SHAVS/SHA1Monte.rsp":"d458fa7e39095b4e292a75b0cd224f90b72dc801a63ad2c0d75b8f10d745ab6d","third_party/NIST/SHAVS/SHA1ShortMsg.rsp":"be0991ddc5372932d55804b11713c9140d10435ef4b316a0773e3506eec79cda","third_party/NIST/SHAVS/SHA224LongMsg.rsp":"d37115e5d2286dde969c5e1b2275cd83ecb066366d7a38bb6b2b3adb4a88de89","third_party/NIST/SHAVS/SHA224Monte.rsp":"7854d388666ea3eb01bdaca37dc8ae0bc39d30f8731d9a5487cbd61de47d1d59","third_party/NIST/SHAVS/SHA224ShortMsg.rsp":"0dad6656c08f77252f6ccb789e42284fd61fc53bba30e83162800aa3d2aa939f","third_party/NIST/SHAVS/SHA256LongMsg.rsp":"6fac36f37360bcf74ffcf4465c18e30d6d5a04cc90885b901fc3130c16060974","third_party/NIST/SHAVS/SHA256Monte.rsp":"29ea30c6bb4b84e425fb8c1d731c6bb852dac935825f2bd1143e5d3c4f10bfb9","third_party/NIST/SHAVS/SHA256ShortMsg.rsp":"75e1cb83994638481808e225b9eb0c1ebd0c232d952ac42b61abce6363be283c","third_party/NIST/SHAVS/SHA384LongMsg.rsp":"536171765a4278c000ac3c9913edb2eed0ca7ccd5a10b72ed79fdfe7901a6d6a","third_party/NIST/SHAVS/SHA384Monte.rsp":"4270099431ff52ee1686dc472351e681c26c507433df8f107c7de203b771424e","third_party/NIST/SHAVS/SHA384ShortMsg.rsp":"7ea7bcf00fadc20949fae63703e40681ddf288fea808471cb3cbc95f3ec16811","third_party/NIST/SHAVS/SHA512LongMsg.rsp":"b1f3f05d5c209777954d49521d7ea1349447c36a0c52849e044bc397a27dd410","third_party/NIST/SHAVS/SHA512Monte.rsp":"8ca78659286c2f01667a98fc7accd32fc171ae7b24ac00f1a8ce6b77770247fa","third_party/NIST/SHAVS/SHA512ShortMsg.rsp":"e53a36c03609e5a3e3cc4b6e117a499db7864c23ec825c6cec99503a45f40764","third_party/fiat/LICENSE":"0c125a4dab5ab869473e6491db22f6c0a7f8a4de58588d03bb2b16c0c8ebd7de","third_party/fiat/curve25519.c":"7564f75438fa896278f17c249261030b4c2ebee0304678c01ca8a16a0932f1aa","third_party/fiat/curve25519_tables.h":"668f3615a9cac425b96619b46de44631976e167f0cfc842ab87844dcd8a5c529","third_party/fiat/internal.h":"cfe41b40e51ca477eda94d07dd521fbb5d3389e77d94a55b058bf60efa0d2aa8","third_party/fiat/make_curve25519_tables.py":"c499f166e8df31f23cf00296b46f7634aaacbb0f48f5bfa0277c27bdf89a619d"},"package":"2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"}
\ No newline at end of file
diff --git a/rustc_deps/vendor/ring/Cargo.toml b/rustc_deps/vendor/ring/Cargo.toml
new file mode 100644
index 0000000..2721b93
--- /dev/null
+++ b/rustc_deps/vendor/ring/Cargo.toml
@@ -0,0 +1,64 @@
+# 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 = "ring"
+version = "0.13.5"
+authors = ["Brian Smith <brian@briansmith.org>"]
+build = "build.rs"
+links = "ring-asm"
+exclude = [".gitignore", "pregenerated/tmp"]
+include = ["LICENSE", "Cargo.toml", "pregenerated/*", "build.rs", "crypto/chacha/asm/chacha-armv4.pl", "crypto/chacha/asm/chacha-armv8.pl", "crypto/chacha/asm/chacha-x86.pl", "crypto/chacha/asm/chacha-x86_64.pl", "crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl", "crypto/cipher_extra/e_aesgcmsiv.c", "crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt", "crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt", "crypto/constant_time_test.c", "crypto/cpu-aarch64-linux.c", "crypto/cpu-arm-linux.c", "crypto/cpu-arm.c", "crypto/cpu-intel.c", "crypto/crypto.c", "crypto/curve25519/asm/x25519-asm-arm.S", "crypto/fipsmodule/aes/aes.c", "crypto/fipsmodule/aes/asm/aes-586.pl", "crypto/fipsmodule/aes/asm/aes-armv4.pl", "crypto/fipsmodule/aes/asm/aes-x86_64.pl", "crypto/fipsmodule/aes/asm/aesni-x86.pl", "crypto/fipsmodule/aes/asm/aesni-x86_64.pl", "crypto/fipsmodule/aes/asm/aesv8-armx.pl", "crypto/fipsmodule/aes/asm/bsaes-armv7.pl", "crypto/fipsmodule/aes/asm/bsaes-x86_64.pl", "crypto/fipsmodule/aes/asm/vpaes-x86.pl", "crypto/fipsmodule/aes/asm/vpaes-x86_64.pl", "crypto/fipsmodule/aes/internal.h", "crypto/fipsmodule/bn/asm/armv4-mont.pl", "crypto/fipsmodule/bn/asm/armv8-mont.pl", "crypto/fipsmodule/bn/asm/x86-mont.pl", "crypto/fipsmodule/bn/asm/x86_64-mont.pl", "crypto/fipsmodule/bn/asm/x86_64-mont5.pl", "crypto/fipsmodule/bn/exponentiation.c", "crypto/fipsmodule/bn/generic.c", "crypto/fipsmodule/bn/internal.h", "crypto/fipsmodule/bn/montgomery.c", "crypto/fipsmodule/bn/montgomery_inv.c", "crypto/fipsmodule/bn/shift.c", "crypto/fipsmodule/cipher/e_aes.c", "crypto/fipsmodule/cipher/internal.h", "crypto/fipsmodule/ec/asm/ecp_nistz256-armv4.pl", "crypto/fipsmodule/ec/asm/ecp_nistz256-armv8.pl", "crypto/fipsmodule/ec/asm/ecp_nistz256-x86.pl", "crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl", "crypto/fipsmodule/ec/ecp_nistz.c", "crypto/fipsmodule/ec/ecp_nistz.h", "crypto/fipsmodule/ec/ecp_nistz256.c", "crypto/fipsmodule/ec/ecp_nistz256.h", "crypto/fipsmodule/ec/ecp_nistz256_table.inl", "crypto/fipsmodule/ec/ecp_nistz384.h", "crypto/fipsmodule/ec/ecp_nistz384.inl", "crypto/fipsmodule/ec/gfp_p256.c", "crypto/fipsmodule/ec/gfp_p384.c", "crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl", "crypto/fipsmodule/modes/asm/ghash-armv4.pl", "crypto/fipsmodule/modes/asm/ghash-x86.pl", "crypto/fipsmodule/modes/asm/ghash-x86_64.pl", "crypto/fipsmodule/modes/asm/ghashv8-armx.pl", "crypto/fipsmodule/modes/gcm.c", "crypto/fipsmodule/modes/internal.h", "crypto/fipsmodule/sha/asm/sha256-586.pl", "crypto/fipsmodule/sha/asm/sha256-armv4.pl", "crypto/fipsmodule/sha/asm/sha512-586.pl", "crypto/fipsmodule/sha/asm/sha512-armv4.pl", "crypto/fipsmodule/sha/asm/sha512-armv8.pl", "crypto/fipsmodule/sha/asm/sha512-x86_64.pl", "crypto/internal.h", "crypto/limbs/limbs.c", "crypto/limbs/limbs.h", "crypto/limbs/limbs.inl", "crypto/mem.c", "crypto/perlasm/arm-xlate.pl", "crypto/perlasm/x86asm.pl", "crypto/perlasm/x86gas.pl", "crypto/perlasm/x86nasm.pl", "crypto/perlasm/x86_64-xlate.pl", "crypto/poly1305/asm/poly1305-armv4.pl", "crypto/poly1305/asm/poly1305-armv8.pl", "crypto/poly1305/asm/poly1305-x86.pl", "crypto/poly1305/asm/poly1305-x86_64.pl", "examples/checkdigest.rs", "include/GFp/aes.h", "include/GFp/arm_arch.h", "include/GFp/base.h", "include/GFp/cpu.h", "include/GFp/mem.h", "include/GFp/type_check.h", "src/aead/aes_gcm.rs", "src/aead/aes_tests.txt", "src/aead/chacha20_poly1305.rs", "src/aead/chacha20_poly1305_openssh.rs", "src/aead/mod.rs", "src/agreement.rs", "src/arithmetic/mod.rs", "src/arithmetic/montgomery.rs", "src/bits.rs", "src/bssl.rs", "src/c.rs", "src/chacha.rs", "src/chacha_tests.txt", "src/constant_time.rs", "src/data/alg-rsa-encryption.der", "src/debug.rs", "src/der.rs", "src/digest/mod.rs", "src/digest/sha1.rs", "src/ec/curve25519/ed25519/digest.rs", "src/ec/curve25519/ed25519/mod.rs", "src/ec/curve25519/ed25519/signing.rs", "src/ec/curve25519/ed25519/verification.rs", "src/ec/curve25519/ed25519/ed25519_pkcs8_v2_template.der", "src/ec/curve25519/mod.rs", "src/ec/curve25519/ops.rs", "src/ec/curve25519/x25519.rs", "src/ec/mod.rs", "src/ec/suite_b/curve.rs", "src/ec/suite_b/ecdh.rs", "src/ec/suite_b/ecdsa/digest_scalar.rs", "src/ec/suite_b/ecdsa/mod.rs", "src/ec/suite_b/ecdsa/signing.rs", "src/ec/suite_b/ecdsa/verification.rs", "src/ec/suite_b/ecdsa/ecdsa_digest_scalar_tests.txt", "src/ec/suite_b/ecdsa/ecPublicKey_p256_pkcs8_v1_template.der", "src/ec/suite_b/ecdsa/ecPublicKey_p384_pkcs8_v1_template.der", "src/ec/suite_b/ecdsa/ecdsa_sign_asn1_tests.txt", "src/ec/suite_b/ecdsa/ecdsa_sign_fixed_tests.txt", "src/ec/suite_b/mod.rs", "src/ec/suite_b/ops/elem.rs", "src/ec/suite_b/ops/mod.rs", "src/ec/suite_b/ops/p256.rs", "src/ec/suite_b/ops/p256_elem_mul_tests.txt", "src/ec/suite_b/ops/p256_elem_neg_tests.txt", "src/ec/suite_b/ops/p256_elem_sum_tests.txt", "src/ec/suite_b/ops/p256_point_double_tests.txt", "src/ec/suite_b/ops/p256_point_mul_base_tests.txt", "src/ec/suite_b/ops/p256_point_mul_serialized_tests.txt", "src/ec/suite_b/ops/p256_point_mul_tests.txt", "src/ec/suite_b/ops/p256_point_sum_mixed_tests.txt", "src/ec/suite_b/ops/p256_point_sum_tests.txt", "src/ec/suite_b/ops/p256_scalar_mul_tests.txt", "src/ec/suite_b/ops/p256_scalar_square_tests.txt", "src/ec/suite_b/ops/p384.rs", "src/ec/suite_b/ops/p384_elem_div_by_2_tests.txt", "src/ec/suite_b/ops/p384_elem_mul_tests.txt", "src/ec/suite_b/ops/p384_elem_neg_tests.txt", "src/ec/suite_b/ops/p384_elem_sum_tests.txt", "src/ec/suite_b/ops/p384_point_double_tests.txt", "src/ec/suite_b/ops/p384_point_mul_base_tests.txt", "src/ec/suite_b/ops/p384_point_mul_tests.txt", "src/ec/suite_b/ops/p384_point_sum_tests.txt", "src/ec/suite_b/ops/p384_scalar_mul_tests.txt", "src/ec/suite_b/private_key.rs", "src/ec/suite_b/public_key.rs", "src/ec/suite_b/suite_b_public_key_tests.txt", "src/error.rs", "src/hkdf.rs", "src/hmac.rs", "src/hmac_generate_serializable_tests.txt", "src/init.rs", "src/lib.rs", "src/limb.rs", "src/pbkdf2.rs", "src/pkcs8.rs", "src/poly1305.rs", "src/poly1305_test.txt", "src/polyfill.rs", "src/rand.rs", "src/rsa/bigint.rs", "src/rsa/bigint_elem_exp_consttime_tests.txt", "src/rsa/bigint_elem_exp_vartime_tests.txt", "src/rsa/bigint_elem_mul_tests.txt", "src/rsa/bigint_elem_reduced_once_tests.txt", "src/rsa/bigint_elem_reduced_tests.txt", "src/rsa/bigint_elem_squared_tests.txt", "src/rsa/convert_nist_rsa_test_vectors.py", "src/rsa/mod.rs", "src/rsa/padding.rs", "src/rsa/random.rs", "src/rsa/rsa_pss_padding_tests.txt", "src/rsa/signature_rsa_example_private_key.der", "src/rsa/signature_rsa_example_public_key.der", "src/rsa/signing.rs", "src/rsa/verification.rs", "src/signature.rs", "src/signature_impl.rs", "src/test.rs", "src/test_1_syntax_error_tests.txt", "src/test_1_tests.txt", "src/test_3_tests.txt", "tests/aead_aes_128_gcm_tests.txt", "tests/aead_aes_256_gcm_tests.txt", "tests/aead_chacha20_poly1305_tests.txt", "tests/aead_tests.rs", "tests/agreement_tests.rs", "tests/agreement_tests.txt", "tests/digest_tests.rs", "tests/digest_tests.txt", "tests/ecdsa_from_pkcs8_tests.txt", "tests/ecdsa_tests.rs", "tests/ecdsa_sign_asn1_tests.txt", "tests/ecdsa_sign_fixed_tests.txt", "tests/ecdsa_verify_asn1_tests.txt", "tests/ecdsa_verify_fixed_tests.txt", "tests/ed25519_from_pkcs8_tests.txt", "tests/ed25519_from_pkcs8_unchecked_tests.txt", "tests/ed25519_tests.rs", "tests/ed25519_tests.txt", "tests/ed25519_test_private_key.bin", "tests/ed25519_test_public_key.bin", "tests/hkdf_tests.rs", "tests/hkdf_tests.txt", "tests/hmac_tests.rs", "tests/hmac_tests.txt", "tests/pbkdf2_tests.rs", "tests/pbkdf2_tests.txt", "tests/rsa_from_pkcs8_tests.txt", "tests/rsa_pkcs1_sign_tests.txt", "tests/rsa_pkcs1_verify_tests.txt", "tests/rsa_primitive_verify_tests.txt", "tests/rsa_pss_sign_tests.txt", "tests/rsa_pss_verify_tests.txt", "tests/rsa_tests.rs", "tests/signature_tests.rs", "third_party/fiat/curve25519.c", "third_party/fiat/curve25519_tables.h", "third_party/fiat/internal.h", "third_party/fiat/LICENSE", "third_party/fiat/make_curve25519_tables.py", "third_party/NIST/SHAVS/SHA1LongMsg.rsp", "third_party/NIST/SHAVS/SHA1Monte.rsp", "third_party/NIST/SHAVS/SHA1ShortMsg.rsp", "third_party/NIST/SHAVS/SHA224LongMsg.rsp", "third_party/NIST/SHAVS/SHA224Monte.rsp", "third_party/NIST/SHAVS/SHA224ShortMsg.rsp", "third_party/NIST/SHAVS/SHA256LongMsg.rsp", "third_party/NIST/SHAVS/SHA256Monte.rsp", "third_party/NIST/SHAVS/SHA256ShortMsg.rsp", "third_party/NIST/SHAVS/SHA384LongMsg.rsp", "third_party/NIST/SHAVS/SHA384Monte.rsp", "third_party/NIST/SHAVS/SHA384ShortMsg.rsp", "third_party/NIST/SHAVS/SHA512LongMsg.rsp", "third_party/NIST/SHAVS/SHA512Monte.rsp", "third_party/NIST/SHAVS/SHA512ShortMsg.rsp"]
+description = "Safe, fast, small crypto using Rust."
+documentation = "https://briansmith.org/rustdoc/ring/"
+readme = "doc/link-to-readme.md"
+keywords = ["crypto", "cryptography", "rand", "ECC", "RSA"]
+categories = ["cryptography", "no-std"]
+license-file = "LICENSE"
+repository = "https://github.com/briansmith/ring"
+[package.metadata.docs.rs]
+features = ["rsa_signing"]
+[profile.bench]
+opt-level = 3
+lto = true
+codegen-units = 1
+debug = false
+debug-assertions = false
+rpath = false
+
+[profile.release]
+opt-level = 3
+lto = true
+codegen-units = 1
+debug = false
+debug-assertions = false
+rpath = false
+
+[lib]
+name = "ring"
+[dependencies.untrusted]
+version = "0.6.2"
+[build-dependencies.cc]
+version = "1.0.9"
+
+[features]
+default = ["use_heap", "dev_urandom_fallback"]
+dev_urandom_fallback = []
+internal_benches = []
+rsa_signing = ["use_heap"]
+slow_tests = []
+test_logging = []
+use_heap = []
+[target."cfg(any(target_os = \"redox\", all(unix, not(any(target_os = \"macos\", target_os = \"ios\")))))".dependencies.lazy_static]
+version = "1.2"
+[target."cfg(target_os = \"linux\")".dependencies.libc]
+version = "0.2.34"
diff --git a/rustc_deps/vendor/ring/LICENSE b/rustc_deps/vendor/ring/LICENSE
new file mode 100644
index 0000000..bf78743
--- /dev/null
+++ b/rustc_deps/vendor/ring/LICENSE
@@ -0,0 +1,204 @@
+Note that it is easy for this file to get out of sync with the licenses in the
+source code files. It's recommended to compare the licenses in the source code
+with what's mentioned here.
+
+*ring* is derived from BoringSSL, so the licensing situation in *ring* is
+similar to BoringSSL.
+
+*ring* uses an ISC-style license like BoringSSL for code in new files,
+including in particular all the Rust code:
+
+   Copyright 2015-2016 Brian Smith.
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+   SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+   OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL
+licensing. Files that are completely new have a Google copyright and an ISC
+license. This license is reproduced at the bottom of this file.
+
+Contributors to BoringSSL are required to follow the CLA rules for Chromium:
+https://cla.developers.google.com/clas
+
+Files in third_party/ have their own licenses, as described therein. The MIT
+license, for third_party/fiat, which, unlike other third_party directories, is
+compiled into non-test libraries, is included below.
+
+The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
+OpenSSL License and the original SSLeay license apply to the toolkit. See below
+for the actual license texts. Actually both licenses are BSD-style Open Source
+licenses. In case of any license issues related to OpenSSL please contact
+openssl-core@openssl.org.
+
+The following are Google-internal bug numbers where explicit permission from
+some authors is recorded for use of their work:
+  27287199
+  27287880
+  27287883
+
+  OpenSSL License
+  ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2011 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+
+ISC license used for completely new code in BoringSSL:
+
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+
+The code in third_party/fiat carries the MIT license:
+
+Copyright (c) 2015-2016 the fiat-crypto authors (see
+https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).
+
+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.
diff --git a/rustc_deps/vendor/ring/build.rs b/rustc_deps/vendor/ring/build.rs
new file mode 100644
index 0000000..29e6e6f
--- /dev/null
+++ b/rustc_deps/vendor/ring/build.rs
@@ -0,0 +1,794 @@
+// Copyright 2015-2016 Brian Smith.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+//! Build the non-Rust components.
+
+#![deny(box_pointers)]
+#![forbid(
+    anonymous_parameters,
+    legacy_directory_ownership,
+    missing_copy_implementations,
+    missing_debug_implementations,
+    missing_docs,
+    trivial_casts,
+    trivial_numeric_casts,
+    unsafe_code,
+    unstable_features,
+    unused_extern_crates,
+    unused_import_braces,
+    unused_qualifications,
+    unused_results,
+    variant_size_differences,
+    warnings
+)]
+
+extern crate cc;
+
+// In the `pregenerate_asm_main()` case we don't want to access (Cargo)
+// environment variables at all, so avoid `use std::env` here.
+
+use std::{
+    fs::{self, DirEntry},
+    path::{Path, PathBuf},
+    process::Command,
+    time::SystemTime,
+};
+
+const X86: &str = "x86";
+const X86_64: &str = "x86_64";
+const AARCH64: &str = "aarch64";
+const ARM: &str = "arm";
+const NEVER: &str = "Don't ever build this file.";
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+const RING_SRCS: &[(&[&str], &str)] = &[
+    (&[], "crypto/fipsmodule/aes/aes.c"),
+    (&[], "crypto/fipsmodule/bn/exponentiation.c"),
+    (&[], "crypto/fipsmodule/bn/generic.c"),
+    (&[], "crypto/fipsmodule/bn/montgomery.c"),
+    (&[], "crypto/fipsmodule/bn/montgomery_inv.c"),
+    (&[], "crypto/fipsmodule/bn/shift.c"),
+    (&[], "crypto/fipsmodule/cipher/e_aes.c"),
+    (&[NEVER], "crypto/cipher_extra/e_aesgcmsiv.c"),
+    (&[], "crypto/crypto.c"),
+    (&[], "crypto/fipsmodule/ec/ecp_nistz.c"),
+    (&[], "crypto/fipsmodule/ec/ecp_nistz256.c"),
+    (&[], "crypto/fipsmodule/ec/gfp_p256.c"),
+    (&[], "crypto/fipsmodule/ec/gfp_p384.c"),
+    (&[], "crypto/limbs/limbs.c"),
+    (&[], "crypto/mem.c"),
+    (&[], "crypto/fipsmodule/modes/gcm.c"),
+    (&[], "third_party/fiat/curve25519.c"),
+
+    (&[X86_64, X86], "crypto/cpu-intel.c"),
+
+    (&[X86], "crypto/fipsmodule/aes/asm/aes-586.pl"),
+    (&[X86], "crypto/fipsmodule/aes/asm/aesni-x86.pl"),
+    (&[X86], "crypto/fipsmodule/aes/asm/vpaes-x86.pl"),
+    (&[X86], "crypto/fipsmodule/bn/asm/x86-mont.pl"),
+    (&[X86], "crypto/chacha/asm/chacha-x86.pl"),
+    (&[X86], "crypto/fipsmodule/ec/asm/ecp_nistz256-x86.pl"),
+    (&[X86], "crypto/fipsmodule/modes/asm/ghash-x86.pl"),
+    (&[X86], "crypto/poly1305/asm/poly1305-x86.pl"),
+    (&[X86], "crypto/fipsmodule/sha/asm/sha256-586.pl"),
+    (&[X86], "crypto/fipsmodule/sha/asm/sha512-586.pl"),
+
+    (&[X86_64], "crypto/fipsmodule/aes/asm/aes-x86_64.pl"),
+    (&[X86_64], "crypto/fipsmodule/aes/asm/aesni-x86_64.pl"),
+    (&[X86_64], "crypto/fipsmodule/aes/asm/vpaes-x86_64.pl"),
+    (&[X86_64], "crypto/fipsmodule/bn/asm/x86_64-mont.pl"),
+    (&[X86_64], "crypto/fipsmodule/bn/asm/x86_64-mont5.pl"),
+    (&[X86_64], "crypto/chacha/asm/chacha-x86_64.pl"),
+    (&[NEVER], "crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl"),
+    (&[X86_64], "crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl"),
+    (&[X86_64], "crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl"),
+    (&[X86_64], "crypto/fipsmodule/modes/asm/ghash-x86_64.pl"),
+    (&[X86_64], "crypto/poly1305/asm/poly1305-x86_64.pl"),
+    (&[X86_64], SHA512_X86_64),
+
+    (&[AARCH64, ARM], "crypto/fipsmodule/aes/asm/aesv8-armx.pl"),
+    (&[AARCH64, ARM], "crypto/cpu-arm-linux.c"),
+    (&[AARCH64, ARM], "crypto/cpu-arm.c"),
+    (&[AARCH64, ARM], "crypto/fipsmodule/modes/asm/ghashv8-armx.pl"),
+
+    (&[ARM], "crypto/fipsmodule/aes/asm/aes-armv4.pl"),
+    (&[ARM], "crypto/fipsmodule/aes/asm/bsaes-armv7.pl"),
+    (&[ARM], "crypto/fipsmodule/bn/asm/armv4-mont.pl"),
+    (&[ARM], "crypto/chacha/asm/chacha-armv4.pl"),
+    (&[ARM], "crypto/curve25519/asm/x25519-asm-arm.S"),
+    (&[ARM], "crypto/fipsmodule/ec/asm/ecp_nistz256-armv4.pl"),
+    (&[ARM], "crypto/fipsmodule/modes/asm/ghash-armv4.pl"),
+    (&[ARM], "crypto/poly1305/asm/poly1305-armv4.pl"),
+    (&[ARM], "crypto/fipsmodule/sha/asm/sha256-armv4.pl"),
+    (&[ARM], "crypto/fipsmodule/sha/asm/sha512-armv4.pl"),
+
+    (&[AARCH64], "crypto/fipsmodule/bn/asm/armv8-mont.pl"),
+    (&[AARCH64], "crypto/cpu-aarch64-linux.c"),
+    (&[AARCH64], "crypto/chacha/asm/chacha-armv8.pl"),
+    (&[AARCH64], "crypto/fipsmodule/ec/asm/ecp_nistz256-armv8.pl"),
+    (&[AARCH64], "crypto/poly1305/asm/poly1305-armv8.pl"),
+    (&[AARCH64], SHA512_ARMV8),
+];
+
+const SHA256_X86_64: &str = "crypto/fipsmodule/sha/asm/sha256-x86_64.pl";
+const SHA512_X86_64: &str = "crypto/fipsmodule/sha/asm/sha512-x86_64.pl";
+
+const SHA256_ARMV8: &str = "crypto/fipsmodule/sha/asm/sha256-armv8.pl";
+const SHA512_ARMV8: &str = "crypto/fipsmodule/sha/asm/sha512-armv8.pl";
+
+const RING_TEST_SRCS: &[&str] = &[("crypto/constant_time_test.c")];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+const RING_INCLUDES: &[&str] =
+    &["crypto/fipsmodule/aes/internal.h",
+      "crypto/fipsmodule/bn/internal.h",
+      "crypto/fipsmodule/cipher/internal.h",
+      "crypto/fipsmodule/ec/ecp_nistz256_table.inl",
+      "crypto/fipsmodule/ec/ecp_nistz384.inl",
+      "crypto/fipsmodule/ec/ecp_nistz.h",
+      "crypto/fipsmodule/ec/ecp_nistz384.h",
+      "crypto/fipsmodule/ec/ecp_nistz256.h",
+      "crypto/internal.h",
+      "crypto/limbs/limbs.h",
+      "crypto/limbs/limbs.inl",
+      "crypto/fipsmodule/modes/internal.h",
+      "include/GFp/aes.h",
+      "include/GFp/arm_arch.h",
+      "include/GFp/base.h",
+      "include/GFp/cpu.h",
+      "include/GFp/mem.h",
+      "include/GFp/type_check.h",
+      "third_party/fiat/curve25519_tables.h",
+      "third_party/fiat/internal.h",
+    ];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+const RING_PERL_INCLUDES: &[&str] =
+    &["crypto/perlasm/arm-xlate.pl",
+      "crypto/perlasm/x86gas.pl",
+      "crypto/perlasm/x86nasm.pl",
+      "crypto/perlasm/x86asm.pl",
+      "crypto/perlasm/x86_64-xlate.pl"];
+
+const RING_BUILD_FILE: &[&str] = &["build.rs"];
+
+const PREGENERATED: &'static str = "pregenerated";
+
+fn c_flags(target: &Target) -> &'static [&'static str] {
+    if target.env != MSVC {
+        static NON_MSVC_FLAGS: &[&str] = &[
+            "-std=c1x", // GCC 4.6 requires "c1x" instead of "c11"
+            "-Wbad-function-cast",
+            "-Wmissing-prototypes",
+            "-Wnested-externs",
+            "-Wstrict-prototypes",
+        ];
+        NON_MSVC_FLAGS
+    } else {
+        &[]
+    }
+}
+
+fn cpp_flags(target: &Target) -> &'static [&'static str] {
+    if target.env != MSVC {
+        static NON_MSVC_FLAGS: &[&str] = &[
+            "-pedantic",
+            "-pedantic-errors",
+            "-Wall",
+            "-Wextra",
+            "-Wcast-align",
+            "-Wcast-qual",
+            "-Wenum-compare",
+            "-Wfloat-equal",
+            "-Wformat=2",
+            "-Winline",
+            "-Winvalid-pch",
+            "-Wmissing-declarations",
+            "-Wmissing-field-initializers",
+            "-Wmissing-include-dirs",
+            "-Wredundant-decls",
+            "-Wshadow",
+            "-Wsign-compare",
+            "-Wundef",
+            "-Wuninitialized",
+            "-Wwrite-strings",
+            "-fno-strict-aliasing",
+            "-fvisibility=hidden",
+            "-Wno-cast-align",
+        ];
+        NON_MSVC_FLAGS
+    } else {
+        static MSVC_FLAGS: &[&str] = &[
+            "/GS",   // Buffer security checks.
+            "/Gy",   // Enable function-level linking.
+            "/EHsc", // C++ exceptions only, only in C++.
+            "/GR-",  // Disable RTTI.
+            "/Zc:wchar_t",
+            "/Zc:forScope",
+            "/Zc:inline",
+            "/Zc:rvalueCast",
+            // Warnings.
+            "/sdl",
+            "/Wall",
+            "/wd4127", // C4127: conditional expression is constant
+            "/wd4464", // C4464: relative include path contains '..'
+            "/wd4514", // C4514: <name>: unreferenced inline function has be
+            "/wd4710", // C4710: function not inlined
+            "/wd4711", // C4711: function 'function' selected for inline expansion
+            "/wd4820", // C4820: <struct>: <n> bytes padding added after <name>
+            "/wd5045", /* C5045: Compiler will insert Spectre mitigation for memory load if
+                        * /Qspectre switch specified */
+        ];
+        MSVC_FLAGS
+    }
+}
+
+const LD_FLAGS: &[&str] = &[];
+
+// None means "any OS" or "any target". The first match in sequence order is
+// taken.
+const ASM_TARGETS: &[(&str, Option<&str>, &str)] = &[
+    ("x86_64", Some("ios"), "macosx"),
+    ("x86_64", Some("macos"), "macosx"),
+    ("x86_64", Some(WINDOWS), "nasm"),
+    ("x86_64", None, "elf"),
+    ("aarch64", Some("ios"), "ios64"),
+    ("aarch64", None, "linux64"),
+    ("x86", Some(WINDOWS), "win32n"),
+    ("x86", Some("ios"), "macosx"),
+    ("x86", None, "elf"),
+    ("arm", Some("ios"), "ios32"),
+    ("arm", None, "linux32"),
+];
+
+const WINDOWS: &'static str = "windows";
+const MSVC: &'static str = "msvc";
+const MSVC_OBJ_OPT: &'static str = "/Fo";
+const MSVC_OBJ_EXT: &'static str = "obj";
+
+fn main() {
+    if let Ok(package_name) = std::env::var("CARGO_PKG_NAME") {
+        if package_name == "ring" {
+            ring_build_rs_main();
+            return;
+        }
+    }
+
+    pregenerate_asm_main();
+}
+
+fn ring_build_rs_main() {
+    use std::env;
+
+    for (key, value) in env::vars() {
+        println!("{}: {}", key, value);
+    }
+
+    let out_dir = env::var("OUT_DIR").unwrap();
+    let out_dir = PathBuf::from(out_dir);
+
+    let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
+    let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
+    let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
+    let (obj_ext, obj_opt) = if env == MSVC {
+        (MSVC_OBJ_EXT, MSVC_OBJ_OPT)
+    } else {
+        ("o", "-o")
+    };
+
+    let is_debug = env::var("DEBUG").unwrap() != "false";
+    let target = Target {
+        arch,
+        os,
+        env,
+        obj_ext,
+        obj_opt,
+        is_debug,
+    };
+    let pregenerated = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join(PREGENERATED);
+
+    build_c_code(&target, pregenerated, &out_dir);
+    check_all_files_tracked()
+}
+
+fn pregenerate_asm_main() {
+    let pregenerated = PathBuf::from(PREGENERATED);
+    std::fs::create_dir(&pregenerated).unwrap();
+    let pregenerated_tmp = pregenerated.join("tmp");
+    std::fs::create_dir(&pregenerated_tmp).unwrap();
+
+    for &(target_arch, target_os, perlasm_format) in ASM_TARGETS {
+        // For Windows, package pregenerated object files instead of
+        // pregenerated assembly language source files, so that the user
+        // doesn't need to install the assembler.
+        let asm_dir = if target_os == Some(WINDOWS) {
+            &pregenerated_tmp
+        } else {
+            &pregenerated
+        };
+
+        let perlasm_src_dsts = perlasm_src_dsts(&asm_dir, target_arch, target_os, perlasm_format);
+        perlasm(&perlasm_src_dsts, target_arch, perlasm_format, None);
+
+        if target_os == Some(WINDOWS) {
+            //let lib_name = ring_asm_name(target_arch);
+            let srcs = asm_srcs(perlasm_src_dsts);
+            for src in srcs {
+                let src_path = PathBuf::from(src);
+                let obj_path = obj_path(&pregenerated, &src_path, MSVC_OBJ_EXT);
+                run_command(yasm(&src_path, target_arch, &obj_path));
+            }
+        }
+    }
+}
+
+struct Target {
+    arch: String,
+    os: String,
+    env: String,
+    obj_ext: &'static str,
+    obj_opt: &'static str,
+    is_debug: bool,
+}
+
+impl Target {
+    pub fn arch(&self) -> &str { &self.arch }
+    pub fn os(&self) -> &str { &self.os }
+    pub fn env(&self) -> &str { &self.env }
+    pub fn is_debug(&self) -> bool { self.is_debug }
+}
+
+fn build_c_code(target: &Target, pregenerated: PathBuf, out_dir: &Path) {
+    let includes_modified = RING_INCLUDES
+        .iter()
+        .chain(RING_BUILD_FILE.iter())
+        .chain(RING_PERL_INCLUDES.iter())
+        .map(|f| file_modified(Path::new(*f)))
+        .max()
+        .unwrap();
+
+    fn is_none_or_equals<T>(opt: Option<T>, other: T) -> bool
+    where
+        T: PartialEq,
+    {
+        if let Some(value) = opt {
+            value == other
+        } else {
+            true
+        }
+    }
+
+    let (_, _, perlasm_format) = ASM_TARGETS
+        .iter()
+        .find(|entry| {
+            let &(entry_arch, entry_os, _) = *entry;
+            entry_arch == target.arch() && is_none_or_equals(entry_os, target.os())
+        })
+        .unwrap();
+
+    let is_git = std::fs::metadata(".git").is_ok();
+
+    let use_pregenerated = !is_git;
+    let warnings_are_errors = is_git;
+
+    let asm_dir = if use_pregenerated {
+        &pregenerated
+    } else {
+        out_dir
+    };
+
+    let perlasm_src_dsts =
+        perlasm_src_dsts(asm_dir, target.arch(), Some(target.os()), perlasm_format);
+
+    if !use_pregenerated {
+        perlasm(
+            &perlasm_src_dsts[..],
+            target.arch(),
+            perlasm_format,
+            Some(includes_modified),
+        );
+    }
+
+    let mut asm_srcs = asm_srcs(perlasm_src_dsts);
+
+    // For Windows we also pregenerate the object files for non-Git builds so
+    // the user doesn't need to install the assembler. On other platforms we
+    // assume the C compiler also assembles.
+    if use_pregenerated && target.os() == WINDOWS {
+        // The pregenerated object files always use ".obj" as the extension,
+        // even when the C/C++ compiler outputs files with the ".o" extension.
+        asm_srcs = asm_srcs
+            .iter()
+            .map(|src| obj_path(&pregenerated, src.as_path(), "obj"))
+            .collect::<Vec<_>>();
+    }
+
+    let core_srcs = sources_for_arch(target.arch())
+        .into_iter()
+        .filter(|p| !is_perlasm(&p))
+        .collect::<Vec<_>>();
+
+    let test_srcs = RING_TEST_SRCS.iter().map(PathBuf::from).collect::<Vec<_>>();
+
+    let libs = [
+        ("ring-core", &core_srcs[..], &asm_srcs[..]),
+        ("ring-test", &test_srcs[..], &[]),
+    ];
+
+    // XXX: Ideally, ring-test would only be built for `cargo test`, but Cargo
+    // can't do that yet.
+    libs.into_iter()
+        .for_each(|&(lib_name, srcs, additional_srcs)| {
+            build_library(
+                &target,
+                &out_dir,
+                lib_name,
+                srcs,
+                additional_srcs,
+                warnings_are_errors,
+                includes_modified,
+            )
+        });
+
+    println!(
+        "cargo:rustc-link-search=native={}",
+        out_dir.to_str().expect("Invalid path")
+    );
+}
+
+fn build_library(
+    target: &Target, out_dir: &Path, lib_name: &str, srcs: &[PathBuf], additional_srcs: &[PathBuf],
+    warnings_are_errors: bool, includes_modified: SystemTime,
+) {
+    // Compile all the (dirty) source files into object files.
+    #[allow(box_pointers)] // XXX
+    let objs = additional_srcs
+        .into_iter()
+        .chain(srcs.into_iter())
+        .filter(|f| target.env() != "msvc" || f.extension().unwrap().to_str().unwrap() != "S")
+        .map(|f| compile(f, target, warnings_are_errors, out_dir, includes_modified))
+        .collect::<Vec<_>>();
+
+    // Rebuild the library if necessary.
+    let lib_path = PathBuf::from(out_dir).join(format!("lib{}.a", lib_name));
+
+    if objs
+        .iter()
+        .map(Path::new)
+        .any(|p| need_run(&p, &lib_path, includes_modified))
+    {
+        let mut c = cc::Build::new();
+
+        for f in LD_FLAGS {
+            let _ = c.flag(&f);
+        }
+        match target.os() {
+            "macos" => {
+                let _ = c.flag("-fPIC");
+                let _ = c.flag("-Wl,-dead_strip");
+            },
+            _ => {
+                let _ = c.flag("-Wl,--gc-sections".into());
+            },
+        }
+        for o in objs {
+            let _ = c.object(o);
+        }
+
+        // Handled below.
+        let _ = c.cargo_metadata(false);
+
+        c.compile(
+            lib_path
+                .file_name()
+                .and_then(|f| f.to_str())
+                .expect("No filename"),
+        );
+    }
+
+    // Link the library. This works even when the library doesn't need to be
+    // rebuilt.
+    println!("cargo:rustc-link-lib=static={}", lib_name);
+}
+
+fn compile(
+    p: &Path, target: &Target, warnings_are_errors: bool, out_dir: &Path,
+    includes_modified: SystemTime,
+) -> String {
+    let ext = p.extension().unwrap().to_str().unwrap();
+    if ext == "obj" {
+        p.to_str().expect("Invalid path").into()
+    } else {
+        let mut out_path = out_dir.clone().join(p.file_name().unwrap());
+        assert!(out_path.set_extension(target.obj_ext));
+        if need_run(&p, &out_path, includes_modified) {
+            let cmd = if target.os() != WINDOWS || ext != "asm" {
+                cc(p, ext, target, warnings_are_errors, &out_path)
+            } else {
+                yasm(p, target.arch(), &out_path)
+            };
+
+            run_command(cmd);
+        }
+        out_path.to_str().expect("Invalid path").into()
+    }
+}
+
+fn obj_path(out_dir: &Path, src: &Path, obj_ext: &str) -> PathBuf {
+    let mut out_path = out_dir.clone().join(src.file_name().unwrap());
+    assert!(out_path.set_extension(obj_ext));
+    out_path
+}
+
+fn cc(
+    file: &Path, ext: &str, target: &Target, warnings_are_errors: bool, out_dir: &Path,
+) -> Command {
+    let mut c = cc::Build::new();
+    let _ = c.include("include");
+    match ext {
+        "c" =>
+            for f in c_flags(target) {
+                let _ = c.flag(f);
+            },
+        "S" => (),
+        e => panic!("Unsupported file extension: {:?}", e),
+    };
+    for f in cpp_flags(target) {
+        let _ = c.flag(&f);
+    }
+    if target.os() != "none" && target.os() != "redox" && target.os() != "windows" {
+        let _ = c.flag("-fstack-protector");
+    }
+
+    match (target.os(), target.env()) {
+        // ``-gfull`` is required for Darwin's |-dead_strip|.
+        ("macos", _) => {
+            let _ = c.flag("-gfull");
+        },
+        (_, "msvc") => (),
+        _ => {
+            let _ = c.flag("-g3");
+        },
+    };
+    if !target.is_debug() {
+        let _ = c.define("NDEBUG", None);
+    }
+
+    if target.env() == "msvc" {
+        if std::env::var("OPT_LEVEL").unwrap() == "0" {
+            let _ = c.flag("/Od"); // Disable optimization for debug builds.
+                                   // run-time checking: (s)tack frame, (u)ninitialized variables
+            let _ = c.flag("/RTCsu");
+        } else {
+            let _ = c.flag("/Ox"); // Enable full optimization.
+        }
+    }
+
+    if target.env() != "msvc" {
+        let _ = c.define("_XOPEN_SOURCE", Some("700"));
+    }
+
+    if warnings_are_errors {
+        let flag = if target.env() != "msvc" {
+            "-Werror"
+        } else {
+            "/WX"
+        };
+        let _ = c.flag(flag);
+    }
+    if target.env() == "musl" {
+        // Some platforms enable _FORTIFY_SOURCE by default, but musl
+        // libc doesn't support it yet. See
+        // http://wiki.musl-libc.org/wiki/Future_Ideas#Fortify
+        // http://www.openwall.com/lists/musl/2015/02/04/3
+        // http://www.openwall.com/lists/musl/2015/06/17/1
+        let _ = c.flag("-U_FORTIFY_SOURCE");
+    }
+
+    let mut c = c.get_compiler().to_command();
+    let _ = c
+        .arg("-c")
+        .arg(format!(
+            "{}{}",
+            target.obj_opt,
+            out_dir.to_str().expect("Invalid path")
+        ))
+        .arg(file);
+    c
+}
+
+fn yasm(file: &Path, arch: &str, out_file: &Path) -> Command {
+    let (oformat, machine) = match arch {
+        "x86_64" => ("--oformat=win64", "--machine=amd64"),
+        "x86" => ("--oformat=win32", "--machine=x86"),
+        _ => panic!("unsupported arch: {}", arch),
+    };
+    let mut c = Command::new("yasm.exe");
+    let _ = c
+        .arg("-X")
+        .arg("vc")
+        .arg("--dformat=cv8")
+        .arg(oformat)
+        .arg(machine)
+        .arg("-o")
+        .arg(out_file.to_str().expect("Invalid path"))
+        .arg(file);
+    c
+}
+
+fn run_command_with_args<S>(command_name: S, args: &[String])
+where
+    S: AsRef<std::ffi::OsStr> + Copy,
+{
+    let mut cmd = Command::new(command_name);
+    let _ = cmd.args(args);
+    run_command(cmd)
+}
+
+fn run_command(mut cmd: Command) {
+    println!("running {:?}", cmd);
+    let status = cmd.status().unwrap_or_else(|e| {
+        panic!("failed to execute [{:?}]: {}", cmd, e);
+    });
+    if !status.success() {
+        panic!("execution failed");
+    }
+}
+
+fn sources_for_arch(arch: &str) -> Vec<PathBuf> {
+    RING_SRCS
+        .iter()
+        .filter(|&&(archs, _)| archs.is_empty() || archs.contains(&arch))
+        .map(|&(_, p)| PathBuf::from(p))
+        .collect::<Vec<_>>()
+}
+
+fn perlasm_src_dsts(
+    out_dir: &Path, arch: &str, os: Option<&str>, perlasm_format: &str,
+) -> Vec<(PathBuf, PathBuf)> {
+    let srcs = sources_for_arch(arch);
+    let mut src_dsts = srcs
+        .iter()
+        .filter(|p| is_perlasm(p))
+        .map(|src| (src.clone(), asm_path(out_dir, src, os, perlasm_format)))
+        .collect::<Vec<_>>();
+
+    // Some PerlAsm source files need to be run multiple times with different
+    // output paths.
+    {
+        // Appease the borrow checker.
+        let mut maybe_synthesize = |concrete, synthesized| {
+            let concrete_path = PathBuf::from(concrete);
+            if srcs.contains(&concrete_path) {
+                let synthesized_path = PathBuf::from(synthesized);
+                src_dsts.push((
+                    concrete_path,
+                    asm_path(out_dir, &synthesized_path, os, perlasm_format),
+                ))
+            }
+        };
+        maybe_synthesize(SHA512_X86_64, SHA256_X86_64);
+        maybe_synthesize(SHA512_ARMV8, SHA256_ARMV8);
+    }
+
+    src_dsts
+}
+
+fn asm_srcs(perlasm_src_dsts: Vec<(PathBuf, PathBuf)>) -> Vec<PathBuf> {
+    perlasm_src_dsts
+        .into_iter()
+        .map(|(_src, dst)| dst)
+        .collect::<Vec<_>>()
+}
+
+fn is_perlasm(path: &PathBuf) -> bool { path.extension().unwrap().to_str().unwrap() == "pl" }
+
+fn asm_path(out_dir: &Path, src: &Path, os: Option<&str>, perlasm_format: &str) -> PathBuf {
+    let src_stem = src.file_stem().expect("source file without basename");
+
+    let dst_stem = src_stem.to_str().unwrap();
+    let dst_extension = if os == Some("windows") { "asm" } else { "S" };
+    let dst_filename = format!("{}-{}.{}", dst_stem, perlasm_format, dst_extension);
+    out_dir.join(dst_filename)
+}
+
+fn perlasm(
+    src_dst: &[(PathBuf, PathBuf)], arch: &str, perlasm_format: &str,
+    includes_modified: Option<SystemTime>,
+) {
+    for (src, dst) in src_dst {
+        if let Some(includes_modified) = includes_modified {
+            if !need_run(src, dst, includes_modified) {
+                continue;
+            }
+        }
+
+        let mut args = Vec::<String>::new();
+        args.push(src.to_string_lossy().into_owned());
+        args.push(perlasm_format.to_owned());
+        if arch == "x86" {
+            args.push("-fPIC".into());
+            args.push("-DOPENSSL_IA32_SSE2".into());
+        }
+        // Work around PerlAsm issue for ARM and AAarch64 targets by replacing
+        // back slashes with forward slashes.
+        let dst = dst
+            .to_str()
+            .expect("Could not convert path")
+            .replace("\\", "/");
+        args.push(dst);
+        run_command_with_args(&get_command("PERL_EXECUTABLE", "perl"), &args);
+    }
+}
+
+fn need_run(source: &Path, target: &Path, includes_modified: SystemTime) -> bool {
+    let s_modified = file_modified(source);
+    if let Ok(target_metadata) = std::fs::metadata(target) {
+        let target_modified = target_metadata.modified().unwrap();
+        s_modified >= target_modified || includes_modified >= target_modified
+    } else {
+        // On error fetching metadata for the target file, assume the target
+        // doesn't exist.
+        true
+    }
+}
+
+fn file_modified(path: &Path) -> SystemTime {
+    let path = Path::new(path);
+    let path_as_str = format!("{:?}", path);
+    std::fs::metadata(path)
+        .expect(&path_as_str)
+        .modified()
+        .expect("nah")
+}
+
+fn get_command(var: &str, default: &str) -> String { std::env::var(var).unwrap_or(default.into()) }
+
+fn check_all_files_tracked() {
+    for path in &["crypto", "include", "third_party/fiat"] {
+        walk_dir(&PathBuf::from(path), &is_tracked);
+    }
+}
+
+fn is_tracked(file: &DirEntry) {
+    let p = file.path();
+    let cmp = |f| p == PathBuf::from(f);
+    let tracked = match p.extension().and_then(|p| p.to_str()) {
+        Some("h") | Some("inl") => RING_INCLUDES.iter().any(cmp),
+        Some("c") | Some("S") | Some("asm") =>
+            RING_SRCS.iter().any(|(_, f)| cmp(f)) || RING_TEST_SRCS.iter().any(cmp),
+        Some("pl") => RING_SRCS.iter().any(|(_, f)| cmp(f)) || RING_PERL_INCLUDES.iter().any(cmp),
+        _ => true,
+    };
+    if !tracked {
+        panic!("{:?} is not tracked in build.rs", p);
+    }
+}
+
+fn walk_dir<F>(dir: &Path, cb: &F)
+where
+    F: Fn(&DirEntry),
+{
+    if dir.is_dir() {
+        for entry in fs::read_dir(dir).unwrap() {
+            let entry = entry.unwrap();
+            let path = entry.path();
+            if path.is_dir() {
+                walk_dir(&path, cb);
+            } else {
+                cb(&entry);
+            }
+        }
+    }
+}
diff --git a/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-armv4.pl b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-armv4.pl
new file mode 100644
index 0000000..ea0ef5f
--- /dev/null
+++ b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-armv4.pl
@@ -0,0 +1,1164 @@
+#! /usr/bin/env perl
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# December 2014
+#
+# ChaCha20 for ARMv4.
+#
+# Performance in cycles per byte out of large buffer.
+#
+#			IALU/gcc-4.4    1xNEON      3xNEON+1xIALU
+#
+# Cortex-A5		19.3(*)/+95%    21.8        14.1
+# Cortex-A8		10.5(*)/+160%   13.9        6.35
+# Cortex-A9		12.9(**)/+110%  14.3        6.50
+# Cortex-A15		11.0/+40%       16.0        5.00
+# Snapdragon S4		11.5/+125%      13.6        4.90
+#
+# (*)	most "favourable" result for aligned data on little-endian
+#	processor, result for misaligned data is 10-15% lower;
+# (**)	this result is a trade-off: it can be improved by 20%,
+#	but then Snapdragon S4 and Cortex-A8 results get
+#	20-25% worse;
+
+$flavour = shift;
+if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
+else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
+
+if ($flavour && $flavour ne "void") {
+    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
+    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
+    die "can't locate arm-xlate.pl";
+
+    open STDOUT,"| \"$^X\" $xlate $flavour $output";
+} else {
+    open STDOUT,">$output";
+}
+
+sub AUTOLOAD()		# thunk [simplified] x86-style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
+  my $arg = pop;
+    $arg = "#$arg" if ($arg*1 eq $arg);
+    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
+}
+
+my @x=map("r$_",(0..7,"x","x","x","x",12,"x",14,"x"));
+my @t=map("r$_",(8..11));
+
+sub ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my $odd = $d0&1;
+my ($xc,$xc_) = (@t[0..1]);
+my ($xd,$xd_) = $odd ? (@t[2],@x[$d1]) : (@x[$d0],@t[2]);
+my @ret;
+
+	# Consider order in which variables are addressed by their
+	# index:
+	#
+	#       a   b   c   d
+	#
+	#       0   4   8  12 < even round
+	#       1   5   9  13
+	#       2   6  10  14
+	#       3   7  11  15
+	#       0   5  10  15 < odd round
+	#       1   6  11  12
+	#       2   7   8  13
+	#       3   4   9  14
+	#
+	# 'a', 'b' are permanently allocated in registers, @x[0..7],
+	# while 'c's and pair of 'd's are maintained in memory. If
+	# you observe 'c' column, you'll notice that pair of 'c's is
+	# invariant between rounds. This means that we have to reload
+	# them once per round, in the middle. This is why you'll see
+	# bunch of 'c' stores and loads in the middle, but none in
+	# the beginning or end. If you observe 'd' column, you'll
+	# notice that 15 and 13 are reused in next pair of rounds.
+	# This is why these two are chosen for offloading to memory,
+	# to make loads count more.
+							push @ret,(
+	"&add	(@x[$a0],@x[$a0],@x[$b0])",
+	"&mov	($xd,$xd,'ror#16')",
+	 "&add	(@x[$a1],@x[$a1],@x[$b1])",
+	 "&mov	($xd_,$xd_,'ror#16')",
+	"&eor	($xd,$xd,@x[$a0],'ror#16')",
+	 "&eor	($xd_,$xd_,@x[$a1],'ror#16')",
+
+	"&add	($xc,$xc,$xd)",
+	"&mov	(@x[$b0],@x[$b0],'ror#20')",
+	 "&add	($xc_,$xc_,$xd_)",
+	 "&mov	(@x[$b1],@x[$b1],'ror#20')",
+	"&eor	(@x[$b0],@x[$b0],$xc,'ror#20')",
+	 "&eor	(@x[$b1],@x[$b1],$xc_,'ror#20')",
+
+	"&add	(@x[$a0],@x[$a0],@x[$b0])",
+	"&mov	($xd,$xd,'ror#24')",
+	 "&add	(@x[$a1],@x[$a1],@x[$b1])",
+	 "&mov	($xd_,$xd_,'ror#24')",
+	"&eor	($xd,$xd,@x[$a0],'ror#24')",
+	 "&eor	($xd_,$xd_,@x[$a1],'ror#24')",
+
+	"&add	($xc,$xc,$xd)",
+	"&mov	(@x[$b0],@x[$b0],'ror#25')"		);
+							push @ret,(
+	"&str	($xd,'[sp,#4*(16+$d0)]')",
+	"&ldr	($xd,'[sp,#4*(16+$d2)]')"		) if ($odd);
+							push @ret,(
+	 "&add	($xc_,$xc_,$xd_)",
+	 "&mov	(@x[$b1],@x[$b1],'ror#25')"		);
+							push @ret,(
+	 "&str	($xd_,'[sp,#4*(16+$d1)]')",
+	 "&ldr	($xd_,'[sp,#4*(16+$d3)]')"		) if (!$odd);
+							push @ret,(
+	"&eor	(@x[$b0],@x[$b0],$xc,'ror#25')",
+	 "&eor	(@x[$b1],@x[$b1],$xc_,'ror#25')"	);
+
+	$xd=@x[$d2]					if (!$odd);
+	$xd_=@x[$d3]					if ($odd);
+							push @ret,(
+	"&str	($xc,'[sp,#4*(16+$c0)]')",
+	"&ldr	($xc,'[sp,#4*(16+$c2)]')",
+	"&add	(@x[$a2],@x[$a2],@x[$b2])",
+	"&mov	($xd,$xd,'ror#16')",
+	 "&str	($xc_,'[sp,#4*(16+$c1)]')",
+	 "&ldr	($xc_,'[sp,#4*(16+$c3)]')",
+	 "&add	(@x[$a3],@x[$a3],@x[$b3])",
+	 "&mov	($xd_,$xd_,'ror#16')",
+	"&eor	($xd,$xd,@x[$a2],'ror#16')",
+	 "&eor	($xd_,$xd_,@x[$a3],'ror#16')",
+
+	"&add	($xc,$xc,$xd)",
+	"&mov	(@x[$b2],@x[$b2],'ror#20')",
+	 "&add	($xc_,$xc_,$xd_)",
+	 "&mov	(@x[$b3],@x[$b3],'ror#20')",
+	"&eor	(@x[$b2],@x[$b2],$xc,'ror#20')",
+	 "&eor	(@x[$b3],@x[$b3],$xc_,'ror#20')",
+
+	"&add	(@x[$a2],@x[$a2],@x[$b2])",
+	"&mov	($xd,$xd,'ror#24')",
+	 "&add	(@x[$a3],@x[$a3],@x[$b3])",
+	 "&mov	($xd_,$xd_,'ror#24')",
+	"&eor	($xd,$xd,@x[$a2],'ror#24')",
+	 "&eor	($xd_,$xd_,@x[$a3],'ror#24')",
+
+	"&add	($xc,$xc,$xd)",
+	"&mov	(@x[$b2],@x[$b2],'ror#25')",
+	 "&add	($xc_,$xc_,$xd_)",
+	 "&mov	(@x[$b3],@x[$b3],'ror#25')",
+	"&eor	(@x[$b2],@x[$b2],$xc,'ror#25')",
+	 "&eor	(@x[$b3],@x[$b3],$xc_,'ror#25')"	);
+
+	@ret;
+}
+
+$code.=<<___;
+#include <GFp/arm_arch.h>
+
+@ Silence ARMv8 deprecated IT instruction warnings. This file is used by both
+@ ARMv7 and ARMv8 processors and does not use ARMv8 instructions.
+.arch  armv7-a
+
+.text
+#if defined(__thumb2__) || defined(__clang__)
+.syntax	unified
+#endif
+#if defined(__thumb2__)
+.thumb
+#else
+.code	32
+#endif
+
+#if defined(__thumb2__) || defined(__clang__)
+#define ldrhsb	ldrbhs
+#endif
+
+.align	5
+.Lsigma:
+.long	0x61707865,0x3320646e,0x79622d32,0x6b206574	@ endian-neutral
+.Lone:
+.long	1,0,0,0
+#if __ARM_MAX_ARCH__>=7
+.LOPENSSL_armcap:
+.word   GFp_armcap_P-.LChaCha20_ctr32
+#else
+.word	-1
+#endif
+
+.globl	GFp_ChaCha20_ctr32
+.type	GFp_ChaCha20_ctr32,%function
+.align	5
+GFp_ChaCha20_ctr32:
+.LChaCha20_ctr32:
+	ldr	r12,[sp,#0]		@ pull pointer to counter and nonce
+	stmdb	sp!,{r0-r2,r4-r11,lr}
+#if __ARM_ARCH__<7 && !defined(__thumb2__)
+	sub	r14,pc,#16		@ ChaCha20_ctr32
+#else
+	adr	r14,.LChaCha20_ctr32
+#endif
+	cmp	r2,#0			@ len==0?
+#ifdef	__thumb2__
+	itt	eq
+#endif
+	addeq	sp,sp,#4*3
+	beq	.Lno_data
+#if __ARM_MAX_ARCH__>=7
+	cmp	r2,#192			@ test len
+	bls	.Lshort
+	ldr	r4,[r14,#-32]
+	ldr	r4,[r14,r4]
+# ifdef	__APPLE__
+	ldr	r4,[r4]
+# endif
+	tst	r4,#ARMV7_NEON
+	bne	.LChaCha20_neon
+.Lshort:
+#endif
+	ldmia	r12,{r4-r7}		@ load counter and nonce
+	sub	sp,sp,#4*(16)		@ off-load area
+	sub	r14,r14,#64		@ .Lsigma
+	stmdb	sp!,{r4-r7}		@ copy counter and nonce
+	ldmia	r3,{r4-r11}		@ load key
+	ldmia	r14,{r0-r3}		@ load sigma
+	stmdb	sp!,{r4-r11}		@ copy key
+	stmdb	sp!,{r0-r3}		@ copy sigma
+	str	r10,[sp,#4*(16+10)]	@ off-load "@x[10]"
+	str	r11,[sp,#4*(16+11)]	@ off-load "@x[11]"
+	b	.Loop_outer_enter
+
+.align	4
+.Loop_outer:
+	ldmia	sp,{r0-r9}		@ load key material
+	str	@t[3],[sp,#4*(32+2)]	@ save len
+	str	r12,  [sp,#4*(32+1)]	@ save inp
+	str	r14,  [sp,#4*(32+0)]	@ save out
+.Loop_outer_enter:
+	ldr	@t[3], [sp,#4*(15)]
+	ldr	@x[12],[sp,#4*(12)]	@ modulo-scheduled load
+	ldr	@t[2], [sp,#4*(13)]
+	ldr	@x[14],[sp,#4*(14)]
+	str	@t[3], [sp,#4*(16+15)]
+	mov	@t[3],#10
+	b	.Loop
+
+.align	4
+.Loop:
+	subs	@t[3],@t[3],#1
+___
+	foreach (&ROUND(0, 4, 8,12)) { eval; }
+	foreach (&ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+	bne	.Loop
+
+	ldr	@t[3],[sp,#4*(32+2)]	@ load len
+
+	str	@t[0], [sp,#4*(16+8)]	@ modulo-scheduled store
+	str	@t[1], [sp,#4*(16+9)]
+	str	@x[12],[sp,#4*(16+12)]
+	str	@t[2], [sp,#4*(16+13)]
+	str	@x[14],[sp,#4*(16+14)]
+
+	@ at this point we have first half of 512-bit result in
+	@ @x[0-7] and second half at sp+4*(16+8)
+
+	cmp	@t[3],#64		@ done yet?
+#ifdef	__thumb2__
+	itete	lo
+#endif
+	addlo	r12,sp,#4*(0)		@ shortcut or ...
+	ldrhs	r12,[sp,#4*(32+1)]	@ ... load inp
+	addlo	r14,sp,#4*(0)		@ shortcut or ...
+	ldrhs	r14,[sp,#4*(32+0)]	@ ... load out
+
+	ldr	@t[0],[sp,#4*(0)]	@ load key material
+	ldr	@t[1],[sp,#4*(1)]
+
+#if __ARM_ARCH__>=6 || !defined(__ARMEB__)
+# if __ARM_ARCH__<7
+	orr	@t[2],r12,r14
+	tst	@t[2],#3		@ are input and output aligned?
+	ldr	@t[2],[sp,#4*(2)]
+	bne	.Lunaligned
+	cmp	@t[3],#64		@ restore flags
+# else
+	ldr	@t[2],[sp,#4*(2)]
+# endif
+	ldr	@t[3],[sp,#4*(3)]
+
+	add	@x[0],@x[0],@t[0]	@ accumulate key material
+	add	@x[1],@x[1],@t[1]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[0],[r12],#16		@ load input
+	ldrhs	@t[1],[r12,#-12]
+
+	add	@x[2],@x[2],@t[2]
+	add	@x[3],@x[3],@t[3]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[2],[r12,#-8]
+	ldrhs	@t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+	rev	@x[0],@x[0]
+	rev	@x[1],@x[1]
+	rev	@x[2],@x[2]
+	rev	@x[3],@x[3]
+# endif
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[0],@x[0],@t[0]	@ xor with input
+	eorhs	@x[1],@x[1],@t[1]
+	 add	@t[0],sp,#4*(4)
+	str	@x[0],[r14],#16		@ store output
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[2],@x[2],@t[2]
+	eorhs	@x[3],@x[3],@t[3]
+	 ldmia	@t[0],{@t[0]-@t[3]}	@ load key material
+	str	@x[1],[r14,#-12]
+	str	@x[2],[r14,#-8]
+	str	@x[3],[r14,#-4]
+
+	add	@x[4],@x[4],@t[0]	@ accumulate key material
+	add	@x[5],@x[5],@t[1]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[0],[r12],#16		@ load input
+	ldrhs	@t[1],[r12,#-12]
+	add	@x[6],@x[6],@t[2]
+	add	@x[7],@x[7],@t[3]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[2],[r12,#-8]
+	ldrhs	@t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+	rev	@x[4],@x[4]
+	rev	@x[5],@x[5]
+	rev	@x[6],@x[6]
+	rev	@x[7],@x[7]
+# endif
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[4],@x[4],@t[0]
+	eorhs	@x[5],@x[5],@t[1]
+	 add	@t[0],sp,#4*(8)
+	str	@x[4],[r14],#16		@ store output
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[6],@x[6],@t[2]
+	eorhs	@x[7],@x[7],@t[3]
+	str	@x[5],[r14,#-12]
+	 ldmia	@t[0],{@t[0]-@t[3]}	@ load key material
+	str	@x[6],[r14,#-8]
+	 add	@x[0],sp,#4*(16+8)
+	str	@x[7],[r14,#-4]
+
+	ldmia	@x[0],{@x[0]-@x[7]}	@ load second half
+
+	add	@x[0],@x[0],@t[0]	@ accumulate key material
+	add	@x[1],@x[1],@t[1]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[0],[r12],#16		@ load input
+	ldrhs	@t[1],[r12,#-12]
+# ifdef	__thumb2__
+	itt	hi
+# endif
+	 strhi	@t[2],[sp,#4*(16+10)]	@ copy "@x[10]" while at it
+	 strhi	@t[3],[sp,#4*(16+11)]	@ copy "@x[11]" while at it
+	add	@x[2],@x[2],@t[2]
+	add	@x[3],@x[3],@t[3]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[2],[r12,#-8]
+	ldrhs	@t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+	rev	@x[0],@x[0]
+	rev	@x[1],@x[1]
+	rev	@x[2],@x[2]
+	rev	@x[3],@x[3]
+# endif
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[0],@x[0],@t[0]
+	eorhs	@x[1],@x[1],@t[1]
+	 add	@t[0],sp,#4*(12)
+	str	@x[0],[r14],#16		@ store output
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[2],@x[2],@t[2]
+	eorhs	@x[3],@x[3],@t[3]
+	str	@x[1],[r14,#-12]
+	 ldmia	@t[0],{@t[0]-@t[3]}	@ load key material
+	str	@x[2],[r14,#-8]
+	str	@x[3],[r14,#-4]
+
+	add	@x[4],@x[4],@t[0]	@ accumulate key material
+	add	@x[5],@x[5],@t[1]
+# ifdef	__thumb2__
+	itt	hi
+# endif
+	 addhi	@t[0],@t[0],#1		@ next counter value
+	 strhi	@t[0],[sp,#4*(12)]	@ save next counter value
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[0],[r12],#16		@ load input
+	ldrhs	@t[1],[r12,#-12]
+	add	@x[6],@x[6],@t[2]
+	add	@x[7],@x[7],@t[3]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhs	@t[2],[r12,#-8]
+	ldrhs	@t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+	rev	@x[4],@x[4]
+	rev	@x[5],@x[5]
+	rev	@x[6],@x[6]
+	rev	@x[7],@x[7]
+# endif
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[4],@x[4],@t[0]
+	eorhs	@x[5],@x[5],@t[1]
+# ifdef	__thumb2__
+	 it	ne
+# endif
+	 ldrne	@t[0],[sp,#4*(32+2)]	@ re-load len
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	eorhs	@x[6],@x[6],@t[2]
+	eorhs	@x[7],@x[7],@t[3]
+	str	@x[4],[r14],#16		@ store output
+	str	@x[5],[r14,#-12]
+# ifdef	__thumb2__
+	it	hs
+# endif
+	 subhs	@t[3],@t[0],#64		@ len-=64
+	str	@x[6],[r14,#-8]
+	str	@x[7],[r14,#-4]
+	bhi	.Loop_outer
+
+	beq	.Ldone
+# if __ARM_ARCH__<7
+	b	.Ltail
+
+.align	4
+.Lunaligned:				@ unaligned endian-neutral path
+	cmp	@t[3],#64		@ restore flags
+# endif
+#endif
+#if __ARM_ARCH__<7
+	ldr	@t[3],[sp,#4*(3)]
+___
+for ($i=0;$i<16;$i+=4) {
+my $j=$i&0x7;
+
+$code.=<<___	if ($i==4);
+	add	@x[0],sp,#4*(16+8)
+___
+$code.=<<___	if ($i==8);
+	ldmia	@x[0],{@x[0]-@x[7]}		@ load second half
+# ifdef	__thumb2__
+	itt	hi
+# endif
+	strhi	@t[2],[sp,#4*(16+10)]		@ copy "@x[10]"
+	strhi	@t[3],[sp,#4*(16+11)]		@ copy "@x[11]"
+___
+$code.=<<___;
+	add	@x[$j+0],@x[$j+0],@t[0]		@ accumulate key material
+___
+$code.=<<___	if ($i==12);
+# ifdef	__thumb2__
+	itt	hi
+# endif
+	addhi	@t[0],@t[0],#1			@ next counter value
+	strhi	@t[0],[sp,#4*(12)]		@ save next counter value
+___
+$code.=<<___;
+	add	@x[$j+1],@x[$j+1],@t[1]
+	add	@x[$j+2],@x[$j+2],@t[2]
+# ifdef	__thumb2__
+	itete	lo
+# endif
+	eorlo	@t[0],@t[0],@t[0]		@ zero or ...
+	ldrhsb	@t[0],[r12],#16			@ ... load input
+	eorlo	@t[1],@t[1],@t[1]
+	ldrhsb	@t[1],[r12,#-12]
+
+	add	@x[$j+3],@x[$j+3],@t[3]
+# ifdef	__thumb2__
+	itete	lo
+# endif
+	eorlo	@t[2],@t[2],@t[2]
+	ldrhsb	@t[2],[r12,#-8]
+	eorlo	@t[3],@t[3],@t[3]
+	ldrhsb	@t[3],[r12,#-4]
+
+	eor	@x[$j+0],@t[0],@x[$j+0]		@ xor with input (or zero)
+	eor	@x[$j+1],@t[1],@x[$j+1]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhsb	@t[0],[r12,#-15]		@ load more input
+	ldrhsb	@t[1],[r12,#-11]
+	eor	@x[$j+2],@t[2],@x[$j+2]
+	 strb	@x[$j+0],[r14],#16		@ store output
+	eor	@x[$j+3],@t[3],@x[$j+3]
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhsb	@t[2],[r12,#-7]
+	ldrhsb	@t[3],[r12,#-3]
+	 strb	@x[$j+1],[r14,#-12]
+	eor	@x[$j+0],@t[0],@x[$j+0],lsr#8
+	 strb	@x[$j+2],[r14,#-8]
+	eor	@x[$j+1],@t[1],@x[$j+1],lsr#8
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhsb	@t[0],[r12,#-14]		@ load more input
+	ldrhsb	@t[1],[r12,#-10]
+	 strb	@x[$j+3],[r14,#-4]
+	eor	@x[$j+2],@t[2],@x[$j+2],lsr#8
+	 strb	@x[$j+0],[r14,#-15]
+	eor	@x[$j+3],@t[3],@x[$j+3],lsr#8
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhsb	@t[2],[r12,#-6]
+	ldrhsb	@t[3],[r12,#-2]
+	 strb	@x[$j+1],[r14,#-11]
+	eor	@x[$j+0],@t[0],@x[$j+0],lsr#8
+	 strb	@x[$j+2],[r14,#-7]
+	eor	@x[$j+1],@t[1],@x[$j+1],lsr#8
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhsb	@t[0],[r12,#-13]		@ load more input
+	ldrhsb	@t[1],[r12,#-9]
+	 strb	@x[$j+3],[r14,#-3]
+	eor	@x[$j+2],@t[2],@x[$j+2],lsr#8
+	 strb	@x[$j+0],[r14,#-14]
+	eor	@x[$j+3],@t[3],@x[$j+3],lsr#8
+# ifdef	__thumb2__
+	itt	hs
+# endif
+	ldrhsb	@t[2],[r12,#-5]
+	ldrhsb	@t[3],[r12,#-1]
+	 strb	@x[$j+1],[r14,#-10]
+	 strb	@x[$j+2],[r14,#-6]
+	eor	@x[$j+0],@t[0],@x[$j+0],lsr#8
+	 strb	@x[$j+3],[r14,#-2]
+	eor	@x[$j+1],@t[1],@x[$j+1],lsr#8
+	 strb	@x[$j+0],[r14,#-13]
+	eor	@x[$j+2],@t[2],@x[$j+2],lsr#8
+	 strb	@x[$j+1],[r14,#-9]
+	eor	@x[$j+3],@t[3],@x[$j+3],lsr#8
+	 strb	@x[$j+2],[r14,#-5]
+	 strb	@x[$j+3],[r14,#-1]
+___
+$code.=<<___	if ($i<12);
+	add	@t[0],sp,#4*(4+$i)
+	ldmia	@t[0],{@t[0]-@t[3]}		@ load key material
+___
+}
+$code.=<<___;
+# ifdef	__thumb2__
+	it	ne
+# endif
+	ldrne	@t[0],[sp,#4*(32+2)]		@ re-load len
+# ifdef	__thumb2__
+	it	hs
+# endif
+	subhs	@t[3],@t[0],#64			@ len-=64
+	bhi	.Loop_outer
+
+	beq	.Ldone
+#endif
+
+.Ltail:
+	ldr	r12,[sp,#4*(32+1)]	@ load inp
+	add	@t[1],sp,#4*(0)
+	ldr	r14,[sp,#4*(32+0)]	@ load out
+
+.Loop_tail:
+	ldrb	@t[2],[@t[1]],#1	@ read buffer on stack
+	ldrb	@t[3],[r12],#1		@ read input
+	subs	@t[0],@t[0],#1
+	eor	@t[3],@t[3],@t[2]
+	strb	@t[3],[r14],#1		@ store output
+	bne	.Loop_tail
+
+.Ldone:
+	add	sp,sp,#4*(32+3)
+.Lno_data:
+	ldmia	sp!,{r4-r11,pc}
+.size	GFp_ChaCha20_ctr32,.-GFp_ChaCha20_ctr32
+___
+
+{{{
+my ($a0,$b0,$c0,$d0,$a1,$b1,$c1,$d1,$a2,$b2,$c2,$d2,$t0,$t1,$t2,$t3) =
+    map("q$_",(0..15));
+
+sub NEONROUND {
+my $odd = pop;
+my ($a,$b,$c,$d,$t)=@_;
+
+	(
+	"&vadd_i32	($a,$a,$b)",
+	"&veor		($d,$d,$a)",
+	"&vrev32_16	($d,$d)",	# vrot ($d,16)
+
+	"&vadd_i32	($c,$c,$d)",
+	"&veor		($t,$b,$c)",
+	"&vshr_u32	($b,$t,20)",
+	"&vsli_32	($b,$t,12)",
+
+	"&vadd_i32	($a,$a,$b)",
+	"&veor		($t,$d,$a)",
+	"&vshr_u32	($d,$t,24)",
+	"&vsli_32	($d,$t,8)",
+
+	"&vadd_i32	($c,$c,$d)",
+	"&veor		($t,$b,$c)",
+	"&vshr_u32	($b,$t,25)",
+	"&vsli_32	($b,$t,7)",
+
+	"&vext_8	($c,$c,$c,8)",
+	"&vext_8	($b,$b,$b,$odd?12:4)",
+	"&vext_8	($d,$d,$d,$odd?4:12)"
+	);
+}
+
+$code.=<<___;
+#if __ARM_MAX_ARCH__>=7
+.arch	armv7-a
+.fpu	neon
+
+.type	ChaCha20_neon,%function
+.align	5
+ChaCha20_neon:
+	ldr		r12,[sp,#0]		@ pull pointer to counter and nonce
+	stmdb		sp!,{r0-r2,r4-r11,lr}
+.LChaCha20_neon:
+	adr		r14,.Lsigma
+	vstmdb		sp!,{d8-d15}		@ ABI spec says so
+	stmdb		sp!,{r0-r3}
+
+	vld1.32		{$b0-$c0},[r3]		@ load key
+	ldmia		r3,{r4-r11}		@ load key
+
+	sub		sp,sp,#4*(16+16)
+	vld1.32		{$d0},[r12]		@ load counter and nonce
+	add		r12,sp,#4*8
+	ldmia		r14,{r0-r3}		@ load sigma
+	vld1.32		{$a0},[r14]!		@ load sigma
+	vld1.32		{$t0},[r14]		@ one
+	vst1.32		{$c0-$d0},[r12]		@ copy 1/2key|counter|nonce
+	vst1.32		{$a0-$b0},[sp]		@ copy sigma|1/2key
+
+	str		r10,[sp,#4*(16+10)]	@ off-load "@x[10]"
+	str		r11,[sp,#4*(16+11)]	@ off-load "@x[11]"
+	vshl.i32	$t1#lo,$t0#lo,#1	@ two
+	vstr		$t0#lo,[sp,#4*(16+0)]
+	vshl.i32	$t2#lo,$t0#lo,#2	@ four
+	vstr		$t1#lo,[sp,#4*(16+2)]
+	vmov		$a1,$a0
+	vstr		$t2#lo,[sp,#4*(16+4)]
+	vmov		$a2,$a0
+	vmov		$b1,$b0
+	vmov		$b2,$b0
+	b		.Loop_neon_enter
+
+.align	4
+.Loop_neon_outer:
+	ldmia		sp,{r0-r9}		@ load key material
+	cmp		@t[3],#64*2		@ if len<=64*2
+	bls		.Lbreak_neon		@ switch to integer-only
+	vmov		$a1,$a0
+	str		@t[3],[sp,#4*(32+2)]	@ save len
+	vmov		$a2,$a0
+	str		r12,  [sp,#4*(32+1)]	@ save inp
+	vmov		$b1,$b0
+	str		r14,  [sp,#4*(32+0)]	@ save out
+	vmov		$b2,$b0
+.Loop_neon_enter:
+	ldr		@t[3], [sp,#4*(15)]
+	vadd.i32	$d1,$d0,$t0		@ counter+1
+	ldr		@x[12],[sp,#4*(12)]	@ modulo-scheduled load
+	vmov		$c1,$c0
+	ldr		@t[2], [sp,#4*(13)]
+	vmov		$c2,$c0
+	ldr		@x[14],[sp,#4*(14)]
+	vadd.i32	$d2,$d1,$t0		@ counter+2
+	str		@t[3], [sp,#4*(16+15)]
+	mov		@t[3],#10
+	add		@x[12],@x[12],#3	@ counter+3
+	b		.Loop_neon
+
+.align	4
+.Loop_neon:
+	subs		@t[3],@t[3],#1
+___
+	my @thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,0);
+	my @thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,0);
+	my @thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,0);
+	my @thread3=&ROUND(0,4,8,12);
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread3));
+		eval(shift(@thread1));	eval(shift(@thread3));
+		eval(shift(@thread2));	eval(shift(@thread3));
+	}
+
+	@thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,1);
+	@thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,1);
+	@thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,1);
+	@thread3=&ROUND(0,5,10,15);
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread3));
+		eval(shift(@thread1));	eval(shift(@thread3));
+		eval(shift(@thread2));	eval(shift(@thread3));
+	}
+$code.=<<___;
+	bne		.Loop_neon
+
+	add		@t[3],sp,#32
+	vld1.32		{$t0-$t1},[sp]		@ load key material
+	vld1.32		{$t2-$t3},[@t[3]]
+
+	ldr		@t[3],[sp,#4*(32+2)]	@ load len
+
+	str		@t[0], [sp,#4*(16+8)]	@ modulo-scheduled store
+	str		@t[1], [sp,#4*(16+9)]
+	str		@x[12],[sp,#4*(16+12)]
+	str		@t[2], [sp,#4*(16+13)]
+	str		@x[14],[sp,#4*(16+14)]
+
+	@ at this point we have first half of 512-bit result in
+	@ @x[0-7] and second half at sp+4*(16+8)
+
+	ldr		r12,[sp,#4*(32+1)]	@ load inp
+	ldr		r14,[sp,#4*(32+0)]	@ load out
+
+	vadd.i32	$a0,$a0,$t0		@ accumulate key material
+	vadd.i32	$a1,$a1,$t0
+	vadd.i32	$a2,$a2,$t0
+	vldr		$t0#lo,[sp,#4*(16+0)]	@ one
+
+	vadd.i32	$b0,$b0,$t1
+	vadd.i32	$b1,$b1,$t1
+	vadd.i32	$b2,$b2,$t1
+	vldr		$t1#lo,[sp,#4*(16+2)]	@ two
+
+	vadd.i32	$c0,$c0,$t2
+	vadd.i32	$c1,$c1,$t2
+	vadd.i32	$c2,$c2,$t2
+	vadd.i32	$d1#lo,$d1#lo,$t0#lo	@ counter+1
+	vadd.i32	$d2#lo,$d2#lo,$t1#lo	@ counter+2
+
+	vadd.i32	$d0,$d0,$t3
+	vadd.i32	$d1,$d1,$t3
+	vadd.i32	$d2,$d2,$t3
+
+	cmp		@t[3],#64*4
+	blo		.Ltail_neon
+
+	vld1.8		{$t0-$t1},[r12]!	@ load input
+	 mov		@t[3],sp
+	vld1.8		{$t2-$t3},[r12]!
+	veor		$a0,$a0,$t0		@ xor with input
+	veor		$b0,$b0,$t1
+	vld1.8		{$t0-$t1},[r12]!
+	veor		$c0,$c0,$t2
+	veor		$d0,$d0,$t3
+	vld1.8		{$t2-$t3},[r12]!
+
+	veor		$a1,$a1,$t0
+	 vst1.8		{$a0-$b0},[r14]!	@ store output
+	veor		$b1,$b1,$t1
+	vld1.8		{$t0-$t1},[r12]!
+	veor		$c1,$c1,$t2
+	 vst1.8		{$c0-$d0},[r14]!
+	veor		$d1,$d1,$t3
+	vld1.8		{$t2-$t3},[r12]!
+
+	veor		$a2,$a2,$t0
+	 vld1.32	{$a0-$b0},[@t[3]]!	@ load for next iteration
+	 veor		$t0#hi,$t0#hi,$t0#hi
+	 vldr		$t0#lo,[sp,#4*(16+4)]	@ four
+	veor		$b2,$b2,$t1
+	 vld1.32	{$c0-$d0},[@t[3]]
+	veor		$c2,$c2,$t2
+	 vst1.8		{$a1-$b1},[r14]!
+	veor		$d2,$d2,$t3
+	 vst1.8		{$c1-$d1},[r14]!
+
+	vadd.i32	$d0#lo,$d0#lo,$t0#lo	@ next counter value
+	vldr		$t0#lo,[sp,#4*(16+0)]	@ one
+
+	ldmia		sp,{@t[0]-@t[3]}	@ load key material
+	add		@x[0],@x[0],@t[0]	@ accumulate key material
+	ldr		@t[0],[r12],#16		@ load input
+	 vst1.8		{$a2-$b2},[r14]!
+	add		@x[1],@x[1],@t[1]
+	ldr		@t[1],[r12,#-12]
+	 vst1.8		{$c2-$d2},[r14]!
+	add		@x[2],@x[2],@t[2]
+	ldr		@t[2],[r12,#-8]
+	add		@x[3],@x[3],@t[3]
+	ldr		@t[3],[r12,#-4]
+# ifdef	__ARMEB__
+	rev		@x[0],@x[0]
+	rev		@x[1],@x[1]
+	rev		@x[2],@x[2]
+	rev		@x[3],@x[3]
+# endif
+	eor		@x[0],@x[0],@t[0]	@ xor with input
+	 add		@t[0],sp,#4*(4)
+	eor		@x[1],@x[1],@t[1]
+	str		@x[0],[r14],#16		@ store output
+	eor		@x[2],@x[2],@t[2]
+	str		@x[1],[r14,#-12]
+	eor		@x[3],@x[3],@t[3]
+	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
+	str		@x[2],[r14,#-8]
+	str		@x[3],[r14,#-4]
+
+	add		@x[4],@x[4],@t[0]	@ accumulate key material
+	ldr		@t[0],[r12],#16		@ load input
+	add		@x[5],@x[5],@t[1]
+	ldr		@t[1],[r12,#-12]
+	add		@x[6],@x[6],@t[2]
+	ldr		@t[2],[r12,#-8]
+	add		@x[7],@x[7],@t[3]
+	ldr		@t[3],[r12,#-4]
+# ifdef	__ARMEB__
+	rev		@x[4],@x[4]
+	rev		@x[5],@x[5]
+	rev		@x[6],@x[6]
+	rev		@x[7],@x[7]
+# endif
+	eor		@x[4],@x[4],@t[0]
+	 add		@t[0],sp,#4*(8)
+	eor		@x[5],@x[5],@t[1]
+	str		@x[4],[r14],#16		@ store output
+	eor		@x[6],@x[6],@t[2]
+	str		@x[5],[r14,#-12]
+	eor		@x[7],@x[7],@t[3]
+	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
+	str		@x[6],[r14,#-8]
+	 add		@x[0],sp,#4*(16+8)
+	str		@x[7],[r14,#-4]
+
+	ldmia		@x[0],{@x[0]-@x[7]}	@ load second half
+
+	add		@x[0],@x[0],@t[0]	@ accumulate key material
+	ldr		@t[0],[r12],#16		@ load input
+	add		@x[1],@x[1],@t[1]
+	ldr		@t[1],[r12,#-12]
+# ifdef	__thumb2__
+	it	hi
+# endif
+	 strhi		@t[2],[sp,#4*(16+10)]	@ copy "@x[10]" while at it
+	add		@x[2],@x[2],@t[2]
+	ldr		@t[2],[r12,#-8]
+# ifdef	__thumb2__
+	it	hi
+# endif
+	 strhi		@t[3],[sp,#4*(16+11)]	@ copy "@x[11]" while at it
+	add		@x[3],@x[3],@t[3]
+	ldr		@t[3],[r12,#-4]
+# ifdef	__ARMEB__
+	rev		@x[0],@x[0]
+	rev		@x[1],@x[1]
+	rev		@x[2],@x[2]
+	rev		@x[3],@x[3]
+# endif
+	eor		@x[0],@x[0],@t[0]
+	 add		@t[0],sp,#4*(12)
+	eor		@x[1],@x[1],@t[1]
+	str		@x[0],[r14],#16		@ store output
+	eor		@x[2],@x[2],@t[2]
+	str		@x[1],[r14,#-12]
+	eor		@x[3],@x[3],@t[3]
+	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
+	str		@x[2],[r14,#-8]
+	str		@x[3],[r14,#-4]
+
+	add		@x[4],@x[4],@t[0]	@ accumulate key material
+	 add		@t[0],@t[0],#4		@ next counter value
+	add		@x[5],@x[5],@t[1]
+	 str		@t[0],[sp,#4*(12)]	@ save next counter value
+	ldr		@t[0],[r12],#16		@ load input
+	add		@x[6],@x[6],@t[2]
+	 add		@x[4],@x[4],#3		@ counter+3
+	ldr		@t[1],[r12,#-12]
+	add		@x[7],@x[7],@t[3]
+	ldr		@t[2],[r12,#-8]
+	ldr		@t[3],[r12,#-4]
+# ifdef	__ARMEB__
+	rev		@x[4],@x[4]
+	rev		@x[5],@x[5]
+	rev		@x[6],@x[6]
+	rev		@x[7],@x[7]
+# endif
+	eor		@x[4],@x[4],@t[0]
+# ifdef	__thumb2__
+	it	hi
+# endif
+	 ldrhi		@t[0],[sp,#4*(32+2)]	@ re-load len
+	eor		@x[5],@x[5],@t[1]
+	eor		@x[6],@x[6],@t[2]
+	str		@x[4],[r14],#16		@ store output
+	eor		@x[7],@x[7],@t[3]
+	str		@x[5],[r14,#-12]
+	 sub		@t[3],@t[0],#64*4	@ len-=64*4
+	str		@x[6],[r14,#-8]
+	str		@x[7],[r14,#-4]
+	bhi		.Loop_neon_outer
+
+	b		.Ldone_neon
+
+.align	4
+.Lbreak_neon:
+	@ harmonize NEON and integer-only stack frames: load data
+	@ from NEON frame, but save to integer-only one; distance
+	@ between the two is 4*(32+4+16-32)=4*(20).
+
+	str		@t[3], [sp,#4*(20+32+2)]	@ save len
+	 add		@t[3],sp,#4*(32+4)
+	str		r12,   [sp,#4*(20+32+1)]	@ save inp
+	str		r14,   [sp,#4*(20+32+0)]	@ save out
+
+	ldr		@x[12],[sp,#4*(16+10)]
+	ldr		@x[14],[sp,#4*(16+11)]
+	 vldmia		@t[3],{d8-d15}			@ fulfill ABI requirement
+	str		@x[12],[sp,#4*(20+16+10)]	@ copy "@x[10]"
+	str		@x[14],[sp,#4*(20+16+11)]	@ copy "@x[11]"
+
+	ldr		@t[3], [sp,#4*(15)]
+	ldr		@x[12],[sp,#4*(12)]		@ modulo-scheduled load
+	ldr		@t[2], [sp,#4*(13)]
+	ldr		@x[14],[sp,#4*(14)]
+	str		@t[3], [sp,#4*(20+16+15)]
+	add		@t[3],sp,#4*(20)
+	vst1.32		{$a0-$b0},[@t[3]]!		@ copy key
+	add		sp,sp,#4*(20)			@ switch frame
+	vst1.32		{$c0-$d0},[@t[3]]
+	mov		@t[3],#10
+	b		.Loop				@ go integer-only
+
+.align	4
+.Ltail_neon:
+	cmp		@t[3],#64*3
+	bhs		.L192_or_more_neon
+	cmp		@t[3],#64*2
+	bhs		.L128_or_more_neon
+	cmp		@t[3],#64*1
+	bhs		.L64_or_more_neon
+
+	add		@t[0],sp,#4*(8)
+	vst1.8		{$a0-$b0},[sp]
+	add		@t[2],sp,#4*(0)
+	vst1.8		{$c0-$d0},[@t[0]]
+	b		.Loop_tail_neon
+
+.align	4
+.L64_or_more_neon:
+	vld1.8		{$t0-$t1},[r12]!
+	vld1.8		{$t2-$t3},[r12]!
+	veor		$a0,$a0,$t0
+	veor		$b0,$b0,$t1
+	veor		$c0,$c0,$t2
+	veor		$d0,$d0,$t3
+	vst1.8		{$a0-$b0},[r14]!
+	vst1.8		{$c0-$d0},[r14]!
+
+	beq		.Ldone_neon
+
+	add		@t[0],sp,#4*(8)
+	vst1.8		{$a1-$b1},[sp]
+	add		@t[2],sp,#4*(0)
+	vst1.8		{$c1-$d1},[@t[0]]
+	sub		@t[3],@t[3],#64*1	@ len-=64*1
+	b		.Loop_tail_neon
+
+.align	4
+.L128_or_more_neon:
+	vld1.8		{$t0-$t1},[r12]!
+	vld1.8		{$t2-$t3},[r12]!
+	veor		$a0,$a0,$t0
+	veor		$b0,$b0,$t1
+	vld1.8		{$t0-$t1},[r12]!
+	veor		$c0,$c0,$t2
+	veor		$d0,$d0,$t3
+	vld1.8		{$t2-$t3},[r12]!
+
+	veor		$a1,$a1,$t0
+	veor		$b1,$b1,$t1
+	 vst1.8		{$a0-$b0},[r14]!
+	veor		$c1,$c1,$t2
+	 vst1.8		{$c0-$d0},[r14]!
+	veor		$d1,$d1,$t3
+	vst1.8		{$a1-$b1},[r14]!
+	vst1.8		{$c1-$d1},[r14]!
+
+	beq		.Ldone_neon
+
+	add		@t[0],sp,#4*(8)
+	vst1.8		{$a2-$b2},[sp]
+	add		@t[2],sp,#4*(0)
+	vst1.8		{$c2-$d2},[@t[0]]
+	sub		@t[3],@t[3],#64*2	@ len-=64*2
+	b		.Loop_tail_neon
+
+.align	4
+.L192_or_more_neon:
+	vld1.8		{$t0-$t1},[r12]!
+	vld1.8		{$t2-$t3},[r12]!
+	veor		$a0,$a0,$t0
+	veor		$b0,$b0,$t1
+	vld1.8		{$t0-$t1},[r12]!
+	veor		$c0,$c0,$t2
+	veor		$d0,$d0,$t3
+	vld1.8		{$t2-$t3},[r12]!
+
+	veor		$a1,$a1,$t0
+	veor		$b1,$b1,$t1
+	vld1.8		{$t0-$t1},[r12]!
+	veor		$c1,$c1,$t2
+	 vst1.8		{$a0-$b0},[r14]!
+	veor		$d1,$d1,$t3
+	vld1.8		{$t2-$t3},[r12]!
+
+	veor		$a2,$a2,$t0
+	 vst1.8		{$c0-$d0},[r14]!
+	veor		$b2,$b2,$t1
+	 vst1.8		{$a1-$b1},[r14]!
+	veor		$c2,$c2,$t2
+	 vst1.8		{$c1-$d1},[r14]!
+	veor		$d2,$d2,$t3
+	vst1.8		{$a2-$b2},[r14]!
+	vst1.8		{$c2-$d2},[r14]!
+
+	beq		.Ldone_neon
+
+	ldmia		sp,{@t[0]-@t[3]}	@ load key material
+	add		@x[0],@x[0],@t[0]	@ accumulate key material
+	 add		@t[0],sp,#4*(4)
+	add		@x[1],@x[1],@t[1]
+	add		@x[2],@x[2],@t[2]
+	add		@x[3],@x[3],@t[3]
+	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
+
+	add		@x[4],@x[4],@t[0]	@ accumulate key material
+	 add		@t[0],sp,#4*(8)
+	add		@x[5],@x[5],@t[1]
+	add		@x[6],@x[6],@t[2]
+	add		@x[7],@x[7],@t[3]
+	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
+# ifdef	__ARMEB__
+	rev		@x[0],@x[0]
+	rev		@x[1],@x[1]
+	rev		@x[2],@x[2]
+	rev		@x[3],@x[3]
+	rev		@x[4],@x[4]
+	rev		@x[5],@x[5]
+	rev		@x[6],@x[6]
+	rev		@x[7],@x[7]
+# endif
+	stmia		sp,{@x[0]-@x[7]}
+	 add		@x[0],sp,#4*(16+8)
+
+	ldmia		@x[0],{@x[0]-@x[7]}	@ load second half
+
+	add		@x[0],@x[0],@t[0]	@ accumulate key material
+	 add		@t[0],sp,#4*(12)
+	add		@x[1],@x[1],@t[1]
+	add		@x[2],@x[2],@t[2]
+	add		@x[3],@x[3],@t[3]
+	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
+
+	add		@x[4],@x[4],@t[0]	@ accumulate key material
+	 add		@t[0],sp,#4*(8)
+	add		@x[5],@x[5],@t[1]
+	 add		@x[4],@x[4],#3		@ counter+3
+	add		@x[6],@x[6],@t[2]
+	add		@x[7],@x[7],@t[3]
+	 ldr		@t[3],[sp,#4*(32+2)]	@ re-load len
+# ifdef	__ARMEB__
+	rev		@x[0],@x[0]
+	rev		@x[1],@x[1]
+	rev		@x[2],@x[2]
+	rev		@x[3],@x[3]
+	rev		@x[4],@x[4]
+	rev		@x[5],@x[5]
+	rev		@x[6],@x[6]
+	rev		@x[7],@x[7]
+# endif
+	stmia		@t[0],{@x[0]-@x[7]}
+	 add		@t[2],sp,#4*(0)
+	 sub		@t[3],@t[3],#64*3	@ len-=64*3
+
+.Loop_tail_neon:
+	ldrb		@t[0],[@t[2]],#1	@ read buffer on stack
+	ldrb		@t[1],[r12],#1		@ read input
+	subs		@t[3],@t[3],#1
+	eor		@t[0],@t[0],@t[1]
+	strb		@t[0],[r14],#1		@ store output
+	bne		.Loop_tail_neon
+
+.Ldone_neon:
+	add		sp,sp,#4*(32+4)
+	vldmia		sp,{d8-d15}
+	add		sp,sp,#4*(16+3)
+	ldmia		sp!,{r4-r11,pc}
+.size	ChaCha20_neon,.-ChaCha20_neon
+.comm	GFp_armcap_P,4,4
+#endif
+___
+}}}
+
+foreach (split("\n",$code)) {
+	s/\`([^\`]*)\`/eval $1/geo;
+
+	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
+
+	print $_,"\n";
+}
+close STDOUT;
diff --git a/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-armv8.pl b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-armv8.pl
new file mode 100644
index 0000000..02c412b
--- /dev/null
+++ b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-armv8.pl
@@ -0,0 +1,1136 @@
+#! /usr/bin/env perl
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# June 2015
+#
+# ChaCha20 for ARMv8.
+#
+# Performance in cycles per byte out of large buffer.
+#
+#			IALU/gcc-4.9    3xNEON+1xIALU	6xNEON+2xIALU
+#
+# Apple A7		5.50/+49%       3.33            1.70
+# Cortex-A53		8.40/+80%       4.72		4.72(*)
+# Cortex-A57		8.06/+43%       4.90            4.43(**)
+# Denver		4.50/+82%       2.63		2.67(*)
+# X-Gene		9.50/+46%       8.82		8.89(*)
+# Mongoose		8.00/+44%	3.64		3.25
+# Kryo			8.17/+50%	4.83		4.65
+#
+# (*)	it's expected that doubling interleave factor doesn't help
+#	all processors, only those with higher NEON latency and
+#	higher instruction issue rate;
+# (**)	expected improvement was actually higher;
+
+$flavour=shift;
+$output=shift;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
+die "can't locate arm-xlate.pl";
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+sub AUTOLOAD()		# thunk [simplified] x86-style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
+  my $arg = pop;
+    $arg = "#$arg" if ($arg*1 eq $arg);
+    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
+}
+
+my ($out,$inp,$len,$key,$ctr) = map("x$_",(0..4));
+
+my @x=map("x$_",(5..17,19..21));
+my @d=map("x$_",(22..28,30));
+
+sub ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+
+    (
+	"&add_32	(@x[$a0],@x[$a0],@x[$b0])",
+	 "&add_32	(@x[$a1],@x[$a1],@x[$b1])",
+	  "&add_32	(@x[$a2],@x[$a2],@x[$b2])",
+	   "&add_32	(@x[$a3],@x[$a3],@x[$b3])",
+	"&eor_32	(@x[$d0],@x[$d0],@x[$a0])",
+	 "&eor_32	(@x[$d1],@x[$d1],@x[$a1])",
+	  "&eor_32	(@x[$d2],@x[$d2],@x[$a2])",
+	   "&eor_32	(@x[$d3],@x[$d3],@x[$a3])",
+	"&ror_32	(@x[$d0],@x[$d0],16)",
+	 "&ror_32	(@x[$d1],@x[$d1],16)",
+	  "&ror_32	(@x[$d2],@x[$d2],16)",
+	   "&ror_32	(@x[$d3],@x[$d3],16)",
+
+	"&add_32	(@x[$c0],@x[$c0],@x[$d0])",
+	 "&add_32	(@x[$c1],@x[$c1],@x[$d1])",
+	  "&add_32	(@x[$c2],@x[$c2],@x[$d2])",
+	   "&add_32	(@x[$c3],@x[$c3],@x[$d3])",
+	"&eor_32	(@x[$b0],@x[$b0],@x[$c0])",
+	 "&eor_32	(@x[$b1],@x[$b1],@x[$c1])",
+	  "&eor_32	(@x[$b2],@x[$b2],@x[$c2])",
+	   "&eor_32	(@x[$b3],@x[$b3],@x[$c3])",
+	"&ror_32	(@x[$b0],@x[$b0],20)",
+	 "&ror_32	(@x[$b1],@x[$b1],20)",
+	  "&ror_32	(@x[$b2],@x[$b2],20)",
+	   "&ror_32	(@x[$b3],@x[$b3],20)",
+
+	"&add_32	(@x[$a0],@x[$a0],@x[$b0])",
+	 "&add_32	(@x[$a1],@x[$a1],@x[$b1])",
+	  "&add_32	(@x[$a2],@x[$a2],@x[$b2])",
+	   "&add_32	(@x[$a3],@x[$a3],@x[$b3])",
+	"&eor_32	(@x[$d0],@x[$d0],@x[$a0])",
+	 "&eor_32	(@x[$d1],@x[$d1],@x[$a1])",
+	  "&eor_32	(@x[$d2],@x[$d2],@x[$a2])",
+	   "&eor_32	(@x[$d3],@x[$d3],@x[$a3])",
+	"&ror_32	(@x[$d0],@x[$d0],24)",
+	 "&ror_32	(@x[$d1],@x[$d1],24)",
+	  "&ror_32	(@x[$d2],@x[$d2],24)",
+	   "&ror_32	(@x[$d3],@x[$d3],24)",
+
+	"&add_32	(@x[$c0],@x[$c0],@x[$d0])",
+	 "&add_32	(@x[$c1],@x[$c1],@x[$d1])",
+	  "&add_32	(@x[$c2],@x[$c2],@x[$d2])",
+	   "&add_32	(@x[$c3],@x[$c3],@x[$d3])",
+	"&eor_32	(@x[$b0],@x[$b0],@x[$c0])",
+	 "&eor_32	(@x[$b1],@x[$b1],@x[$c1])",
+	  "&eor_32	(@x[$b2],@x[$b2],@x[$c2])",
+	   "&eor_32	(@x[$b3],@x[$b3],@x[$c3])",
+	"&ror_32	(@x[$b0],@x[$b0],25)",
+	 "&ror_32	(@x[$b1],@x[$b1],25)",
+	  "&ror_32	(@x[$b2],@x[$b2],25)",
+	   "&ror_32	(@x[$b3],@x[$b3],25)"
+    );
+}
+
+$code.=<<___;
+#include <GFp/arm_arch.h>
+
+.text
+
+.extern	GFp_armcap_P
+
+.align	5
+.Lsigma:
+.quad	0x3320646e61707865,0x6b20657479622d32		// endian-neutral
+.Lone:
+.long	1,0,0,0
+.LGFp_armcap_P:
+#ifdef	__ILP32__
+.long	GFp_armcap_P-.
+#else
+.quad	GFp_armcap_P-.
+#endif
+.asciz	"ChaCha20 for ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
+
+.globl	GFp_ChaCha20_ctr32
+.type	GFp_ChaCha20_ctr32,%function
+.align	5
+GFp_ChaCha20_ctr32:
+	cbz	$len,.Labort
+	adr	@x[0],.LGFp_armcap_P
+	cmp	$len,#192
+	b.lo	.Lshort
+#ifdef	__ILP32__
+	ldrsw	@x[1],[@x[0]]
+#else
+	ldr	@x[1],[@x[0]]
+#endif
+	ldr	w17,[@x[1],@x[0]]
+	tst	w17,#ARMV7_NEON
+	b.ne	ChaCha20_neon
+
+.Lshort:
+	stp	x29,x30,[sp,#-96]!
+	add	x29,sp,#0
+
+	adr	@x[0],.Lsigma
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+	stp	x25,x26,[sp,#64]
+	stp	x27,x28,[sp,#80]
+	sub	sp,sp,#64
+
+	ldp	@d[0],@d[1],[@x[0]]		// load sigma
+	ldp	@d[2],@d[3],[$key]		// load key
+	ldp	@d[4],@d[5],[$key,#16]
+	ldp	@d[6],@d[7],[$ctr]		// load counter
+#ifdef	__ARMEB__
+	ror	@d[2],@d[2],#32
+	ror	@d[3],@d[3],#32
+	ror	@d[4],@d[4],#32
+	ror	@d[5],@d[5],#32
+	ror	@d[6],@d[6],#32
+	ror	@d[7],@d[7],#32
+#endif
+
+.Loop_outer:
+	mov.32	@x[0],@d[0]			// unpack key block
+	lsr	@x[1],@d[0],#32
+	mov.32	@x[2],@d[1]
+	lsr	@x[3],@d[1],#32
+	mov.32	@x[4],@d[2]
+	lsr	@x[5],@d[2],#32
+	mov.32	@x[6],@d[3]
+	lsr	@x[7],@d[3],#32
+	mov.32	@x[8],@d[4]
+	lsr	@x[9],@d[4],#32
+	mov.32	@x[10],@d[5]
+	lsr	@x[11],@d[5],#32
+	mov.32	@x[12],@d[6]
+	lsr	@x[13],@d[6],#32
+	mov.32	@x[14],@d[7]
+	lsr	@x[15],@d[7],#32
+
+	mov	$ctr,#10
+	subs	$len,$len,#64
+.Loop:
+	sub	$ctr,$ctr,#1
+___
+	foreach (&ROUND(0, 4, 8,12)) { eval; }
+	foreach (&ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+	cbnz	$ctr,.Loop
+
+	add.32	@x[0],@x[0],@d[0]		// accumulate key block
+	add	@x[1],@x[1],@d[0],lsr#32
+	add.32	@x[2],@x[2],@d[1]
+	add	@x[3],@x[3],@d[1],lsr#32
+	add.32	@x[4],@x[4],@d[2]
+	add	@x[5],@x[5],@d[2],lsr#32
+	add.32	@x[6],@x[6],@d[3]
+	add	@x[7],@x[7],@d[3],lsr#32
+	add.32	@x[8],@x[8],@d[4]
+	add	@x[9],@x[9],@d[4],lsr#32
+	add.32	@x[10],@x[10],@d[5]
+	add	@x[11],@x[11],@d[5],lsr#32
+	add.32	@x[12],@x[12],@d[6]
+	add	@x[13],@x[13],@d[6],lsr#32
+	add.32	@x[14],@x[14],@d[7]
+	add	@x[15],@x[15],@d[7],lsr#32
+
+	b.lo	.Ltail
+
+	add	@x[0],@x[0],@x[1],lsl#32	// pack
+	add	@x[2],@x[2],@x[3],lsl#32
+	ldp	@x[1],@x[3],[$inp,#0]		// load input
+	add	@x[4],@x[4],@x[5],lsl#32
+	add	@x[6],@x[6],@x[7],lsl#32
+	ldp	@x[5],@x[7],[$inp,#16]
+	add	@x[8],@x[8],@x[9],lsl#32
+	add	@x[10],@x[10],@x[11],lsl#32
+	ldp	@x[9],@x[11],[$inp,#32]
+	add	@x[12],@x[12],@x[13],lsl#32
+	add	@x[14],@x[14],@x[15],lsl#32
+	ldp	@x[13],@x[15],[$inp,#48]
+	add	$inp,$inp,#64
+#ifdef	__ARMEB__
+	rev	@x[0],@x[0]
+	rev	@x[2],@x[2]
+	rev	@x[4],@x[4]
+	rev	@x[6],@x[6]
+	rev	@x[8],@x[8]
+	rev	@x[10],@x[10]
+	rev	@x[12],@x[12]
+	rev	@x[14],@x[14]
+#endif
+	eor	@x[0],@x[0],@x[1]
+	eor	@x[2],@x[2],@x[3]
+	eor	@x[4],@x[4],@x[5]
+	eor	@x[6],@x[6],@x[7]
+	eor	@x[8],@x[8],@x[9]
+	eor	@x[10],@x[10],@x[11]
+	eor	@x[12],@x[12],@x[13]
+	eor	@x[14],@x[14],@x[15]
+
+	stp	@x[0],@x[2],[$out,#0]		// store output
+	 add	@d[6],@d[6],#1			// increment counter
+	stp	@x[4],@x[6],[$out,#16]
+	stp	@x[8],@x[10],[$out,#32]
+	stp	@x[12],@x[14],[$out,#48]
+	add	$out,$out,#64
+
+	b.hi	.Loop_outer
+
+	ldp	x19,x20,[x29,#16]
+	add	sp,sp,#64
+	ldp	x21,x22,[x29,#32]
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldp	x29,x30,[sp],#96
+.Labort:
+	ret
+
+.align	4
+.Ltail:
+	add	$len,$len,#64
+.Less_than_64:
+	sub	$out,$out,#1
+	add	$inp,$inp,$len
+	add	$out,$out,$len
+	add	$ctr,sp,$len
+	neg	$len,$len
+
+	add	@x[0],@x[0],@x[1],lsl#32	// pack
+	add	@x[2],@x[2],@x[3],lsl#32
+	add	@x[4],@x[4],@x[5],lsl#32
+	add	@x[6],@x[6],@x[7],lsl#32
+	add	@x[8],@x[8],@x[9],lsl#32
+	add	@x[10],@x[10],@x[11],lsl#32
+	add	@x[12],@x[12],@x[13],lsl#32
+	add	@x[14],@x[14],@x[15],lsl#32
+#ifdef	__ARMEB__
+	rev	@x[0],@x[0]
+	rev	@x[2],@x[2]
+	rev	@x[4],@x[4]
+	rev	@x[6],@x[6]
+	rev	@x[8],@x[8]
+	rev	@x[10],@x[10]
+	rev	@x[12],@x[12]
+	rev	@x[14],@x[14]
+#endif
+	stp	@x[0],@x[2],[sp,#0]
+	stp	@x[4],@x[6],[sp,#16]
+	stp	@x[8],@x[10],[sp,#32]
+	stp	@x[12],@x[14],[sp,#48]
+
+.Loop_tail:
+	ldrb	w10,[$inp,$len]
+	ldrb	w11,[$ctr,$len]
+	add	$len,$len,#1
+	eor	w10,w10,w11
+	strb	w10,[$out,$len]
+	cbnz	$len,.Loop_tail
+
+	stp	xzr,xzr,[sp,#0]
+	stp	xzr,xzr,[sp,#16]
+	stp	xzr,xzr,[sp,#32]
+	stp	xzr,xzr,[sp,#48]
+
+	ldp	x19,x20,[x29,#16]
+	add	sp,sp,#64
+	ldp	x21,x22,[x29,#32]
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldp	x29,x30,[sp],#96
+	ret
+.size	GFp_ChaCha20_ctr32,.-GFp_ChaCha20_ctr32
+___
+
+{{{
+my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,$T0,$T1,$T2,$T3) =
+    map("v$_.4s",(0..7,16..23));
+my (@K)=map("v$_.4s",(24..30));
+my $ONE="v31.4s";
+
+sub NEONROUND {
+my $odd = pop;
+my ($a,$b,$c,$d,$t)=@_;
+
+	(
+	"&add		('$a','$a','$b')",
+	"&eor		('$d','$d','$a')",
+	"&rev32_16	('$d','$d')",		# vrot ($d,16)
+
+	"&add		('$c','$c','$d')",
+	"&eor		('$t','$b','$c')",
+	"&ushr		('$b','$t',20)",
+	"&sli		('$b','$t',12)",
+
+	"&add		('$a','$a','$b')",
+	"&eor		('$t','$d','$a')",
+	"&ushr		('$d','$t',24)",
+	"&sli		('$d','$t',8)",
+
+	"&add		('$c','$c','$d')",
+	"&eor		('$t','$b','$c')",
+	"&ushr		('$b','$t',25)",
+	"&sli		('$b','$t',7)",
+
+	"&ext		('$c','$c','$c',8)",
+	"&ext		('$d','$d','$d',$odd?4:12)",
+	"&ext		('$b','$b','$b',$odd?12:4)"
+	);
+}
+
+$code.=<<___;
+
+.type	ChaCha20_neon,%function
+.align	5
+ChaCha20_neon:
+	stp	x29,x30,[sp,#-96]!
+	add	x29,sp,#0
+
+	adr	@x[0],.Lsigma
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+	stp	x25,x26,[sp,#64]
+	stp	x27,x28,[sp,#80]
+	cmp	$len,#512
+	b.hs	.L512_or_more_neon
+
+	sub	sp,sp,#64
+
+	ldp	@d[0],@d[1],[@x[0]]		// load sigma
+	ld1	{@K[0]},[@x[0]],#16
+	ldp	@d[2],@d[3],[$key]		// load key
+	ldp	@d[4],@d[5],[$key,#16]
+	ld1	{@K[1],@K[2]},[$key]
+	ldp	@d[6],@d[7],[$ctr]		// load counter
+	ld1	{@K[3]},[$ctr]
+	ld1	{$ONE},[@x[0]]
+#ifdef	__ARMEB__
+	rev64	@K[0],@K[0]
+	ror	@d[2],@d[2],#32
+	ror	@d[3],@d[3],#32
+	ror	@d[4],@d[4],#32
+	ror	@d[5],@d[5],#32
+	ror	@d[6],@d[6],#32
+	ror	@d[7],@d[7],#32
+#endif
+	add	@K[3],@K[3],$ONE		// += 1
+	add	@K[4],@K[3],$ONE
+	add	@K[5],@K[4],$ONE
+	shl	$ONE,$ONE,#2			// 1 -> 4
+
+.Loop_outer_neon:
+	mov.32	@x[0],@d[0]			// unpack key block
+	lsr	@x[1],@d[0],#32
+	 mov	$A0,@K[0]
+	mov.32	@x[2],@d[1]
+	lsr	@x[3],@d[1],#32
+	 mov	$A1,@K[0]
+	mov.32	@x[4],@d[2]
+	lsr	@x[5],@d[2],#32
+	 mov	$A2,@K[0]
+	mov.32	@x[6],@d[3]
+	 mov	$B0,@K[1]
+	lsr	@x[7],@d[3],#32
+	 mov	$B1,@K[1]
+	mov.32	@x[8],@d[4]
+	 mov	$B2,@K[1]
+	lsr	@x[9],@d[4],#32
+	 mov	$D0,@K[3]
+	mov.32	@x[10],@d[5]
+	 mov	$D1,@K[4]
+	lsr	@x[11],@d[5],#32
+	 mov	$D2,@K[5]
+	mov.32	@x[12],@d[6]
+	 mov	$C0,@K[2]
+	lsr	@x[13],@d[6],#32
+	 mov	$C1,@K[2]
+	mov.32	@x[14],@d[7]
+	 mov	$C2,@K[2]
+	lsr	@x[15],@d[7],#32
+
+	mov	$ctr,#10
+	subs	$len,$len,#256
+.Loop_neon:
+	sub	$ctr,$ctr,#1
+___
+	my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
+	my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
+	my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
+	my @thread3=&ROUND(0,4,8,12);
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread3));
+		eval(shift(@thread1));	eval(shift(@thread3));
+		eval(shift(@thread2));	eval(shift(@thread3));
+	}
+
+	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
+	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
+	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
+	@thread3=&ROUND(0,5,10,15);
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread3));
+		eval(shift(@thread1));	eval(shift(@thread3));
+		eval(shift(@thread2));	eval(shift(@thread3));
+	}
+$code.=<<___;
+	cbnz	$ctr,.Loop_neon
+
+	add.32	@x[0],@x[0],@d[0]		// accumulate key block
+	 add	$A0,$A0,@K[0]
+	add	@x[1],@x[1],@d[0],lsr#32
+	 add	$A1,$A1,@K[0]
+	add.32	@x[2],@x[2],@d[1]
+	 add	$A2,$A2,@K[0]
+	add	@x[3],@x[3],@d[1],lsr#32
+	 add	$C0,$C0,@K[2]
+	add.32	@x[4],@x[4],@d[2]
+	 add	$C1,$C1,@K[2]
+	add	@x[5],@x[5],@d[2],lsr#32
+	 add	$C2,$C2,@K[2]
+	add.32	@x[6],@x[6],@d[3]
+	 add	$D0,$D0,@K[3]
+	add	@x[7],@x[7],@d[3],lsr#32
+	add.32	@x[8],@x[8],@d[4]
+	 add	$D1,$D1,@K[4]
+	add	@x[9],@x[9],@d[4],lsr#32
+	add.32	@x[10],@x[10],@d[5]
+	 add	$D2,$D2,@K[5]
+	add	@x[11],@x[11],@d[5],lsr#32
+	add.32	@x[12],@x[12],@d[6]
+	 add	$B0,$B0,@K[1]
+	add	@x[13],@x[13],@d[6],lsr#32
+	add.32	@x[14],@x[14],@d[7]
+	 add	$B1,$B1,@K[1]
+	add	@x[15],@x[15],@d[7],lsr#32
+	 add	$B2,$B2,@K[1]
+
+	b.lo	.Ltail_neon
+
+	add	@x[0],@x[0],@x[1],lsl#32	// pack
+	add	@x[2],@x[2],@x[3],lsl#32
+	ldp	@x[1],@x[3],[$inp,#0]		// load input
+	add	@x[4],@x[4],@x[5],lsl#32
+	add	@x[6],@x[6],@x[7],lsl#32
+	ldp	@x[5],@x[7],[$inp,#16]
+	add	@x[8],@x[8],@x[9],lsl#32
+	add	@x[10],@x[10],@x[11],lsl#32
+	ldp	@x[9],@x[11],[$inp,#32]
+	add	@x[12],@x[12],@x[13],lsl#32
+	add	@x[14],@x[14],@x[15],lsl#32
+	ldp	@x[13],@x[15],[$inp,#48]
+	add	$inp,$inp,#64
+#ifdef	__ARMEB__
+	rev	@x[0],@x[0]
+	rev	@x[2],@x[2]
+	rev	@x[4],@x[4]
+	rev	@x[6],@x[6]
+	rev	@x[8],@x[8]
+	rev	@x[10],@x[10]
+	rev	@x[12],@x[12]
+	rev	@x[14],@x[14]
+#endif
+	ld1.8	{$T0-$T3},[$inp],#64
+	eor	@x[0],@x[0],@x[1]
+	eor	@x[2],@x[2],@x[3]
+	eor	@x[4],@x[4],@x[5]
+	eor	@x[6],@x[6],@x[7]
+	eor	@x[8],@x[8],@x[9]
+	 eor	$A0,$A0,$T0
+	eor	@x[10],@x[10],@x[11]
+	 eor	$B0,$B0,$T1
+	eor	@x[12],@x[12],@x[13]
+	 eor	$C0,$C0,$T2
+	eor	@x[14],@x[14],@x[15]
+	 eor	$D0,$D0,$T3
+	 ld1.8	{$T0-$T3},[$inp],#64
+
+	stp	@x[0],@x[2],[$out,#0]		// store output
+	 add	@d[6],@d[6],#4			// increment counter
+	stp	@x[4],@x[6],[$out,#16]
+	 add	@K[3],@K[3],$ONE		// += 4
+	stp	@x[8],@x[10],[$out,#32]
+	 add	@K[4],@K[4],$ONE
+	stp	@x[12],@x[14],[$out,#48]
+	 add	@K[5],@K[5],$ONE
+	add	$out,$out,#64
+
+	st1.8	{$A0-$D0},[$out],#64
+	ld1.8	{$A0-$D0},[$inp],#64
+
+	eor	$A1,$A1,$T0
+	eor	$B1,$B1,$T1
+	eor	$C1,$C1,$T2
+	eor	$D1,$D1,$T3
+	st1.8	{$A1-$D1},[$out],#64
+
+	eor	$A2,$A2,$A0
+	eor	$B2,$B2,$B0
+	eor	$C2,$C2,$C0
+	eor	$D2,$D2,$D0
+	st1.8	{$A2-$D2},[$out],#64
+
+	b.hi	.Loop_outer_neon
+
+	ldp	x19,x20,[x29,#16]
+	add	sp,sp,#64
+	ldp	x21,x22,[x29,#32]
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldp	x29,x30,[sp],#96
+	ret
+
+.Ltail_neon:
+	add	$len,$len,#256
+	cmp	$len,#64
+	b.lo	.Less_than_64
+
+	add	@x[0],@x[0],@x[1],lsl#32	// pack
+	add	@x[2],@x[2],@x[3],lsl#32
+	ldp	@x[1],@x[3],[$inp,#0]		// load input
+	add	@x[4],@x[4],@x[5],lsl#32
+	add	@x[6],@x[6],@x[7],lsl#32
+	ldp	@x[5],@x[7],[$inp,#16]
+	add	@x[8],@x[8],@x[9],lsl#32
+	add	@x[10],@x[10],@x[11],lsl#32
+	ldp	@x[9],@x[11],[$inp,#32]
+	add	@x[12],@x[12],@x[13],lsl#32
+	add	@x[14],@x[14],@x[15],lsl#32
+	ldp	@x[13],@x[15],[$inp,#48]
+	add	$inp,$inp,#64
+#ifdef	__ARMEB__
+	rev	@x[0],@x[0]
+	rev	@x[2],@x[2]
+	rev	@x[4],@x[4]
+	rev	@x[6],@x[6]
+	rev	@x[8],@x[8]
+	rev	@x[10],@x[10]
+	rev	@x[12],@x[12]
+	rev	@x[14],@x[14]
+#endif
+	eor	@x[0],@x[0],@x[1]
+	eor	@x[2],@x[2],@x[3]
+	eor	@x[4],@x[4],@x[5]
+	eor	@x[6],@x[6],@x[7]
+	eor	@x[8],@x[8],@x[9]
+	eor	@x[10],@x[10],@x[11]
+	eor	@x[12],@x[12],@x[13]
+	eor	@x[14],@x[14],@x[15]
+
+	stp	@x[0],@x[2],[$out,#0]		// store output
+	 add	@d[6],@d[6],#4			// increment counter
+	stp	@x[4],@x[6],[$out,#16]
+	stp	@x[8],@x[10],[$out,#32]
+	stp	@x[12],@x[14],[$out,#48]
+	add	$out,$out,#64
+	b.eq	.Ldone_neon
+	sub	$len,$len,#64
+	cmp	$len,#64
+	b.lo	.Less_than_128
+
+	ld1.8	{$T0-$T3},[$inp],#64
+	eor	$A0,$A0,$T0
+	eor	$B0,$B0,$T1
+	eor	$C0,$C0,$T2
+	eor	$D0,$D0,$T3
+	st1.8	{$A0-$D0},[$out],#64
+	b.eq	.Ldone_neon
+	sub	$len,$len,#64
+	cmp	$len,#64
+	b.lo	.Less_than_192
+
+	ld1.8	{$T0-$T3},[$inp],#64
+	eor	$A1,$A1,$T0
+	eor	$B1,$B1,$T1
+	eor	$C1,$C1,$T2
+	eor	$D1,$D1,$T3
+	st1.8	{$A1-$D1},[$out],#64
+	b.eq	.Ldone_neon
+	sub	$len,$len,#64
+
+	st1.8	{$A2-$D2},[sp]
+	b	.Last_neon
+
+.Less_than_128:
+	st1.8	{$A0-$D0},[sp]
+	b	.Last_neon
+.Less_than_192:
+	st1.8	{$A1-$D1},[sp]
+	b	.Last_neon
+
+.align	4
+.Last_neon:
+	sub	$out,$out,#1
+	add	$inp,$inp,$len
+	add	$out,$out,$len
+	add	$ctr,sp,$len
+	neg	$len,$len
+
+.Loop_tail_neon:
+	ldrb	w10,[$inp,$len]
+	ldrb	w11,[$ctr,$len]
+	add	$len,$len,#1
+	eor	w10,w10,w11
+	strb	w10,[$out,$len]
+	cbnz	$len,.Loop_tail_neon
+
+	stp	xzr,xzr,[sp,#0]
+	stp	xzr,xzr,[sp,#16]
+	stp	xzr,xzr,[sp,#32]
+	stp	xzr,xzr,[sp,#48]
+
+.Ldone_neon:
+	ldp	x19,x20,[x29,#16]
+	add	sp,sp,#64
+	ldp	x21,x22,[x29,#32]
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldp	x29,x30,[sp],#96
+	ret
+.size	ChaCha20_neon,.-ChaCha20_neon
+___
+{
+my ($T0,$T1,$T2,$T3,$T4,$T5)=@K;
+my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,
+    $A3,$B3,$C3,$D3,$A4,$B4,$C4,$D4,$A5,$B5,$C5,$D5) = map("v$_.4s",(0..23));
+
+$code.=<<___;
+.type	ChaCha20_512_neon,%function
+.align	5
+ChaCha20_512_neon:
+	stp	x29,x30,[sp,#-96]!
+	add	x29,sp,#0
+
+	adr	@x[0],.Lsigma
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+	stp	x25,x26,[sp,#64]
+	stp	x27,x28,[sp,#80]
+
+.L512_or_more_neon:
+	sub	sp,sp,#128+64
+
+	ldp	@d[0],@d[1],[@x[0]]		// load sigma
+	ld1	{@K[0]},[@x[0]],#16
+	ldp	@d[2],@d[3],[$key]		// load key
+	ldp	@d[4],@d[5],[$key,#16]
+	ld1	{@K[1],@K[2]},[$key]
+	ldp	@d[6],@d[7],[$ctr]		// load counter
+	ld1	{@K[3]},[$ctr]
+	ld1	{$ONE},[@x[0]]
+#ifdef	__ARMEB__
+	rev64	@K[0],@K[0]
+	ror	@d[2],@d[2],#32
+	ror	@d[3],@d[3],#32
+	ror	@d[4],@d[4],#32
+	ror	@d[5],@d[5],#32
+	ror	@d[6],@d[6],#32
+	ror	@d[7],@d[7],#32
+#endif
+	add	@K[3],@K[3],$ONE		// += 1
+	stp	@K[0],@K[1],[sp,#0]		// off-load key block, invariant part
+	add	@K[3],@K[3],$ONE		// not typo
+	str	@K[2],[sp,#32]
+	add	@K[4],@K[3],$ONE
+	add	@K[5],@K[4],$ONE
+	add	@K[6],@K[5],$ONE
+	shl	$ONE,$ONE,#2			// 1 -> 4
+
+	stp	d8,d9,[sp,#128+0]		// meet ABI requirements
+	stp	d10,d11,[sp,#128+16]
+	stp	d12,d13,[sp,#128+32]
+	stp	d14,d15,[sp,#128+48]
+
+	sub	$len,$len,#512			// not typo
+
+.Loop_outer_512_neon:
+	 mov	$A0,@K[0]
+	 mov	$A1,@K[0]
+	 mov	$A2,@K[0]
+	 mov	$A3,@K[0]
+	 mov	$A4,@K[0]
+	 mov	$A5,@K[0]
+	 mov	$B0,@K[1]
+	mov.32	@x[0],@d[0]			// unpack key block
+	 mov	$B1,@K[1]
+	lsr	@x[1],@d[0],#32
+	 mov	$B2,@K[1]
+	mov.32	@x[2],@d[1]
+	 mov	$B3,@K[1]
+	lsr	@x[3],@d[1],#32
+	 mov	$B4,@K[1]
+	mov.32	@x[4],@d[2]
+	 mov	$B5,@K[1]
+	lsr	@x[5],@d[2],#32
+	 mov	$D0,@K[3]
+	mov.32	@x[6],@d[3]
+	 mov	$D1,@K[4]
+	lsr	@x[7],@d[3],#32
+	 mov	$D2,@K[5]
+	mov.32	@x[8],@d[4]
+	 mov	$D3,@K[6]
+	lsr	@x[9],@d[4],#32
+	 mov	$C0,@K[2]
+	mov.32	@x[10],@d[5]
+	 mov	$C1,@K[2]
+	lsr	@x[11],@d[5],#32
+	 add	$D4,$D0,$ONE			// +4
+	mov.32	@x[12],@d[6]
+	 add	$D5,$D1,$ONE			// +4
+	lsr	@x[13],@d[6],#32
+	 mov	$C2,@K[2]
+	mov.32	@x[14],@d[7]
+	 mov	$C3,@K[2]
+	lsr	@x[15],@d[7],#32
+	 mov	$C4,@K[2]
+	 stp	@K[3],@K[4],[sp,#48]		// off-load key block, variable part
+	 mov	$C5,@K[2]
+	 str	@K[5],[sp,#80]
+
+	mov	$ctr,#5
+	subs	$len,$len,#512
+.Loop_upper_neon:
+	sub	$ctr,$ctr,#1
+___
+	my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
+	my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
+	my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
+	my @thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
+	my @thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
+	my @thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
+	my @thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+	my $diff = ($#thread0+1)*6 - $#thread67 - 1;
+	my $i = 0;
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread67));
+		eval(shift(@thread1));	eval(shift(@thread67));
+		eval(shift(@thread2));	eval(shift(@thread67));
+		eval(shift(@thread3));	eval(shift(@thread67));
+		eval(shift(@thread4));	eval(shift(@thread67));
+		eval(shift(@thread5));	eval(shift(@thread67));
+	}
+
+	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
+	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
+	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
+	@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
+	@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
+	@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
+	@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread67));
+		eval(shift(@thread1));	eval(shift(@thread67));
+		eval(shift(@thread2));	eval(shift(@thread67));
+		eval(shift(@thread3));	eval(shift(@thread67));
+		eval(shift(@thread4));	eval(shift(@thread67));
+		eval(shift(@thread5));	eval(shift(@thread67));
+	}
+$code.=<<___;
+	cbnz	$ctr,.Loop_upper_neon
+
+	add.32	@x[0],@x[0],@d[0]		// accumulate key block
+	add	@x[1],@x[1],@d[0],lsr#32
+	add.32	@x[2],@x[2],@d[1]
+	add	@x[3],@x[3],@d[1],lsr#32
+	add.32	@x[4],@x[4],@d[2]
+	add	@x[5],@x[5],@d[2],lsr#32
+	add.32	@x[6],@x[6],@d[3]
+	add	@x[7],@x[7],@d[3],lsr#32
+	add.32	@x[8],@x[8],@d[4]
+	add	@x[9],@x[9],@d[4],lsr#32
+	add.32	@x[10],@x[10],@d[5]
+	add	@x[11],@x[11],@d[5],lsr#32
+	add.32	@x[12],@x[12],@d[6]
+	add	@x[13],@x[13],@d[6],lsr#32
+	add.32	@x[14],@x[14],@d[7]
+	add	@x[15],@x[15],@d[7],lsr#32
+
+	add	@x[0],@x[0],@x[1],lsl#32	// pack
+	add	@x[2],@x[2],@x[3],lsl#32
+	ldp	@x[1],@x[3],[$inp,#0]		// load input
+	add	@x[4],@x[4],@x[5],lsl#32
+	add	@x[6],@x[6],@x[7],lsl#32
+	ldp	@x[5],@x[7],[$inp,#16]
+	add	@x[8],@x[8],@x[9],lsl#32
+	add	@x[10],@x[10],@x[11],lsl#32
+	ldp	@x[9],@x[11],[$inp,#32]
+	add	@x[12],@x[12],@x[13],lsl#32
+	add	@x[14],@x[14],@x[15],lsl#32
+	ldp	@x[13],@x[15],[$inp,#48]
+	add	$inp,$inp,#64
+#ifdef	__ARMEB__
+	rev	@x[0],@x[0]
+	rev	@x[2],@x[2]
+	rev	@x[4],@x[4]
+	rev	@x[6],@x[6]
+	rev	@x[8],@x[8]
+	rev	@x[10],@x[10]
+	rev	@x[12],@x[12]
+	rev	@x[14],@x[14]
+#endif
+	eor	@x[0],@x[0],@x[1]
+	eor	@x[2],@x[2],@x[3]
+	eor	@x[4],@x[4],@x[5]
+	eor	@x[6],@x[6],@x[7]
+	eor	@x[8],@x[8],@x[9]
+	eor	@x[10],@x[10],@x[11]
+	eor	@x[12],@x[12],@x[13]
+	eor	@x[14],@x[14],@x[15]
+
+	 stp	@x[0],@x[2],[$out,#0]		// store output
+	 add	@d[6],@d[6],#1			// increment counter
+	mov.32	@x[0],@d[0]			// unpack key block
+	lsr	@x[1],@d[0],#32
+	 stp	@x[4],@x[6],[$out,#16]
+	mov.32	@x[2],@d[1]
+	lsr	@x[3],@d[1],#32
+	 stp	@x[8],@x[10],[$out,#32]
+	mov.32	@x[4],@d[2]
+	lsr	@x[5],@d[2],#32
+	 stp	@x[12],@x[14],[$out,#48]
+	 add	$out,$out,#64
+	mov.32	@x[6],@d[3]
+	lsr	@x[7],@d[3],#32
+	mov.32	@x[8],@d[4]
+	lsr	@x[9],@d[4],#32
+	mov.32	@x[10],@d[5]
+	lsr	@x[11],@d[5],#32
+	mov.32	@x[12],@d[6]
+	lsr	@x[13],@d[6],#32
+	mov.32	@x[14],@d[7]
+	lsr	@x[15],@d[7],#32
+
+	mov	$ctr,#5
+.Loop_lower_neon:
+	sub	$ctr,$ctr,#1
+___
+	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
+	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
+	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
+	@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
+	@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
+	@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
+	@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread67));
+		eval(shift(@thread1));	eval(shift(@thread67));
+		eval(shift(@thread2));	eval(shift(@thread67));
+		eval(shift(@thread3));	eval(shift(@thread67));
+		eval(shift(@thread4));	eval(shift(@thread67));
+		eval(shift(@thread5));	eval(shift(@thread67));
+	}
+
+	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
+	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
+	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
+	@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
+	@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
+	@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
+	@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+
+	foreach (@thread0) {
+		eval;			eval(shift(@thread67));
+		eval(shift(@thread1));	eval(shift(@thread67));
+		eval(shift(@thread2));	eval(shift(@thread67));
+		eval(shift(@thread3));	eval(shift(@thread67));
+		eval(shift(@thread4));	eval(shift(@thread67));
+		eval(shift(@thread5));	eval(shift(@thread67));
+	}
+$code.=<<___;
+	cbnz	$ctr,.Loop_lower_neon
+
+	add.32	@x[0],@x[0],@d[0]		// accumulate key block
+	 ldp	@K[0],@K[1],[sp,#0]
+	add	@x[1],@x[1],@d[0],lsr#32
+	 ldp	@K[2],@K[3],[sp,#32]
+	add.32	@x[2],@x[2],@d[1]
+	 ldp	@K[4],@K[5],[sp,#64]
+	add	@x[3],@x[3],@d[1],lsr#32
+	 add	$A0,$A0,@K[0]
+	add.32	@x[4],@x[4],@d[2]
+	 add	$A1,$A1,@K[0]
+	add	@x[5],@x[5],@d[2],lsr#32
+	 add	$A2,$A2,@K[0]
+	add.32	@x[6],@x[6],@d[3]
+	 add	$A3,$A3,@K[0]
+	add	@x[7],@x[7],@d[3],lsr#32
+	 add	$A4,$A4,@K[0]
+	add.32	@x[8],@x[8],@d[4]
+	 add	$A5,$A5,@K[0]
+	add	@x[9],@x[9],@d[4],lsr#32
+	 add	$C0,$C0,@K[2]
+	add.32	@x[10],@x[10],@d[5]
+	 add	$C1,$C1,@K[2]
+	add	@x[11],@x[11],@d[5],lsr#32
+	 add	$C2,$C2,@K[2]
+	add.32	@x[12],@x[12],@d[6]
+	 add	$C3,$C3,@K[2]
+	add	@x[13],@x[13],@d[6],lsr#32
+	 add	$C4,$C4,@K[2]
+	add.32	@x[14],@x[14],@d[7]
+	 add	$C5,$C5,@K[2]
+	add	@x[15],@x[15],@d[7],lsr#32
+	 add	$D4,$D4,$ONE			// +4
+	add	@x[0],@x[0],@x[1],lsl#32	// pack
+	 add	$D5,$D5,$ONE			// +4
+	add	@x[2],@x[2],@x[3],lsl#32
+	 add	$D0,$D0,@K[3]
+	ldp	@x[1],@x[3],[$inp,#0]		// load input
+	 add	$D1,$D1,@K[4]
+	add	@x[4],@x[4],@x[5],lsl#32
+	 add	$D2,$D2,@K[5]
+	add	@x[6],@x[6],@x[7],lsl#32
+	 add	$D3,$D3,@K[6]
+	ldp	@x[5],@x[7],[$inp,#16]
+	 add	$D4,$D4,@K[3]
+	add	@x[8],@x[8],@x[9],lsl#32
+	 add	$D5,$D5,@K[4]
+	add	@x[10],@x[10],@x[11],lsl#32
+	 add	$B0,$B0,@K[1]
+	ldp	@x[9],@x[11],[$inp,#32]
+	 add	$B1,$B1,@K[1]
+	add	@x[12],@x[12],@x[13],lsl#32
+	 add	$B2,$B2,@K[1]
+	add	@x[14],@x[14],@x[15],lsl#32
+	 add	$B3,$B3,@K[1]
+	ldp	@x[13],@x[15],[$inp,#48]
+	 add	$B4,$B4,@K[1]
+	add	$inp,$inp,#64
+	 add	$B5,$B5,@K[1]
+
+#ifdef	__ARMEB__
+	rev	@x[0],@x[0]
+	rev	@x[2],@x[2]
+	rev	@x[4],@x[4]
+	rev	@x[6],@x[6]
+	rev	@x[8],@x[8]
+	rev	@x[10],@x[10]
+	rev	@x[12],@x[12]
+	rev	@x[14],@x[14]
+#endif
+	ld1.8	{$T0-$T3},[$inp],#64
+	eor	@x[0],@x[0],@x[1]
+	eor	@x[2],@x[2],@x[3]
+	eor	@x[4],@x[4],@x[5]
+	eor	@x[6],@x[6],@x[7]
+	eor	@x[8],@x[8],@x[9]
+	 eor	$A0,$A0,$T0
+	eor	@x[10],@x[10],@x[11]
+	 eor	$B0,$B0,$T1
+	eor	@x[12],@x[12],@x[13]
+	 eor	$C0,$C0,$T2
+	eor	@x[14],@x[14],@x[15]
+	 eor	$D0,$D0,$T3
+	 ld1.8	{$T0-$T3},[$inp],#64
+
+	stp	@x[0],@x[2],[$out,#0]		// store output
+	 add	@d[6],@d[6],#7			// increment counter
+	stp	@x[4],@x[6],[$out,#16]
+	stp	@x[8],@x[10],[$out,#32]
+	stp	@x[12],@x[14],[$out,#48]
+	add	$out,$out,#64
+	st1.8	{$A0-$D0},[$out],#64
+
+	ld1.8	{$A0-$D0},[$inp],#64
+	eor	$A1,$A1,$T0
+	eor	$B1,$B1,$T1
+	eor	$C1,$C1,$T2
+	eor	$D1,$D1,$T3
+	st1.8	{$A1-$D1},[$out],#64
+
+	ld1.8	{$A1-$D1},[$inp],#64
+	eor	$A2,$A2,$A0
+	 ldp	@K[0],@K[1],[sp,#0]
+	eor	$B2,$B2,$B0
+	 ldp	@K[2],@K[3],[sp,#32]
+	eor	$C2,$C2,$C0
+	eor	$D2,$D2,$D0
+	st1.8	{$A2-$D2},[$out],#64
+
+	ld1.8	{$A2-$D2},[$inp],#64
+	eor	$A3,$A3,$A1
+	eor	$B3,$B3,$B1
+	eor	$C3,$C3,$C1
+	eor	$D3,$D3,$D1
+	st1.8	{$A3-$D3},[$out],#64
+
+	ld1.8	{$A3-$D3},[$inp],#64
+	eor	$A4,$A4,$A2
+	eor	$B4,$B4,$B2
+	eor	$C4,$C4,$C2
+	eor	$D4,$D4,$D2
+	st1.8	{$A4-$D4},[$out],#64
+
+	shl	$A0,$ONE,#1			// 4 -> 8
+	eor	$A5,$A5,$A3
+	eor	$B5,$B5,$B3
+	eor	$C5,$C5,$C3
+	eor	$D5,$D5,$D3
+	st1.8	{$A5-$D5},[$out],#64
+
+	add	@K[3],@K[3],$A0			// += 8
+	add	@K[4],@K[4],$A0
+	add	@K[5],@K[5],$A0
+	add	@K[6],@K[6],$A0
+
+	b.hs	.Loop_outer_512_neon
+
+	adds	$len,$len,#512
+	ushr	$A0,$ONE,#2			// 4 -> 1
+
+	ldp	d8,d9,[sp,#128+0]		// meet ABI requirements
+	ldp	d10,d11,[sp,#128+16]
+	ldp	d12,d13,[sp,#128+32]
+	ldp	d14,d15,[sp,#128+48]
+
+	stp	@K[0],$ONE,[sp,#0]		// wipe off-load area
+	stp	@K[0],$ONE,[sp,#32]
+	stp	@K[0],$ONE,[sp,#64]
+
+	b.eq	.Ldone_512_neon
+
+	cmp	$len,#192
+	sub	@K[3],@K[3],$A0			// -= 1
+	sub	@K[4],@K[4],$A0
+	sub	@K[5],@K[5],$A0
+	add	sp,sp,#128
+	b.hs	.Loop_outer_neon
+
+	eor	@K[1],@K[1],@K[1]
+	eor	@K[2],@K[2],@K[2]
+	eor	@K[3],@K[3],@K[3]
+	eor	@K[4],@K[4],@K[4]
+	eor	@K[5],@K[5],@K[5]
+	eor	@K[6],@K[6],@K[6]
+	b	.Loop_outer
+
+.Ldone_512_neon:
+	ldp	x19,x20,[x29,#16]
+	add	sp,sp,#128+64
+	ldp	x21,x22,[x29,#32]
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldp	x29,x30,[sp],#96
+	ret
+.size	ChaCha20_512_neon,.-ChaCha20_512_neon
+___
+}
+}}}
+
+foreach (split("\n",$code)) {
+	s/\`([^\`]*)\`/eval $1/geo;
+
+	(s/\b([a-z]+)\.32\b/$1/ and (s/x([0-9]+)/w$1/g or 1))	or
+	(m/\b(eor|ext|mov)\b/ and (s/\.4s/\.16b/g or 1))	or
+	(s/\b((?:ld|st)1)\.8\b/$1/ and (s/\.4s/\.16b/g or 1))	or
+	(m/\b(ld|st)[rp]\b/ and (s/v([0-9]+)\.4s/q$1/g or 1))	or
+	(s/\brev32\.16\b/rev32/ and (s/\.4s/\.8h/g or 1));
+
+	#s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
+
+	print $_,"\n";
+}
+close STDOUT;	# flush
diff --git a/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-x86.pl b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-x86.pl
new file mode 100644
index 0000000..e3851d7
--- /dev/null
+++ b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-x86.pl
@@ -0,0 +1,772 @@
+#! /usr/bin/env perl
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# January 2015
+#
+# ChaCha20 for x86.
+#
+# Performance in cycles per byte out of large buffer.
+#
+#		1xIALU/gcc	4xSSSE3
+# Pentium	17.5/+80%
+# PIII		14.2/+60%
+# P4		18.6/+84%
+# Core2		9.56/+89%	4.83
+# Westmere	9.50/+45%	3.35
+# Sandy Bridge	10.5/+47%	3.20
+# Haswell	8.15/+50%	2.83
+# Skylake	7.53/+22%	2.75
+# Silvermont	17.4/+36%	8.35
+# Goldmont	13.4/+40%	4.36
+# Sledgehammer	10.2/+54%
+# Bulldozer	13.4/+50%	4.38(*)
+#
+# (*)	Bulldozer actually executes 4xXOP code path that delivers 3.55;
+#
+# Modified from upstream OpenSSL to remove the XOP code.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+$output=pop;
+open STDOUT,">$output";
+
+&asm_init($ARGV[0],$ARGV[$#ARGV] eq "386");
+
+$xmm=$ymm=1;
+$gasver=999;  # enable everything
+
+$a="eax";
+($b,$b_)=("ebx","ebp");
+($c,$c_)=("ecx","esi");
+($d,$d_)=("edx","edi");
+
+sub QUARTERROUND {
+my ($ai,$bi,$ci,$di,$i)=@_;
+my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di));	# next
+my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di));	# previous
+
+	#       a   b   c   d
+	#
+	#       0   4   8  12 < even round
+	#       1   5   9  13
+	#       2   6  10  14
+	#       3   7  11  15
+	#       0   5  10  15 < odd round
+	#       1   6  11  12
+	#       2   7   8  13
+	#       3   4   9  14
+
+	if ($i==0) {
+            my $j=4;
+	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
+	} elsif ($i==3) {
+            my $j=0;
+	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
+	} elsif ($i==4) {
+            my $j=4;
+	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
+	} elsif ($i==7) {
+            my $j=0;
+	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
+	}
+
+	#&add	($a,$b);			# see elsewhere
+	&xor	($d,$a);
+	 &mov	(&DWP(4*$cp,"esp"),$c_)		if ($ai>0 && $ai<3);
+	&rol	($d,16);
+	 &mov	(&DWP(4*$bp,"esp"),$b_)		if ($i!=0);
+	&add	($c,$d);
+	 &mov	($c_,&DWP(4*$cn,"esp"))		if ($ai>0 && $ai<3);
+	&xor	($b,$c);
+	 &mov	($d_,&DWP(4*$dn,"esp"))		if ($di!=$dn);
+	&rol	($b,12);
+	 &mov	($b_,&DWP(4*$bn,"esp"))		if ($i<7);
+	 &mov	($b_,&DWP(128,"esp"))		if ($i==7);	# loop counter
+	&add	($a,$b);
+	&xor	($d,$a);
+	&mov	(&DWP(4*$ai,"esp"),$a);
+	&rol	($d,8);
+	&mov	($a,&DWP(4*$an,"esp"));
+	&add	($c,$d);
+	&mov	(&DWP(4*$di,"esp"),$d)		if ($di!=$dn);
+	&mov	($d_,$d)			if ($di==$dn);
+	&xor	($b,$c);
+	 &add	($a,$b_)			if ($i<7);	# elsewhere
+	&rol	($b,7);
+
+	($b,$b_)=($b_,$b);
+	($c,$c_)=($c_,$c);
+	($d,$d_)=($d_,$d);
+}
+
+&static_label("ssse3_shortcut");
+&static_label("ssse3_data");
+&static_label("pic_point");
+
+&function_begin("GFp_ChaCha20_ctr32");
+	&xor	("eax","eax");
+	&cmp	("eax",&wparam(2));		# len==0?
+	&je	(&label("no_data"));
+if ($xmm) {
+	&call	(&label("pic_point"));
+&set_label("pic_point");
+	&blindpop("eax");
+	&picmeup("ebp","GFp_ia32cap_P","eax",&label("pic_point"));
+	&test	(&DWP(0,"ebp"),1<<24);		# test FXSR bit
+	&jz	(&label("x86"));
+	&test	(&DWP(4,"ebp"),1<<9);		# test SSSE3 bit
+	&jz	(&label("x86"));
+	&jmp	(&label("ssse3_shortcut"));
+&set_label("x86");
+}
+	&mov	("esi",&wparam(3));		# key
+	&mov	("edi",&wparam(4));		# counter and nonce
+
+	&stack_push(33);
+
+	&mov	("eax",&DWP(4*0,"esi"));	# copy key
+	&mov	("ebx",&DWP(4*1,"esi"));
+	&mov	("ecx",&DWP(4*2,"esi"));
+	&mov	("edx",&DWP(4*3,"esi"));
+	&mov	(&DWP(64+4*4,"esp"),"eax");
+	&mov	(&DWP(64+4*5,"esp"),"ebx");
+	&mov	(&DWP(64+4*6,"esp"),"ecx");
+	&mov	(&DWP(64+4*7,"esp"),"edx");
+	&mov	("eax",&DWP(4*4,"esi"));
+	&mov	("ebx",&DWP(4*5,"esi"));
+	&mov	("ecx",&DWP(4*6,"esi"));
+	&mov	("edx",&DWP(4*7,"esi"));
+	&mov	(&DWP(64+4*8,"esp"),"eax");
+	&mov	(&DWP(64+4*9,"esp"),"ebx");
+	&mov	(&DWP(64+4*10,"esp"),"ecx");
+	&mov	(&DWP(64+4*11,"esp"),"edx");
+	&mov	("eax",&DWP(4*0,"edi"));	# copy counter and nonce
+	&mov	("ebx",&DWP(4*1,"edi"));
+	&mov	("ecx",&DWP(4*2,"edi"));
+	&mov	("edx",&DWP(4*3,"edi"));
+	&sub	("eax",1);
+	&mov	(&DWP(64+4*12,"esp"),"eax");
+	&mov	(&DWP(64+4*13,"esp"),"ebx");
+	&mov	(&DWP(64+4*14,"esp"),"ecx");
+	&mov	(&DWP(64+4*15,"esp"),"edx");
+	&jmp	(&label("entry"));
+
+&set_label("outer_loop",16);
+	&mov	(&wparam(1),$b);		# save input
+	&mov	(&wparam(0),$a);		# save output
+	&mov	(&wparam(2),$c);		# save len
+&set_label("entry");
+	&mov	($a,0x61707865);
+	&mov	(&DWP(4*1,"esp"),0x3320646e);
+	&mov	(&DWP(4*2,"esp"),0x79622d32);
+	&mov	(&DWP(4*3,"esp"),0x6b206574);
+
+	&mov	($b, &DWP(64+4*5,"esp"));	# copy key material
+	&mov	($b_,&DWP(64+4*6,"esp"));
+	&mov	($c, &DWP(64+4*10,"esp"));
+	&mov	($c_,&DWP(64+4*11,"esp"));
+	&mov	($d, &DWP(64+4*13,"esp"));
+	&mov	($d_,&DWP(64+4*14,"esp"));
+	&mov	(&DWP(4*5,"esp"),$b);
+	&mov	(&DWP(4*6,"esp"),$b_);
+	&mov	(&DWP(4*10,"esp"),$c);
+	&mov	(&DWP(4*11,"esp"),$c_);
+	&mov	(&DWP(4*13,"esp"),$d);
+	&mov	(&DWP(4*14,"esp"),$d_);
+
+	&mov	($b, &DWP(64+4*7,"esp"));
+	&mov	($d_,&DWP(64+4*15,"esp"));
+	&mov	($d, &DWP(64+4*12,"esp"));
+	&mov	($b_,&DWP(64+4*4,"esp"));
+	&mov	($c, &DWP(64+4*8,"esp"));
+	&mov	($c_,&DWP(64+4*9,"esp"));
+	&add	($d,1);				# counter value
+	&mov	(&DWP(4*7,"esp"),$b);
+	&mov	(&DWP(4*15,"esp"),$d_);
+	&mov	(&DWP(64+4*12,"esp"),$d);	# save counter value
+
+	&mov	($b,10);			# loop counter
+	&jmp	(&label("loop"));
+
+&set_label("loop",16);
+	&add	($a,$b_);			# elsewhere
+	&mov	(&DWP(128,"esp"),$b);		# save loop counter
+	&mov	($b,$b_);
+	&QUARTERROUND(0, 4, 8, 12, 0);
+	&QUARTERROUND(1, 5, 9, 13, 1);
+	&QUARTERROUND(2, 6,10, 14, 2);
+	&QUARTERROUND(3, 7,11, 15, 3);
+	&QUARTERROUND(0, 5,10, 15, 4);
+	&QUARTERROUND(1, 6,11, 12, 5);
+	&QUARTERROUND(2, 7, 8, 13, 6);
+	&QUARTERROUND(3, 4, 9, 14, 7);
+	&dec	($b);
+	&jnz	(&label("loop"));
+
+	&mov	($b,&wparam(2));		# load len
+
+	&add	($a,0x61707865);		# accumulate key material
+	&add	($b_,&DWP(64+4*4,"esp"));
+	&add	($c, &DWP(64+4*8,"esp"));
+	&add	($c_,&DWP(64+4*9,"esp"));
+
+	&cmp	($b,64);
+	&jb	(&label("tail"));
+
+	&mov	($b,&wparam(1));		# load input pointer
+	&add	($d, &DWP(64+4*12,"esp"));
+	&add	($d_,&DWP(64+4*14,"esp"));
+
+	&xor	($a, &DWP(4*0,$b));		# xor with input
+	&xor	($b_,&DWP(4*4,$b));
+	&mov	(&DWP(4*0,"esp"),$a);
+	&mov	($a,&wparam(0));		# load output pointer
+	&xor	($c, &DWP(4*8,$b));
+	&xor	($c_,&DWP(4*9,$b));
+	&xor	($d, &DWP(4*12,$b));
+	&xor	($d_,&DWP(4*14,$b));
+	&mov	(&DWP(4*4,$a),$b_);		# write output
+	&mov	(&DWP(4*8,$a),$c);
+	&mov	(&DWP(4*9,$a),$c_);
+	&mov	(&DWP(4*12,$a),$d);
+	&mov	(&DWP(4*14,$a),$d_);
+
+	&mov	($b_,&DWP(4*1,"esp"));
+	&mov	($c, &DWP(4*2,"esp"));
+	&mov	($c_,&DWP(4*3,"esp"));
+	&mov	($d, &DWP(4*5,"esp"));
+	&mov	($d_,&DWP(4*6,"esp"));
+	&add	($b_,0x3320646e);		# accumulate key material
+	&add	($c, 0x79622d32);
+	&add	($c_,0x6b206574);
+	&add	($d, &DWP(64+4*5,"esp"));
+	&add	($d_,&DWP(64+4*6,"esp"));
+	&xor	($b_,&DWP(4*1,$b));
+	&xor	($c, &DWP(4*2,$b));
+	&xor	($c_,&DWP(4*3,$b));
+	&xor	($d, &DWP(4*5,$b));
+	&xor	($d_,&DWP(4*6,$b));
+	&mov	(&DWP(4*1,$a),$b_);
+	&mov	(&DWP(4*2,$a),$c);
+	&mov	(&DWP(4*3,$a),$c_);
+	&mov	(&DWP(4*5,$a),$d);
+	&mov	(&DWP(4*6,$a),$d_);
+
+	&mov	($b_,&DWP(4*7,"esp"));
+	&mov	($c, &DWP(4*10,"esp"));
+	&mov	($c_,&DWP(4*11,"esp"));
+	&mov	($d, &DWP(4*13,"esp"));
+	&mov	($d_,&DWP(4*15,"esp"));
+	&add	($b_,&DWP(64+4*7,"esp"));
+	&add	($c, &DWP(64+4*10,"esp"));
+	&add	($c_,&DWP(64+4*11,"esp"));
+	&add	($d, &DWP(64+4*13,"esp"));
+	&add	($d_,&DWP(64+4*15,"esp"));
+	&xor	($b_,&DWP(4*7,$b));
+	&xor	($c, &DWP(4*10,$b));
+	&xor	($c_,&DWP(4*11,$b));
+	&xor	($d, &DWP(4*13,$b));
+	&xor	($d_,&DWP(4*15,$b));
+	&lea	($b,&DWP(4*16,$b));
+	&mov	(&DWP(4*7,$a),$b_);
+	&mov	($b_,&DWP(4*0,"esp"));
+	&mov	(&DWP(4*10,$a),$c);
+	&mov	($c,&wparam(2));		# len
+	&mov	(&DWP(4*11,$a),$c_);
+	&mov	(&DWP(4*13,$a),$d);
+	&mov	(&DWP(4*15,$a),$d_);
+	&mov	(&DWP(4*0,$a),$b_);
+	&lea	($a,&DWP(4*16,$a));
+	&sub	($c,64);
+	&jnz	(&label("outer_loop"));
+
+	&jmp	(&label("done"));
+
+&set_label("tail");
+	&add	($d, &DWP(64+4*12,"esp"));
+	&add	($d_,&DWP(64+4*14,"esp"));
+	&mov	(&DWP(4*0,"esp"),$a);
+	&mov	(&DWP(4*4,"esp"),$b_);
+	&mov	(&DWP(4*8,"esp"),$c);
+	&mov	(&DWP(4*9,"esp"),$c_);
+	&mov	(&DWP(4*12,"esp"),$d);
+	&mov	(&DWP(4*14,"esp"),$d_);
+
+	&mov	($b_,&DWP(4*1,"esp"));
+	&mov	($c, &DWP(4*2,"esp"));
+	&mov	($c_,&DWP(4*3,"esp"));
+	&mov	($d, &DWP(4*5,"esp"));
+	&mov	($d_,&DWP(4*6,"esp"));
+	&add	($b_,0x3320646e);		# accumulate key material
+	&add	($c, 0x79622d32);
+	&add	($c_,0x6b206574);
+	&add	($d, &DWP(64+4*5,"esp"));
+	&add	($d_,&DWP(64+4*6,"esp"));
+	&mov	(&DWP(4*1,"esp"),$b_);
+	&mov	(&DWP(4*2,"esp"),$c);
+	&mov	(&DWP(4*3,"esp"),$c_);
+	&mov	(&DWP(4*5,"esp"),$d);
+	&mov	(&DWP(4*6,"esp"),$d_);
+
+	&mov	($b_,&DWP(4*7,"esp"));
+	&mov	($c, &DWP(4*10,"esp"));
+	&mov	($c_,&DWP(4*11,"esp"));
+	&mov	($d, &DWP(4*13,"esp"));
+	&mov	($d_,&DWP(4*15,"esp"));
+	&add	($b_,&DWP(64+4*7,"esp"));
+	&add	($c, &DWP(64+4*10,"esp"));
+	&add	($c_,&DWP(64+4*11,"esp"));
+	&add	($d, &DWP(64+4*13,"esp"));
+	&add	($d_,&DWP(64+4*15,"esp"));
+	&mov	(&DWP(4*7,"esp"),$b_);
+	&mov	($b_,&wparam(1));		# load input
+	&mov	(&DWP(4*10,"esp"),$c);
+	&mov	($c,&wparam(0));		# load output
+	&mov	(&DWP(4*11,"esp"),$c_);
+	&xor	($c_,$c_);
+	&mov	(&DWP(4*13,"esp"),$d);
+	&mov	(&DWP(4*15,"esp"),$d_);
+
+	&xor	("eax","eax");
+	&xor	("edx","edx");
+&set_label("tail_loop");
+	&movb	("al",&BP(0,$c_,$b_));
+	&movb	("dl",&BP(0,"esp",$c_));
+	&lea	($c_,&DWP(1,$c_));
+	&xor	("al","dl");
+	&mov	(&BP(-1,$c,$c_),"al");
+	&dec	($b);
+	&jnz	(&label("tail_loop"));
+
+&set_label("done");
+	&stack_pop(33);
+&set_label("no_data");
+&function_end("GFp_ChaCha20_ctr32");
+
+if ($xmm) {
+my ($xa,$xa_,$xb,$xb_,$xc,$xc_,$xd,$xd_)=map("xmm$_",(0..7));
+my ($out,$inp,$len)=("edi","esi","ecx");
+
+sub QUARTERROUND_SSSE3 {
+my ($ai,$bi,$ci,$di,$i)=@_;
+my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di));	# next
+my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di));	# previous
+
+	#       a   b   c   d
+	#
+	#       0   4   8  12 < even round
+	#       1   5   9  13
+	#       2   6  10  14
+	#       3   7  11  15
+	#       0   5  10  15 < odd round
+	#       1   6  11  12
+	#       2   7   8  13
+	#       3   4   9  14
+
+	if ($i==0) {
+            my $j=4;
+	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
+	} elsif ($i==3) {
+            my $j=0;
+	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
+	} elsif ($i==4) {
+            my $j=4;
+	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
+	} elsif ($i==7) {
+            my $j=0;
+	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
+	}
+
+	#&paddd	($xa,$xb);			# see elsewhere
+	#&pxor	($xd,$xa);			# see elsewhere
+	 &movdqa(&QWP(16*$cp-128,"ebx"),$xc_)	if ($ai>0 && $ai<3);
+	&pshufb	($xd,&QWP(0,"eax"));		# rot16
+	 &movdqa(&QWP(16*$bp-128,"ebx"),$xb_)	if ($i!=0);
+	&paddd	($xc,$xd);
+	 &movdqa($xc_,&QWP(16*$cn-128,"ebx"))	if ($ai>0 && $ai<3);
+	&pxor	($xb,$xc);
+	 &movdqa($xb_,&QWP(16*$bn-128,"ebx"))	if ($i<7);
+	&movdqa	($xa_,$xb);			# borrow as temporary
+	&pslld	($xb,12);
+	&psrld	($xa_,20);
+	&por	($xb,$xa_);
+	 &movdqa($xa_,&QWP(16*$an-128,"ebx"));
+	&paddd	($xa,$xb);
+	 &movdqa($xd_,&QWP(16*$dn-128,"ebx"))	if ($di!=$dn);
+	&pxor	($xd,$xa);
+	&movdqa	(&QWP(16*$ai-128,"ebx"),$xa);
+	&pshufb	($xd,&QWP(16,"eax"));		# rot8
+	&paddd	($xc,$xd);
+	&movdqa	(&QWP(16*$di-128,"ebx"),$xd)	if ($di!=$dn);
+	&movdqa	($xd_,$xd)			if ($di==$dn);
+	&pxor	($xb,$xc);
+	 &paddd	($xa_,$xb_)			if ($i<7);	# elsewhere
+	&movdqa	($xa,$xb);			# borrow as temporary
+	&pslld	($xb,7);
+	&psrld	($xa,25);
+	 &pxor	($xd_,$xa_)			if ($i<7);	# elsewhere
+	&por	($xb,$xa);
+
+	($xa,$xa_)=($xa_,$xa);
+	($xb,$xb_)=($xb_,$xb);
+	($xc,$xc_)=($xc_,$xc);
+	($xd,$xd_)=($xd_,$xd);
+}
+
+&function_begin("_ChaCha20_ssse3");
+&set_label("ssse3_shortcut");
+	&mov		($out,&wparam(0));
+	&mov		($inp,&wparam(1));
+	&mov		($len,&wparam(2));
+	&mov		("edx",&wparam(3));		# key
+	&mov		("ebx",&wparam(4));		# counter and nonce
+
+	&mov		("ebp","esp");
+	&stack_push	(131);
+	&and		("esp",-64);
+	&mov		(&DWP(512,"esp"),"ebp");
+
+	&lea		("eax",&DWP(&label("ssse3_data")."-".
+				    &label("pic_point"),"eax"));
+	&movdqu		("xmm3",&QWP(0,"ebx"));		# counter and nonce
+
+if (defined($gasver) && $gasver>=2.17) {		# even though we encode
+							# pshufb manually, we
+							# handle only register
+							# operands, while this
+							# segment uses memory
+							# operand...
+	&cmp		($len,64*4);
+	&jb		(&label("1x"));
+
+	&mov		(&DWP(512+4,"esp"),"edx");	# offload pointers
+	&mov		(&DWP(512+8,"esp"),"ebx");
+	&sub		($len,64*4);			# bias len
+	&lea		("ebp",&DWP(256+128,"esp"));	# size optimization
+
+	&movdqu		("xmm7",&QWP(0,"edx"));		# key
+	&pshufd		("xmm0","xmm3",0x00);
+	&pshufd		("xmm1","xmm3",0x55);
+	&pshufd		("xmm2","xmm3",0xaa);
+	&pshufd		("xmm3","xmm3",0xff);
+	 &paddd		("xmm0",&QWP(16*3,"eax"));	# fix counters
+	&pshufd		("xmm4","xmm7",0x00);
+	&pshufd		("xmm5","xmm7",0x55);
+	 &psubd		("xmm0",&QWP(16*4,"eax"));
+	&pshufd		("xmm6","xmm7",0xaa);
+	&pshufd		("xmm7","xmm7",0xff);
+	&movdqa		(&QWP(16*12-128,"ebp"),"xmm0");
+	&movdqa		(&QWP(16*13-128,"ebp"),"xmm1");
+	&movdqa		(&QWP(16*14-128,"ebp"),"xmm2");
+	&movdqa		(&QWP(16*15-128,"ebp"),"xmm3");
+	 &movdqu	("xmm3",&QWP(16,"edx"));	# key
+	&movdqa		(&QWP(16*4-128,"ebp"),"xmm4");
+	&movdqa		(&QWP(16*5-128,"ebp"),"xmm5");
+	&movdqa		(&QWP(16*6-128,"ebp"),"xmm6");
+	&movdqa		(&QWP(16*7-128,"ebp"),"xmm7");
+	 &movdqa	("xmm7",&QWP(16*2,"eax"));	# sigma
+	 &lea		("ebx",&DWP(128,"esp"));	# size optimization
+
+	&pshufd		("xmm0","xmm3",0x00);
+	&pshufd		("xmm1","xmm3",0x55);
+	&pshufd		("xmm2","xmm3",0xaa);
+	&pshufd		("xmm3","xmm3",0xff);
+	&pshufd		("xmm4","xmm7",0x00);
+	&pshufd		("xmm5","xmm7",0x55);
+	&pshufd		("xmm6","xmm7",0xaa);
+	&pshufd		("xmm7","xmm7",0xff);
+	&movdqa		(&QWP(16*8-128,"ebp"),"xmm0");
+	&movdqa		(&QWP(16*9-128,"ebp"),"xmm1");
+	&movdqa		(&QWP(16*10-128,"ebp"),"xmm2");
+	&movdqa		(&QWP(16*11-128,"ebp"),"xmm3");
+	&movdqa		(&QWP(16*0-128,"ebp"),"xmm4");
+	&movdqa		(&QWP(16*1-128,"ebp"),"xmm5");
+	&movdqa		(&QWP(16*2-128,"ebp"),"xmm6");
+	&movdqa		(&QWP(16*3-128,"ebp"),"xmm7");
+
+	&lea		($inp,&DWP(128,$inp));		# size optimization
+	&lea		($out,&DWP(128,$out));		# size optimization
+	&jmp		(&label("outer_loop"));
+
+&set_label("outer_loop",16);
+	#&movdqa	("xmm0",&QWP(16*0-128,"ebp"));	# copy key material
+	&movdqa		("xmm1",&QWP(16*1-128,"ebp"));
+	&movdqa		("xmm2",&QWP(16*2-128,"ebp"));
+	&movdqa		("xmm3",&QWP(16*3-128,"ebp"));
+	#&movdqa	("xmm4",&QWP(16*4-128,"ebp"));
+	&movdqa		("xmm5",&QWP(16*5-128,"ebp"));
+	&movdqa		("xmm6",&QWP(16*6-128,"ebp"));
+	&movdqa		("xmm7",&QWP(16*7-128,"ebp"));
+	#&movdqa	(&QWP(16*0-128,"ebx"),"xmm0");
+	&movdqa		(&QWP(16*1-128,"ebx"),"xmm1");
+	&movdqa		(&QWP(16*2-128,"ebx"),"xmm2");
+	&movdqa		(&QWP(16*3-128,"ebx"),"xmm3");
+	#&movdqa	(&QWP(16*4-128,"ebx"),"xmm4");
+	&movdqa		(&QWP(16*5-128,"ebx"),"xmm5");
+	&movdqa		(&QWP(16*6-128,"ebx"),"xmm6");
+	&movdqa		(&QWP(16*7-128,"ebx"),"xmm7");
+	#&movdqa	("xmm0",&QWP(16*8-128,"ebp"));
+	#&movdqa	("xmm1",&QWP(16*9-128,"ebp"));
+	&movdqa		("xmm2",&QWP(16*10-128,"ebp"));
+	&movdqa		("xmm3",&QWP(16*11-128,"ebp"));
+	&movdqa		("xmm4",&QWP(16*12-128,"ebp"));
+	&movdqa		("xmm5",&QWP(16*13-128,"ebp"));
+	&movdqa		("xmm6",&QWP(16*14-128,"ebp"));
+	&movdqa		("xmm7",&QWP(16*15-128,"ebp"));
+	&paddd		("xmm4",&QWP(16*4,"eax"));	# counter value
+	#&movdqa	(&QWP(16*8-128,"ebx"),"xmm0");
+	#&movdqa	(&QWP(16*9-128,"ebx"),"xmm1");
+	&movdqa		(&QWP(16*10-128,"ebx"),"xmm2");
+	&movdqa		(&QWP(16*11-128,"ebx"),"xmm3");
+	&movdqa		(&QWP(16*12-128,"ebx"),"xmm4");
+	&movdqa		(&QWP(16*13-128,"ebx"),"xmm5");
+	&movdqa		(&QWP(16*14-128,"ebx"),"xmm6");
+	&movdqa		(&QWP(16*15-128,"ebx"),"xmm7");
+	&movdqa		(&QWP(16*12-128,"ebp"),"xmm4");	# save counter value
+
+	&movdqa		($xa, &QWP(16*0-128,"ebp"));
+	&movdqa		($xd, "xmm4");
+	&movdqa		($xb_,&QWP(16*4-128,"ebp"));
+	&movdqa		($xc, &QWP(16*8-128,"ebp"));
+	&movdqa		($xc_,&QWP(16*9-128,"ebp"));
+
+	&mov		("edx",10);			# loop counter
+	&nop		();
+
+&set_label("loop",16);
+	&paddd		($xa,$xb_);			# elsewhere
+	&movdqa		($xb,$xb_);
+	&pxor		($xd,$xa);			# elsewhere
+	&QUARTERROUND_SSSE3(0, 4, 8, 12, 0);
+	&QUARTERROUND_SSSE3(1, 5, 9, 13, 1);
+	&QUARTERROUND_SSSE3(2, 6,10, 14, 2);
+	&QUARTERROUND_SSSE3(3, 7,11, 15, 3);
+	&QUARTERROUND_SSSE3(0, 5,10, 15, 4);
+	&QUARTERROUND_SSSE3(1, 6,11, 12, 5);
+	&QUARTERROUND_SSSE3(2, 7, 8, 13, 6);
+	&QUARTERROUND_SSSE3(3, 4, 9, 14, 7);
+	&dec		("edx");
+	&jnz		(&label("loop"));
+
+	&movdqa		(&QWP(16*4-128,"ebx"),$xb_);
+	&movdqa		(&QWP(16*8-128,"ebx"),$xc);
+	&movdqa		(&QWP(16*9-128,"ebx"),$xc_);
+	&movdqa		(&QWP(16*12-128,"ebx"),$xd);
+	&movdqa		(&QWP(16*14-128,"ebx"),$xd_);
+
+    my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
+
+	#&movdqa	($xa0,&QWP(16*0-128,"ebx"));	# it's there
+	&movdqa		($xa1,&QWP(16*1-128,"ebx"));
+	&movdqa		($xa2,&QWP(16*2-128,"ebx"));
+	&movdqa		($xa3,&QWP(16*3-128,"ebx"));
+
+    for($i=0;$i<256;$i+=64) {
+	&paddd		($xa0,&QWP($i+16*0-128,"ebp"));	# accumulate key material
+	&paddd		($xa1,&QWP($i+16*1-128,"ebp"));
+	&paddd		($xa2,&QWP($i+16*2-128,"ebp"));
+	&paddd		($xa3,&QWP($i+16*3-128,"ebp"));
+
+	&movdqa		($xt2,$xa0);		# "de-interlace" data
+	&punpckldq	($xa0,$xa1);
+	&movdqa		($xt3,$xa2);
+	&punpckldq	($xa2,$xa3);
+	&punpckhdq	($xt2,$xa1);
+	&punpckhdq	($xt3,$xa3);
+	&movdqa		($xa1,$xa0);
+	&punpcklqdq	($xa0,$xa2);		# "a0"
+	&movdqa		($xa3,$xt2);
+	&punpcklqdq	($xt2,$xt3);		# "a2"
+	&punpckhqdq	($xa1,$xa2);		# "a1"
+	&punpckhqdq	($xa3,$xt3);		# "a3"
+
+	#($xa2,$xt2)=($xt2,$xa2);
+
+	&movdqu		($xt0,&QWP(64*0-128,$inp));	# load input
+	&movdqu		($xt1,&QWP(64*1-128,$inp));
+	&movdqu		($xa2,&QWP(64*2-128,$inp));
+	&movdqu		($xt3,&QWP(64*3-128,$inp));
+	&lea		($inp,&QWP($i<192?16:(64*4-16*3),$inp));
+	&pxor		($xt0,$xa0);
+	&movdqa		($xa0,&QWP($i+16*4-128,"ebx"))	if ($i<192);
+	&pxor		($xt1,$xa1);
+	&movdqa		($xa1,&QWP($i+16*5-128,"ebx"))	if ($i<192);
+	&pxor		($xt2,$xa2);
+	&movdqa		($xa2,&QWP($i+16*6-128,"ebx"))	if ($i<192);
+	&pxor		($xt3,$xa3);
+	&movdqa		($xa3,&QWP($i+16*7-128,"ebx"))	if ($i<192);
+	&movdqu		(&QWP(64*0-128,$out),$xt0);	# store output
+	&movdqu		(&QWP(64*1-128,$out),$xt1);
+	&movdqu		(&QWP(64*2-128,$out),$xt2);
+	&movdqu		(&QWP(64*3-128,$out),$xt3);
+	&lea		($out,&QWP($i<192?16:(64*4-16*3),$out));
+    }
+	&sub		($len,64*4);
+	&jnc		(&label("outer_loop"));
+
+	&add		($len,64*4);
+	&jz		(&label("done"));
+
+	&mov		("ebx",&DWP(512+8,"esp"));	# restore pointers
+	&lea		($inp,&DWP(-128,$inp));
+	&mov		("edx",&DWP(512+4,"esp"));
+	&lea		($out,&DWP(-128,$out));
+
+	&movd		("xmm2",&DWP(16*12-128,"ebp"));	# counter value
+	&movdqu		("xmm3",&QWP(0,"ebx"));
+	&paddd		("xmm2",&QWP(16*6,"eax"));	# +four
+	&pand		("xmm3",&QWP(16*7,"eax"));
+	&por		("xmm3","xmm2");		# counter value
+}
+{
+my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("xmm$_",(0..7));
+
+sub SSSE3ROUND {	# critical path is 20 "SIMD ticks" per round
+	&paddd		($a,$b);
+	&pxor		($d,$a);
+	&pshufb		($d,$rot16);
+
+	&paddd		($c,$d);
+	&pxor		($b,$c);
+	&movdqa		($t,$b);
+	&psrld		($b,20);
+	&pslld		($t,12);
+	&por		($b,$t);
+
+	&paddd		($a,$b);
+	&pxor		($d,$a);
+	&pshufb		($d,$rot24);
+
+	&paddd		($c,$d);
+	&pxor		($b,$c);
+	&movdqa		($t,$b);
+	&psrld		($b,25);
+	&pslld		($t,7);
+	&por		($b,$t);
+}
+
+&set_label("1x");
+	&movdqa		($a,&QWP(16*2,"eax"));		# sigma
+	&movdqu		($b,&QWP(0,"edx"));
+	&movdqu		($c,&QWP(16,"edx"));
+	#&movdqu	($d,&QWP(0,"ebx"));		# already loaded
+	&movdqa		($rot16,&QWP(0,"eax"));
+	&movdqa		($rot24,&QWP(16,"eax"));
+	&mov		(&DWP(16*3,"esp"),"ebp");
+
+	&movdqa		(&QWP(16*0,"esp"),$a);
+	&movdqa		(&QWP(16*1,"esp"),$b);
+	&movdqa		(&QWP(16*2,"esp"),$c);
+	&movdqa		(&QWP(16*3,"esp"),$d);
+	&mov		("edx",10);
+	&jmp		(&label("loop1x"));
+
+&set_label("outer1x",16);
+	&movdqa		($d,&QWP(16*5,"eax"));		# one
+	&movdqa		($a,&QWP(16*0,"esp"));
+	&movdqa		($b,&QWP(16*1,"esp"));
+	&movdqa		($c,&QWP(16*2,"esp"));
+	&paddd		($d,&QWP(16*3,"esp"));
+	&mov		("edx",10);
+	&movdqa		(&QWP(16*3,"esp"),$d);
+	&jmp		(&label("loop1x"));
+
+&set_label("loop1x",16);
+	&SSSE3ROUND();
+	&pshufd	($c,$c,0b01001110);
+	&pshufd	($b,$b,0b00111001);
+	&pshufd	($d,$d,0b10010011);
+	&nop	();
+
+	&SSSE3ROUND();
+	&pshufd	($c,$c,0b01001110);
+	&pshufd	($b,$b,0b10010011);
+	&pshufd	($d,$d,0b00111001);
+
+	&dec		("edx");
+	&jnz		(&label("loop1x"));
+
+	&paddd		($a,&QWP(16*0,"esp"));
+	&paddd		($b,&QWP(16*1,"esp"));
+	&paddd		($c,&QWP(16*2,"esp"));
+	&paddd		($d,&QWP(16*3,"esp"));
+
+	&cmp		($len,64);
+	&jb		(&label("tail"));
+
+	&movdqu		($t,&QWP(16*0,$inp));
+	&movdqu		($t1,&QWP(16*1,$inp));
+	&pxor		($a,$t);		# xor with input
+	&movdqu		($t,&QWP(16*2,$inp));
+	&pxor		($b,$t1);
+	&movdqu		($t1,&QWP(16*3,$inp));
+	&pxor		($c,$t);
+	&pxor		($d,$t1);
+	&lea		($inp,&DWP(16*4,$inp));	# inp+=64
+
+	&movdqu		(&QWP(16*0,$out),$a);	# write output
+	&movdqu		(&QWP(16*1,$out),$b);
+	&movdqu		(&QWP(16*2,$out),$c);
+	&movdqu		(&QWP(16*3,$out),$d);
+	&lea		($out,&DWP(16*4,$out));	# inp+=64
+
+	&sub		($len,64);
+	&jnz		(&label("outer1x"));
+
+	&jmp		(&label("done"));
+
+&set_label("tail");
+	&movdqa		(&QWP(16*0,"esp"),$a);
+	&movdqa		(&QWP(16*1,"esp"),$b);
+	&movdqa		(&QWP(16*2,"esp"),$c);
+	&movdqa		(&QWP(16*3,"esp"),$d);
+
+	&xor		("eax","eax");
+	&xor		("edx","edx");
+	&xor		("ebp","ebp");
+
+&set_label("tail_loop");
+	&movb		("al",&BP(0,"esp","ebp"));
+	&movb		("dl",&BP(0,$inp,"ebp"));
+	&lea		("ebp",&DWP(1,"ebp"));
+	&xor		("al","dl");
+	&movb		(&BP(-1,$out,"ebp"),"al");
+	&dec		($len);
+	&jnz		(&label("tail_loop"));
+}
+&set_label("done");
+	&mov		("esp",&DWP(512,"esp"));
+&function_end("_ChaCha20_ssse3");
+
+&align	(64);
+&set_label("ssse3_data");
+&data_byte(0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd);
+&data_byte(0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe);
+&data_word(0x61707865,0x3320646e,0x79622d32,0x6b206574);
+&data_word(0,1,2,3);
+&data_word(4,4,4,4);
+&data_word(1,0,0,0);
+&data_word(4,0,0,0);
+&data_word(0,-1,-1,-1);
+&align	(64);
+}
+&asciz	("ChaCha20 for x86, CRYPTOGAMS by <appro\@openssl.org>");
+
+&asm_finish();
+
+close STDOUT;
diff --git a/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-x86_64.pl b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-x86_64.pl
new file mode 100644
index 0000000..13527da
--- /dev/null
+++ b/rustc_deps/vendor/ring/crypto/chacha/asm/chacha-x86_64.pl
@@ -0,0 +1,2749 @@
+#! /usr/bin/env perl
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# November 2014
+#
+# ChaCha20 for x86_64.
+#
+# December 2016
+#
+# Add AVX512F code path.
+#
+# Performance in cycles per byte out of large buffer.
+#
+#		IALU/gcc 4.8(i)	1xSSSE3/SSE2	4xSSSE3	    NxAVX(v)
+#
+# P4		9.48/+99%	-/22.7(ii)	-
+# Core2		7.83/+55%	7.90/8.08	4.35
+# Westmere	7.19/+50%	5.60/6.70	3.00
+# Sandy Bridge	8.31/+42%	5.45/6.76	2.72
+# Ivy Bridge	6.71/+46%	5.40/6.49	2.41
+# Haswell	5.92/+43%	5.20/6.45	2.42	    1.23
+# Skylake[-X]	5.87/+39%	4.70/-		2.31	    1.19[0.57]
+# Silvermont	12.0/+33%	7.75/7.40	7.03(iii)
+# Knights L	11.7/-		-		9.60(iii)   0.80
+# Goldmont	10.6/+17%	5.10/-		3.28
+# Sledgehammer	7.28/+52%	-/14.2(ii)	-
+# Bulldozer	9.66/+28%	9.85/11.1	3.06(iv)
+# Ryzen		5.96/+50%	5.19/-		2.40        2.09
+# VIA Nano	10.5/+46%	6.72/8.60	6.05
+#
+# (i)	compared to older gcc 3.x one can observe >2x improvement on
+#	most platforms;
+# (ii)	as it can be seen, SSE2 performance is too low on legacy
+#	processors; NxSSE2 results are naturally better, but not
+#	impressively better than IALU ones, which is why you won't
+#	find SSE2 code below;
+# (iii)	this is not optimal result for Atom because of MSROM
+#	limitations, SSE2 can do better, but gain is considered too
+#	low to justify the [maintenance] effort;
+# (iv)	Bulldozer actually executes 4xXOP code path that delivers 2.20;
+#
+# Modified from upstream OpenSSL to remove the XOP code.
+
+$flavour = shift;
+$output  = shift;
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
+die "can't locate x86_64-xlate.pl";
+
+$avx = 2;
+
+open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
+*STDOUT=*OUT;
+
+# input parameter block
+($out,$inp,$len,$key,$counter)=("%rdi","%rsi","%rdx","%rcx","%r8");
+
+$code.=<<___;
+.text
+
+.extern GFp_ia32cap_P
+
+.align	64
+.Lzero:
+.long	0,0,0,0
+.Lone:
+.long	1,0,0,0
+.Linc:
+.long	0,1,2,3
+.Lfour:
+.long	4,4,4,4
+.Lincy:
+.long	0,2,4,6,1,3,5,7
+.Leight:
+.long	8,8,8,8,8,8,8,8
+.Lrot16:
+.byte	0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd
+.Lrot24:
+.byte	0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe
+.Lsigma:
+.asciz	"expand 32-byte k"
+.align	64
+.Lzeroz:
+.long	0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0
+.Lfourz:
+.long	4,0,0,0, 4,0,0,0, 4,0,0,0, 4,0,0,0
+.Lincz:
+.long	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+.Lsixteen:
+.long	16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16
+.asciz	"ChaCha20 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+___
+
+sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
+  my $arg = pop;
+    $arg = "\$$arg" if ($arg*1 eq $arg);
+    $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
+}
+
+@x=("%eax","%ebx","%ecx","%edx",map("%r${_}d",(8..11)),
+    "%nox","%nox","%nox","%nox",map("%r${_}d",(12..15)));
+@t=("%esi","%edi");
+
+sub ROUND {			# critical path is 24 cycles per round
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my ($xc,$xc_)=map("\"$_\"",@t);
+my @x=map("\"$_\"",@x);
+
+	# Consider order in which variables are addressed by their
+	# index:
+	#
+	#	a   b   c   d
+	#
+	#	0   4   8  12 < even round
+	#	1   5   9  13
+	#	2   6  10  14
+	#	3   7  11  15
+	#	0   5  10  15 < odd round
+	#	1   6  11  12
+	#	2   7   8  13
+	#	3   4   9  14
+	#
+	# 'a', 'b' and 'd's are permanently allocated in registers,
+	# @x[0..7,12..15], while 'c's are maintained in memory. If
+	# you observe 'c' column, you'll notice that pair of 'c's is
+	# invariant between rounds. This means that we have to reload
+	# them once per round, in the middle. This is why you'll see
+	# bunch of 'c' stores and loads in the middle, but none in
+	# the beginning or end.
+
+	# Normally instructions would be interleaved to favour in-order
+	# execution. Generally out-of-order cores manage it gracefully,
+	# but not this time for some reason. As in-order execution
+	# cores are dying breed, old Atom is the only one around,
+	# instructions are left uninterleaved. Besides, Atom is better
+	# off executing 1xSSSE3 code anyway...
+
+	(
+	"&add	(@x[$a0],@x[$b0])",	# Q1
+	"&xor	(@x[$d0],@x[$a0])",
+	"&rol	(@x[$d0],16)",
+	 "&add	(@x[$a1],@x[$b1])",	# Q2
+	 "&xor	(@x[$d1],@x[$a1])",
+	 "&rol	(@x[$d1],16)",
+
+	"&add	($xc,@x[$d0])",
+	"&xor	(@x[$b0],$xc)",
+	"&rol	(@x[$b0],12)",
+	 "&add	($xc_,@x[$d1])",
+	 "&xor	(@x[$b1],$xc_)",
+	 "&rol	(@x[$b1],12)",
+
+	"&add	(@x[$a0],@x[$b0])",
+	"&xor	(@x[$d0],@x[$a0])",
+	"&rol	(@x[$d0],8)",
+	 "&add	(@x[$a1],@x[$b1])",
+	 "&xor	(@x[$d1],@x[$a1])",
+	 "&rol	(@x[$d1],8)",
+
+	"&add	($xc,@x[$d0])",
+	"&xor	(@x[$b0],$xc)",
+	"&rol	(@x[$b0],7)",
+	 "&add	($xc_,@x[$d1])",
+	 "&xor	(@x[$b1],$xc_)",
+	 "&rol	(@x[$b1],7)",
+
+	"&mov	(\"4*$c0(%rsp)\",$xc)",	# reload pair of 'c's
+	 "&mov	(\"4*$c1(%rsp)\",$xc_)",
+	"&mov	($xc,\"4*$c2(%rsp)\")",
+	 "&mov	($xc_,\"4*$c3(%rsp)\")",
+
+	"&add	(@x[$a2],@x[$b2])",	# Q3
+	"&xor	(@x[$d2],@x[$a2])",
+	"&rol	(@x[$d2],16)",
+	 "&add	(@x[$a3],@x[$b3])",	# Q4
+	 "&xor	(@x[$d3],@x[$a3])",
+	 "&rol	(@x[$d3],16)",
+
+	"&add	($xc,@x[$d2])",
+	"&xor	(@x[$b2],$xc)",
+	"&rol	(@x[$b2],12)",
+	 "&add	($xc_,@x[$d3])",
+	 "&xor	(@x[$b3],$xc_)",
+	 "&rol	(@x[$b3],12)",
+
+	"&add	(@x[$a2],@x[$b2])",
+	"&xor	(@x[$d2],@x[$a2])",
+	"&rol	(@x[$d2],8)",
+	 "&add	(@x[$a3],@x[$b3])",
+	 "&xor	(@x[$d3],@x[$a3])",
+	 "&rol	(@x[$d3],8)",
+
+	"&add	($xc,@x[$d2])",
+	"&xor	(@x[$b2],$xc)",
+	"&rol	(@x[$b2],7)",
+	 "&add	($xc_,@x[$d3])",
+	 "&xor	(@x[$b3],$xc_)",
+	 "&rol	(@x[$b3],7)"
+	);
+}
+
+########################################################################
+# Generic code path that handles all lengths on pre-SSSE3 processors.
+$code.=<<___;
+.globl	GFp_ChaCha20_ctr32
+.type	GFp_ChaCha20_ctr32,\@function,5
+.align	64
+GFp_ChaCha20_ctr32:
+	cmp	\$0,$len
+	je	.Lno_data
+	mov	GFp_ia32cap_P+4(%rip),%r10
+___
+$code.=<<___	if ($avx>2);
+	bt	\$48,%r10		# check for AVX512F
+	jc	.LChaCha20_avx512
+___
+$code.=<<___;
+	test	\$`1<<(41-32)`,%r10d
+	jnz	.LChaCha20_ssse3
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+	sub	\$64+24,%rsp
+.Lctr32_body:
+
+	#movdqa	.Lsigma(%rip),%xmm0
+	movdqu	($key),%xmm1
+	movdqu	16($key),%xmm2
+	movdqu	($counter),%xmm3
+	movdqa	.Lone(%rip),%xmm4
+
+	#movdqa	%xmm0,4*0(%rsp)		# key[0]
+	movdqa	%xmm1,4*4(%rsp)		# key[1]
+	movdqa	%xmm2,4*8(%rsp)		# key[2]
+	movdqa	%xmm3,4*12(%rsp)	# key[3]
+	mov	$len,%rbp		# reassign $len
+	jmp	.Loop_outer
+
+.align	32
+.Loop_outer:
+	mov	\$0x61707865,@x[0]      # 'expa'
+	mov	\$0x3320646e,@x[1]      # 'nd 3'
+	mov	\$0x79622d32,@x[2]      # '2-by'
+	mov	\$0x6b206574,@x[3]      # 'te k'
+	mov	4*4(%rsp),@x[4]
+	mov	4*5(%rsp),@x[5]
+	mov	4*6(%rsp),@x[6]
+	mov	4*7(%rsp),@x[7]
+	movd	%xmm3,@x[12]
+	mov	4*13(%rsp),@x[13]
+	mov	4*14(%rsp),@x[14]
+	mov	4*15(%rsp),@x[15]
+
+	mov	%rbp,64+0(%rsp)		# save len
+	mov	\$10,%ebp
+	mov	$inp,64+8(%rsp)		# save inp
+	movq	%xmm2,%rsi		# "@x[8]"
+	mov	$out,64+16(%rsp)	# save out
+	mov	%rsi,%rdi
+	shr	\$32,%rdi		# "@x[9]"
+	jmp	.Loop
+
+.align	32
+.Loop:
+___
+	foreach (&ROUND (0, 4, 8,12)) { eval; }
+	foreach (&ROUND	(0, 5,10,15)) { eval; }
+	&dec	("%ebp");
+	&jnz	(".Loop");
+
+$code.=<<___;
+	mov	@t[1],4*9(%rsp)		# modulo-scheduled
+	mov	@t[0],4*8(%rsp)
+	mov	64(%rsp),%rbp		# load len
+	movdqa	%xmm2,%xmm1
+	mov	64+8(%rsp),$inp		# load inp
+	paddd	%xmm4,%xmm3		# increment counter
+	mov	64+16(%rsp),$out	# load out
+
+	add	\$0x61707865,@x[0]      # 'expa'
+	add	\$0x3320646e,@x[1]      # 'nd 3'
+	add	\$0x79622d32,@x[2]      # '2-by'
+	add	\$0x6b206574,@x[3]      # 'te k'
+	add	4*4(%rsp),@x[4]
+	add	4*5(%rsp),@x[5]
+	add	4*6(%rsp),@x[6]
+	add	4*7(%rsp),@x[7]
+	add	4*12(%rsp),@x[12]
+	add	4*13(%rsp),@x[13]
+	add	4*14(%rsp),@x[14]
+	add	4*15(%rsp),@x[15]
+	paddd	4*8(%rsp),%xmm1
+
+	cmp	\$64,%rbp
+	jb	.Ltail
+
+	xor	4*0($inp),@x[0]		# xor with input
+	xor	4*1($inp),@x[1]
+	xor	4*2($inp),@x[2]
+	xor	4*3($inp),@x[3]
+	xor	4*4($inp),@x[4]
+	xor	4*5($inp),@x[5]
+	xor	4*6($inp),@x[6]
+	xor	4*7($inp),@x[7]
+	movdqu	4*8($inp),%xmm0
+	xor	4*12($inp),@x[12]
+	xor	4*13($inp),@x[13]
+	xor	4*14($inp),@x[14]
+	xor	4*15($inp),@x[15]
+	lea	4*16($inp),$inp		# inp+=64
+	pxor	%xmm1,%xmm0
+
+	movdqa	%xmm2,4*8(%rsp)
+	movd	%xmm3,4*12(%rsp)
+
+	mov	@x[0],4*0($out)		# write output
+	mov	@x[1],4*1($out)
+	mov	@x[2],4*2($out)
+	mov	@x[3],4*3($out)
+	mov	@x[4],4*4($out)
+	mov	@x[5],4*5($out)
+	mov	@x[6],4*6($out)
+	mov	@x[7],4*7($out)
+	movdqu	%xmm0,4*8($out)
+	mov	@x[12],4*12($out)
+	mov	@x[13],4*13($out)
+	mov	@x[14],4*14($out)
+	mov	@x[15],4*15($out)
+	lea	4*16($out),$out		# out+=64
+
+	sub	\$64,%rbp
+	jnz	.Loop_outer
+
+	jmp	.Ldone
+
+.align	16
+.Ltail:
+	mov	@x[0],4*0(%rsp)
+	mov	@x[1],4*1(%rsp)
+	xor	%rbx,%rbx
+	mov	@x[2],4*2(%rsp)
+	mov	@x[3],4*3(%rsp)
+	mov	@x[4],4*4(%rsp)
+	mov	@x[5],4*5(%rsp)
+	mov	@x[6],4*6(%rsp)
+	mov	@x[7],4*7(%rsp)
+	movdqa	%xmm1,4*8(%rsp)
+	mov	@x[12],4*12(%rsp)
+	mov	@x[13],4*13(%rsp)
+	mov	@x[14],4*14(%rsp)
+	mov	@x[15],4*15(%rsp)
+
+.Loop_tail:
+	movzb	($inp,%rbx),%eax
+	movzb	(%rsp,%rbx),%edx
+	lea	1(%rbx),%rbx
+	xor	%edx,%eax
+	mov	%al,-1($out,%rbx)
+	dec	%rbp
+	jnz	.Loop_tail
+
+.Ldone:
+	lea	64+24+48(%rsp),%rsi
+	mov	-48(%rsi),%r15
+	mov	-40(%rsi),%r14
+	mov	-32(%rsi),%r13
+	mov	-24(%rsi),%r12
+	mov	-16(%rsi),%rbp
+	mov	-8(%rsi),%rbx
+	lea	(%rsi),%rsp
+.Lno_data:
+	ret
+.size	GFp_ChaCha20_ctr32,.-GFp_ChaCha20_ctr32
+___
+
+########################################################################
+# SSSE3 code path that handles shorter lengths
+{
+my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("%xmm$_",(0..7));
+
+sub SSSE3ROUND {	# critical path is 20 "SIMD ticks" per round
+	&paddd	($a,$b);
+	&pxor	($d,$a);
+	&pshufb	($d,$rot16);
+
+	&paddd	($c,$d);
+	&pxor	($b,$c);
+	&movdqa	($t,$b);
+	&psrld	($b,20);
+	&pslld	($t,12);
+	&por	($b,$t);
+
+	&paddd	($a,$b);
+	&pxor	($d,$a);
+	&pshufb	($d,$rot24);
+
+	&paddd	($c,$d);
+	&pxor	($b,$c);
+	&movdqa	($t,$b);
+	&psrld	($b,25);
+	&pslld	($t,7);
+	&por	($b,$t);
+}
+
+my $xframe = $win64 ? 32+8 : 8;
+
+$code.=<<___;
+.type	ChaCha20_ssse3,\@function,5
+.align	32
+ChaCha20_ssse3:
+.LChaCha20_ssse3:
+	mov	%rsp,%r9		# frame pointer
+___
+$code.=<<___;
+	cmp	\$128,$len		# we might throw away some data,
+	ja	.LChaCha20_4x		# but overall it won't be slower
+
+.Ldo_sse3_after_all:
+	sub	\$64+$xframe,%rsp
+___
+$code.=<<___	if ($win64);
+	movaps	%xmm6,-0x28(%r9)
+	movaps	%xmm7,-0x18(%r9)
+.Lssse3_body:
+___
+$code.=<<___;
+	movdqa	.Lsigma(%rip),$a
+	movdqu	($key),$b
+	movdqu	16($key),$c
+	movdqu	($counter),$d
+	movdqa	.Lrot16(%rip),$rot16
+	movdqa	.Lrot24(%rip),$rot24
+
+	movdqa	$a,0x00(%rsp)
+	movdqa	$b,0x10(%rsp)
+	movdqa	$c,0x20(%rsp)
+	movdqa	$d,0x30(%rsp)
+	mov	\$10,$counter		# reuse $counter
+	jmp	.Loop_ssse3
+
+.align	32
+.Loop_outer_ssse3:
+	movdqa	.Lone(%rip),$d
+	movdqa	0x00(%rsp),$a
+	movdqa	0x10(%rsp),$b
+	movdqa	0x20(%rsp),$c
+	paddd	0x30(%rsp),$d
+	mov	\$10,$counter
+	movdqa	$d,0x30(%rsp)
+	jmp	.Loop_ssse3
+
+.align	32
+.Loop_ssse3:
+___
+	&SSSE3ROUND();
+	&pshufd	($c,$c,0b01001110);
+	&pshufd	($b,$b,0b00111001);
+	&pshufd	($d,$d,0b10010011);
+	&nop	();
+
+	&SSSE3ROUND();
+	&pshufd	($c,$c,0b01001110);
+	&pshufd	($b,$b,0b10010011);
+	&pshufd	($d,$d,0b00111001);
+
+	&dec	($counter);
+	&jnz	(".Loop_ssse3");
+
+$code.=<<___;
+	paddd	0x00(%rsp),$a
+	paddd	0x10(%rsp),$b
+	paddd	0x20(%rsp),$c
+	paddd	0x30(%rsp),$d
+
+	cmp	\$64,$len
+	jb	.Ltail_ssse3
+
+	movdqu	0x00($inp),$t
+	movdqu	0x10($inp),$t1
+	pxor	$t,$a			# xor with input
+	movdqu	0x20($inp),$t
+	pxor	$t1,$b
+	movdqu	0x30($inp),$t1
+	lea	0x40($inp),$inp		# inp+=64
+	pxor	$t,$c
+	pxor	$t1,$d
+
+	movdqu	$a,0x00($out)		# write output
+	movdqu	$b,0x10($out)
+	movdqu	$c,0x20($out)
+	movdqu	$d,0x30($out)
+	lea	0x40($out),$out		# out+=64
+
+	sub	\$64,$len
+	jnz	.Loop_outer_ssse3
+
+	jmp	.Ldone_ssse3
+
+.align	16
+.Ltail_ssse3:
+	movdqa	$a,0x00(%rsp)
+	movdqa	$b,0x10(%rsp)
+	movdqa	$c,0x20(%rsp)
+	movdqa	$d,0x30(%rsp)
+	xor	$counter,$counter
+
+.Loop_tail_ssse3:
+	movzb	($inp,$counter),%eax
+	movzb	(%rsp,$counter),%ecx
+	lea	1($counter),$counter
+	xor	%ecx,%eax
+	mov	%al,-1($out,$counter)
+	dec	$len
+	jnz	.Loop_tail_ssse3
+
+.Ldone_ssse3:
+___
+$code.=<<___	if ($win64);
+	movaps	-0x28(%r9),%xmm6
+	movaps	-0x18(%r9),%xmm7
+___
+$code.=<<___;
+	lea	(%r9),%rsp
+.Lssse3_epilogue:
+	ret
+.size	ChaCha20_ssse3,.-ChaCha20_ssse3
+___
+}
+
+########################################################################
+# SSSE3 code path that handles longer messages.
+{
+# assign variables to favor Atom front-end
+my ($xd0,$xd1,$xd2,$xd3, $xt0,$xt1,$xt2,$xt3,
+    $xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3)=map("%xmm$_",(0..15));
+my  @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
+	"%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
+
+sub SSSE3_lane_ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
+my @x=map("\"$_\"",@xx);
+
+	# Consider order in which variables are addressed by their
+	# index:
+	#
+	#	a   b   c   d
+	#
+	#	0   4   8  12 < even round
+	#	1   5   9  13
+	#	2   6  10  14
+	#	3   7  11  15
+	#	0   5  10  15 < odd round
+	#	1   6  11  12
+	#	2   7   8  13
+	#	3   4   9  14
+	#
+	# 'a', 'b' and 'd's are permanently allocated in registers,
+	# @x[0..7,12..15], while 'c's are maintained in memory. If
+	# you observe 'c' column, you'll notice that pair of 'c's is
+	# invariant between rounds. This means that we have to reload
+	# them once per round, in the middle. This is why you'll see
+	# bunch of 'c' stores and loads in the middle, but none in
+	# the beginning or end.
+
+	(
+	"&paddd		(@x[$a0],@x[$b0])",	# Q1
+	 "&paddd	(@x[$a1],@x[$b1])",	# Q2
+	"&pxor		(@x[$d0],@x[$a0])",
+	 "&pxor		(@x[$d1],@x[$a1])",
+	"&pshufb	(@x[$d0],$t1)",
+	 "&pshufb	(@x[$d1],$t1)",
+
+	"&paddd		($xc,@x[$d0])",
+	 "&paddd	($xc_,@x[$d1])",
+	"&pxor		(@x[$b0],$xc)",
+	 "&pxor		(@x[$b1],$xc_)",
+	"&movdqa	($t0,@x[$b0])",
+	"&pslld		(@x[$b0],12)",
+	"&psrld		($t0,20)",
+	 "&movdqa	($t1,@x[$b1])",
+	 "&pslld	(@x[$b1],12)",
+	"&por		(@x[$b0],$t0)",
+	 "&psrld	($t1,20)",
+	"&movdqa	($t0,'(%r11)')",	# .Lrot24(%rip)
+	 "&por		(@x[$b1],$t1)",
+
+	"&paddd		(@x[$a0],@x[$b0])",
+	 "&paddd	(@x[$a1],@x[$b1])",
+	"&pxor		(@x[$d0],@x[$a0])",
+	 "&pxor		(@x[$d1],@x[$a1])",
+	"&pshufb	(@x[$d0],$t0)",
+	 "&pshufb	(@x[$d1],$t0)",
+
+	"&paddd		($xc,@x[$d0])",
+	 "&paddd	($xc_,@x[$d1])",
+	"&pxor		(@x[$b0],$xc)",
+	 "&pxor		(@x[$b1],$xc_)",
+	"&movdqa	($t1,@x[$b0])",
+	"&pslld		(@x[$b0],7)",
+	"&psrld		($t1,25)",
+	 "&movdqa	($t0,@x[$b1])",
+	 "&pslld	(@x[$b1],7)",
+	"&por		(@x[$b0],$t1)",
+	 "&psrld	($t0,25)",
+	"&movdqa	($t1,'(%r10)')",	# .Lrot16(%rip)
+	 "&por		(@x[$b1],$t0)",
+
+	"&movdqa	(\"`16*($c0-8)`(%rsp)\",$xc)",	# reload pair of 'c's
+	 "&movdqa	(\"`16*($c1-8)`(%rsp)\",$xc_)",
+	"&movdqa	($xc,\"`16*($c2-8)`(%rsp)\")",
+	 "&movdqa	($xc_,\"`16*($c3-8)`(%rsp)\")",
+
+	"&paddd		(@x[$a2],@x[$b2])",	# Q3
+	 "&paddd	(@x[$a3],@x[$b3])",	# Q4
+	"&pxor		(@x[$d2],@x[$a2])",
+	 "&pxor		(@x[$d3],@x[$a3])",
+	"&pshufb	(@x[$d2],$t1)",
+	 "&pshufb	(@x[$d3],$t1)",
+
+	"&paddd		($xc,@x[$d2])",
+	 "&paddd	($xc_,@x[$d3])",
+	"&pxor		(@x[$b2],$xc)",
+	 "&pxor		(@x[$b3],$xc_)",
+	"&movdqa	($t0,@x[$b2])",
+	"&pslld		(@x[$b2],12)",
+	"&psrld		($t0,20)",
+	 "&movdqa	($t1,@x[$b3])",
+	 "&pslld	(@x[$b3],12)",
+	"&por		(@x[$b2],$t0)",
+	 "&psrld	($t1,20)",
+	"&movdqa	($t0,'(%r11)')",	# .Lrot24(%rip)
+	 "&por		(@x[$b3],$t1)",
+
+	"&paddd		(@x[$a2],@x[$b2])",
+	 "&paddd	(@x[$a3],@x[$b3])",
+	"&pxor		(@x[$d2],@x[$a2])",
+	 "&pxor		(@x[$d3],@x[$a3])",
+	"&pshufb	(@x[$d2],$t0)",
+	 "&pshufb	(@x[$d3],$t0)",
+
+	"&paddd		($xc,@x[$d2])",
+	 "&paddd	($xc_,@x[$d3])",
+	"&pxor		(@x[$b2],$xc)",
+	 "&pxor		(@x[$b3],$xc_)",
+	"&movdqa	($t1,@x[$b2])",
+	"&pslld		(@x[$b2],7)",
+	"&psrld		($t1,25)",
+	 "&movdqa	($t0,@x[$b3])",
+	 "&pslld	(@x[$b3],7)",
+	"&por		(@x[$b2],$t1)",
+	 "&psrld	($t0,25)",
+	"&movdqa	($t1,'(%r10)')",	# .Lrot16(%rip)
+	 "&por		(@x[$b3],$t0)"
+	);
+}
+
+my $xframe = $win64 ? 0xa8 : 8;
+
+$code.=<<___;
+.type	ChaCha20_4x,\@function,5
+.align	32
+ChaCha20_4x:
+.LChaCha20_4x:
+	mov		%rsp,%r9		# frame pointer
+	mov		%r10,%r11
+___
+$code.=<<___	if ($avx>1);
+	shr		\$32,%r10		# GFp_ia32cap_P+8
+	test		\$`1<<5`,%r10		# test AVX2
+	jnz		.LChaCha20_8x
+___
+$code.=<<___;
+	cmp		\$192,$len
+	ja		.Lproceed4x
+
+	and		\$`1<<26|1<<22`,%r11	# isolate XSAVE+MOVBE
+	cmp		\$`1<<22`,%r11		# check for MOVBE without XSAVE
+	je		.Ldo_sse3_after_all	# to detect Atom
+
+.Lproceed4x:
+	sub		\$0x140+$xframe,%rsp
+___
+	################ stack layout
+	# +0x00		SIMD equivalent of @x[8-12]
+	# ...
+	# +0x40		constant copy of key[0-2] smashed by lanes
+	# ...
+	# +0x100	SIMD counters (with nonce smashed by lanes)
+	# ...
+	# +0x140
+$code.=<<___	if ($win64);
+	movaps		%xmm6,-0xa8(%r9)
+	movaps		%xmm7,-0x98(%r9)
+	movaps		%xmm8,-0x88(%r9)
+	movaps		%xmm9,-0x78(%r9)
+	movaps		%xmm10,-0x68(%r9)
+	movaps		%xmm11,-0x58(%r9)
+	movaps		%xmm12,-0x48(%r9)
+	movaps		%xmm13,-0x38(%r9)
+	movaps		%xmm14,-0x28(%r9)
+	movaps		%xmm15,-0x18(%r9)
+.L4x_body:
+___
+$code.=<<___;
+	movdqa		.Lsigma(%rip),$xa3	# key[0]
+	movdqu		($key),$xb3		# key[1]
+	movdqu		16($key),$xt3		# key[2]
+	movdqu		($counter),$xd3		# key[3]
+	lea		0x100(%rsp),%rcx	# size optimization
+	lea		.Lrot16(%rip),%r10
+	lea		.Lrot24(%rip),%r11
+
+	pshufd		\$0x00,$xa3,$xa0	# smash key by lanes...
+	pshufd		\$0x55,$xa3,$xa1
+	movdqa		$xa0,0x40(%rsp)		# ... and offload
+	pshufd		\$0xaa,$xa3,$xa2
+	movdqa		$xa1,0x50(%rsp)
+	pshufd		\$0xff,$xa3,$xa3
+	movdqa		$xa2,0x60(%rsp)
+	movdqa		$xa3,0x70(%rsp)
+
+	pshufd		\$0x00,$xb3,$xb0
+	pshufd		\$0x55,$xb3,$xb1
+	movdqa		$xb0,0x80-0x100(%rcx)
+	pshufd		\$0xaa,$xb3,$xb2
+	movdqa		$xb1,0x90-0x100(%rcx)
+	pshufd		\$0xff,$xb3,$xb3
+	movdqa		$xb2,0xa0-0x100(%rcx)
+	movdqa		$xb3,0xb0-0x100(%rcx)
+
+	pshufd		\$0x00,$xt3,$xt0	# "$xc0"
+	pshufd		\$0x55,$xt3,$xt1	# "$xc1"
+	movdqa		$xt0,0xc0-0x100(%rcx)
+	pshufd		\$0xaa,$xt3,$xt2	# "$xc2"
+	movdqa		$xt1,0xd0-0x100(%rcx)
+	pshufd		\$0xff,$xt3,$xt3	# "$xc3"
+	movdqa		$xt2,0xe0-0x100(%rcx)
+	movdqa		$xt3,0xf0-0x100(%rcx)
+
+	pshufd		\$0x00,$xd3,$xd0
+	pshufd		\$0x55,$xd3,$xd1
+	paddd		.Linc(%rip),$xd0	# don't save counters yet
+	pshufd		\$0xaa,$xd3,$xd2
+	movdqa		$xd1,0x110-0x100(%rcx)
+	pshufd		\$0xff,$xd3,$xd3
+	movdqa		$xd2,0x120-0x100(%rcx)
+	movdqa		$xd3,0x130-0x100(%rcx)
+
+	jmp		.Loop_enter4x
+
+.align	32
+.Loop_outer4x:
+	movdqa		0x40(%rsp),$xa0		# re-load smashed key
+	movdqa		0x50(%rsp),$xa1
+	movdqa		0x60(%rsp),$xa2
+	movdqa		0x70(%rsp),$xa3
+	movdqa		0x80-0x100(%rcx),$xb0
+	movdqa		0x90-0x100(%rcx),$xb1
+	movdqa		0xa0-0x100(%rcx),$xb2
+	movdqa		0xb0-0x100(%rcx),$xb3
+	movdqa		0xc0-0x100(%rcx),$xt0	# "$xc0"
+	movdqa		0xd0-0x100(%rcx),$xt1	# "$xc1"
+	movdqa		0xe0-0x100(%rcx),$xt2	# "$xc2"
+	movdqa		0xf0-0x100(%rcx),$xt3	# "$xc3"
+	movdqa		0x100-0x100(%rcx),$xd0
+	movdqa		0x110-0x100(%rcx),$xd1
+	movdqa		0x120-0x100(%rcx),$xd2
+	movdqa		0x130-0x100(%rcx),$xd3
+	paddd		.Lfour(%rip),$xd0	# next SIMD counters
+
+.Loop_enter4x:
+	movdqa		$xt2,0x20(%rsp)		# SIMD equivalent of "@x[10]"
+	movdqa		$xt3,0x30(%rsp)		# SIMD equivalent of "@x[11]"
+	movdqa		(%r10),$xt3		# .Lrot16(%rip)
+	mov		\$10,%eax
+	movdqa		$xd0,0x100-0x100(%rcx)	# save SIMD counters
+	jmp		.Loop4x
+
+.align	32
+.Loop4x:
+___
+	foreach (&SSSE3_lane_ROUND(0, 4, 8,12)) { eval; }
+	foreach (&SSSE3_lane_ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+	dec		%eax
+	jnz		.Loop4x
+
+	paddd		0x40(%rsp),$xa0		# accumulate key material
+	paddd		0x50(%rsp),$xa1
+	paddd		0x60(%rsp),$xa2
+	paddd		0x70(%rsp),$xa3
+
+	movdqa		$xa0,$xt2		# "de-interlace" data
+	punpckldq	$xa1,$xa0
+	movdqa		$xa2,$xt3
+	punpckldq	$xa3,$xa2
+	punpckhdq	$xa1,$xt2
+	punpckhdq	$xa3,$xt3
+	movdqa		$xa0,$xa1
+	punpcklqdq	$xa2,$xa0		# "a0"
+	movdqa		$xt2,$xa3
+	punpcklqdq	$xt3,$xt2		# "a2"
+	punpckhqdq	$xa2,$xa1		# "a1"
+	punpckhqdq	$xt3,$xa3		# "a3"
+___
+	($xa2,$xt2)=($xt2,$xa2);
+$code.=<<___;
+	paddd		0x80-0x100(%rcx),$xb0
+	paddd		0x90-0x100(%rcx),$xb1
+	paddd		0xa0-0x100(%rcx),$xb2
+	paddd		0xb0-0x100(%rcx),$xb3
+
+	movdqa		$xa0,0x00(%rsp)		# offload $xaN
+	movdqa		$xa1,0x10(%rsp)
+	movdqa		0x20(%rsp),$xa0		# "xc2"
+	movdqa		0x30(%rsp),$xa1		# "xc3"
+
+	movdqa		$xb0,$xt2
+	punpckldq	$xb1,$xb0
+	movdqa		$xb2,$xt3
+	punpckldq	$xb3,$xb2
+	punpckhdq	$xb1,$xt2
+	punpckhdq	$xb3,$xt3
+	movdqa		$xb0,$xb1
+	punpcklqdq	$xb2,$xb0		# "b0"
+	movdqa		$xt2,$xb3
+	punpcklqdq	$xt3,$xt2		# "b2"
+	punpckhqdq	$xb2,$xb1		# "b1"
+	punpckhqdq	$xt3,$xb3		# "b3"
+___
+	($xb2,$xt2)=($xt2,$xb2);
+	my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
+$code.=<<___;
+	paddd		0xc0-0x100(%rcx),$xc0
+	paddd		0xd0-0x100(%rcx),$xc1
+	paddd		0xe0-0x100(%rcx),$xc2
+	paddd		0xf0-0x100(%rcx),$xc3
+
+	movdqa		$xa2,0x20(%rsp)		# keep offloading $xaN
+	movdqa		$xa3,0x30(%rsp)
+
+	movdqa		$xc0,$xt2
+	punpckldq	$xc1,$xc0
+	movdqa		$xc2,$xt3
+	punpckldq	$xc3,$xc2
+	punpckhdq	$xc1,$xt2
+	punpckhdq	$xc3,$xt3
+	movdqa		$xc0,$xc1
+	punpcklqdq	$xc2,$xc0		# "c0"
+	movdqa		$xt2,$xc3
+	punpcklqdq	$xt3,$xt2		# "c2"
+	punpckhqdq	$xc2,$xc1		# "c1"
+	punpckhqdq	$xt3,$xc3		# "c3"
+___
+	($xc2,$xt2)=($xt2,$xc2);
+	($xt0,$xt1)=($xa2,$xa3);		# use $xaN as temporary
+$code.=<<___;
+	paddd		0x100-0x100(%rcx),$xd0
+	paddd		0x110-0x100(%rcx),$xd1
+	paddd		0x120-0x100(%rcx),$xd2
+	paddd		0x130-0x100(%rcx),$xd3
+
+	movdqa		$xd0,$xt2
+	punpckldq	$xd1,$xd0
+	movdqa		$xd2,$xt3
+	punpckldq	$xd3,$xd2
+	punpckhdq	$xd1,$xt2
+	punpckhdq	$xd3,$xt3
+	movdqa		$xd0,$xd1
+	punpcklqdq	$xd2,$xd0		# "d0"
+	movdqa		$xt2,$xd3
+	punpcklqdq	$xt3,$xt2		# "d2"
+	punpckhqdq	$xd2,$xd1		# "d1"
+	punpckhqdq	$xt3,$xd3		# "d3"
+___
+	($xd2,$xt2)=($xt2,$xd2);
+$code.=<<___;
+	cmp		\$64*4,$len
+	jb		.Ltail4x
+
+	movdqu		0x00($inp),$xt0		# xor with input
+	movdqu		0x10($inp),$xt1
+	movdqu		0x20($inp),$xt2
+	movdqu		0x30($inp),$xt3
+	pxor		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
+	pxor		$xb0,$xt1
+	pxor		$xc0,$xt2
+	pxor		$xd0,$xt3
+
+	 movdqu		$xt0,0x00($out)
+	movdqu		0x40($inp),$xt0
+	 movdqu		$xt1,0x10($out)
+	movdqu		0x50($inp),$xt1
+	 movdqu		$xt2,0x20($out)
+	movdqu		0x60($inp),$xt2
+	 movdqu		$xt3,0x30($out)
+	movdqu		0x70($inp),$xt3
+	lea		0x80($inp),$inp		# size optimization
+	pxor		0x10(%rsp),$xt0
+	pxor		$xb1,$xt1
+	pxor		$xc1,$xt2
+	pxor		$xd1,$xt3
+
+	 movdqu		$xt0,0x40($out)
+	movdqu		0x00($inp),$xt0
+	 movdqu		$xt1,0x50($out)
+	movdqu		0x10($inp),$xt1
+	 movdqu		$xt2,0x60($out)
+	movdqu		0x20($inp),$xt2
+	 movdqu		$xt3,0x70($out)
+	 lea		0x80($out),$out		# size optimization
+	movdqu		0x30($inp),$xt3
+	pxor		0x20(%rsp),$xt0
+	pxor		$xb2,$xt1
+	pxor		$xc2,$xt2
+	pxor		$xd2,$xt3
+
+	 movdqu		$xt0,0x00($out)
+	movdqu		0x40($inp),$xt0
+	 movdqu		$xt1,0x10($out)
+	movdqu		0x50($inp),$xt1
+	 movdqu		$xt2,0x20($out)
+	movdqu		0x60($inp),$xt2
+	 movdqu		$xt3,0x30($out)
+	movdqu		0x70($inp),$xt3
+	lea		0x80($inp),$inp		# inp+=64*4
+	pxor		0x30(%rsp),$xt0
+	pxor		$xb3,$xt1
+	pxor		$xc3,$xt2
+	pxor		$xd3,$xt3
+	movdqu		$xt0,0x40($out)
+	movdqu		$xt1,0x50($out)
+	movdqu		$xt2,0x60($out)
+	movdqu		$xt3,0x70($out)
+	lea		0x80($out),$out		# out+=64*4
+
+	sub		\$64*4,$len
+	jnz		.Loop_outer4x
+
+	jmp		.Ldone4x
+
+.Ltail4x:
+	cmp		\$192,$len
+	jae		.L192_or_more4x
+	cmp		\$128,$len
+	jae		.L128_or_more4x
+	cmp		\$64,$len
+	jae		.L64_or_more4x
+
+	#movdqa		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
+	xor		%r10,%r10
+	#movdqa		$xt0,0x00(%rsp)
+	movdqa		$xb0,0x10(%rsp)
+	movdqa		$xc0,0x20(%rsp)
+	movdqa		$xd0,0x30(%rsp)
+	jmp		.Loop_tail4x
+
+.align	32
+.L64_or_more4x:
+	movdqu		0x00($inp),$xt0		# xor with input
+	movdqu		0x10($inp),$xt1
+	movdqu		0x20($inp),$xt2
+	movdqu		0x30($inp),$xt3
+	pxor		0x00(%rsp),$xt0		# $xaxN is offloaded, remember?
+	pxor		$xb0,$xt1
+	pxor		$xc0,$xt2
+	pxor		$xd0,$xt3
+	movdqu		$xt0,0x00($out)
+	movdqu		$xt1,0x10($out)
+	movdqu		$xt2,0x20($out)
+	movdqu		$xt3,0x30($out)
+	je		.Ldone4x
+
+	movdqa		0x10(%rsp),$xt0		# $xaN is offloaded, remember?
+	lea		0x40($inp),$inp		# inp+=64*1
+	xor		%r10,%r10
+	movdqa		$xt0,0x00(%rsp)
+	movdqa		$xb1,0x10(%rsp)
+	lea		0x40($out),$out		# out+=64*1
+	movdqa		$xc1,0x20(%rsp)
+	sub		\$64,$len		# len-=64*1
+	movdqa		$xd1,0x30(%rsp)
+	jmp		.Loop_tail4x
+
+.align	32
+.L128_or_more4x:
+	movdqu		0x00($inp),$xt0		# xor with input
+	movdqu		0x10($inp),$xt1
+	movdqu		0x20($inp),$xt2
+	movdqu		0x30($inp),$xt3
+	pxor		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
+	pxor		$xb0,$xt1
+	pxor		$xc0,$xt2
+	pxor		$xd0,$xt3
+
+	 movdqu		$xt0,0x00($out)
+	movdqu		0x40($inp),$xt0
+	 movdqu		$xt1,0x10($out)
+	movdqu		0x50($inp),$xt1
+	 movdqu		$xt2,0x20($out)
+	movdqu		0x60($inp),$xt2
+	 movdqu		$xt3,0x30($out)
+	movdqu		0x70($inp),$xt3
+	pxor		0x10(%rsp),$xt0
+	pxor		$xb1,$xt1
+	pxor		$xc1,$xt2
+	pxor		$xd1,$xt3
+	movdqu		$xt0,0x40($out)
+	movdqu		$xt1,0x50($out)
+	movdqu		$xt2,0x60($out)
+	movdqu		$xt3,0x70($out)
+	je		.Ldone4x
+
+	movdqa		0x20(%rsp),$xt0		# $xaN is offloaded, remember?
+	lea		0x80($inp),$inp		# inp+=64*2
+	xor		%r10,%r10
+	movdqa		$xt0,0x00(%rsp)
+	movdqa		$xb2,0x10(%rsp)
+	lea		0x80($out),$out		# out+=64*2
+	movdqa		$xc2,0x20(%rsp)
+	sub		\$128,$len		# len-=64*2
+	movdqa		$xd2,0x30(%rsp)
+	jmp		.Loop_tail4x
+
+.align	32
+.L192_or_more4x:
+	movdqu		0x00($inp),$xt0		# xor with input
+	movdqu		0x10($inp),$xt1
+	movdqu		0x20($inp),$xt2
+	movdqu		0x30($inp),$xt3
+	pxor		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
+	pxor		$xb0,$xt1
+	pxor		$xc0,$xt2
+	pxor		$xd0,$xt3
+
+	 movdqu		$xt0,0x00($out)
+	movdqu		0x40($inp),$xt0
+	 movdqu		$xt1,0x10($out)
+	movdqu		0x50($inp),$xt1
+	 movdqu		$xt2,0x20($out)
+	movdqu		0x60($inp),$xt2
+	 movdqu		$xt3,0x30($out)
+	movdqu		0x70($inp),$xt3
+	lea		0x80($inp),$inp		# size optimization
+	pxor		0x10(%rsp),$xt0
+	pxor		$xb1,$xt1
+	pxor		$xc1,$xt2
+	pxor		$xd1,$xt3
+
+	 movdqu		$xt0,0x40($out)
+	movdqu		0x00($inp),$xt0
+	 movdqu		$xt1,0x50($out)
+	movdqu		0x10($inp),$xt1
+	 movdqu		$xt2,0x60($out)
+	movdqu		0x20($inp),$xt2
+	 movdqu		$xt3,0x70($out)
+	 lea		0x80($out),$out		# size optimization
+	movdqu		0x30($inp),$xt3
+	pxor		0x20(%rsp),$xt0
+	pxor		$xb2,$xt1
+	pxor		$xc2,$xt2
+	pxor		$xd2,$xt3
+	movdqu		$xt0,0x00($out)
+	movdqu		$xt1,0x10($out)
+	movdqu		$xt2,0x20($out)
+	movdqu		$xt3,0x30($out)
+	je		.Ldone4x
+
+	movdqa		0x30(%rsp),$xt0		# $xaN is offloaded, remember?
+	lea		0x40($inp),$inp		# inp+=64*3
+	xor		%r10,%r10
+	movdqa		$xt0,0x00(%rsp)
+	movdqa		$xb3,0x10(%rsp)
+	lea		0x40($out),$out		# out+=64*3
+	movdqa		$xc3,0x20(%rsp)
+	sub		\$192,$len		# len-=64*3
+	movdqa		$xd3,0x30(%rsp)
+
+.Loop_tail4x:
+	movzb		($inp,%r10),%eax
+	movzb		(%rsp,%r10),%ecx
+	lea		1(%r10),%r10
+	xor		%ecx,%eax
+	mov		%al,-1($out,%r10)
+	dec		$len
+	jnz		.Loop_tail4x
+
+.Ldone4x:
+___
+$code.=<<___	if ($win64);
+	movaps		-0xa8(%r9),%xmm6
+	movaps		-0x98(%r9),%xmm7
+	movaps		-0x88(%r9),%xmm8
+	movaps		-0x78(%r9),%xmm9
+	movaps		-0x68(%r9),%xmm10
+	movaps		-0x58(%r9),%xmm11
+	movaps		-0x48(%r9),%xmm12
+	movaps		-0x38(%r9),%xmm13
+	movaps		-0x28(%r9),%xmm14
+	movaps		-0x18(%r9),%xmm15
+___
+$code.=<<___;
+	lea		(%r9),%rsp
+.L4x_epilogue:
+	ret
+.size	ChaCha20_4x,.-ChaCha20_4x
+___
+}
+
+########################################################################
+# AVX2 code path
+if ($avx>1) {
+my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
+    $xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%ymm$_",(0..15));
+my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
+	"%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
+
+sub AVX2_lane_ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
+my @x=map("\"$_\"",@xx);
+
+	# Consider order in which variables are addressed by their
+	# index:
+	#
+	#	a   b   c   d
+	#
+	#	0   4   8  12 < even round
+	#	1   5   9  13
+	#	2   6  10  14
+	#	3   7  11  15
+	#	0   5  10  15 < odd round
+	#	1   6  11  12
+	#	2   7   8  13
+	#	3   4   9  14
+	#
+	# 'a', 'b' and 'd's are permanently allocated in registers,
+	# @x[0..7,12..15], while 'c's are maintained in memory. If
+	# you observe 'c' column, you'll notice that pair of 'c's is
+	# invariant between rounds. This means that we have to reload
+	# them once per round, in the middle. This is why you'll see
+	# bunch of 'c' stores and loads in the middle, but none in
+	# the beginning or end.
+
+	(
+	"&vpaddd	(@x[$a0],@x[$a0],@x[$b0])",	# Q1
+	"&vpxor		(@x[$d0],@x[$a0],@x[$d0])",
+	"&vpshufb	(@x[$d0],@x[$d0],$t1)",
+	 "&vpaddd	(@x[$a1],@x[$a1],@x[$b1])",	# Q2
+	 "&vpxor	(@x[$d1],@x[$a1],@x[$d1])",
+	 "&vpshufb	(@x[$d1],@x[$d1],$t1)",
+
+	"&vpaddd	($xc,$xc,@x[$d0])",
+	"&vpxor		(@x[$b0],$xc,@x[$b0])",
+	"&vpslld	($t0,@x[$b0],12)",
+	"&vpsrld	(@x[$b0],@x[$b0],20)",
+	"&vpor		(@x[$b0],$t0,@x[$b0])",
+	"&vbroadcasti128($t0,'(%r11)')",		# .Lrot24(%rip)
+	 "&vpaddd	($xc_,$xc_,@x[$d1])",
+	 "&vpxor	(@x[$b1],$xc_,@x[$b1])",
+	 "&vpslld	($t1,@x[$b1],12)",
+	 "&vpsrld	(@x[$b1],@x[$b1],20)",
+	 "&vpor		(@x[$b1],$t1,@x[$b1])",
+
+	"&vpaddd	(@x[$a0],@x[$a0],@x[$b0])",
+	"&vpxor		(@x[$d0],@x[$a0],@x[$d0])",
+	"&vpshufb	(@x[$d0],@x[$d0],$t0)",
+	 "&vpaddd	(@x[$a1],@x[$a1],@x[$b1])",
+	 "&vpxor	(@x[$d1],@x[$a1],@x[$d1])",
+	 "&vpshufb	(@x[$d1],@x[$d1],$t0)",
+
+	"&vpaddd	($xc,$xc,@x[$d0])",
+	"&vpxor		(@x[$b0],$xc,@x[$b0])",
+	"&vpslld	($t1,@x[$b0],7)",
+	"&vpsrld	(@x[$b0],@x[$b0],25)",
+	"&vpor		(@x[$b0],$t1,@x[$b0])",
+	"&vbroadcasti128($t1,'(%r10)')",		# .Lrot16(%rip)
+	 "&vpaddd	($xc_,$xc_,@x[$d1])",
+	 "&vpxor	(@x[$b1],$xc_,@x[$b1])",
+	 "&vpslld	($t0,@x[$b1],7)",
+	 "&vpsrld	(@x[$b1],@x[$b1],25)",
+	 "&vpor		(@x[$b1],$t0,@x[$b1])",
+
+	"&vmovdqa	(\"`32*($c0-8)`(%rsp)\",$xc)",	# reload pair of 'c's
+	 "&vmovdqa	(\"`32*($c1-8)`(%rsp)\",$xc_)",
+	"&vmovdqa	($xc,\"`32*($c2-8)`(%rsp)\")",
+	 "&vmovdqa	($xc_,\"`32*($c3-8)`(%rsp)\")",
+
+	"&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",	# Q3
+	"&vpxor		(@x[$d2],@x[$a2],@x[$d2])",
+	"&vpshufb	(@x[$d2],@x[$d2],$t1)",
+	 "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",	# Q4
+	 "&vpxor	(@x[$d3],@x[$a3],@x[$d3])",
+	 "&vpshufb	(@x[$d3],@x[$d3],$t1)",
+
+	"&vpaddd	($xc,$xc,@x[$d2])",
+	"&vpxor		(@x[$b2],$xc,@x[$b2])",
+	"&vpslld	($t0,@x[$b2],12)",
+	"&vpsrld	(@x[$b2],@x[$b2],20)",
+	"&vpor		(@x[$b2],$t0,@x[$b2])",
+	"&vbroadcasti128($t0,'(%r11)')",		# .Lrot24(%rip)
+	 "&vpaddd	($xc_,$xc_,@x[$d3])",
+	 "&vpxor	(@x[$b3],$xc_,@x[$b3])",
+	 "&vpslld	($t1,@x[$b3],12)",
+	 "&vpsrld	(@x[$b3],@x[$b3],20)",
+	 "&vpor		(@x[$b3],$t1,@x[$b3])",
+
+	"&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",
+	"&vpxor		(@x[$d2],@x[$a2],@x[$d2])",
+	"&vpshufb	(@x[$d2],@x[$d2],$t0)",
+	 "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",
+	 "&vpxor	(@x[$d3],@x[$a3],@x[$d3])",
+	 "&vpshufb	(@x[$d3],@x[$d3],$t0)",
+
+	"&vpaddd	($xc,$xc,@x[$d2])",
+	"&vpxor		(@x[$b2],$xc,@x[$b2])",
+	"&vpslld	($t1,@x[$b2],7)",
+	"&vpsrld	(@x[$b2],@x[$b2],25)",
+	"&vpor		(@x[$b2],$t1,@x[$b2])",
+	"&vbroadcasti128($t1,'(%r10)')",		# .Lrot16(%rip)
+	 "&vpaddd	($xc_,$xc_,@x[$d3])",
+	 "&vpxor	(@x[$b3],$xc_,@x[$b3])",
+	 "&vpslld	($t0,@x[$b3],7)",
+	 "&vpsrld	(@x[$b3],@x[$b3],25)",
+	 "&vpor		(@x[$b3],$t0,@x[$b3])"
+	);
+}
+
+my $xframe = $win64 ? 0xa8 : 8;
+
+$code.=<<___;
+.type	ChaCha20_8x,\@function,5
+.align	32
+ChaCha20_8x:
+.LChaCha20_8x:
+	mov		%rsp,%r9		# frame register
+	sub		\$0x280+$xframe,%rsp
+	and		\$-32,%rsp
+___
+$code.=<<___	if ($win64);
+	movaps		%xmm6,-0xa8(%r9)
+	movaps		%xmm7,-0x98(%r9)
+	movaps		%xmm8,-0x88(%r9)
+	movaps		%xmm9,-0x78(%r9)
+	movaps		%xmm10,-0x68(%r9)
+	movaps		%xmm11,-0x58(%r9)
+	movaps		%xmm12,-0x48(%r9)
+	movaps		%xmm13,-0x38(%r9)
+	movaps		%xmm14,-0x28(%r9)
+	movaps		%xmm15,-0x18(%r9)
+.L8x_body:
+___
+$code.=<<___;
+	vzeroupper
+
+	################ stack layout
+	# +0x00		SIMD equivalent of @x[8-12]
+	# ...
+	# +0x80		constant copy of key[0-2] smashed by lanes
+	# ...
+	# +0x200	SIMD counters (with nonce smashed by lanes)
+	# ...
+	# +0x280
+
+	vbroadcasti128	.Lsigma(%rip),$xa3	# key[0]
+	vbroadcasti128	($key),$xb3		# key[1]
+	vbroadcasti128	16($key),$xt3		# key[2]
+	vbroadcasti128	($counter),$xd3		# key[3]
+	lea		0x100(%rsp),%rcx	# size optimization
+	lea		0x200(%rsp),%rax	# size optimization
+	lea		.Lrot16(%rip),%r10
+	lea		.Lrot24(%rip),%r11
+
+	vpshufd		\$0x00,$xa3,$xa0	# smash key by lanes...
+	vpshufd		\$0x55,$xa3,$xa1
+	vmovdqa		$xa0,0x80-0x100(%rcx)	# ... and offload
+	vpshufd		\$0xaa,$xa3,$xa2
+	vmovdqa		$xa1,0xa0-0x100(%rcx)
+	vpshufd		\$0xff,$xa3,$xa3
+	vmovdqa		$xa2,0xc0-0x100(%rcx)
+	vmovdqa		$xa3,0xe0-0x100(%rcx)
+
+	vpshufd		\$0x00,$xb3,$xb0
+	vpshufd		\$0x55,$xb3,$xb1
+	vmovdqa		$xb0,0x100-0x100(%rcx)
+	vpshufd		\$0xaa,$xb3,$xb2
+	vmovdqa		$xb1,0x120-0x100(%rcx)
+	vpshufd		\$0xff,$xb3,$xb3
+	vmovdqa		$xb2,0x140-0x100(%rcx)
+	vmovdqa		$xb3,0x160-0x100(%rcx)
+
+	vpshufd		\$0x00,$xt3,$xt0	# "xc0"
+	vpshufd		\$0x55,$xt3,$xt1	# "xc1"
+	vmovdqa		$xt0,0x180-0x200(%rax)
+	vpshufd		\$0xaa,$xt3,$xt2	# "xc2"
+	vmovdqa		$xt1,0x1a0-0x200(%rax)
+	vpshufd		\$0xff,$xt3,$xt3	# "xc3"
+	vmovdqa		$xt2,0x1c0-0x200(%rax)
+	vmovdqa		$xt3,0x1e0-0x200(%rax)
+
+	vpshufd		\$0x00,$xd3,$xd0
+	vpshufd		\$0x55,$xd3,$xd1
+	vpaddd		.Lincy(%rip),$xd0,$xd0	# don't save counters yet
+	vpshufd		\$0xaa,$xd3,$xd2
+	vmovdqa		$xd1,0x220-0x200(%rax)
+	vpshufd		\$0xff,$xd3,$xd3
+	vmovdqa		$xd2,0x240-0x200(%rax)
+	vmovdqa		$xd3,0x260-0x200(%rax)
+
+	jmp		.Loop_enter8x
+
+.align	32
+.Loop_outer8x:
+	vmovdqa		0x80-0x100(%rcx),$xa0	# re-load smashed key
+	vmovdqa		0xa0-0x100(%rcx),$xa1
+	vmovdqa		0xc0-0x100(%rcx),$xa2
+	vmovdqa		0xe0-0x100(%rcx),$xa3
+	vmovdqa		0x100-0x100(%rcx),$xb0
+	vmovdqa		0x120-0x100(%rcx),$xb1
+	vmovdqa		0x140-0x100(%rcx),$xb2
+	vmovdqa		0x160-0x100(%rcx),$xb3
+	vmovdqa		0x180-0x200(%rax),$xt0	# "xc0"
+	vmovdqa		0x1a0-0x200(%rax),$xt1	# "xc1"
+	vmovdqa		0x1c0-0x200(%rax),$xt2	# "xc2"
+	vmovdqa		0x1e0-0x200(%rax),$xt3	# "xc3"
+	vmovdqa		0x200-0x200(%rax),$xd0
+	vmovdqa		0x220-0x200(%rax),$xd1
+	vmovdqa		0x240-0x200(%rax),$xd2
+	vmovdqa		0x260-0x200(%rax),$xd3
+	vpaddd		.Leight(%rip),$xd0,$xd0	# next SIMD counters
+
+.Loop_enter8x:
+	vmovdqa		$xt2,0x40(%rsp)		# SIMD equivalent of "@x[10]"
+	vmovdqa		$xt3,0x60(%rsp)		# SIMD equivalent of "@x[11]"
+	vbroadcasti128	(%r10),$xt3
+	vmovdqa		$xd0,0x200-0x200(%rax)	# save SIMD counters
+	mov		\$10,%eax
+	jmp		.Loop8x
+
+.align	32
+.Loop8x:
+___
+	foreach (&AVX2_lane_ROUND(0, 4, 8,12)) { eval; }
+	foreach (&AVX2_lane_ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+	dec		%eax
+	jnz		.Loop8x
+
+	lea		0x200(%rsp),%rax	# size optimization
+	vpaddd		0x80-0x100(%rcx),$xa0,$xa0	# accumulate key
+	vpaddd		0xa0-0x100(%rcx),$xa1,$xa1
+	vpaddd		0xc0-0x100(%rcx),$xa2,$xa2
+	vpaddd		0xe0-0x100(%rcx),$xa3,$xa3
+
+	vpunpckldq	$xa1,$xa0,$xt2		# "de-interlace" data
+	vpunpckldq	$xa3,$xa2,$xt3
+	vpunpckhdq	$xa1,$xa0,$xa0
+	vpunpckhdq	$xa3,$xa2,$xa2
+	vpunpcklqdq	$xt3,$xt2,$xa1		# "a0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "a1"
+	vpunpcklqdq	$xa2,$xa0,$xa3		# "a2"
+	vpunpckhqdq	$xa2,$xa0,$xa0		# "a3"
+___
+	($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
+$code.=<<___;
+	vpaddd		0x100-0x100(%rcx),$xb0,$xb0
+	vpaddd		0x120-0x100(%rcx),$xb1,$xb1
+	vpaddd		0x140-0x100(%rcx),$xb2,$xb2
+	vpaddd		0x160-0x100(%rcx),$xb3,$xb3
+
+	vpunpckldq	$xb1,$xb0,$xt2
+	vpunpckldq	$xb3,$xb2,$xt3
+	vpunpckhdq	$xb1,$xb0,$xb0
+	vpunpckhdq	$xb3,$xb2,$xb2
+	vpunpcklqdq	$xt3,$xt2,$xb1		# "b0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "b1"
+	vpunpcklqdq	$xb2,$xb0,$xb3		# "b2"
+	vpunpckhqdq	$xb2,$xb0,$xb0		# "b3"
+___
+	($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
+$code.=<<___;
+	vperm2i128	\$0x20,$xb0,$xa0,$xt3	# "de-interlace" further
+	vperm2i128	\$0x31,$xb0,$xa0,$xb0
+	vperm2i128	\$0x20,$xb1,$xa1,$xa0
+	vperm2i128	\$0x31,$xb1,$xa1,$xb1
+	vperm2i128	\$0x20,$xb2,$xa2,$xa1
+	vperm2i128	\$0x31,$xb2,$xa2,$xb2
+	vperm2i128	\$0x20,$xb3,$xa3,$xa2
+	vperm2i128	\$0x31,$xb3,$xa3,$xb3
+___
+	($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
+	my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
+$code.=<<___;
+	vmovdqa		$xa0,0x00(%rsp)		# offload $xaN
+	vmovdqa		$xa1,0x20(%rsp)
+	vmovdqa		0x40(%rsp),$xc2		# $xa0
+	vmovdqa		0x60(%rsp),$xc3		# $xa1
+
+	vpaddd		0x180-0x200(%rax),$xc0,$xc0
+	vpaddd		0x1a0-0x200(%rax),$xc1,$xc1
+	vpaddd		0x1c0-0x200(%rax),$xc2,$xc2
+	vpaddd		0x1e0-0x200(%rax),$xc3,$xc3
+
+	vpunpckldq	$xc1,$xc0,$xt2
+	vpunpckldq	$xc3,$xc2,$xt3
+	vpunpckhdq	$xc1,$xc0,$xc0
+	vpunpckhdq	$xc3,$xc2,$xc2
+	vpunpcklqdq	$xt3,$xt2,$xc1		# "c0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "c1"
+	vpunpcklqdq	$xc2,$xc0,$xc3		# "c2"
+	vpunpckhqdq	$xc2,$xc0,$xc0		# "c3"
+___
+	($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
+$code.=<<___;
+	vpaddd		0x200-0x200(%rax),$xd0,$xd0
+	vpaddd		0x220-0x200(%rax),$xd1,$xd1
+	vpaddd		0x240-0x200(%rax),$xd2,$xd2
+	vpaddd		0x260-0x200(%rax),$xd3,$xd3
+
+	vpunpckldq	$xd1,$xd0,$xt2
+	vpunpckldq	$xd3,$xd2,$xt3
+	vpunpckhdq	$xd1,$xd0,$xd0
+	vpunpckhdq	$xd3,$xd2,$xd2
+	vpunpcklqdq	$xt3,$xt2,$xd1		# "d0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "d1"
+	vpunpcklqdq	$xd2,$xd0,$xd3		# "d2"
+	vpunpckhqdq	$xd2,$xd0,$xd0		# "d3"
+___
+	($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
+$code.=<<___;
+	vperm2i128	\$0x20,$xd0,$xc0,$xt3	# "de-interlace" further
+	vperm2i128	\$0x31,$xd0,$xc0,$xd0
+	vperm2i128	\$0x20,$xd1,$xc1,$xc0
+	vperm2i128	\$0x31,$xd1,$xc1,$xd1
+	vperm2i128	\$0x20,$xd2,$xc2,$xc1
+	vperm2i128	\$0x31,$xd2,$xc2,$xd2
+	vperm2i128	\$0x20,$xd3,$xc3,$xc2
+	vperm2i128	\$0x31,$xd3,$xc3,$xd3
+___
+	($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
+	($xb0,$xb1,$xb2,$xb3,$xc0,$xc1,$xc2,$xc3)=
+	($xc0,$xc1,$xc2,$xc3,$xb0,$xb1,$xb2,$xb3);
+	($xa0,$xa1)=($xt2,$xt3);
+$code.=<<___;
+	vmovdqa		0x00(%rsp),$xa0		# $xaN was offloaded, remember?
+	vmovdqa		0x20(%rsp),$xa1
+
+	cmp		\$64*8,$len
+	jb		.Ltail8x
+
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vpxor		0x40($inp),$xc0,$xc0
+	vpxor		0x60($inp),$xd0,$xd0
+	lea		0x80($inp),$inp		# size optimization
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	vmovdqu		$xc0,0x40($out)
+	vmovdqu		$xd0,0x60($out)
+	lea		0x80($out),$out		# size optimization
+
+	vpxor		0x00($inp),$xa1,$xa1
+	vpxor		0x20($inp),$xb1,$xb1
+	vpxor		0x40($inp),$xc1,$xc1
+	vpxor		0x60($inp),$xd1,$xd1
+	lea		0x80($inp),$inp		# size optimization
+	vmovdqu		$xa1,0x00($out)
+	vmovdqu		$xb1,0x20($out)
+	vmovdqu		$xc1,0x40($out)
+	vmovdqu		$xd1,0x60($out)
+	lea		0x80($out),$out		# size optimization
+
+	vpxor		0x00($inp),$xa2,$xa2
+	vpxor		0x20($inp),$xb2,$xb2
+	vpxor		0x40($inp),$xc2,$xc2
+	vpxor		0x60($inp),$xd2,$xd2
+	lea		0x80($inp),$inp		# size optimization
+	vmovdqu		$xa2,0x00($out)
+	vmovdqu		$xb2,0x20($out)
+	vmovdqu		$xc2,0x40($out)
+	vmovdqu		$xd2,0x60($out)
+	lea		0x80($out),$out		# size optimization
+
+	vpxor		0x00($inp),$xa3,$xa3
+	vpxor		0x20($inp),$xb3,$xb3
+	vpxor		0x40($inp),$xc3,$xc3
+	vpxor		0x60($inp),$xd3,$xd3
+	lea		0x80($inp),$inp		# size optimization
+	vmovdqu		$xa3,0x00($out)
+	vmovdqu		$xb3,0x20($out)
+	vmovdqu		$xc3,0x40($out)
+	vmovdqu		$xd3,0x60($out)
+	lea		0x80($out),$out		# size optimization
+
+	sub		\$64*8,$len
+	jnz		.Loop_outer8x
+
+	jmp		.Ldone8x
+
+.Ltail8x:
+	cmp		\$448,$len
+	jae		.L448_or_more8x
+	cmp		\$384,$len
+	jae		.L384_or_more8x
+	cmp		\$320,$len
+	jae		.L320_or_more8x
+	cmp		\$256,$len
+	jae		.L256_or_more8x
+	cmp		\$192,$len
+	jae		.L192_or_more8x
+	cmp		\$128,$len
+	jae		.L128_or_more8x
+	cmp		\$64,$len
+	jae		.L64_or_more8x
+
+	xor		%r10,%r10
+	vmovdqa		$xa0,0x00(%rsp)
+	vmovdqa		$xb0,0x20(%rsp)
+	jmp		.Loop_tail8x
+
+.align	32
+.L64_or_more8x:
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	je		.Ldone8x
+
+	lea		0x40($inp),$inp		# inp+=64*1
+	xor		%r10,%r10
+	vmovdqa		$xc0,0x00(%rsp)
+	lea		0x40($out),$out		# out+=64*1
+	sub		\$64,$len		# len-=64*1
+	vmovdqa		$xd0,0x20(%rsp)
+	jmp		.Loop_tail8x
+
+.align	32
+.L128_or_more8x:
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vpxor		0x40($inp),$xc0,$xc0
+	vpxor		0x60($inp),$xd0,$xd0
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	vmovdqu		$xc0,0x40($out)
+	vmovdqu		$xd0,0x60($out)
+	je		.Ldone8x
+
+	lea		0x80($inp),$inp		# inp+=64*2
+	xor		%r10,%r10
+	vmovdqa		$xa1,0x00(%rsp)
+	lea		0x80($out),$out		# out+=64*2
+	sub		\$128,$len		# len-=64*2
+	vmovdqa		$xb1,0x20(%rsp)
+	jmp		.Loop_tail8x
+
+.align	32
+.L192_or_more8x:
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vpxor		0x40($inp),$xc0,$xc0
+	vpxor		0x60($inp),$xd0,$xd0
+	vpxor		0x80($inp),$xa1,$xa1
+	vpxor		0xa0($inp),$xb1,$xb1
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	vmovdqu		$xc0,0x40($out)
+	vmovdqu		$xd0,0x60($out)
+	vmovdqu		$xa1,0x80($out)
+	vmovdqu		$xb1,0xa0($out)
+	je		.Ldone8x
+
+	lea		0xc0($inp),$inp		# inp+=64*3
+	xor		%r10,%r10
+	vmovdqa		$xc1,0x00(%rsp)
+	lea		0xc0($out),$out		# out+=64*3
+	sub		\$192,$len		# len-=64*3
+	vmovdqa		$xd1,0x20(%rsp)
+	jmp		.Loop_tail8x
+
+.align	32
+.L256_or_more8x:
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vpxor		0x40($inp),$xc0,$xc0
+	vpxor		0x60($inp),$xd0,$xd0
+	vpxor		0x80($inp),$xa1,$xa1
+	vpxor		0xa0($inp),$xb1,$xb1
+	vpxor		0xc0($inp),$xc1,$xc1
+	vpxor		0xe0($inp),$xd1,$xd1
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	vmovdqu		$xc0,0x40($out)
+	vmovdqu		$xd0,0x60($out)
+	vmovdqu		$xa1,0x80($out)
+	vmovdqu		$xb1,0xa0($out)
+	vmovdqu		$xc1,0xc0($out)
+	vmovdqu		$xd1,0xe0($out)
+	je		.Ldone8x
+
+	lea		0x100($inp),$inp	# inp+=64*4
+	xor		%r10,%r10
+	vmovdqa		$xa2,0x00(%rsp)
+	lea		0x100($out),$out	# out+=64*4
+	sub		\$256,$len		# len-=64*4
+	vmovdqa		$xb2,0x20(%rsp)
+	jmp		.Loop_tail8x
+
+.align	32
+.L320_or_more8x:
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vpxor		0x40($inp),$xc0,$xc0
+	vpxor		0x60($inp),$xd0,$xd0
+	vpxor		0x80($inp),$xa1,$xa1
+	vpxor		0xa0($inp),$xb1,$xb1
+	vpxor		0xc0($inp),$xc1,$xc1
+	vpxor		0xe0($inp),$xd1,$xd1
+	vpxor		0x100($inp),$xa2,$xa2
+	vpxor		0x120($inp),$xb2,$xb2
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	vmovdqu		$xc0,0x40($out)
+	vmovdqu		$xd0,0x60($out)
+	vmovdqu		$xa1,0x80($out)
+	vmovdqu		$xb1,0xa0($out)
+	vmovdqu		$xc1,0xc0($out)
+	vmovdqu		$xd1,0xe0($out)
+	vmovdqu		$xa2,0x100($out)
+	vmovdqu		$xb2,0x120($out)
+	je		.Ldone8x
+
+	lea		0x140($inp),$inp	# inp+=64*5
+	xor		%r10,%r10
+	vmovdqa		$xc2,0x00(%rsp)
+	lea		0x140($out),$out	# out+=64*5
+	sub		\$320,$len		# len-=64*5
+	vmovdqa		$xd2,0x20(%rsp)
+	jmp		.Loop_tail8x
+
+.align	32
+.L384_or_more8x:
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vpxor		0x40($inp),$xc0,$xc0
+	vpxor		0x60($inp),$xd0,$xd0
+	vpxor		0x80($inp),$xa1,$xa1
+	vpxor		0xa0($inp),$xb1,$xb1
+	vpxor		0xc0($inp),$xc1,$xc1
+	vpxor		0xe0($inp),$xd1,$xd1
+	vpxor		0x100($inp),$xa2,$xa2
+	vpxor		0x120($inp),$xb2,$xb2
+	vpxor		0x140($inp),$xc2,$xc2
+	vpxor		0x160($inp),$xd2,$xd2
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	vmovdqu		$xc0,0x40($out)
+	vmovdqu		$xd0,0x60($out)
+	vmovdqu		$xa1,0x80($out)
+	vmovdqu		$xb1,0xa0($out)
+	vmovdqu		$xc1,0xc0($out)
+	vmovdqu		$xd1,0xe0($out)
+	vmovdqu		$xa2,0x100($out)
+	vmovdqu		$xb2,0x120($out)
+	vmovdqu		$xc2,0x140($out)
+	vmovdqu		$xd2,0x160($out)
+	je		.Ldone8x
+
+	lea		0x180($inp),$inp	# inp+=64*6
+	xor		%r10,%r10
+	vmovdqa		$xa3,0x00(%rsp)
+	lea		0x180($out),$out	# out+=64*6
+	sub		\$384,$len		# len-=64*6
+	vmovdqa		$xb3,0x20(%rsp)
+	jmp		.Loop_tail8x
+
+.align	32
+.L448_or_more8x:
+	vpxor		0x00($inp),$xa0,$xa0	# xor with input
+	vpxor		0x20($inp),$xb0,$xb0
+	vpxor		0x40($inp),$xc0,$xc0
+	vpxor		0x60($inp),$xd0,$xd0
+	vpxor		0x80($inp),$xa1,$xa1
+	vpxor		0xa0($inp),$xb1,$xb1
+	vpxor		0xc0($inp),$xc1,$xc1
+	vpxor		0xe0($inp),$xd1,$xd1
+	vpxor		0x100($inp),$xa2,$xa2
+	vpxor		0x120($inp),$xb2,$xb2
+	vpxor		0x140($inp),$xc2,$xc2
+	vpxor		0x160($inp),$xd2,$xd2
+	vpxor		0x180($inp),$xa3,$xa3
+	vpxor		0x1a0($inp),$xb3,$xb3
+	vmovdqu		$xa0,0x00($out)
+	vmovdqu		$xb0,0x20($out)
+	vmovdqu		$xc0,0x40($out)
+	vmovdqu		$xd0,0x60($out)
+	vmovdqu		$xa1,0x80($out)
+	vmovdqu		$xb1,0xa0($out)
+	vmovdqu		$xc1,0xc0($out)
+	vmovdqu		$xd1,0xe0($out)
+	vmovdqu		$xa2,0x100($out)
+	vmovdqu		$xb2,0x120($out)
+	vmovdqu		$xc2,0x140($out)
+	vmovdqu		$xd2,0x160($out)
+	vmovdqu		$xa3,0x180($out)
+	vmovdqu		$xb3,0x1a0($out)
+	je		.Ldone8x
+
+	lea		0x1c0($inp),$inp	# inp+=64*7
+	xor		%r10,%r10
+	vmovdqa		$xc3,0x00(%rsp)
+	lea		0x1c0($out),$out	# out+=64*7
+	sub		\$448,$len		# len-=64*7
+	vmovdqa		$xd3,0x20(%rsp)
+
+.Loop_tail8x:
+	movzb		($inp,%r10),%eax
+	movzb		(%rsp,%r10),%ecx
+	lea		1(%r10),%r10
+	xor		%ecx,%eax
+	mov		%al,-1($out,%r10)
+	dec		$len
+	jnz		.Loop_tail8x
+
+.Ldone8x:
+	vzeroall
+___
+$code.=<<___	if ($win64);
+	movaps		-0xa8(%r9),%xmm6
+	movaps		-0x98(%r9),%xmm7
+	movaps		-0x88(%r9),%xmm8
+	movaps		-0x78(%r9),%xmm9
+	movaps		-0x68(%r9),%xmm10
+	movaps		-0x58(%r9),%xmm11
+	movaps		-0x48(%r9),%xmm12
+	movaps		-0x38(%r9),%xmm13
+	movaps		-0x28(%r9),%xmm14
+	movaps		-0x18(%r9),%xmm15
+___
+$code.=<<___;
+	lea		(%r9),%rsp
+.L8x_epilogue:
+	ret
+.size	ChaCha20_8x,.-ChaCha20_8x
+___
+}
+
+########################################################################
+# AVX512 code paths
+if ($avx>2) {
+# This one handles shorter inputs...
+
+my ($a,$b,$c,$d, $a_,$b_,$c_,$d_,$fourz) = map("%zmm$_",(0..3,16..20));
+my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
+
+sub AVX512ROUND {	# critical path is 14 "SIMD ticks" per round
+	&vpaddd	($a,$a,$b);
+	&vpxord	($d,$d,$a);
+	&vprold	($d,$d,16);
+
+	&vpaddd	($c,$c,$d);
+	&vpxord	($b,$b,$c);
+	&vprold	($b,$b,12);
+
+	&vpaddd	($a,$a,$b);
+	&vpxord	($d,$d,$a);
+	&vprold	($d,$d,8);
+
+	&vpaddd	($c,$c,$d);
+	&vpxord	($b,$b,$c);
+	&vprold	($b,$b,7);
+}
+
+my $xframe = $win64 ? 32+8 : 8;
+
+$code.=<<___;
+.type	ChaCha20_avx512,\@function,5
+.align	32
+ChaCha20_avx512:
+.LChaCha20_avx512:
+	mov	%rsp,%r9		# frame pointer
+	cmp	\$512,$len
+	ja	.LChaCha20_16x
+
+	sub	\$64+$xframe,%rsp
+___
+$code.=<<___	if ($win64);
+	movaps	%xmm6,-0x28(%r9)
+	movaps	%xmm7,-0x18(%r9)
+.Lavx512_body:
+___
+$code.=<<___;
+	vbroadcasti32x4	.Lsigma(%rip),$a
+	vbroadcasti32x4	($key),$b
+	vbroadcasti32x4	16($key),$c
+	vbroadcasti32x4	($counter),$d
+
+	vmovdqa32	$a,$a_
+	vmovdqa32	$b,$b_
+	vmovdqa32	$c,$c_
+	vpaddd		.Lzeroz(%rip),$d,$d
+	vmovdqa32	.Lfourz(%rip),$fourz
+	mov		\$10,$counter	# reuse $counter
+	vmovdqa32	$d,$d_
+	jmp		.Loop_avx512
+
+.align	16
+.Loop_outer_avx512:
+	vmovdqa32	$a_,$a
+	vmovdqa32	$b_,$b
+	vmovdqa32	$c_,$c
+	vpaddd		$fourz,$d_,$d
+	mov		\$10,$counter
+	vmovdqa32	$d,$d_
+	jmp		.Loop_avx512
+
+.align	32
+.Loop_avx512:
+___
+	&AVX512ROUND();
+	&vpshufd	($c,$c,0b01001110);
+	&vpshufd	($b,$b,0b00111001);
+	&vpshufd	($d,$d,0b10010011);
+
+	&AVX512ROUND();
+	&vpshufd	($c,$c,0b01001110);
+	&vpshufd	($b,$b,0b10010011);
+	&vpshufd	($d,$d,0b00111001);
+
+	&dec		($counter);
+	&jnz		(".Loop_avx512");
+
+$code.=<<___;
+	vpaddd		$a_,$a,$a
+	vpaddd		$b_,$b,$b
+	vpaddd		$c_,$c,$c
+	vpaddd		$d_,$d,$d
+
+	sub		\$64,$len
+	jb		.Ltail64_avx512
+
+	vpxor		0x00($inp),%x#$a,$t0	# xor with input
+	vpxor		0x10($inp),%x#$b,$t1
+	vpxor		0x20($inp),%x#$c,$t2
+	vpxor		0x30($inp),%x#$d,$t3
+	lea		0x40($inp),$inp		# inp+=64
+
+	vmovdqu		$t0,0x00($out)		# write output
+	vmovdqu		$t1,0x10($out)
+	vmovdqu		$t2,0x20($out)
+	vmovdqu		$t3,0x30($out)
+	lea		0x40($out),$out		# out+=64
+
+	jz		.Ldone_avx512
+
+	vextracti32x4	\$1,$a,$t0
+	vextracti32x4	\$1,$b,$t1
+	vextracti32x4	\$1,$c,$t2
+	vextracti32x4	\$1,$d,$t3
+
+	sub		\$64,$len
+	jb		.Ltail_avx512
+
+	vpxor		0x00($inp),$t0,$t0	# xor with input
+	vpxor		0x10($inp),$t1,$t1
+	vpxor		0x20($inp),$t2,$t2
+	vpxor		0x30($inp),$t3,$t3
+	lea		0x40($inp),$inp		# inp+=64
+
+	vmovdqu		$t0,0x00($out)		# write output
+	vmovdqu		$t1,0x10($out)
+	vmovdqu		$t2,0x20($out)
+	vmovdqu		$t3,0x30($out)
+	lea		0x40($out),$out		# out+=64
+
+	jz		.Ldone_avx512
+
+	vextracti32x4	\$2,$a,$t0
+	vextracti32x4	\$2,$b,$t1
+	vextracti32x4	\$2,$c,$t2
+	vextracti32x4	\$2,$d,$t3
+
+	sub		\$64,$len
+	jb		.Ltail_avx512
+
+	vpxor		0x00($inp),$t0,$t0	# xor with input
+	vpxor		0x10($inp),$t1,$t1
+	vpxor		0x20($inp),$t2,$t2
+	vpxor		0x30($inp),$t3,$t3
+	lea		0x40($inp),$inp		# inp+=64
+
+	vmovdqu		$t0,0x00($out)		# write output
+	vmovdqu		$t1,0x10($out)
+	vmovdqu		$t2,0x20($out)
+	vmovdqu		$t3,0x30($out)
+	lea		0x40($out),$out		# out+=64
+
+	jz		.Ldone_avx512
+
+	vextracti32x4	\$3,$a,$t0
+	vextracti32x4	\$3,$b,$t1
+	vextracti32x4	\$3,$c,$t2
+	vextracti32x4	\$3,$d,$t3
+
+	sub		\$64,$len
+	jb		.Ltail_avx512
+
+	vpxor		0x00($inp),$t0,$t0	# xor with input
+	vpxor		0x10($inp),$t1,$t1
+	vpxor		0x20($inp),$t2,$t2
+	vpxor		0x30($inp),$t3,$t3
+	lea		0x40($inp),$inp		# inp+=64
+
+	vmovdqu		$t0,0x00($out)		# write output
+	vmovdqu		$t1,0x10($out)
+	vmovdqu		$t2,0x20($out)
+	vmovdqu		$t3,0x30($out)
+	lea		0x40($out),$out		# out+=64
+
+	jnz		.Loop_outer_avx512
+
+	jmp		.Ldone_avx512
+
+.align	16
+.Ltail64_avx512:
+	vmovdqa		%x#$a,0x00(%rsp)
+	vmovdqa		%x#$b,0x10(%rsp)
+	vmovdqa		%x#$c,0x20(%rsp)
+	vmovdqa		%x#$d,0x30(%rsp)
+	add		\$64,$len
+	jmp		.Loop_tail_avx512
+
+.align	16
+.Ltail_avx512:
+	vmovdqa		$t0,0x00(%rsp)
+	vmovdqa		$t1,0x10(%rsp)
+	vmovdqa		$t2,0x20(%rsp)
+	vmovdqa		$t3,0x30(%rsp)
+	add		\$64,$len
+
+.Loop_tail_avx512:
+	movzb		($inp,$counter),%eax
+	movzb		(%rsp,$counter),%ecx
+	lea		1($counter),$counter
+	xor		%ecx,%eax
+	mov		%al,-1($out,$counter)
+	dec		$len
+	jnz		.Loop_tail_avx512
+
+	vmovdqa32	$a_,0x00(%rsp)
+
+.Ldone_avx512:
+	vzeroall
+___
+$code.=<<___	if ($win64);
+	movaps	-0x28(%r9),%xmm6
+	movaps	-0x18(%r9),%xmm7
+___
+$code.=<<___;
+	lea	(%r9),%rsp
+.Lavx512_epilogue:
+	ret
+.size	ChaCha20_avx512,.-ChaCha20_avx512
+___
+}
+if ($avx>2) {
+# This one handles longer inputs...
+
+my ($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
+    $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3)=map("%zmm$_",(0..15));
+my  @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
+	 $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3);
+my @key=map("%zmm$_",(16..31));
+my ($xt0,$xt1,$xt2,$xt3)=@key[0..3];
+
+sub AVX512_lane_ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my @x=map("\"$_\"",@xx);
+
+	(
+	"&vpaddd	(@x[$a0],@x[$a0],@x[$b0])",	# Q1
+	 "&vpaddd	(@x[$a1],@x[$a1],@x[$b1])",	# Q2
+	  "&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",	# Q3
+	   "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",	# Q4
+	"&vpxord	(@x[$d0],@x[$d0],@x[$a0])",
+	 "&vpxord	(@x[$d1],@x[$d1],@x[$a1])",
+	  "&vpxord	(@x[$d2],@x[$d2],@x[$a2])",
+	   "&vpxord	(@x[$d3],@x[$d3],@x[$a3])",
+	"&vprold	(@x[$d0],@x[$d0],16)",
+	 "&vprold	(@x[$d1],@x[$d1],16)",
+	  "&vprold	(@x[$d2],@x[$d2],16)",
+	   "&vprold	(@x[$d3],@x[$d3],16)",
+
+	"&vpaddd	(@x[$c0],@x[$c0],@x[$d0])",
+	 "&vpaddd	(@x[$c1],@x[$c1],@x[$d1])",
+	  "&vpaddd	(@x[$c2],@x[$c2],@x[$d2])",
+	   "&vpaddd	(@x[$c3],@x[$c3],@x[$d3])",
+	"&vpxord	(@x[$b0],@x[$b0],@x[$c0])",
+	 "&vpxord	(@x[$b1],@x[$b1],@x[$c1])",
+	  "&vpxord	(@x[$b2],@x[$b2],@x[$c2])",
+	   "&vpxord	(@x[$b3],@x[$b3],@x[$c3])",
+	"&vprold	(@x[$b0],@x[$b0],12)",
+	 "&vprold	(@x[$b1],@x[$b1],12)",
+	  "&vprold	(@x[$b2],@x[$b2],12)",
+	   "&vprold	(@x[$b3],@x[$b3],12)",
+
+	"&vpaddd	(@x[$a0],@x[$a0],@x[$b0])",
+	 "&vpaddd	(@x[$a1],@x[$a1],@x[$b1])",
+	  "&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",
+	   "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",
+	"&vpxord	(@x[$d0],@x[$d0],@x[$a0])",
+	 "&vpxord	(@x[$d1],@x[$d1],@x[$a1])",
+	  "&vpxord	(@x[$d2],@x[$d2],@x[$a2])",
+	   "&vpxord	(@x[$d3],@x[$d3],@x[$a3])",
+	"&vprold	(@x[$d0],@x[$d0],8)",
+	 "&vprold	(@x[$d1],@x[$d1],8)",
+	  "&vprold	(@x[$d2],@x[$d2],8)",
+	   "&vprold	(@x[$d3],@x[$d3],8)",
+
+	"&vpaddd	(@x[$c0],@x[$c0],@x[$d0])",
+	 "&vpaddd	(@x[$c1],@x[$c1],@x[$d1])",
+	  "&vpaddd	(@x[$c2],@x[$c2],@x[$d2])",
+	   "&vpaddd	(@x[$c3],@x[$c3],@x[$d3])",
+	"&vpxord	(@x[$b0],@x[$b0],@x[$c0])",
+	 "&vpxord	(@x[$b1],@x[$b1],@x[$c1])",
+	  "&vpxord	(@x[$b2],@x[$b2],@x[$c2])",
+	   "&vpxord	(@x[$b3],@x[$b3],@x[$c3])",
+	"&vprold	(@x[$b0],@x[$b0],7)",
+	 "&vprold	(@x[$b1],@x[$b1],7)",
+	  "&vprold	(@x[$b2],@x[$b2],7)",
+	   "&vprold	(@x[$b3],@x[$b3],7)"
+	);
+}
+
+my $xframe = $win64 ? 0xa8 : 8;
+
+$code.=<<___;
+.type	ChaCha20_16x,\@function,5
+.align	32
+ChaCha20_16x:
+.LChaCha20_16x:
+	mov		%rsp,%r9		# frame register
+	sub		\$64+$xframe,%rsp
+	and		\$-64,%rsp
+___
+$code.=<<___	if ($win64);
+	movaps		%xmm6,-0xa8(%r9)
+	movaps		%xmm7,-0x98(%r9)
+	movaps		%xmm8,-0x88(%r9)
+	movaps		%xmm9,-0x78(%r9)
+	movaps		%xmm10,-0x68(%r9)
+	movaps		%xmm11,-0x58(%r9)
+	movaps		%xmm12,-0x48(%r9)
+	movaps		%xmm13,-0x38(%r9)
+	movaps		%xmm14,-0x28(%r9)
+	movaps		%xmm15,-0x18(%r9)
+.L16x_body:
+___
+$code.=<<___;
+	vzeroupper
+
+	lea		.Lsigma(%rip),%r10
+	vbroadcasti32x4	(%r10),$xa3		# key[0]
+	vbroadcasti32x4	($key),$xb3		# key[1]
+	vbroadcasti32x4	16($key),$xc3		# key[2]
+	vbroadcasti32x4	($counter),$xd3		# key[3]
+
+	vpshufd		\$0x00,$xa3,$xa0	# smash key by lanes...
+	vpshufd		\$0x55,$xa3,$xa1
+	vpshufd		\$0xaa,$xa3,$xa2
+	vpshufd		\$0xff,$xa3,$xa3
+	vmovdqa64	$xa0,@key[0]
+	vmovdqa64	$xa1,@key[1]
+	vmovdqa64	$xa2,@key[2]
+	vmovdqa64	$xa3,@key[3]
+
+	vpshufd		\$0x00,$xb3,$xb0
+	vpshufd		\$0x55,$xb3,$xb1
+	vpshufd		\$0xaa,$xb3,$xb2
+	vpshufd		\$0xff,$xb3,$xb3
+	vmovdqa64	$xb0,@key[4]
+	vmovdqa64	$xb1,@key[5]
+	vmovdqa64	$xb2,@key[6]
+	vmovdqa64	$xb3,@key[7]
+
+	vpshufd		\$0x00,$xc3,$xc0
+	vpshufd		\$0x55,$xc3,$xc1
+	vpshufd		\$0xaa,$xc3,$xc2
+	vpshufd		\$0xff,$xc3,$xc3
+	vmovdqa64	$xc0,@key[8]
+	vmovdqa64	$xc1,@key[9]
+	vmovdqa64	$xc2,@key[10]
+	vmovdqa64	$xc3,@key[11]
+
+	vpshufd		\$0x00,$xd3,$xd0
+	vpshufd		\$0x55,$xd3,$xd1
+	vpshufd		\$0xaa,$xd3,$xd2
+	vpshufd		\$0xff,$xd3,$xd3
+	vpaddd		.Lincz(%rip),$xd0,$xd0	# don't save counters yet
+	vmovdqa64	$xd0,@key[12]
+	vmovdqa64	$xd1,@key[13]
+	vmovdqa64	$xd2,@key[14]
+	vmovdqa64	$xd3,@key[15]
+
+	mov		\$10,%eax
+	jmp		.Loop16x
+
+.align	32
+.Loop_outer16x:
+	vpbroadcastd	0(%r10),$xa0		# reload key
+	vpbroadcastd	4(%r10),$xa1
+	vpbroadcastd	8(%r10),$xa2
+	vpbroadcastd	12(%r10),$xa3
+	vpaddd		.Lsixteen(%rip),@key[12],@key[12]	# next SIMD counters
+	vmovdqa64	@key[4],$xb0
+	vmovdqa64	@key[5],$xb1
+	vmovdqa64	@key[6],$xb2
+	vmovdqa64	@key[7],$xb3
+	vmovdqa64	@key[8],$xc0
+	vmovdqa64	@key[9],$xc1
+	vmovdqa64	@key[10],$xc2
+	vmovdqa64	@key[11],$xc3
+	vmovdqa64	@key[12],$xd0
+	vmovdqa64	@key[13],$xd1
+	vmovdqa64	@key[14],$xd2
+	vmovdqa64	@key[15],$xd3
+
+	vmovdqa64	$xa0,@key[0]
+	vmovdqa64	$xa1,@key[1]
+	vmovdqa64	$xa2,@key[2]
+	vmovdqa64	$xa3,@key[3]
+
+	mov		\$10,%eax
+	jmp		.Loop16x
+
+.align	32
+.Loop16x:
+___
+	foreach (&AVX512_lane_ROUND(0, 4, 8,12)) { eval; }
+	foreach (&AVX512_lane_ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+	dec		%eax
+	jnz		.Loop16x
+
+	vpaddd		@key[0],$xa0,$xa0	# accumulate key
+	vpaddd		@key[1],$xa1,$xa1
+	vpaddd		@key[2],$xa2,$xa2
+	vpaddd		@key[3],$xa3,$xa3
+
+	vpunpckldq	$xa1,$xa0,$xt2		# "de-interlace" data
+	vpunpckldq	$xa3,$xa2,$xt3
+	vpunpckhdq	$xa1,$xa0,$xa0
+	vpunpckhdq	$xa3,$xa2,$xa2
+	vpunpcklqdq	$xt3,$xt2,$xa1		# "a0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "a1"
+	vpunpcklqdq	$xa2,$xa0,$xa3		# "a2"
+	vpunpckhqdq	$xa2,$xa0,$xa0		# "a3"
+___
+	($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
+$code.=<<___;
+	vpaddd		@key[4],$xb0,$xb0
+	vpaddd		@key[5],$xb1,$xb1
+	vpaddd		@key[6],$xb2,$xb2
+	vpaddd		@key[7],$xb3,$xb3
+
+	vpunpckldq	$xb1,$xb0,$xt2
+	vpunpckldq	$xb3,$xb2,$xt3
+	vpunpckhdq	$xb1,$xb0,$xb0
+	vpunpckhdq	$xb3,$xb2,$xb2
+	vpunpcklqdq	$xt3,$xt2,$xb1		# "b0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "b1"
+	vpunpcklqdq	$xb2,$xb0,$xb3		# "b2"
+	vpunpckhqdq	$xb2,$xb0,$xb0		# "b3"
+___
+	($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
+$code.=<<___;
+	vshufi32x4	\$0x44,$xb0,$xa0,$xt3	# "de-interlace" further
+	vshufi32x4	\$0xee,$xb0,$xa0,$xb0
+	vshufi32x4	\$0x44,$xb1,$xa1,$xa0
+	vshufi32x4	\$0xee,$xb1,$xa1,$xb1
+	vshufi32x4	\$0x44,$xb2,$xa2,$xa1
+	vshufi32x4	\$0xee,$xb2,$xa2,$xb2
+	vshufi32x4	\$0x44,$xb3,$xa3,$xa2
+	vshufi32x4	\$0xee,$xb3,$xa3,$xb3
+___
+	($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
+$code.=<<___;
+	vpaddd		@key[8],$xc0,$xc0
+	vpaddd		@key[9],$xc1,$xc1
+	vpaddd		@key[10],$xc2,$xc2
+	vpaddd		@key[11],$xc3,$xc3
+
+	vpunpckldq	$xc1,$xc0,$xt2
+	vpunpckldq	$xc3,$xc2,$xt3
+	vpunpckhdq	$xc1,$xc0,$xc0
+	vpunpckhdq	$xc3,$xc2,$xc2
+	vpunpcklqdq	$xt3,$xt2,$xc1		# "c0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "c1"
+	vpunpcklqdq	$xc2,$xc0,$xc3		# "c2"
+	vpunpckhqdq	$xc2,$xc0,$xc0		# "c3"
+___
+	($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
+$code.=<<___;
+	vpaddd		@key[12],$xd0,$xd0
+	vpaddd		@key[13],$xd1,$xd1
+	vpaddd		@key[14],$xd2,$xd2
+	vpaddd		@key[15],$xd3,$xd3
+
+	vpunpckldq	$xd1,$xd0,$xt2
+	vpunpckldq	$xd3,$xd2,$xt3
+	vpunpckhdq	$xd1,$xd0,$xd0
+	vpunpckhdq	$xd3,$xd2,$xd2
+	vpunpcklqdq	$xt3,$xt2,$xd1		# "d0"
+	vpunpckhqdq	$xt3,$xt2,$xt2		# "d1"
+	vpunpcklqdq	$xd2,$xd0,$xd3		# "d2"
+	vpunpckhqdq	$xd2,$xd0,$xd0		# "d3"
+___
+	($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
+$code.=<<___;
+	vshufi32x4	\$0x44,$xd0,$xc0,$xt3	# "de-interlace" further
+	vshufi32x4	\$0xee,$xd0,$xc0,$xd0
+	vshufi32x4	\$0x44,$xd1,$xc1,$xc0
+	vshufi32x4	\$0xee,$xd1,$xc1,$xd1
+	vshufi32x4	\$0x44,$xd2,$xc2,$xc1
+	vshufi32x4	\$0xee,$xd2,$xc2,$xd2
+	vshufi32x4	\$0x44,$xd3,$xc3,$xc2
+	vshufi32x4	\$0xee,$xd3,$xc3,$xd3
+___
+	($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
+$code.=<<___;
+	vshufi32x4	\$0x88,$xc0,$xa0,$xt0	# "de-interlace" further
+	vshufi32x4	\$0xdd,$xc0,$xa0,$xa0
+	 vshufi32x4	\$0x88,$xd0,$xb0,$xc0
+	 vshufi32x4	\$0xdd,$xd0,$xb0,$xd0
+	vshufi32x4	\$0x88,$xc1,$xa1,$xt1
+	vshufi32x4	\$0xdd,$xc1,$xa1,$xa1
+	 vshufi32x4	\$0x88,$xd1,$xb1,$xc1
+	 vshufi32x4	\$0xdd,$xd1,$xb1,$xd1
+	vshufi32x4	\$0x88,$xc2,$xa2,$xt2
+	vshufi32x4	\$0xdd,$xc2,$xa2,$xa2
+	 vshufi32x4	\$0x88,$xd2,$xb2,$xc2
+	 vshufi32x4	\$0xdd,$xd2,$xb2,$xd2
+	vshufi32x4	\$0x88,$xc3,$xa3,$xt3
+	vshufi32x4	\$0xdd,$xc3,$xa3,$xa3
+	 vshufi32x4	\$0x88,$xd3,$xb3,$xc3
+	 vshufi32x4	\$0xdd,$xd3,$xb3,$xd3
+___
+	($xa0,$xa1,$xa2,$xa3,$xb0,$xb1,$xb2,$xb3)=
+	($xt0,$xt1,$xt2,$xt3,$xa0,$xa1,$xa2,$xa3);
+
+	($xa0,$xb0,$xc0,$xd0, $xa1,$xb1,$xc1,$xd1,
+	 $xa2,$xb2,$xc2,$xd2, $xa3,$xb3,$xc3,$xd3) =
+	($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
+	 $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3);
+$code.=<<___;
+	cmp		\$64*16,$len
+	jb		.Ltail16x
+
+	vpxord		0x00($inp),$xa0,$xa0	# xor with input
+	vpxord		0x40($inp),$xb0,$xb0
+	vpxord		0x80($inp),$xc0,$xc0
+	vpxord		0xc0($inp),$xd0,$xd0
+	vmovdqu32	$xa0,0x00($out)
+	vmovdqu32	$xb0,0x40($out)
+	vmovdqu32	$xc0,0x80($out)
+	vmovdqu32	$xd0,0xc0($out)
+
+	vpxord		0x100($inp),$xa1,$xa1
+	vpxord		0x140($inp),$xb1,$xb1
+	vpxord		0x180($inp),$xc1,$xc1
+	vpxord		0x1c0($inp),$xd1,$xd1
+	vmovdqu32	$xa1,0x100($out)
+	vmovdqu32	$xb1,0x140($out)
+	vmovdqu32	$xc1,0x180($out)
+	vmovdqu32	$xd1,0x1c0($out)
+
+	vpxord		0x200($inp),$xa2,$xa2
+	vpxord		0x240($inp),$xb2,$xb2
+	vpxord		0x280($inp),$xc2,$xc2
+	vpxord		0x2c0($inp),$xd2,$xd2
+	vmovdqu32	$xa2,0x200($out)
+	vmovdqu32	$xb2,0x240($out)
+	vmovdqu32	$xc2,0x280($out)
+	vmovdqu32	$xd2,0x2c0($out)
+
+	vpxord		0x300($inp),$xa3,$xa3
+	vpxord		0x340($inp),$xb3,$xb3
+	vpxord		0x380($inp),$xc3,$xc3
+	vpxord		0x3c0($inp),$xd3,$xd3
+	lea		0x400($inp),$inp
+	vmovdqu32	$xa3,0x300($out)
+	vmovdqu32	$xb3,0x340($out)
+	vmovdqu32	$xc3,0x380($out)
+	vmovdqu32	$xd3,0x3c0($out)
+	lea		0x400($out),$out
+
+	sub		\$64*16,$len
+	jnz		.Loop_outer16x
+
+	jmp		.Ldone16x
+
+.align	32
+.Ltail16x:
+	xor		%r10,%r10
+	sub		$inp,$out
+	cmp		\$64*1,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xa0,$xa0	# xor with input
+	vmovdqu32	$xa0,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xb0,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*2,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xb0,$xb0
+	vmovdqu32	$xb0,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xc0,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*3,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xc0,$xc0
+	vmovdqu32	$xc0,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xd0,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*4,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xd0,$xd0
+	vmovdqu32	$xd0,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xa1,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*5,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xa1,$xa1
+	vmovdqu32	$xa1,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xb1,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*6,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xb1,$xb1
+	vmovdqu32	$xb1,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xc1,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*7,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xc1,$xc1
+	vmovdqu32	$xc1,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xd1,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*8,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xd1,$xd1
+	vmovdqu32	$xd1,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xa2,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*9,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xa2,$xa2
+	vmovdqu32	$xa2,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xb2,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*10,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xb2,$xb2
+	vmovdqu32	$xb2,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xc2,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*11,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xc2,$xc2
+	vmovdqu32	$xc2,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xd2,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*12,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xd2,$xd2
+	vmovdqu32	$xd2,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xa3,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*13,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xa3,$xa3
+	vmovdqu32	$xa3,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xb3,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*14,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xb3,$xb3
+	vmovdqu32	$xb3,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xc3,$xa0
+	lea		64($inp),$inp
+
+	cmp		\$64*15,$len
+	jb		.Less_than_64_16x
+	vpxord		($inp),$xc3,$xc3
+	vmovdqu32	$xc3,($out,$inp)
+	je		.Ldone16x
+	vmovdqa32	$xd3,$xa0
+	lea		64($inp),$inp
+
+.Less_than_64_16x:
+	vmovdqa32	$xa0,0x00(%rsp)
+	lea		($out,$inp),$out
+	and		\$63,$len
+
+.Loop_tail16x:
+	movzb		($inp,%r10),%eax
+	movzb		(%rsp,%r10),%ecx
+	lea		1(%r10),%r10
+	xor		%ecx,%eax
+	mov		%al,-1($out,%r10)
+	dec		$len
+	jnz		.Loop_tail16x
+
+	vpxord		$xa0,$xa0,$xa0
+	vmovdqa32	$xa0,0(%rsp)
+
+.Ldone16x:
+	vzeroall
+___
+$code.=<<___	if ($win64);
+	movaps		-0xa8(%r9),%xmm6
+	movaps		-0x98(%r9),%xmm7
+	movaps		-0x88(%r9),%xmm8
+	movaps		-0x78(%r9),%xmm9
+	movaps		-0x68(%r9),%xmm10
+	movaps		-0x58(%r9),%xmm11
+	movaps		-0x48(%r9),%xmm12
+	movaps		-0x38(%r9),%xmm13
+	movaps		-0x28(%r9),%xmm14
+	movaps		-0x18(%r9),%xmm15
+___
+$code.=<<___;
+	lea		(%r9),%rsp
+.L16x_epilogue:
+	ret
+.size	ChaCha20_16x,.-ChaCha20_16x
+___
+}
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern	__imp_RtlVirtualUnwind
+.type	se_handler,\@abi-omnipotent
+.align	16
+se_handler:
+	push	%rsi
+	push	%rdi
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+	pushfq
+	sub	\$64,%rsp
+
+	mov	120($context),%rax	# pull context->Rax
+	mov	248($context),%rbx	# pull context->Rip
+
+	mov	8($disp),%rsi		# disp->ImageBase
+	mov	56($disp),%r11		# disp->HandlerData
+
+	lea	.Lctr32_body(%rip),%r10
+	cmp	%r10,%rbx		# context->Rip<.Lprologue
+	jb	.Lcommon_seh_tail
+
+	mov	152($context),%rax	# pull context->Rsp
+
+	lea	.Lno_data(%rip),%r10	# epilogue label
+	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
+	jae	.Lcommon_seh_tail
+
+	lea	64+24+48(%rax),%rax
+
+	mov	-8(%rax),%rbx
+	mov	-16(%rax),%rbp
+	mov	-24(%rax),%r12
+	mov	-32(%rax),%r13
+	mov	-40(%rax),%r14
+	mov	-48(%rax),%r15
+	mov	%rbx,144($context)	# restore context->Rbx
+	mov	%rbp,160($context)	# restore context->Rbp
+	mov	%r12,216($context)	# restore context->R12
+	mov	%r13,224($context)	# restore context->R13
+	mov	%r14,232($context)	# restore context->R14
+	mov	%r15,240($context)	# restore context->R14
+
+.Lcommon_seh_tail:
+	mov	8(%rax),%rdi
+	mov	16(%rax),%rsi
+	mov	%rax,152($context)	# restore context->Rsp
+	mov	%rsi,168($context)	# restore context->Rsi
+	mov	%rdi,176($context)	# restore context->Rdi
+
+	mov	40($disp),%rdi		# disp->ContextRecord
+	mov	$context,%rsi		# context
+	mov	\$154,%ecx		# sizeof(CONTEXT)
+	.long	0xa548f3fc		# cld; rep movsq
+
+	mov	$disp,%rsi
+	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
+	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
+	mov	0(%rsi),%r8		# arg3, disp->ControlPc
+	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
+	mov	40(%rsi),%r10		# disp->ContextRecord
+	lea	56(%rsi),%r11		# &disp->HandlerData
+	lea	24(%rsi),%r12		# &disp->EstablisherFrame
+	mov	%r10,32(%rsp)		# arg5
+	mov	%r11,40(%rsp)		# arg6
+	mov	%r12,48(%rsp)		# arg7
+	mov	%rcx,56(%rsp)		# arg8, (NULL)
+	call	*__imp_RtlVirtualUnwind(%rip)
+
+	mov	\$1,%eax		# ExceptionContinueSearch
+	add	\$64,%rsp
+	popfq
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	pop	%rdi
+	pop	%rsi
+	ret
+.size	se_handler,.-se_handler
+
+.type	ssse3_handler,\@abi-omnipotent
+.align	16
+ssse3_handler:
+	push	%rsi
+	push	%rdi
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+	pushfq
+	sub	\$64,%rsp
+
+	mov	120($context),%rax	# pull context->Rax
+	mov	248($context),%rbx	# pull context->Rip
+
+	mov	8($disp),%rsi		# disp->ImageBase
+	mov	56($disp),%r11		# disp->HandlerData
+
+	mov	0(%r11),%r10d		# HandlerData[0]
+	lea	(%rsi,%r10),%r10	# prologue label
+	cmp	%r10,%rbx		# context->Rip<prologue label
+	jb	.Lcommon_seh_tail
+
+	mov	192($context),%rax	# pull context->R9
+
+	mov	4(%r11),%r10d		# HandlerData[1]
+	lea	(%rsi,%r10),%r10	# epilogue label
+	cmp	%r10,%rbx		# context->Rip>=epilogue label
+	jae	.Lcommon_seh_tail
+
+	lea	-0x28(%rax),%rsi
+	lea	512($context),%rdi	# &context.Xmm6
+	mov	\$4,%ecx
+	.long	0xa548f3fc		# cld; rep movsq
+
+	jmp	.Lcommon_seh_tail
+.size	ssse3_handler,.-ssse3_handler
+
+.type	full_handler,\@abi-omnipotent
+.align	16
+full_handler:
+	push	%rsi
+	push	%rdi
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+	pushfq
+	sub	\$64,%rsp
+
+	mov	120($context),%rax	# pull context->Rax
+	mov	248($context),%rbx	# pull context->Rip
+
+	mov	8($disp),%rsi		# disp->ImageBase
+	mov	56($disp),%r11		# disp->HandlerData
+
+	mov	0(%r11),%r10d		# HandlerData[0]
+	lea	(%rsi,%r10),%r10	# prologue label
+	cmp	%r10,%rbx		# context->Rip<prologue label
+	jb	.Lcommon_seh_tail
+
+	mov	192($context),%rax	# pull context->R9
+
+	mov	4(%r11),%r10d		# HandlerData[1]
+	lea	(%rsi,%r10),%r10	# epilogue label
+	cmp	%r10,%rbx		# context->Rip>=epilogue label
+	jae	.Lcommon_seh_tail
+
+	lea	-0xa8(%rax),%rsi
+	lea	512($context),%rdi	# &context.Xmm6
+	mov	\$20,%ecx
+	.long	0xa548f3fc		# cld; rep movsq
+
+	jmp	.Lcommon_seh_tail
+.size	full_handler,.-full_handler
+
+.section	.pdata
+.align	4
+	.rva	.LSEH_begin_GFp_ChaCha20_ctr32
+	.rva	.LSEH_end_GFp_ChaCha20_ctr32
+	.rva	.LSEH_info_GFp_ChaCha20_ctr32
+
+	.rva	.LSEH_begin_ChaCha20_ssse3
+	.rva	.LSEH_end_ChaCha20_ssse3
+	.rva	.LSEH_info_ChaCha20_ssse3
+
+	.rva	.LSEH_begin_ChaCha20_4x
+	.rva	.LSEH_end_ChaCha20_4x
+	.rva	.LSEH_info_ChaCha20_4x
+___
+$code.=<<___ if ($avx>1);
+	.rva	.LSEH_begin_ChaCha20_8x
+	.rva	.LSEH_end_ChaCha20_8x
+	.rva	.LSEH_info_ChaCha20_8x
+___
+$code.=<<___ if ($avx>2);
+	.rva	.LSEH_begin_ChaCha20_avx512
+	.rva	.LSEH_end_ChaCha20_avx512
+	.rva	.LSEH_info_ChaCha20_avx512
+
+	.rva	.LSEH_begin_ChaCha20_16x
+	.rva	.LSEH_end_ChaCha20_16x
+	.rva	.LSEH_info_ChaCha20_16x
+___
+$code.=<<___;
+.section	.xdata
+.align	8
+.LSEH_info_GFp_ChaCha20_ctr32:
+	.byte	9,0,0,0
+	.rva	se_handler
+
+.LSEH_info_ChaCha20_ssse3:
+	.byte	9,0,0,0
+	.rva	ssse3_handler
+	.rva	.Lssse3_body,.Lssse3_epilogue
+
+.LSEH_info_ChaCha20_4x:
+	.byte	9,0,0,0
+	.rva	full_handler
+	.rva	.L4x_body,.L4x_epilogue
+___
+$code.=<<___ if ($avx>1);
+.LSEH_info_ChaCha20_8x:
+	.byte	9,0,0,0
+	.rva	full_handler
+	.rva	.L8x_body,.L8x_epilogue			# HandlerData[]
+___
+$code.=<<___ if ($avx>2);
+.LSEH_info_ChaCha20_avx512:
+	.byte	9,0,0,0
+	.rva	ssse3_handler
+	.rva	.Lavx512_body,.Lavx512_epilogue		# HandlerData[]
+
+.LSEH_info_ChaCha20_16x:
+	.byte	9,0,0,0
+	.rva	full_handler
+	.rva	.L16x_body,.L16x_epilogue		# HandlerData[]
+___
+}
+
+foreach (split("\n",$code)) {
+	s/\`([^\`]*)\`/eval $1/ge;
+
+	s/%x#%[yz]/%x/g;	# "down-shift"
+
+	print $_,"\n";
+}
+
+close STDOUT;
diff --git a/rustc_deps/vendor/ring/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl b/rustc_deps/vendor/ring/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl
new file mode 100644
index 0000000..1a3d064
--- /dev/null
+++ b/rustc_deps/vendor/ring/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl
@@ -0,0 +1,2256 @@
+#!/usr/bin/env perl
+
+# Copyright (c) 2017, Shay Gueron.
+# Copyright (c) 2017, Google Inc.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+use warnings FATAL => 'all';
+
+$flavour = shift;
+$output  = shift;
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
+die "can't locate x86_64-xlate.pl";
+
+open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
+*STDOUT=*OUT;
+
+$code.=<<___;
+.data
+
+.align 16
+one:
+.quad 1,0
+two:
+.quad 2,0
+three:
+.quad 3,0
+four:
+.quad 4,0
+five:
+.quad 5,0
+six:
+.quad 6,0
+seven:
+.quad 7,0
+eight:
+.quad 8,0
+
+OR_MASK:
+.long 0x00000000,0x00000000,0x00000000,0x80000000
+poly:
+.quad 0x1, 0xc200000000000000
+mask:
+.long 0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d
+con1:
+.long 1,1,1,1
+con2:
+.long 0x1b,0x1b,0x1b,0x1b
+con3:
+.byte -1,-1,-1,-1,-1,-1,-1,-1,4,5,6,7,4,5,6,7
+and_mask:
+.long 0,0xffffffff, 0xffffffff, 0xffffffff
+___
+
+$code.=<<___;
+.text
+___
+
+sub gfmul {
+  #########################
+  # a = T
+  # b = TMP0 - remains unchanged
+  # res = T
+  # uses also TMP1,TMP2,TMP3,TMP4
+  # __m128i GFMUL(__m128i A, __m128i B);
+
+  my $T = "%xmm0";
+  my $TMP0 = "%xmm1";
+  my $TMP1 = "%xmm2";
+  my $TMP2 = "%xmm3";
+  my $TMP3 = "%xmm4";
+  my $TMP4 = "%xmm5";
+
+  $code.=<<___;
+.type GFMUL,\@abi-omnipotent
+.align 16
+GFMUL:
+.cfi_startproc
+    vpclmulqdq  \$0x00, $TMP0, $T, $TMP1
+    vpclmulqdq  \$0x11, $TMP0, $T, $TMP4
+    vpclmulqdq  \$0x10, $TMP0, $T, $TMP2
+    vpclmulqdq  \$0x01, $TMP0, $T, $TMP3
+    vpxor       $TMP3, $TMP2, $TMP2
+    vpslldq     \$8, $TMP2, $TMP3
+    vpsrldq     \$8, $TMP2, $TMP2
+    vpxor       $TMP3, $TMP1, $TMP1
+    vpxor       $TMP2, $TMP4, $TMP4
+
+    vpclmulqdq  \$0x10, poly(%rip), $TMP1, $TMP2
+    vpshufd     \$78, $TMP1, $TMP3
+    vpxor       $TMP3, $TMP2, $TMP1
+
+    vpclmulqdq  \$0x10, poly(%rip), $TMP1, $TMP2
+    vpshufd     \$78, $TMP1, $TMP3
+    vpxor       $TMP3, $TMP2, $TMP1
+
+    vpxor       $TMP4, $TMP1, $T
+    ret
+.cfi_endproc
+.size GFMUL, .-GFMUL
+___
+}
+gfmul();
+
+sub aesgcmsiv_htable_init {
+  # aesgcmsiv_htable_init writes an eight-entry table of powers of |H| to
+  # |out_htable|.
+  # void aesgcmsiv_htable_init(uint8_t out_htable[16*8], uint8_t *H);
+
+  my $Htbl = "%rdi";
+  my $H = "%rsi";
+  my $T = "%xmm0";
+  my $TMP0 = "%xmm1";
+
+$code.=<<___;
+.globl aesgcmsiv_htable_init
+.type aesgcmsiv_htable_init,\@function,2
+.align 16
+aesgcmsiv_htable_init:
+.cfi_startproc
+    vmovdqa ($H), $T
+    vmovdqa $T, $TMP0
+    vmovdqa $T, ($Htbl)      # H
+    call GFMUL
+    vmovdqa $T, 16($Htbl)    # H^2
+    call GFMUL
+    vmovdqa $T, 32($Htbl)    # H^3
+    call GFMUL
+    vmovdqa $T, 48($Htbl)    # H^4
+    call GFMUL
+    vmovdqa $T, 64($Htbl)    # H^5
+    call GFMUL
+    vmovdqa $T, 80($Htbl)    # H^6
+    call GFMUL
+    vmovdqa $T, 96($Htbl)    # H^7
+    call GFMUL
+    vmovdqa $T, 112($Htbl)   # H^8
+    ret
+.cfi_endproc
+.size aesgcmsiv_htable_init, .-aesgcmsiv_htable_init
+___
+}
+aesgcmsiv_htable_init();
+
+sub aesgcmsiv_htable6_init {
+  # aesgcmsiv_htable6_init writes a six-entry table of powers of |H| to
+  # |out_htable|.
+  # void aesgcmsiv_htable6_init(uint8_t out_htable[16*6], uint8_t *H);
+  #
+  my $Htbl = "%rdi";
+  my $H = "%rsi";
+  my $T = "%xmm0";
+  my $TMP0 = "%xmm1";
+
+  $code.=<<___;
+.globl aesgcmsiv_htable6_init
+.type aesgcmsiv_htable6_init,\@function,2
+.align 16
+aesgcmsiv_htable6_init:
+.cfi_startproc
+    vmovdqa ($H), $T
+    vmovdqa $T, $TMP0
+    vmovdqa $T, ($Htbl)      # H
+    call GFMUL
+    vmovdqa $T, 16($Htbl)    # H^2
+    call GFMUL
+    vmovdqa $T, 32($Htbl)    # H^3
+    call GFMUL
+    vmovdqa $T, 48($Htbl)    # H^4
+    call GFMUL
+    vmovdqa $T, 64($Htbl)    # H^5
+    call GFMUL
+    vmovdqa $T, 80($Htbl)    # H^6
+    ret
+.cfi_endproc
+.size aesgcmsiv_htable6_init, .-aesgcmsiv_htable6_init
+___
+}
+aesgcmsiv_htable6_init();
+
+sub aesgcmsiv_htable_polyval {
+  # void aesgcmsiv_htable_polyval(uint8_t Htbl[16*8], uint8_t *MSG, uint64_t LEN, uint8_t *T);
+  # parameter 1: %rdi     Htable  - pointer to Htable
+  # parameter 2: %rsi     INp     - pointer to input
+  # parameter 3: %rdx     LEN     - length of BUFFER in bytes
+  # parameter 4: %rcx     T       - pointer to POLYVAL output
+
+  my $DATA = "%xmm0";
+  my $hlp0 = "%r11";
+  my $Htbl = "%rdi";
+  my $inp = "%rsi";
+  my $len = "%rdx";
+  my $TMP0 = "%xmm3";
+  my $TMP1 = "%xmm4";
+  my $TMP2 = "%xmm5";
+  my $TMP3 = "%xmm6";
+  my $TMP4 = "%xmm7";
+  my $Tp = "%rcx";
+  my $T = "%xmm1";
+  my $Xhi = "%xmm9";
+
+  my $SCHOOLBOOK_AAD = sub {
+    my ($i)=@_;
+    return <<___;
+    vpclmulqdq \$0x01, ${\eval(16*$i)}($Htbl), $DATA, $TMP3
+    vpxor $TMP3, $TMP2, $TMP2
+    vpclmulqdq \$0x00, ${\eval(16*$i)}($Htbl), $DATA, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+    vpclmulqdq \$0x11, ${\eval(16*$i)}($Htbl), $DATA, $TMP3
+    vpxor $TMP3, $TMP1, $TMP1
+    vpclmulqdq \$0x10, ${\eval(16*$i)}($Htbl), $DATA, $TMP3
+    vpxor $TMP3, $TMP2, $TMP2
+___
+  };
+
+  $code.=<<___;
+.globl aesgcmsiv_htable_polyval
+.type aesgcmsiv_htable_polyval,\@function,4
+.align 16
+aesgcmsiv_htable_polyval:
+.cfi_startproc
+    test  $len, $len
+    jnz   .Lhtable_polyval_start
+    ret
+
+.Lhtable_polyval_start:
+    vzeroall
+
+    # We hash 8 blocks each iteration. If the total number of blocks is not a
+    # multiple of 8, we first hash the leading n%8 blocks.
+    movq $len, $hlp0
+    andq \$127, $hlp0
+
+    jz .Lhtable_polyval_no_prefix
+
+    vpxor $Xhi, $Xhi, $Xhi
+    vmovdqa ($Tp), $T
+    sub $hlp0, $len
+
+    sub \$16, $hlp0
+
+    # hash first prefix block
+    vmovdqu ($inp), $DATA
+    vpxor $T, $DATA, $DATA
+
+    vpclmulqdq \$0x01, ($Htbl,$hlp0), $DATA, $TMP2
+    vpclmulqdq \$0x00, ($Htbl,$hlp0), $DATA, $TMP0
+    vpclmulqdq \$0x11, ($Htbl,$hlp0), $DATA, $TMP1
+    vpclmulqdq \$0x10, ($Htbl,$hlp0), $DATA, $TMP3
+    vpxor $TMP3, $TMP2, $TMP2
+
+    lea 16($inp), $inp
+    test $hlp0, $hlp0
+    jnz .Lhtable_polyval_prefix_loop
+    jmp .Lhtable_polyval_prefix_complete
+
+    # hash remaining prefix bocks (up to 7 total prefix blocks)
+.align 64
+.Lhtable_polyval_prefix_loop:
+    sub \$16, $hlp0
+
+    vmovdqu ($inp), $DATA           # next data block
+
+    vpclmulqdq  \$0x00, ($Htbl,$hlp0), $DATA, $TMP3
+    vpxor       $TMP3, $TMP0, $TMP0
+    vpclmulqdq  \$0x11, ($Htbl,$hlp0), $DATA, $TMP3
+    vpxor       $TMP3, $TMP1, $TMP1
+    vpclmulqdq  \$0x01, ($Htbl,$hlp0), $DATA, $TMP3
+    vpxor       $TMP3, $TMP2, $TMP2
+    vpclmulqdq  \$0x10, ($Htbl,$hlp0), $DATA, $TMP3
+    vpxor       $TMP3, $TMP2, $TMP2
+
+    test $hlp0, $hlp0
+
+    lea 16($inp), $inp
+
+    jnz .Lhtable_polyval_prefix_loop
+
+.Lhtable_polyval_prefix_complete:
+    vpsrldq \$8, $TMP2, $TMP3
+    vpslldq \$8, $TMP2, $TMP2
+
+    vpxor $TMP3, $TMP1, $Xhi
+    vpxor $TMP2, $TMP0, $T
+
+    jmp .Lhtable_polyval_main_loop
+
+.Lhtable_polyval_no_prefix:
+    # At this point we know the number of blocks is a multiple of 8. However,
+    # the reduction in the main loop includes a multiplication by x^(-128). In
+    # order to counter this, the existing tag needs to be multipled by x^128.
+    # In practice, this just means that it is loaded into $Xhi, not $T.
+    vpxor $T, $T, $T
+    vmovdqa ($Tp), $Xhi
+
+.align 64
+.Lhtable_polyval_main_loop:
+    sub \$0x80, $len
+    jb .Lhtable_polyval_out
+
+    vmovdqu 16*7($inp), $DATA      # Ii
+
+    vpclmulqdq \$0x01, ($Htbl), $DATA, $TMP2
+    vpclmulqdq \$0x00, ($Htbl), $DATA, $TMP0
+    vpclmulqdq \$0x11, ($Htbl), $DATA, $TMP1
+    vpclmulqdq \$0x10, ($Htbl), $DATA, $TMP3
+    vpxor $TMP3, $TMP2, $TMP2
+
+    #########################################################
+    vmovdqu 16*6($inp), $DATA
+    ${\$SCHOOLBOOK_AAD->(1)}
+
+    #########################################################
+    vmovdqu 16*5($inp), $DATA
+
+    vpclmulqdq \$0x10, poly(%rip), $T, $TMP4         # reduction stage 1a
+    vpalignr \$8, $T, $T, $T
+
+    ${\$SCHOOLBOOK_AAD->(2)}
+
+    vpxor $TMP4, $T, $T                              # reduction stage 1b
+    #########################################################
+    vmovdqu     16*4($inp), $DATA
+
+    ${\$SCHOOLBOOK_AAD->(3)}
+    #########################################################
+    vmovdqu     16*3($inp), $DATA
+
+    vpclmulqdq \$0x10, poly(%rip), $T, $TMP4         # reduction stage 2a
+    vpalignr \$8, $T, $T, $T
+
+    ${\$SCHOOLBOOK_AAD->(4)}
+
+    vpxor $TMP4, $T, $T                              # reduction stage 2b
+    #########################################################
+    vmovdqu 16*2($inp), $DATA
+
+    ${\$SCHOOLBOOK_AAD->(5)}
+
+    vpxor $Xhi, $T, $T                               # reduction finalize
+    #########################################################
+    vmovdqu 16*1($inp), $DATA
+
+    ${\$SCHOOLBOOK_AAD->(6)}
+    #########################################################
+    vmovdqu 16*0($inp), $DATA
+    vpxor $T, $DATA, $DATA
+
+    ${\$SCHOOLBOOK_AAD->(7)}
+    #########################################################
+    vpsrldq \$8, $TMP2, $TMP3
+    vpslldq \$8, $TMP2, $TMP2
+
+    vpxor $TMP3, $TMP1, $Xhi
+    vpxor $TMP2, $TMP0, $T
+
+    lea 16*8($inp), $inp
+    jmp .Lhtable_polyval_main_loop
+
+    #########################################################
+
+.Lhtable_polyval_out:
+    vpclmulqdq  \$0x10, poly(%rip), $T, $TMP3
+    vpalignr    \$8, $T, $T, $T
+    vpxor       $TMP3, $T, $T
+
+    vpclmulqdq  \$0x10, poly(%rip), $T, $TMP3
+    vpalignr    \$8, $T, $T, $T
+    vpxor       $TMP3, $T, $T
+    vpxor       $Xhi, $T, $T
+
+    vmovdqu $T, ($Tp)
+    vzeroupper
+    ret
+.cfi_endproc
+.size aesgcmsiv_htable_polyval,.-aesgcmsiv_htable_polyval
+___
+}
+aesgcmsiv_htable_polyval();
+
+sub aesgcmsiv_polyval_horner {
+  #void aesgcmsiv_polyval_horner(unsigned char T[16],  // output
+  #      const unsigned char* H, // H
+  #      unsigned char* BUF,  // Buffer
+  #      unsigned int blocks);  // Len2
+  #
+  # parameter 1: %rdi T - pointers to POLYVAL output
+  # parameter 2: %rsi Hp - pointer to H (user key)
+  # parameter 3: %rdx INp - pointer to input
+  # parameter 4: %rcx L - total number of blocks in input BUFFER
+  #
+  my $T = "%rdi";
+  my $Hp = "%rsi";
+  my $INp = "%rdx";
+  my $L = "%rcx";
+  my $LOC = "%r10";
+  my $LEN = "%eax";
+  my $H = "%xmm1";
+  my $RES = "%xmm0";
+
+  $code.=<<___;
+.globl aesgcmsiv_polyval_horner
+.type aesgcmsiv_polyval_horner,\@function,4
+.align 16
+aesgcmsiv_polyval_horner:
+.cfi_startproc
+    test $L, $L
+    jnz .Lpolyval_horner_start
+    ret
+
+.Lpolyval_horner_start:
+    # We will start with L GFMULS for POLYVAL(BIG_BUFFER)
+    # RES = GFMUL(RES, H)
+
+    xorq $LOC, $LOC
+    shlq \$4, $L    # L contains number of bytes to process
+
+    vmovdqa ($Hp), $H
+    vmovdqa ($T), $RES
+
+.Lpolyval_horner_loop:
+    vpxor ($INp,$LOC), $RES, $RES  # RES = RES + Xi
+    call GFMUL  # RES = RES * H
+
+    add \$16, $LOC
+    cmp $LOC, $L
+    jne .Lpolyval_horner_loop
+
+    # calculation of T is complete. RES=T
+    vmovdqa $RES, ($T)
+    ret
+.cfi_endproc
+.size aesgcmsiv_polyval_horner,.-aesgcmsiv_polyval_horner
+___
+}
+aesgcmsiv_polyval_horner();
+
+# void aes128gcmsiv_aes_ks(const uint8_t *key, uint8_t *out_expanded_key);
+# parameter 1: %rdi
+# parameter 2: %rsi
+$code.=<<___;
+.globl aes128gcmsiv_aes_ks
+.type aes128gcmsiv_aes_ks,\@function,2
+.align 16
+aes128gcmsiv_aes_ks:
+.cfi_startproc
+    vmovdqu (%rdi), %xmm1           # xmm1 = user key
+    vmovdqa %xmm1, (%rsi)           # rsi points to output
+
+    vmovdqa con1(%rip), %xmm0
+    vmovdqa mask(%rip), %xmm15
+
+    movq \$8, %rax
+
+.Lks128_loop:
+    addq \$16, %rsi                 # rsi points for next key
+    subq \$1, %rax
+    vpshufb %xmm15, %xmm1, %xmm2    # xmm2 = shuffled user key
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpslld \$1, %xmm0, %xmm0
+    vpslldq \$4, %xmm1, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpslldq \$4, %xmm3, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpslldq \$4, %xmm3, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpxor %xmm2, %xmm1, %xmm1
+    vmovdqa %xmm1, (%rsi)
+    jne .Lks128_loop
+
+    vmovdqa con2(%rip), %xmm0
+    vpshufb %xmm15, %xmm1, %xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpslld \$1, %xmm0, %xmm0
+    vpslldq \$4, %xmm1, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpslldq \$4, %xmm3, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpslldq \$4, %xmm3, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpxor %xmm2, %xmm1, %xmm1
+    vmovdqa %xmm1, 16(%rsi)
+
+    vpshufb %xmm15, %xmm1, %xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpslldq \$4, %xmm1, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpslldq \$4, %xmm3, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpslldq \$4, %xmm3, %xmm3
+    vpxor %xmm3, %xmm1, %xmm1
+    vpxor %xmm2, %xmm1, %xmm1
+    vmovdqa %xmm1, 32(%rsi)
+    ret
+.cfi_endproc
+.size aes128gcmsiv_aes_ks,.-aes128gcmsiv_aes_ks
+___
+
+# void aes256gcmsiv_aes_ks(const uint8_t *key, uint8_t *out_expanded_key);
+# parameter 1: %rdi
+# parameter 2: %rsi
+$code.=<<___;
+.globl aes256gcmsiv_aes_ks
+.type aes256gcmsiv_aes_ks,\@function,2
+.align 16
+aes256gcmsiv_aes_ks:
+.cfi_startproc
+    vmovdqu (%rdi), %xmm1
+    vmovdqu 16(%rdi), %xmm3
+    vmovdqa %xmm1, (%rsi)
+    vmovdqa %xmm3, 16(%rsi)
+    vmovdqa con1(%rip), %xmm0
+    vmovdqa mask(%rip), %xmm15
+    vpxor %xmm14, %xmm14, %xmm14
+    mov \$6, %rax
+
+.Lks256_loop:
+    add \$32, %rsi
+    subq \$1, %rax
+    vpshufb %xmm15, %xmm3, %xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpslld \$1, %xmm0, %xmm0
+    vpsllq \$32, %xmm1, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpshufb con3(%rip), %xmm1,  %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpxor %xmm2, %xmm1, %xmm1
+    vmovdqa %xmm1, (%rsi)
+    vpshufd \$0xff, %xmm1, %xmm2
+    vaesenclast %xmm14, %xmm2, %xmm2
+    vpsllq \$32, %xmm3, %xmm4
+    vpxor %xmm4, %xmm3, %xmm3
+    vpshufb con3(%rip), %xmm3,  %xmm4
+    vpxor %xmm4, %xmm3, %xmm3
+    vpxor %xmm2, %xmm3, %xmm3
+    vmovdqa %xmm3, 16(%rsi)
+    jne .Lks256_loop
+
+    vpshufb %xmm15, %xmm3, %xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpsllq \$32, %xmm1, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpshufb con3(%rip), %xmm1,  %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpxor %xmm2, %xmm1, %xmm1
+    vmovdqa %xmm1, 32(%rsi)
+    ret
+.cfi_endproc
+___
+
+sub aes128gcmsiv_aes_ks_enc_x1 {
+  my $KS1_REGA = "%xmm1";
+  my $KS1_REGB = "%xmm2";
+  my $BLOCK1 = "%xmm4";
+  my $AUXREG = "%xmm3";
+
+  my $KS_BLOCK = sub {
+    my ($reg, $reg2, $auxReg) = @_;
+    return <<___;
+    vpsllq \$32, $reg, $auxReg         #!!saving mov instruction to xmm3
+    vpxor $auxReg, $reg, $reg
+    vpshufb con3(%rip), $reg,  $auxReg
+    vpxor $auxReg, $reg, $reg
+    vpxor $reg2, $reg, $reg
+___
+  };
+
+  my $round = sub {
+    my ($i, $j) = @_;
+    return <<___;
+    vpshufb %xmm15, %xmm1, %xmm2      #!!saving mov instruction to xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpslld \$1, %xmm0, %xmm0
+    ${\$KS_BLOCK->($KS1_REGA, $KS1_REGB, $AUXREG)}
+    vaesenc %xmm1, $BLOCK1, $BLOCK1
+    vmovdqa %xmm1, ${\eval(16*$i)}($j)
+___
+  };
+
+  my $roundlast = sub {
+    my ($i, $j) = @_;
+    return <<___;
+    vpshufb %xmm15, %xmm1, %xmm2      #!!saving mov instruction to xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    ${\$KS_BLOCK->($KS1_REGA, $KS1_REGB, $AUXREG)}
+    vaesenclast %xmm1, $BLOCK1, $BLOCK1
+    vmovdqa %xmm1, ${\eval(16*$i)}($j)
+___
+  };
+
+# parameter 1: %rdi                         Pointer to PT
+# parameter 2: %rsi                         Pointer to CT
+# parameter 4: %rdx                         Pointer to keys
+# parameter 5: %rcx                         Pointer to initial key
+  $code.=<<___;
+.globl aes128gcmsiv_aes_ks_enc_x1
+.type aes128gcmsiv_aes_ks_enc_x1,\@function,4
+.align 16
+aes128gcmsiv_aes_ks_enc_x1:
+.cfi_startproc
+    vmovdqa (%rcx), %xmm1                 # xmm1 = first 16 bytes of random key
+    vmovdqa 0*16(%rdi), $BLOCK1
+
+    vmovdqa %xmm1, (%rdx)                 # KEY[0] = first 16 bytes of random key
+    vpxor %xmm1, $BLOCK1, $BLOCK1
+
+    vmovdqa con1(%rip), %xmm0             # xmm0  = 1,1,1,1
+    vmovdqa mask(%rip), %xmm15            # xmm15 = mask
+
+    ${\$round->(1, "%rdx")}
+    ${\$round->(2, "%rdx")}
+    ${\$round->(3, "%rdx")}
+    ${\$round->(4, "%rdx")}
+    ${\$round->(5, "%rdx")}
+    ${\$round->(6, "%rdx")}
+    ${\$round->(7, "%rdx")}
+    ${\$round->(8, "%rdx")}
+
+    vmovdqa con2(%rip), %xmm0
+
+    ${\$round->(9, "%rdx")}
+    ${\$roundlast->(10, "%rdx")}
+
+    vmovdqa $BLOCK1, 0*16(%rsi)
+    ret
+.cfi_endproc
+.size aes128gcmsiv_aes_ks_enc_x1,.-aes128gcmsiv_aes_ks_enc_x1
+___
+}
+aes128gcmsiv_aes_ks_enc_x1();
+
+sub aes128gcmsiv_kdf {
+  my $BLOCK1 = "%xmm9";
+  my $BLOCK2 = "%xmm10";
+  my $BLOCK3 = "%xmm11";
+  my $BLOCK4 = "%xmm12";
+  my $BLOCK5 = "%xmm13";
+  my $BLOCK6 = "%xmm14";
+  my $ONE = "%xmm13";
+  my $KSp = "%rdx";
+  my $STATE_1 = "%xmm1";
+
+  my $enc_roundx4 = sub {
+    my ($i, $j) = @_;
+    return <<___;
+    vmovdqa ${\eval($i*16)}(%rdx), $j
+    vaesenc $j, $BLOCK1, $BLOCK1
+    vaesenc $j, $BLOCK2, $BLOCK2
+    vaesenc $j, $BLOCK3, $BLOCK3
+    vaesenc $j, $BLOCK4, $BLOCK4
+___
+  };
+
+  my $enc_roundlastx4 = sub {
+    my ($i, $j) = @_;
+    return <<___;
+    vmovdqa ${\eval($i*16)}(%rdx), $j
+    vaesenclast $j, $BLOCK1, $BLOCK1
+    vaesenclast $j, $BLOCK2, $BLOCK2
+    vaesenclast $j, $BLOCK3, $BLOCK3
+    vaesenclast $j, $BLOCK4, $BLOCK4
+___
+  };
+
+# void aes128gcmsiv_kdf(const uint8_t nonce[16],
+#                       uint8_t *out_key_material,
+#                       const uint8_t *key_schedule);
+  $code.=<<___;
+.globl aes128gcmsiv_kdf
+.type aes128gcmsiv_kdf,\@function,3
+.align 16
+aes128gcmsiv_kdf:
+.cfi_startproc
+# parameter 1: %rdi                         Pointer to NONCE
+# parameter 2: %rsi                         Pointer to CT
+# parameter 4: %rdx                         Pointer to keys
+
+    vmovdqa (%rdx), %xmm1                  # xmm1 = first 16 bytes of random key
+    vmovdqa 0*16(%rdi), $BLOCK1
+    vmovdqa and_mask(%rip), $BLOCK4
+    vmovdqa one(%rip), $ONE
+    vpshufd \$0x90, $BLOCK1, $BLOCK1
+    vpand $BLOCK4, $BLOCK1, $BLOCK1
+    vpaddd $ONE, $BLOCK1, $BLOCK2
+    vpaddd $ONE, $BLOCK2, $BLOCK3
+    vpaddd $ONE, $BLOCK3, $BLOCK4
+
+    vpxor %xmm1, $BLOCK1, $BLOCK1
+    vpxor %xmm1, $BLOCK2, $BLOCK2
+    vpxor %xmm1, $BLOCK3, $BLOCK3
+    vpxor %xmm1, $BLOCK4, $BLOCK4
+
+    ${\$enc_roundx4->(1, "%xmm1")}
+    ${\$enc_roundx4->(2, "%xmm2")}
+    ${\$enc_roundx4->(3, "%xmm1")}
+    ${\$enc_roundx4->(4, "%xmm2")}
+    ${\$enc_roundx4->(5, "%xmm1")}
+    ${\$enc_roundx4->(6, "%xmm2")}
+    ${\$enc_roundx4->(7, "%xmm1")}
+    ${\$enc_roundx4->(8, "%xmm2")}
+    ${\$enc_roundx4->(9, "%xmm1")}
+    ${\$enc_roundlastx4->(10, "%xmm2")}
+
+    vmovdqa $BLOCK1, 0*16(%rsi)
+    vmovdqa $BLOCK2, 1*16(%rsi)
+    vmovdqa $BLOCK3, 2*16(%rsi)
+    vmovdqa $BLOCK4, 3*16(%rsi)
+    ret
+.cfi_endproc
+.size aes128gcmsiv_kdf,.-aes128gcmsiv_kdf
+___
+}
+aes128gcmsiv_kdf();
+
+sub aes128gcmsiv_enc_msg_x4 {
+  my $CTR1 = "%xmm0";
+  my $CTR2 = "%xmm1";
+  my $CTR3 = "%xmm2";
+  my $CTR4 = "%xmm3";
+  my $ADDER = "%xmm4";
+
+  my $STATE1 = "%xmm5";
+  my $STATE2 = "%xmm6";
+  my $STATE3 = "%xmm7";
+  my $STATE4 = "%xmm8";
+
+  my $TMP = "%xmm12";
+  my $TMP2 = "%xmm13";
+  my $TMP3 = "%xmm14";
+  my $IV = "%xmm15";
+
+  my $PT = "%rdi";
+  my $CT = "%rsi";
+  my $TAG = "%rdx";
+  my $KS = "%rcx";
+  my $LEN = "%r8";
+
+  my $aes_round = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $TMP
+    vaesenc $TMP, $STATE1, $STATE1
+    vaesenc $TMP, $STATE2, $STATE2
+    vaesenc $TMP, $STATE3, $STATE3
+    vaesenc $TMP, $STATE4, $STATE4
+___
+  };
+
+  my $aes_lastround = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $TMP
+    vaesenclast $TMP, $STATE1, $STATE1
+    vaesenclast $TMP, $STATE2, $STATE2
+    vaesenclast $TMP, $STATE3, $STATE3
+    vaesenclast $TMP, $STATE4, $STATE4
+___
+  };
+
+# void aes128gcmsiv_enc_msg_x4(unsigned char* PT, unsigned char* CT,
+#                              unsigned char* TAG, unsigned char* KS,
+#                              size_t byte_len);
+# parameter 1: %rdi     #PT
+# parameter 2: %rsi     #CT
+# parameter 3: %rdx     #TAG  [127 126 ... 0]  IV=[127...32]
+# parameter 4: %rcx     #KS
+# parameter 5: %r8      #LEN MSG_length in bytes
+  $code.=<<___;
+.globl aes128gcmsiv_enc_msg_x4
+.type aes128gcmsiv_enc_msg_x4,\@function,5
+.align 16
+aes128gcmsiv_enc_msg_x4:
+.cfi_startproc
+    test $LEN, $LEN
+    jnz .L128_enc_msg_x4_start
+    ret
+
+.L128_enc_msg_x4_start:
+    pushq %r12
+.cfi_push %r12
+    pushq %r13
+.cfi_push %r13
+
+    shrq \$4, $LEN      # LEN = num of blocks
+    movq $LEN, %r10
+    shlq \$62, %r10
+    shrq \$62, %r10
+
+    # make IV from TAG
+    vmovdqa ($TAG), $IV
+    vpor OR_MASK(%rip), $IV, $IV  #IV = [1]TAG[126...32][00..00]
+
+    vmovdqu four(%rip), $ADDER     # Register to increment counters
+    vmovdqa $IV, $CTR1             # CTR1 = TAG[1][127...32][00..00]
+    vpaddd one(%rip), $IV, $CTR2   # CTR2 = TAG[1][127...32][00..01]
+    vpaddd two(%rip), $IV, $CTR3   # CTR3 = TAG[1][127...32][00..02]
+    vpaddd three(%rip), $IV, $CTR4 # CTR4 = TAG[1][127...32][00..03]
+
+    shrq \$2, $LEN
+    je .L128_enc_msg_x4_check_remainder
+
+    subq \$64, $CT
+    subq \$64, $PT
+
+.L128_enc_msg_x4_loop1:
+    addq \$64, $CT
+    addq \$64, $PT
+
+    vmovdqa $CTR1, $STATE1
+    vmovdqa $CTR2, $STATE2
+    vmovdqa $CTR3, $STATE3
+    vmovdqa $CTR4, $STATE4
+
+    vpxor ($KS), $STATE1, $STATE1
+    vpxor ($KS), $STATE2, $STATE2
+    vpxor ($KS), $STATE3, $STATE3
+    vpxor ($KS), $STATE4, $STATE4
+
+    ${\$aes_round->(1)}
+    vpaddd $ADDER, $CTR1, $CTR1
+    ${\$aes_round->(2)}
+    vpaddd $ADDER, $CTR2, $CTR2
+    ${\$aes_round->(3)}
+    vpaddd $ADDER, $CTR3, $CTR3
+    ${\$aes_round->(4)}
+    vpaddd $ADDER, $CTR4, $CTR4
+
+    ${\$aes_round->(5)}
+    ${\$aes_round->(6)}
+    ${\$aes_round->(7)}
+    ${\$aes_round->(8)}
+    ${\$aes_round->(9)}
+    ${\$aes_lastround->(10)}
+
+    # XOR with Plaintext
+    vpxor 0*16($PT), $STATE1, $STATE1
+    vpxor 1*16($PT), $STATE2, $STATE2
+    vpxor 2*16($PT), $STATE3, $STATE3
+    vpxor 3*16($PT), $STATE4, $STATE4
+
+    subq \$1, $LEN
+
+    vmovdqu $STATE1, 0*16($CT)
+    vmovdqu $STATE2, 1*16($CT)
+    vmovdqu $STATE3, 2*16($CT)
+    vmovdqu $STATE4, 3*16($CT)
+
+    jne .L128_enc_msg_x4_loop1
+
+    addq \$64,$CT
+    addq \$64,$PT
+
+.L128_enc_msg_x4_check_remainder:
+    cmpq \$0, %r10
+    je .L128_enc_msg_x4_out
+
+.L128_enc_msg_x4_loop2:
+    # enc each block separately
+    # CTR1 is the highest counter (even if no LOOP done)
+    vmovdqa $CTR1, $STATE1
+    vpaddd one(%rip), $CTR1, $CTR1  # inc counter
+
+    vpxor ($KS), $STATE1, $STATE1
+    vaesenc 16($KS), $STATE1, $STATE1
+    vaesenc 32($KS), $STATE1, $STATE1
+    vaesenc 48($KS), $STATE1, $STATE1
+    vaesenc 64($KS), $STATE1, $STATE1
+    vaesenc 80($KS), $STATE1, $STATE1
+    vaesenc 96($KS), $STATE1, $STATE1
+    vaesenc 112($KS), $STATE1, $STATE1
+    vaesenc 128($KS), $STATE1, $STATE1
+    vaesenc 144($KS), $STATE1, $STATE1
+    vaesenclast 160($KS), $STATE1, $STATE1
+
+    # XOR with plaintext
+    vpxor ($PT), $STATE1, $STATE1
+    vmovdqu $STATE1, ($CT)
+
+    addq \$16, $PT
+    addq \$16, $CT
+
+    subq \$1, %r10
+    jne .L128_enc_msg_x4_loop2
+
+.L128_enc_msg_x4_out:
+    popq %r13
+.cfi_pop %r13
+    popq %r12
+.cfi_pop %r12
+    ret
+.cfi_endproc
+.size aes128gcmsiv_enc_msg_x4,.-aes128gcmsiv_enc_msg_x4
+___
+}
+aes128gcmsiv_enc_msg_x4();
+
+sub aes128gcmsiv_enc_msg_x8 {
+  my $STATE1 = "%xmm1";
+  my $STATE2 = "%xmm2";
+  my $STATE3 = "%xmm3";
+  my $STATE4 = "%xmm4";
+  my $STATE5 = "%xmm5";
+  my $STATE6 = "%xmm6";
+  my $STATE7 = "%xmm7";
+  my $STATE8 = "%xmm8";
+
+  my $CTR1 = "%xmm0";
+  my $CTR2 = "%xmm9";
+  my $CTR3 = "%xmm10";
+  my $CTR4 = "%xmm11";
+  my $CTR5 = "%xmm12";
+  my $CTR6 = "%xmm13";
+  my $CTR7 = "%xmm14";
+  my $SCHED = "%xmm15";
+
+  my $TMP1 = "%xmm1";
+  my $TMP2 = "%xmm2";
+
+  my $PT = "%rdi";
+  my $CT = "%rsi";
+  my $TAG = "%rdx";
+  my $KS = "%rcx";
+  my $LEN = "%r8";
+
+  my $aes_round8 = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $SCHED
+    vaesenc $SCHED, $STATE1, $STATE1
+    vaesenc $SCHED, $STATE2, $STATE2
+    vaesenc $SCHED, $STATE3, $STATE3
+    vaesenc $SCHED, $STATE4, $STATE4
+    vaesenc $SCHED, $STATE5, $STATE5
+    vaesenc $SCHED, $STATE6, $STATE6
+    vaesenc $SCHED, $STATE7, $STATE7
+    vaesenc $SCHED, $STATE8, $STATE8
+___
+  };
+
+  my $aes_lastround8 = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $SCHED
+    vaesenclast $SCHED, $STATE1, $STATE1
+    vaesenclast $SCHED, $STATE2, $STATE2
+    vaesenclast $SCHED, $STATE3, $STATE3
+    vaesenclast $SCHED, $STATE4, $STATE4
+    vaesenclast $SCHED, $STATE5, $STATE5
+    vaesenclast $SCHED, $STATE6, $STATE6
+    vaesenclast $SCHED, $STATE7, $STATE7
+    vaesenclast $SCHED, $STATE8, $STATE8
+___
+  };
+
+# void ENC_MSG_x8(unsigned char* PT,
+#                 unsigned char* CT,
+#                 unsigned char* TAG,
+#                 unsigned char* KS,
+#                 size_t byte_len);
+# parameter 1: %rdi     #PT
+# parameter 2: %rsi     #CT
+# parameter 3: %rdx     #TAG        [127 126 ... 0]  IV=[127...32]
+# parameter 4: %rcx     #KS
+# parameter 5: %r8      #LEN MSG_length in bytes
+  $code.=<<___;
+.globl aes128gcmsiv_enc_msg_x8
+.type aes128gcmsiv_enc_msg_x8,\@function,5
+.align 16
+aes128gcmsiv_enc_msg_x8:
+.cfi_startproc
+    test $LEN, $LEN
+    jnz .L128_enc_msg_x8_start
+    ret
+
+.L128_enc_msg_x8_start:
+    pushq %r12
+.cfi_push %r12
+    pushq %r13
+.cfi_push %r13
+    pushq %rbp
+.cfi_push %rbp
+    movq %rsp, %rbp
+.cfi_def_cfa_register rbp
+
+    # Place in stack
+    subq \$128, %rsp
+    andq \$-64, %rsp
+
+    shrq \$4, $LEN  # LEN = num of blocks
+    movq $LEN, %r10
+    shlq \$61, %r10
+    shrq \$61, %r10
+
+    # make IV from TAG
+    vmovdqu ($TAG), $TMP1
+    vpor OR_MASK(%rip), $TMP1, $TMP1  # TMP1= IV = [1]TAG[126...32][00..00]
+
+    # store counter8 in the stack
+    vpaddd seven(%rip), $TMP1, $CTR1
+    vmovdqu $CTR1, (%rsp)             # CTR8 = TAG[127...32][00..07]
+    vpaddd one(%rip), $TMP1, $CTR2    # CTR2 = TAG[127...32][00..01]
+    vpaddd two(%rip), $TMP1, $CTR3    # CTR3 = TAG[127...32][00..02]
+    vpaddd three(%rip), $TMP1, $CTR4  # CTR4 = TAG[127...32][00..03]
+    vpaddd four(%rip), $TMP1, $CTR5   # CTR5 = TAG[127...32][00..04]
+    vpaddd five(%rip), $TMP1, $CTR6   # CTR6 = TAG[127...32][00..05]
+    vpaddd six(%rip), $TMP1, $CTR7    # CTR7 = TAG[127...32][00..06]
+    vmovdqa $TMP1, $CTR1              # CTR1 = TAG[127...32][00..00]
+
+    shrq \$3, $LEN
+    je .L128_enc_msg_x8_check_remainder
+
+    subq \$128, $CT
+    subq \$128, $PT
+
+.L128_enc_msg_x8_loop1:
+    addq \$128, $CT
+    addq \$128, $PT
+
+    vmovdqa $CTR1, $STATE1
+    vmovdqa $CTR2, $STATE2
+    vmovdqa $CTR3, $STATE3
+    vmovdqa $CTR4, $STATE4
+    vmovdqa $CTR5, $STATE5
+    vmovdqa $CTR6, $STATE6
+    vmovdqa $CTR7, $STATE7
+    # move from stack
+    vmovdqu (%rsp), $STATE8
+
+    vpxor ($KS), $STATE1, $STATE1
+    vpxor ($KS), $STATE2, $STATE2
+    vpxor ($KS), $STATE3, $STATE3
+    vpxor ($KS), $STATE4, $STATE4
+    vpxor ($KS), $STATE5, $STATE5
+    vpxor ($KS), $STATE6, $STATE6
+    vpxor ($KS), $STATE7, $STATE7
+    vpxor ($KS), $STATE8, $STATE8
+
+    ${\$aes_round8->(1)}
+    vmovdqu (%rsp), $CTR7  # deal with CTR8
+    vpaddd eight(%rip), $CTR7, $CTR7
+    vmovdqu $CTR7, (%rsp)
+    ${\$aes_round8->(2)}
+    vpsubd one(%rip), $CTR7, $CTR7
+    ${\$aes_round8->(3)}
+    vpaddd eight(%rip), $CTR1, $CTR1
+    ${\$aes_round8->(4)}
+    vpaddd eight(%rip), $CTR2, $CTR2
+    ${\$aes_round8->(5)}
+    vpaddd eight(%rip), $CTR3, $CTR3
+    ${\$aes_round8->(6)}
+    vpaddd eight(%rip), $CTR4, $CTR4
+    ${\$aes_round8->(7)}
+    vpaddd eight(%rip), $CTR5, $CTR5
+    ${\$aes_round8->(8)}
+    vpaddd eight(%rip), $CTR6, $CTR6
+    ${\$aes_round8->(9)}
+    ${\$aes_lastround8->(10)}
+
+    # XOR with Plaintext
+    vpxor 0*16($PT), $STATE1, $STATE1
+    vpxor 1*16($PT), $STATE2, $STATE2
+    vpxor 2*16($PT), $STATE3, $STATE3
+    vpxor 3*16($PT), $STATE4, $STATE4
+    vpxor 4*16($PT), $STATE5, $STATE5
+    vpxor 5*16($PT), $STATE6, $STATE6
+    vpxor 6*16($PT), $STATE7, $STATE7
+    vpxor 7*16($PT), $STATE8, $STATE8
+
+    dec $LEN
+
+    vmovdqu $STATE1, 0*16($CT)
+    vmovdqu $STATE2, 1*16($CT)
+    vmovdqu $STATE3, 2*16($CT)
+    vmovdqu $STATE4, 3*16($CT)
+    vmovdqu $STATE5, 4*16($CT)
+    vmovdqu $STATE6, 5*16($CT)
+    vmovdqu $STATE7, 6*16($CT)
+    vmovdqu $STATE8, 7*16($CT)
+
+    jne .L128_enc_msg_x8_loop1
+
+    addq \$128, $CT
+    addq \$128, $PT
+
+.L128_enc_msg_x8_check_remainder:
+    cmpq \$0, %r10
+    je .L128_enc_msg_x8_out
+
+.L128_enc_msg_x8_loop2:
+    # enc each block separately
+    # CTR1 is the highest counter (even if no LOOP done)
+    vmovdqa $CTR1, $STATE1
+    vpaddd one(%rip), $CTR1, $CTR1  # inc counter
+
+    vpxor ($KS), $STATE1, $STATE1
+    vaesenc 16($KS), $STATE1, $STATE1
+    vaesenc 32($KS), $STATE1, $STATE1
+    vaesenc 48($KS), $STATE1, $STATE1
+    vaesenc 64($KS), $STATE1, $STATE1
+    vaesenc 80($KS), $STATE1, $STATE1
+    vaesenc 96($KS), $STATE1, $STATE1
+    vaesenc 112($KS), $STATE1, $STATE1
+    vaesenc 128($KS), $STATE1, $STATE1
+    vaesenc 144($KS), $STATE1, $STATE1
+    vaesenclast 160($KS), $STATE1, $STATE1
+
+    # XOR with Plaintext
+    vpxor ($PT), $STATE1, $STATE1
+
+    vmovdqu $STATE1, ($CT)
+
+    addq \$16, $PT
+    addq \$16, $CT
+
+    decq %r10
+    jne .L128_enc_msg_x8_loop2
+
+.L128_enc_msg_x8_out:
+    movq %rbp, %rsp
+.cfi_def_cfa_register %rsp
+    popq %rbp
+.cfi_pop %rbp
+    popq %r13
+.cfi_pop %r13
+    popq %r12
+.cfi_pop %r12
+    ret
+.cfi_endproc
+.size aes128gcmsiv_enc_msg_x8,.-aes128gcmsiv_enc_msg_x8
+___
+}
+aes128gcmsiv_enc_msg_x8();
+
+sub aesgcmsiv_dec {
+  my ($aes256) = @_;
+
+  my $T = "%xmm0";
+  my $TMP0 = "%xmm1";
+  my $TMP1 = "%xmm2";
+  my $TMP2 = "%xmm3";
+  my $TMP3 = "%xmm4";
+  my $TMP4 = "%xmm5";
+  my $TMP5 = "%xmm6";
+  my $CTR1 = "%xmm7";
+  my $CTR2 = "%xmm8";
+  my $CTR3 = "%xmm9";
+  my $CTR4 = "%xmm10";
+  my $CTR5 = "%xmm11";
+  my $CTR6 = "%xmm12";
+  my $CTR = "%xmm15";
+  my $CT = "%rdi";
+  my $PT = "%rsi";
+  my $POL = "%rdx";
+  my $Htbl = "%rcx";
+  my $KS = "%r8";
+  my $LEN = "%r9";
+  my $secureBuffer = "%rax";
+  my $HTABLE_ROUNDS = "%xmm13";
+
+  my $labelPrefix = "128";
+  if ($aes256) {
+    $labelPrefix = "256";
+  }
+
+  my $aes_round_dec = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $TMP3
+    vaesenc $TMP3, $CTR1, $CTR1
+    vaesenc $TMP3, $CTR2, $CTR2
+    vaesenc $TMP3, $CTR3, $CTR3
+    vaesenc $TMP3, $CTR4, $CTR4
+    vaesenc $TMP3, $CTR5, $CTR5
+    vaesenc $TMP3, $CTR6, $CTR6
+___
+  };
+
+  my $aes_lastround_dec = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $TMP3
+    vaesenclast $TMP3, $CTR1, $CTR1
+    vaesenclast $TMP3, $CTR2, $CTR2
+    vaesenclast $TMP3, $CTR3, $CTR3
+    vaesenclast $TMP3, $CTR4, $CTR4
+    vaesenclast $TMP3, $CTR5, $CTR5
+    vaesenclast $TMP3, $CTR6, $CTR6
+___
+  };
+
+  my $schoolbook = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16-32)}($secureBuffer), $TMP5
+    vmovdqu ${\eval($i*16-32)}($Htbl), $HTABLE_ROUNDS
+
+    vpclmulqdq \$0x10, $HTABLE_ROUNDS, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+    vpclmulqdq \$0x11, $HTABLE_ROUNDS, $TMP5, $TMP3
+    vpxor $TMP3, $TMP1, $TMP1
+    vpclmulqdq \$0x00, $HTABLE_ROUNDS, $TMP5, $TMP3
+    vpxor $TMP3, $TMP2, $TMP2
+    vpclmulqdq \$0x01, $HTABLE_ROUNDS, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+___
+  };
+
+  if ($aes256) {
+    $code.=<<___;
+.globl aes256gcmsiv_dec
+.type aes256gcmsiv_dec,\@function,6
+.align 16
+aes256gcmsiv_dec:
+___
+  } else {
+    $code.=<<___;
+.globl aes128gcmsiv_dec
+.type aes128gcmsiv_dec,\@function,6
+.align 16
+aes128gcmsiv_dec:
+___
+  }
+
+  $code.=<<___;
+.cfi_startproc
+    test \$~15, $LEN
+    jnz .L${labelPrefix}_dec_start
+    ret
+
+.L${labelPrefix}_dec_start:
+    vzeroupper
+    vmovdqa ($POL), $T
+    movq $POL, $secureBuffer
+
+    leaq 32($secureBuffer), $secureBuffer
+    leaq 32($Htbl), $Htbl
+
+    # make CTRBLKs from given tag.
+    vmovdqu ($CT,$LEN), $CTR
+    vpor OR_MASK(%rip), $CTR, $CTR      # CTR = [1]TAG[126...32][00..00]
+    andq \$~15, $LEN
+
+    # If less then 6 blocks, make singles
+    cmp \$96, $LEN
+    jb .L${labelPrefix}_dec_loop2
+
+    # Decrypt the first six blocks
+    sub \$96, $LEN
+    vmovdqa $CTR, $CTR1
+    vpaddd one(%rip), $CTR1, $CTR2
+    vpaddd two(%rip), $CTR1, $CTR3
+    vpaddd one(%rip), $CTR3, $CTR4
+    vpaddd two(%rip), $CTR3, $CTR5
+    vpaddd one(%rip), $CTR5, $CTR6
+    vpaddd two(%rip), $CTR5, $CTR
+
+    vpxor ($KS), $CTR1, $CTR1
+    vpxor ($KS), $CTR2, $CTR2
+    vpxor ($KS), $CTR3, $CTR3
+    vpxor ($KS), $CTR4, $CTR4
+    vpxor ($KS), $CTR5, $CTR5
+    vpxor ($KS), $CTR6, $CTR6
+
+    ${\$aes_round_dec->(1)}
+    ${\$aes_round_dec->(2)}
+    ${\$aes_round_dec->(3)}
+    ${\$aes_round_dec->(4)}
+    ${\$aes_round_dec->(5)}
+    ${\$aes_round_dec->(6)}
+    ${\$aes_round_dec->(7)}
+    ${\$aes_round_dec->(8)}
+    ${\$aes_round_dec->(9)}
+___
+
+if ($aes256) {
+$code.=<<___;
+    ${\$aes_round_dec->(10)}
+    ${\$aes_round_dec->(11)}
+    ${\$aes_round_dec->(12)}
+    ${\$aes_round_dec->(13)}
+    ${\$aes_lastround_dec->(14)}
+___
+} else {
+$code.=<<___;
+    ${\$aes_lastround_dec->(10)}
+___
+}
+
+$code.=<<___;
+    # XOR with CT
+    vpxor 0*16($CT), $CTR1, $CTR1
+    vpxor 1*16($CT), $CTR2, $CTR2
+    vpxor 2*16($CT), $CTR3, $CTR3
+    vpxor 3*16($CT), $CTR4, $CTR4
+    vpxor 4*16($CT), $CTR5, $CTR5
+    vpxor 5*16($CT), $CTR6, $CTR6
+
+    vmovdqu $CTR1, 0*16($PT)
+    vmovdqu $CTR2, 1*16($PT)
+    vmovdqu $CTR3, 2*16($PT)
+    vmovdqu $CTR4, 3*16($PT)
+    vmovdqu $CTR5, 4*16($PT)
+    vmovdqu $CTR6, 5*16($PT)
+
+    addq \$96, $CT
+    addq \$96, $PT
+    jmp .L${labelPrefix}_dec_loop1
+
+# Decrypt 6 blocks each time while hashing previous 6 blocks
+.align 64
+.L${labelPrefix}_dec_loop1:
+    cmp \$96, $LEN
+    jb .L${labelPrefix}_dec_finish_96
+    sub \$96, $LEN
+
+    vmovdqa $CTR6, $TMP5
+    vmovdqa $CTR5, 1*16-32($secureBuffer)
+    vmovdqa $CTR4, 2*16-32($secureBuffer)
+    vmovdqa $CTR3, 3*16-32($secureBuffer)
+    vmovdqa $CTR2, 4*16-32($secureBuffer)
+    vmovdqa $CTR1, 5*16-32($secureBuffer)
+
+    vmovdqa $CTR, $CTR1
+    vpaddd one(%rip), $CTR1, $CTR2
+    vpaddd two(%rip), $CTR1, $CTR3
+    vpaddd one(%rip), $CTR3, $CTR4
+    vpaddd two(%rip), $CTR3, $CTR5
+    vpaddd one(%rip), $CTR5, $CTR6
+    vpaddd two(%rip), $CTR5, $CTR
+
+    vmovdqa ($KS), $TMP3
+    vpxor $TMP3, $CTR1, $CTR1
+    vpxor $TMP3, $CTR2, $CTR2
+    vpxor $TMP3, $CTR3, $CTR3
+    vpxor $TMP3, $CTR4, $CTR4
+    vpxor $TMP3, $CTR5, $CTR5
+    vpxor $TMP3, $CTR6, $CTR6
+
+    vmovdqu 0*16-32($Htbl), $TMP3
+    vpclmulqdq \$0x11, $TMP3, $TMP5, $TMP1
+    vpclmulqdq \$0x00, $TMP3, $TMP5, $TMP2
+    vpclmulqdq \$0x01, $TMP3, $TMP5, $TMP0
+    vpclmulqdq \$0x10, $TMP3, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+
+    ${\$aes_round_dec->(1)}
+    ${\$schoolbook->(1)}
+
+    ${\$aes_round_dec->(2)}
+    ${\$schoolbook->(2)}
+
+    ${\$aes_round_dec->(3)}
+    ${\$schoolbook->(3)}
+
+    ${\$aes_round_dec->(4)}
+    ${\$schoolbook->(4)}
+
+    ${\$aes_round_dec->(5)}
+    ${\$aes_round_dec->(6)}
+    ${\$aes_round_dec->(7)}
+
+    vmovdqa 5*16-32($secureBuffer), $TMP5
+    vpxor $T, $TMP5, $TMP5
+    vmovdqu 5*16-32($Htbl), $TMP4
+
+    vpclmulqdq \$0x01, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+    vpclmulqdq \$0x11, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP1, $TMP1
+    vpclmulqdq \$0x00, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP2, $TMP2
+    vpclmulqdq \$0x10, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+
+    ${\$aes_round_dec->(8)}
+
+    vpsrldq \$8, $TMP0, $TMP3
+    vpxor $TMP3, $TMP1, $TMP4
+    vpslldq \$8, $TMP0, $TMP3
+    vpxor $TMP3, $TMP2, $T
+
+    vmovdqa poly(%rip), $TMP2
+
+    ${\$aes_round_dec->(9)}
+___
+
+if ($aes256) {
+$code.=<<___;
+    ${\$aes_round_dec->(10)}
+    ${\$aes_round_dec->(11)}
+    ${\$aes_round_dec->(12)}
+    ${\$aes_round_dec->(13)}
+    vmovdqu 14*16($KS), $TMP5
+___
+} else {
+$code.=<<___;
+    vmovdqu 10*16($KS), $TMP5
+___
+}
+
+$code.=<<___;
+    vpalignr \$8, $T, $T, $TMP1
+    vpclmulqdq \$0x10, $TMP2, $T, $T
+    vpxor $T, $TMP1, $T
+
+    vpxor 0*16($CT), $TMP5, $TMP3
+    vaesenclast $TMP3, $CTR1, $CTR1
+    vpxor 1*16($CT), $TMP5, $TMP3
+    vaesenclast $TMP3, $CTR2, $CTR2
+    vpxor 2*16($CT), $TMP5, $TMP3
+    vaesenclast $TMP3, $CTR3, $CTR3
+    vpxor 3*16($CT), $TMP5, $TMP3
+    vaesenclast $TMP3, $CTR4, $CTR4
+    vpxor 4*16($CT), $TMP5, $TMP3
+    vaesenclast $TMP3, $CTR5, $CTR5
+    vpxor 5*16($CT), $TMP5, $TMP3
+    vaesenclast $TMP3, $CTR6, $CTR6
+
+    vpalignr \$8, $T, $T, $TMP1
+    vpclmulqdq \$0x10, $TMP2, $T, $T
+    vpxor $T, $TMP1, $T
+
+    vmovdqu $CTR1, 0*16($PT)
+    vmovdqu $CTR2, 1*16($PT)
+    vmovdqu $CTR3, 2*16($PT)
+    vmovdqu $CTR4, 3*16($PT)
+    vmovdqu $CTR5, 4*16($PT)
+    vmovdqu $CTR6, 5*16($PT)
+
+    vpxor $TMP4, $T, $T
+
+    lea 96($CT), $CT
+    lea 96($PT), $PT
+    jmp .L${labelPrefix}_dec_loop1
+
+.L${labelPrefix}_dec_finish_96:
+    vmovdqa $CTR6, $TMP5
+    vmovdqa $CTR5, 1*16-32($secureBuffer)
+    vmovdqa $CTR4, 2*16-32($secureBuffer)
+    vmovdqa $CTR3, 3*16-32($secureBuffer)
+    vmovdqa $CTR2, 4*16-32($secureBuffer)
+    vmovdqa $CTR1, 5*16-32($secureBuffer)
+
+    vmovdqu 0*16-32($Htbl), $TMP3
+    vpclmulqdq \$0x10, $TMP3, $TMP5, $TMP0
+    vpclmulqdq \$0x11, $TMP3, $TMP5, $TMP1
+    vpclmulqdq \$0x00, $TMP3, $TMP5, $TMP2
+    vpclmulqdq \$0x01, $TMP3, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+
+    ${\$schoolbook->(1)}
+    ${\$schoolbook->(2)}
+    ${\$schoolbook->(3)}
+    ${\$schoolbook->(4)}
+
+    vmovdqu 5*16-32($secureBuffer), $TMP5
+    vpxor $T, $TMP5, $TMP5
+    vmovdqu 5*16-32($Htbl), $TMP4
+    vpclmulqdq \$0x11, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP1, $TMP1
+    vpclmulqdq \$0x00, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP2, $TMP2
+    vpclmulqdq \$0x10, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+    vpclmulqdq \$0x01, $TMP4, $TMP5, $TMP3
+    vpxor $TMP3, $TMP0, $TMP0
+
+    vpsrldq \$8, $TMP0, $TMP3
+    vpxor $TMP3, $TMP1, $TMP4
+    vpslldq \$8, $TMP0, $TMP3
+    vpxor $TMP3, $TMP2, $T
+
+    vmovdqa poly(%rip), $TMP2
+
+    vpalignr \$8, $T, $T, $TMP1
+    vpclmulqdq \$0x10, $TMP2, $T, $T
+    vpxor $T, $TMP1, $T
+
+    vpalignr \$8, $T, $T, $TMP1
+    vpclmulqdq \$0x10, $TMP2, $T, $T
+    vpxor $T, $TMP1, $T
+
+    vpxor $TMP4, $T, $T
+
+.L${labelPrefix}_dec_loop2:
+    # Here we encrypt any remaining whole block
+
+    # if there are no whole blocks
+    cmp \$16, $LEN
+    jb .L${labelPrefix}_dec_out
+    sub \$16, $LEN
+
+    vmovdqa $CTR, $TMP1
+    vpaddd one(%rip), $CTR, $CTR
+
+    vpxor 0*16($KS), $TMP1, $TMP1
+    vaesenc 1*16($KS), $TMP1, $TMP1
+    vaesenc 2*16($KS), $TMP1, $TMP1
+    vaesenc 3*16($KS), $TMP1, $TMP1
+    vaesenc 4*16($KS), $TMP1, $TMP1
+    vaesenc 5*16($KS), $TMP1, $TMP1
+    vaesenc 6*16($KS), $TMP1, $TMP1
+    vaesenc 7*16($KS), $TMP1, $TMP1
+    vaesenc 8*16($KS), $TMP1, $TMP1
+    vaesenc 9*16($KS), $TMP1, $TMP1
+___
+if ($aes256) {
+$code.=<<___;
+    vaesenc 10*16($KS), $TMP1, $TMP1
+    vaesenc 11*16($KS), $TMP1, $TMP1
+    vaesenc 12*16($KS), $TMP1, $TMP1
+    vaesenc 13*16($KS), $TMP1, $TMP1
+    vaesenclast 14*16($KS), $TMP1, $TMP1
+___
+} else {
+$code.=<<___;
+    vaesenclast 10*16($KS), $TMP1, $TMP1
+___
+}
+
+$code.=<<___;
+    vpxor ($CT), $TMP1, $TMP1
+    vmovdqu $TMP1, ($PT)
+    addq \$16, $CT
+    addq \$16, $PT
+
+    vpxor $TMP1, $T, $T
+    vmovdqa -32($Htbl), $TMP0
+    call GFMUL
+
+    jmp .L${labelPrefix}_dec_loop2
+
+.L${labelPrefix}_dec_out:
+    vmovdqu $T, ($POL)
+    ret
+.cfi_endproc
+___
+
+  if ($aes256) {
+    $code.=<<___;
+.size aes256gcmsiv_dec, .-aes256gcmsiv_dec
+___
+  } else {
+    $code.=<<___;
+.size aes128gcmsiv_dec, .-aes128gcmsiv_dec
+___
+  }
+}
+
+aesgcmsiv_dec(0);  # emit 128-bit version
+
+sub aes128gcmsiv_ecb_enc_block {
+  my $STATE_1 = "%xmm1";
+  my $KSp = "%rdx";
+
+  # parameter 1: PT            %rdi    (pointer to 128 bit)
+  # parameter 2: CT            %rsi    (pointer to 128 bit)
+  # parameter 3: ks            %rdx    (pointer to ks)
+  $code.=<<___;
+.globl aes128gcmsiv_ecb_enc_block
+.type aes128gcmsiv_ecb_enc_block,\@function,3
+.align 16
+aes128gcmsiv_ecb_enc_block:
+.cfi_startproc
+    vmovdqa (%rdi), $STATE_1
+
+    vpxor       ($KSp), $STATE_1, $STATE_1
+    vaesenc 1*16($KSp), $STATE_1, $STATE_1
+    vaesenc 2*16($KSp), $STATE_1, $STATE_1
+    vaesenc 3*16($KSp), $STATE_1, $STATE_1
+    vaesenc 4*16($KSp), $STATE_1, $STATE_1
+    vaesenc 5*16($KSp), $STATE_1, $STATE_1
+    vaesenc 6*16($KSp), $STATE_1, $STATE_1
+    vaesenc 7*16($KSp), $STATE_1, $STATE_1
+    vaesenc 8*16($KSp), $STATE_1, $STATE_1
+    vaesenc 9*16($KSp), $STATE_1, $STATE_1
+    vaesenclast 10*16($KSp), $STATE_1, $STATE_1    # STATE_1 == IV
+
+    vmovdqa $STATE_1, (%rsi)
+
+    ret
+.cfi_endproc
+.size aes128gcmsiv_ecb_enc_block,.-aes128gcmsiv_ecb_enc_block
+___
+}
+aes128gcmsiv_ecb_enc_block();
+
+sub aes256gcmsiv_aes_ks_enc_x1 {
+  my $KS = "%rdx";
+  my $KEYp = "%rcx";
+  my $CON_MASK = "%xmm0";
+  my $MASK_256 = "%xmm15";
+  my $KEY_1 = "%xmm1";
+  my $KEY_2 = "%xmm3";
+  my $BLOCK1 = "%xmm8";
+  my $AUX_REG = "%xmm14";
+  my $PT = "%rdi";
+  my $CT = "%rsi";
+
+  my $round_double = sub {
+    my ($i, $j) = @_;
+    return <<___;
+    vpshufb %xmm15, %xmm3, %xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpslld \$1, %xmm0, %xmm0
+    vpslldq \$4, %xmm1, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpslldq \$4, %xmm4, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpslldq \$4, %xmm4, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpxor %xmm2, %xmm1, %xmm1
+    vaesenc %xmm1, $BLOCK1, $BLOCK1
+    vmovdqu %xmm1, ${\eval(16*$i)}($KS)
+
+    vpshufd \$0xff, %xmm1, %xmm2
+    vaesenclast %xmm14, %xmm2, %xmm2
+    vpslldq \$4, %xmm3, %xmm4
+    vpxor %xmm4, %xmm3, %xmm3
+    vpslldq \$4, %xmm4, %xmm4
+    vpxor %xmm4, %xmm3, %xmm3
+    vpslldq \$4, %xmm4, %xmm4
+    vpxor %xmm4, %xmm3, %xmm3
+    vpxor %xmm2, %xmm3, %xmm3
+    vaesenc %xmm3, $BLOCK1, $BLOCK1
+    vmovdqu %xmm3, ${\eval(16*$j)}($KS)
+___
+  };
+
+  my $round_last = sub {
+    my ($i) = @_;
+    return <<___;
+    vpshufb %xmm15, %xmm3, %xmm2
+    vaesenclast %xmm0, %xmm2, %xmm2
+    vpslldq \$4, %xmm1, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpslldq \$4, %xmm4, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpslldq \$4, %xmm4, %xmm4
+    vpxor %xmm4, %xmm1, %xmm1
+    vpxor %xmm2, %xmm1, %xmm1
+    vaesenclast %xmm1, $BLOCK1, $BLOCK1
+    vmovdqu %xmm1, ${\eval(16*$i)}($KS)
+___
+  };
+
+  # parameter 1: %rdi         Pointer to PT1
+  # parameter 2: %rsi         Pointer to CT1
+  # parameter 3: %rdx         Pointer to KS
+  # parameter 4: %rcx         Pointer to initial key
+  $code.=<<___;
+.globl aes256gcmsiv_aes_ks_enc_x1
+.type aes256gcmsiv_aes_ks_enc_x1,\@function,4
+.align 16
+aes256gcmsiv_aes_ks_enc_x1:
+.cfi_startproc
+    vmovdqa con1(%rip), $CON_MASK    # CON_MASK  = 1,1,1,1
+    vmovdqa mask(%rip), $MASK_256    # MASK_256
+    vmovdqa ($PT), $BLOCK1
+    vmovdqa ($KEYp), $KEY_1          # KEY_1 || KEY_2 [0..7] = user key
+    vmovdqa 16($KEYp), $KEY_2
+    vpxor $KEY_1, $BLOCK1, $BLOCK1
+    vaesenc $KEY_2, $BLOCK1, $BLOCK1
+    vmovdqu $KEY_1, ($KS)            # First round key
+    vmovdqu $KEY_2, 16($KS)
+    vpxor $AUX_REG, $AUX_REG, $AUX_REG
+
+    ${\$round_double->(2, 3)}
+    ${\$round_double->(4, 5)}
+    ${\$round_double->(6, 7)}
+    ${\$round_double->(8, 9)}
+    ${\$round_double->(10, 11)}
+    ${\$round_double->(12, 13)}
+    ${\$round_last->(14)}
+    vmovdqa $BLOCK1, ($CT)
+    ret
+.cfi_endproc
+.size aes256gcmsiv_aes_ks_enc_x1,.-aes256gcmsiv_aes_ks_enc_x1
+___
+}
+aes256gcmsiv_aes_ks_enc_x1();
+
+sub aes256gcmsiv_ecb_enc_block {
+  my $STATE_1 = "%xmm1";
+  my $PT = "%rdi";
+  my $CT = "%rsi";
+  my $KSp = "%rdx";
+
+  # parameter 1: PT            %rdi    (pointer to 128 bit)
+  # parameter 2: CT            %rsi    (pointer to 128 bit)
+  # parameter 3: ks            %rdx    (pointer to ks)
+  $code.=<<___;
+.globl aes256gcmsiv_ecb_enc_block
+.type aes256gcmsiv_ecb_enc_block,\@function,3
+.align 16
+aes256gcmsiv_ecb_enc_block:
+.cfi_startproc
+    vmovdqa (%rdi), $STATE_1
+    vpxor ($KSp), $STATE_1, $STATE_1
+    vaesenc 1*16($KSp), $STATE_1, $STATE_1
+    vaesenc 2*16($KSp), $STATE_1, $STATE_1
+    vaesenc 3*16($KSp), $STATE_1, $STATE_1
+    vaesenc 4*16($KSp), $STATE_1, $STATE_1
+    vaesenc 5*16($KSp), $STATE_1, $STATE_1
+    vaesenc 6*16($KSp), $STATE_1, $STATE_1
+    vaesenc 7*16($KSp), $STATE_1, $STATE_1
+    vaesenc 8*16($KSp), $STATE_1, $STATE_1
+    vaesenc 9*16($KSp), $STATE_1, $STATE_1
+    vaesenc 10*16($KSp), $STATE_1, $STATE_1
+    vaesenc 11*16($KSp), $STATE_1, $STATE_1
+    vaesenc 12*16($KSp), $STATE_1, $STATE_1
+    vaesenc 13*16($KSp), $STATE_1, $STATE_1
+    vaesenclast 14*16($KSp), $STATE_1, $STATE_1    # $STATE_1 == IV
+    vmovdqa $STATE_1, (%rsi)
+    ret
+.cfi_endproc
+.size aes256gcmsiv_ecb_enc_block,.-aes256gcmsiv_ecb_enc_block
+___
+}
+aes256gcmsiv_ecb_enc_block();
+
+sub aes256gcmsiv_enc_msg_x4 {
+  my $CTR1 = "%xmm0";
+  my $CTR2 = "%xmm1";
+  my $CTR3 = "%xmm2";
+  my $CTR4 = "%xmm3";
+  my $ADDER = "%xmm4";
+
+  my $STATE1 = "%xmm5";
+  my $STATE2 = "%xmm6";
+  my $STATE3 = "%xmm7";
+  my $STATE4 = "%xmm8";
+
+  my $TMP = "%xmm12";
+  my $TMP2 = "%xmm13";
+  my $TMP3 = "%xmm14";
+  my $IV = "%xmm15";
+
+  my $PT = "%rdi";
+  my $CT = "%rsi";
+  my $TAG = "%rdx";
+  my $KS = "%rcx";
+  my $LEN = "%r8";
+
+  my $aes_round = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $TMP
+    vaesenc $TMP, $STATE1, $STATE1
+    vaesenc $TMP, $STATE2, $STATE2
+    vaesenc $TMP, $STATE3, $STATE3
+    vaesenc $TMP, $STATE4, $STATE4
+___
+  };
+
+  my $aes_lastround = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $TMP
+    vaesenclast $TMP, $STATE1, $STATE1
+    vaesenclast $TMP, $STATE2, $STATE2
+    vaesenclast $TMP, $STATE3, $STATE3
+    vaesenclast $TMP, $STATE4, $STATE4
+___
+  };
+
+  # void aes256gcmsiv_enc_msg_x4(unsigned char* PT, unsigned char* CT,
+  #                              unsigned char* TAG, unsigned char* KS,
+  #                              size_t byte_len);
+  # parameter 1: %rdi     #PT
+  # parameter 2: %rsi     #CT
+  # parameter 3: %rdx     #TAG  [127 126 ... 0]  IV=[127...32]
+  # parameter 4: %rcx     #KS
+  # parameter 5: %r8      #LEN MSG_length in bytes
+  $code.=<<___;
+.globl aes256gcmsiv_enc_msg_x4
+.type aes256gcmsiv_enc_msg_x4,\@function,5
+.align 16
+aes256gcmsiv_enc_msg_x4:
+.cfi_startproc
+    test $LEN, $LEN
+    jnz .L256_enc_msg_x4_start
+    ret
+
+.L256_enc_msg_x4_start:
+    movq $LEN, %r10
+    shrq \$4, $LEN                       # LEN = num of blocks
+    shlq \$60, %r10
+    jz .L256_enc_msg_x4_start2
+    addq \$1, $LEN
+
+.L256_enc_msg_x4_start2:
+    movq $LEN, %r10
+    shlq \$62, %r10
+    shrq \$62, %r10
+
+    # make IV from TAG
+    vmovdqa ($TAG), $IV
+    vpor OR_MASK(%rip), $IV, $IV        # IV = [1]TAG[126...32][00..00]
+
+    vmovdqa four(%rip), $ADDER          # Register to increment counters
+    vmovdqa $IV, $CTR1                  # CTR1 = TAG[1][127...32][00..00]
+    vpaddd one(%rip), $IV, $CTR2        # CTR2 = TAG[1][127...32][00..01]
+    vpaddd two(%rip), $IV, $CTR3        # CTR3 = TAG[1][127...32][00..02]
+    vpaddd three(%rip), $IV, $CTR4      # CTR4 = TAG[1][127...32][00..03]
+
+    shrq \$2, $LEN
+    je .L256_enc_msg_x4_check_remainder
+
+    subq \$64, $CT
+    subq \$64, $PT
+
+.L256_enc_msg_x4_loop1:
+    addq \$64, $CT
+    addq \$64, $PT
+
+    vmovdqa $CTR1, $STATE1
+    vmovdqa $CTR2, $STATE2
+    vmovdqa $CTR3, $STATE3
+    vmovdqa $CTR4, $STATE4
+
+    vpxor ($KS), $STATE1, $STATE1
+    vpxor ($KS), $STATE2, $STATE2
+    vpxor ($KS), $STATE3, $STATE3
+    vpxor ($KS), $STATE4, $STATE4
+
+    ${\$aes_round->(1)}
+    vpaddd $ADDER, $CTR1, $CTR1
+    ${\$aes_round->(2)}
+    vpaddd $ADDER, $CTR2, $CTR2
+    ${\$aes_round->(3)}
+    vpaddd $ADDER, $CTR3, $CTR3
+    ${\$aes_round->(4)}
+    vpaddd $ADDER, $CTR4, $CTR4
+
+    ${\$aes_round->(5)}
+    ${\$aes_round->(6)}
+    ${\$aes_round->(7)}
+    ${\$aes_round->(8)}
+    ${\$aes_round->(9)}
+    ${\$aes_round->(10)}
+    ${\$aes_round->(11)}
+    ${\$aes_round->(12)}
+    ${\$aes_round->(13)}
+    ${\$aes_lastround->(14)}
+
+    # XOR with Plaintext
+    vpxor 0*16($PT), $STATE1, $STATE1
+    vpxor 1*16($PT), $STATE2, $STATE2
+    vpxor 2*16($PT), $STATE3, $STATE3
+    vpxor 3*16($PT), $STATE4, $STATE4
+
+    subq \$1, $LEN
+
+    vmovdqu $STATE1, 0*16($CT)
+    vmovdqu $STATE2, 1*16($CT)
+    vmovdqu $STATE3, 2*16($CT)
+    vmovdqu $STATE4, 3*16($CT)
+
+    jne .L256_enc_msg_x4_loop1
+
+    addq \$64, $CT
+    addq \$64, $PT
+
+.L256_enc_msg_x4_check_remainder:
+    cmpq \$0, %r10
+    je .L256_enc_msg_x4_out
+
+.L256_enc_msg_x4_loop2:
+    # encrypt each block separately
+    # CTR1 is the highest counter (even if no LOOP done)
+
+    vmovdqa $CTR1, $STATE1
+    vpaddd one(%rip), $CTR1, $CTR1      # inc counter
+    vpxor ($KS), $STATE1, $STATE1
+    vaesenc 16($KS), $STATE1, $STATE1
+    vaesenc 32($KS), $STATE1, $STATE1
+    vaesenc 48($KS), $STATE1, $STATE1
+    vaesenc 64($KS), $STATE1, $STATE1
+    vaesenc 80($KS), $STATE1, $STATE1
+    vaesenc 96($KS), $STATE1, $STATE1
+    vaesenc 112($KS), $STATE1, $STATE1
+    vaesenc 128($KS), $STATE1, $STATE1
+    vaesenc 144($KS), $STATE1, $STATE1
+    vaesenc 160($KS), $STATE1, $STATE1
+    vaesenc 176($KS), $STATE1, $STATE1
+    vaesenc 192($KS), $STATE1, $STATE1
+    vaesenc 208($KS), $STATE1, $STATE1
+    vaesenclast 224($KS), $STATE1, $STATE1
+
+    # XOR with Plaintext
+    vpxor ($PT), $STATE1, $STATE1
+
+    vmovdqu $STATE1, ($CT)
+
+    addq \$16, $PT
+    addq \$16, $CT
+
+    subq \$1, %r10
+    jne .L256_enc_msg_x4_loop2
+
+.L256_enc_msg_x4_out:
+    ret
+.cfi_endproc
+.size aes256gcmsiv_enc_msg_x4,.-aes256gcmsiv_enc_msg_x4
+___
+}
+aes256gcmsiv_enc_msg_x4();
+
+sub aes256gcmsiv_enc_msg_x8() {
+  my $STATE1 = "%xmm1";
+  my $STATE2 = "%xmm2";
+  my $STATE3 = "%xmm3";
+  my $STATE4 = "%xmm4";
+  my $STATE5 = "%xmm5";
+  my $STATE6 = "%xmm6";
+  my $STATE7 = "%xmm7";
+  my $STATE8 = "%xmm8";
+  my $CTR1 = "%xmm0";
+  my $CTR2 = "%xmm9";
+  my $CTR3 = "%xmm10";
+  my $CTR4 = "%xmm11";
+  my $CTR5 = "%xmm12";
+  my $CTR6 = "%xmm13";
+  my $CTR7 = "%xmm14";
+  my $TMP1 = "%xmm1";
+  my $TMP2 = "%xmm2";
+  my $KS = "%rcx";
+  my $LEN = "%r8";
+  my $PT = "%rdi";
+  my $CT = "%rsi";
+  my $TAG = "%rdx";
+  my $SCHED = "%xmm15";
+
+  my $aes_round8 = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $SCHED
+    vaesenc $SCHED, $STATE1, $STATE1
+    vaesenc $SCHED, $STATE2, $STATE2
+    vaesenc $SCHED, $STATE3, $STATE3
+    vaesenc $SCHED, $STATE4, $STATE4
+    vaesenc $SCHED, $STATE5, $STATE5
+    vaesenc $SCHED, $STATE6, $STATE6
+    vaesenc $SCHED, $STATE7, $STATE7
+    vaesenc $SCHED, $STATE8, $STATE8
+___
+  };
+
+  my $aes_lastround8 = sub {
+    my ($i) = @_;
+    return <<___;
+    vmovdqu ${\eval($i*16)}($KS), $SCHED
+    vaesenclast $SCHED, $STATE1, $STATE1
+    vaesenclast $SCHED, $STATE2, $STATE2
+    vaesenclast $SCHED, $STATE3, $STATE3
+    vaesenclast $SCHED, $STATE4, $STATE4
+    vaesenclast $SCHED, $STATE5, $STATE5
+    vaesenclast $SCHED, $STATE6, $STATE6
+    vaesenclast $SCHED, $STATE7, $STATE7
+    vaesenclast $SCHED, $STATE8, $STATE8
+___
+  };
+
+  # void ENC_MSG_x8(unsigned char* PT,
+  #                 unsigned char* CT,
+  #                 unsigned char* TAG,
+  #                 unsigned char* KS,
+  #                 size_t byte_len);
+  # parameter 1: %rdi     #PT
+  # parameter 2: %rsi     #CT
+  # parameter 3: %rdx     #TAG        [127 126 ... 0]  IV=[127...32]
+  # parameter 4: %rcx     #KS
+  # parameter 5: %r8      #LEN MSG_length in bytes
+  $code.=<<___;
+.globl aes256gcmsiv_enc_msg_x8
+.type aes256gcmsiv_enc_msg_x8,\@function,5
+.align 16
+aes256gcmsiv_enc_msg_x8:
+.cfi_startproc
+    test $LEN, $LEN
+    jnz .L256_enc_msg_x8_start
+    ret
+
+.L256_enc_msg_x8_start:
+    # Place in stack
+    movq %rsp, %r11
+    subq \$16, %r11
+    andq \$-64, %r11
+
+    movq $LEN, %r10
+    shrq \$4, $LEN                       # LEN = num of blocks
+    shlq \$60, %r10
+    jz .L256_enc_msg_x8_start2
+    addq \$1, $LEN
+
+.L256_enc_msg_x8_start2:
+    movq $LEN, %r10
+    shlq \$61, %r10
+    shrq \$61, %r10
+
+    # Make IV from TAG
+    vmovdqa ($TAG), $TMP1
+    vpor OR_MASK(%rip), $TMP1, $TMP1    # TMP1= IV = [1]TAG[126...32][00..00]
+
+    # store counter8 on the stack
+    vpaddd seven(%rip), $TMP1, $CTR1
+    vmovdqa $CTR1, (%r11)                # CTR8 = TAG[127...32][00..07]
+    vpaddd one(%rip), $TMP1, $CTR2       # CTR2 = TAG[127...32][00..01]
+    vpaddd two(%rip), $TMP1, $CTR3       # CTR3 = TAG[127...32][00..02]
+    vpaddd three(%rip), $TMP1, $CTR4     # CTR4 = TAG[127...32][00..03]
+    vpaddd four(%rip), $TMP1, $CTR5      # CTR5 = TAG[127...32][00..04]
+    vpaddd five(%rip), $TMP1, $CTR6      # CTR6 = TAG[127...32][00..05]
+    vpaddd six(%rip), $TMP1, $CTR7       # CTR7 = TAG[127...32][00..06]
+    vmovdqa $TMP1, $CTR1                 # CTR1 = TAG[127...32][00..00]
+
+    shrq \$3, $LEN
+    jz .L256_enc_msg_x8_check_remainder
+
+    subq \$128, $CT
+    subq \$128, $PT
+
+.L256_enc_msg_x8_loop1:
+    addq \$128, $CT
+    addq \$128, $PT
+
+    vmovdqa $CTR1, $STATE1
+    vmovdqa $CTR2, $STATE2
+    vmovdqa $CTR3, $STATE3
+    vmovdqa $CTR4, $STATE4
+    vmovdqa $CTR5, $STATE5
+    vmovdqa $CTR6, $STATE6
+    vmovdqa $CTR7, $STATE7
+    # move from stack
+    vmovdqa (%r11), $STATE8
+
+    vpxor ($KS), $STATE1, $STATE1
+    vpxor ($KS), $STATE2, $STATE2
+    vpxor ($KS), $STATE3, $STATE3
+    vpxor ($KS), $STATE4, $STATE4
+    vpxor ($KS), $STATE5, $STATE5
+    vpxor ($KS), $STATE6, $STATE6
+    vpxor ($KS), $STATE7, $STATE7
+    vpxor ($KS), $STATE8, $STATE8
+
+    ${\$aes_round8->(1)}
+    vmovdqa (%r11), $CTR7                # deal with CTR8
+    vpaddd eight(%rip), $CTR7, $CTR7
+    vmovdqa $CTR7, (%r11)
+    ${\$aes_round8->(2)}
+    vpsubd one(%rip), $CTR7, $CTR7
+    ${\$aes_round8->(3)}
+    vpaddd eight(%rip), $CTR1, $CTR1
+    ${\$aes_round8->(4)}
+    vpaddd eight(%rip), $CTR2, $CTR2
+    ${\$aes_round8->(5)}
+    vpaddd eight(%rip), $CTR3, $CTR3
+    ${\$aes_round8->(6)}
+    vpaddd eight(%rip), $CTR4, $CTR4
+    ${\$aes_round8->(7)}
+    vpaddd eight(%rip), $CTR5, $CTR5
+    ${\$aes_round8->(8)}
+    vpaddd eight(%rip), $CTR6, $CTR6
+    ${\$aes_round8->(9)}
+    ${\$aes_round8->(10)}
+    ${\$aes_round8->(11)}
+    ${\$aes_round8->(12)}
+    ${\$aes_round8->(13)}
+    ${\$aes_lastround8->(14)}
+
+    # XOR with Plaintext
+    vpxor 0*16($PT), $STATE1, $STATE1
+    vpxor 1*16($PT), $STATE2, $STATE2
+    vpxor 2*16($PT), $STATE3, $STATE3
+    vpxor 3*16($PT), $STATE4, $STATE4
+    vpxor 4*16($PT), $STATE5, $STATE5
+    vpxor 5*16($PT), $STATE6, $STATE6
+    vpxor 6*16($PT), $STATE7, $STATE7
+    vpxor 7*16($PT), $STATE8, $STATE8
+
+    subq \$1, $LEN
+
+    vmovdqu $STATE1, 0*16($CT)
+    vmovdqu $STATE2, 1*16($CT)
+    vmovdqu $STATE3, 2*16($CT)
+    vmovdqu $STATE4, 3*16($CT)
+    vmovdqu $STATE5, 4*16($CT)
+    vmovdqu $STATE6, 5*16($CT)
+    vmovdqu $STATE7, 6*16($CT)
+    vmovdqu $STATE8, 7*16($CT)
+
+    jne .L256_enc_msg_x8_loop1
+
+    addq \$128, $CT
+    addq \$128, $PT
+
+.L256_enc_msg_x8_check_remainder:
+   cmpq \$0, %r10
+   je .L256_enc_msg_x8_out
+
+.L256_enc_msg_x8_loop2:
+    # encrypt each block separately
+    # CTR1 is the highest counter (even if no LOOP done)
+    vmovdqa $CTR1, $STATE1
+    vpaddd one(%rip), $CTR1, $CTR1
+
+    vpxor ($KS), $STATE1, $STATE1
+    vaesenc 16($KS), $STATE1, $STATE1
+    vaesenc 32($KS), $STATE1, $STATE1
+    vaesenc 48($KS), $STATE1, $STATE1
+    vaesenc 64($KS), $STATE1, $STATE1
+    vaesenc 80($KS), $STATE1, $STATE1
+    vaesenc 96($KS), $STATE1, $STATE1
+    vaesenc 112($KS), $STATE1, $STATE1
+    vaesenc 128($KS), $STATE1, $STATE1
+    vaesenc 144($KS), $STATE1, $STATE1
+    vaesenc 160($KS), $STATE1, $STATE1
+    vaesenc 176($KS), $STATE1, $STATE1
+    vaesenc 192($KS), $STATE1, $STATE1
+    vaesenc 208($KS), $STATE1, $STATE1
+    vaesenclast 224($KS), $STATE1, $STATE1
+
+    # XOR with Plaintext
+    vpxor ($PT), $STATE1, $STATE1
+
+    vmovdqu $STATE1, ($CT)
+
+    addq \$16, $PT
+    addq \$16, $CT
+    subq \$1, %r10
+    jnz .L256_enc_msg_x8_loop2
+
+.L256_enc_msg_x8_out:
+    ret
+
+.cfi_endproc
+.size aes256gcmsiv_enc_msg_x8,.-aes256gcmsiv_enc_msg_x8
+___
+}
+aes256gcmsiv_enc_msg_x8();
+aesgcmsiv_dec(1);
+
+sub aes256gcmsiv_kdf {
+  my $ONE = "%xmm8";
+  my $BLOCK1 = "%xmm4";
+  my $BLOCK2 = "%xmm6";
+  my $BLOCK3 = "%xmm7";
+  my $BLOCK4 = "%xmm11";
+  my $BLOCK5 = "%xmm12";
+  my $BLOCK6 = "%xmm13";
+
+  my $enc_roundx6 = sub {
+    my ($i, $j) = @_;
+    return <<___;
+    vmovdqa ${\eval($i*16)}(%rdx), $j
+    vaesenc $j, $BLOCK1, $BLOCK1
+    vaesenc $j, $BLOCK2, $BLOCK2
+    vaesenc $j, $BLOCK3, $BLOCK3
+    vaesenc $j, $BLOCK4, $BLOCK4
+    vaesenc $j, $BLOCK5, $BLOCK5
+    vaesenc $j, $BLOCK6, $BLOCK6
+___
+  };
+
+  my $enc_roundlastx6 = sub {
+    my ($i, $j) = @_;
+    return <<___;
+    vmovdqa ${\eval($i*16)}(%rdx), $j
+    vaesenclast $j, $BLOCK1, $BLOCK1
+    vaesenclast $j, $BLOCK2, $BLOCK2
+    vaesenclast $j, $BLOCK3, $BLOCK3
+    vaesenclast $j, $BLOCK4, $BLOCK4
+    vaesenclast $j, $BLOCK5, $BLOCK5
+    vaesenclast $j, $BLOCK6, $BLOCK6
+___
+  };
+
+  # void aes256gcmsiv_kdf(const uint8_t nonce[16],
+  #                       uint8_t *out_key_material,
+  #                       const uint8_t *key_schedule);
+  $code.=<<___;
+.globl aes256gcmsiv_kdf
+.type aes256gcmsiv_kdf,\@function,3
+.align 16
+aes256gcmsiv_kdf:
+.cfi_startproc
+# parameter 1: %rdi                         Pointer to NONCE
+# parameter 2: %rsi                         Pointer to CT
+# parameter 4: %rdx                         Pointer to keys
+
+    vmovdqa (%rdx), %xmm1                  # xmm1 = first 16 bytes of random key
+    vmovdqa 0*16(%rdi), $BLOCK1
+    vmovdqa and_mask(%rip), $BLOCK4
+    vmovdqa one(%rip), $ONE
+    vpshufd \$0x90, $BLOCK1, $BLOCK1
+    vpand $BLOCK4, $BLOCK1, $BLOCK1
+    vpaddd $ONE, $BLOCK1, $BLOCK2
+    vpaddd $ONE, $BLOCK2, $BLOCK3
+    vpaddd $ONE, $BLOCK3, $BLOCK4
+    vpaddd $ONE, $BLOCK4, $BLOCK5
+    vpaddd $ONE, $BLOCK5, $BLOCK6
+
+    vpxor %xmm1, $BLOCK1, $BLOCK1
+    vpxor %xmm1, $BLOCK2, $BLOCK2
+    vpxor %xmm1, $BLOCK3, $BLOCK3
+    vpxor %xmm1, $BLOCK4, $BLOCK4
+    vpxor %xmm1, $BLOCK5, $BLOCK5
+    vpxor %xmm1, $BLOCK6, $BLOCK6
+
+    ${\$enc_roundx6->(1, "%xmm1")}
+    ${\$enc_roundx6->(2, "%xmm2")}
+    ${\$enc_roundx6->(3, "%xmm1")}
+    ${\$enc_roundx6->(4, "%xmm2")}
+    ${\$enc_roundx6->(5, "%xmm1")}
+    ${\$enc_roundx6->(6, "%xmm2")}
+    ${\$enc_roundx6->(7, "%xmm1")}
+    ${\$enc_roundx6->(8, "%xmm2")}
+    ${\$enc_roundx6->(9, "%xmm1")}
+    ${\$enc_roundx6->(10, "%xmm2")}
+    ${\$enc_roundx6->(11, "%xmm1")}
+    ${\$enc_roundx6->(12, "%xmm2")}
+    ${\$enc_roundx6->(13, "%xmm1")}
+    ${\$enc_roundlastx6->(14, "%xmm2")}
+
+    vmovdqa $BLOCK1, 0*16(%rsi)
+    vmovdqa $BLOCK2, 1*16(%rsi)
+    vmovdqa $BLOCK3, 2*16(%rsi)
+    vmovdqa $BLOCK4, 3*16(%rsi)
+    vmovdqa $BLOCK5, 4*16(%rsi)
+    vmovdqa $BLOCK6, 5*16(%rsi)
+    ret
+.cfi_endproc
+.size aes256gcmsiv_kdf, .-aes256gcmsiv_kdf
+___
+}
+aes256gcmsiv_kdf();
+
+print $code;
+
+close STDOUT;
diff --git a/rustc_deps/vendor/ring/crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt b/rustc_deps/vendor/ring/crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt
new file mode 100644
index 0000000..8587eea
--- /dev/null
+++ b/rustc_deps/vendor/ring/crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt
@@ -0,0 +1,574 @@
+# This is the example from
+# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-04#section-8
+
+KEY: ee8e1ed9ff2540ae8f2ba9f50bc2f27c
+NONCE: 752abad3e0afb5f434dc4310
+IN: "Hello world"
+AD: "example"
+CT: 5d349ead175ef6b1def6fd
+TAG: 4fbcdeb7e4793f4a1d7e4faa70100af1
+
+# Test vectors from
+# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-04#appendix-C
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 
+AD: 
+CT: 
+TAG: dc20e2d83f25705bb49e439eca56de25
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 0100000000000000
+AD: 
+CT: b5d839330ac7b786
+TAG: 578782fff6013b815b287c22493a364c
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 010000000000000000000000
+AD: 
+CT: 7323ea61d05932260047d942
+TAG: a4978db357391a0bc4fdec8b0d106639
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 01000000000000000000000000000000
+AD: 
+CT: 743f7c8077ab25f8624e2e948579cf77
+TAG: 303aaf90f6fe21199c6068577437a0c4
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 0100000000000000000000000000000002000000000000000000000000000000
+AD: 
+CT: 84e07e62ba83a6585417245d7ec413a9fe427d6315c09b57ce45f2e3936a9445
+TAG: 1a8e45dcd4578c667cd86847bf6155ff
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000
+AD: 
+CT: 3fd24ce1f5a67b75bf2351f181a475c7b800a5b4d3dcf70106b1eea82fa1d64df42bf7226122fa92e17a40eeaac1201b
+TAG: 5e6e311dbf395d35b0fe39c2714388f8
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 
+CT: 2433668f1058190f6d43e360f4f35cd8e475127cfca7028ea8ab5c20f7ab2af02516a2bdcbc08d521be37ff28c152bba36697f25b4cd169c6590d1dd39566d3f
+TAG: 8a263dd317aa88d56bdf3936dba75bb8
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 0200000000000000
+AD: 01
+CT: 1e6daba35669f427
+TAG: 3b0a1a2560969cdf790d99759abd1508
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 020000000000000000000000
+AD: 01
+CT: 296c7889fd99f41917f44620
+TAG: 08299c5102745aaa3a0c469fad9e075a
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 02000000000000000000000000000000
+AD: 01
+CT: e2b0c5da79a901c1745f700525cb335b
+TAG: 8f8936ec039e4e4bb97ebd8c4457441f
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 0200000000000000000000000000000003000000000000000000000000000000
+AD: 01
+CT: 620048ef3c1e73e57e02bb8562c416a319e73e4caac8e96a1ecb2933145a1d71
+TAG: e6af6a7f87287da059a71684ed3498e1
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 01
+CT: 50c8303ea93925d64090d07bd109dfd9515a5a33431019c17d93465999a8b0053201d723120a8562b838cdff25bf9d1e
+TAG: 6a8cc3865f76897c2e4b245cf31c51f2
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000
+AD: 01
+CT: 2f5c64059db55ee0fb847ed513003746aca4e61c711b5de2e7a77ffd02da42feec601910d3467bb8b36ebbaebce5fba30d36c95f48a3e7980f0e7ac299332a80
+TAG: cdc46ae475563de037001ef84ae21744
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 02000000
+AD: 010000000000000000000000
+CT: a8fe3e87
+TAG: 07eb1f84fb28f8cb73de8e99e2f48a14
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 0300000000000000000000000000000004000000
+AD: 010000000000000000000000000000000200
+CT: 6bb0fecf5ded9b77f902c7d5da236a4391dd0297
+TAG: 24afc9805e976f451e6d87f6fe106514
+
+KEY: 01000000000000000000000000000000
+NONCE: 030000000000000000000000
+IN: 030000000000000000000000000000000400
+AD: 0100000000000000000000000000000002000000
+CT: 44d0aaf6fb2f1f34add5e8064e83e12a2ada
+TAG: bff9b2ef00fb47920cc72a0c0f13b9fd
+
+# Random vectors generated by the reference code.
+
+KEY: e66021d5eb8e4f4066d4adb9c33560e4
+NONCE: f46e44bb3da0015c94f70887
+IN: 
+AD: 
+CT: 
+TAG: a4194b79071b01a87d65f706e3949578
+
+KEY: 36864200e0eaf5284d884a0e77d31646
+NONCE: bae8e37fc83441b16034566b
+IN: 7a806c46bb91c3c5aedb64a6c590bc84d1
+AD: a5e269e4b47801afc0
+CT: 8092e6d6d729f5ee7e808d77f3b7a89647
+TAG: dec23ae31e3e97bb364fa18ad85cae0b
+
+KEY: 577e34699b9e671fdd4fbdc66f146545
+NONCE: fc880c94a95198874296d5cc
+IN: 1fd161320b6920ce07787f86743b275d1ab32f6d1f0434d8848c1177441f19549586
+AD: 0f046787f3ea22c127aaf195d1894728b3fe
+CT: 7520668ef1b845aabf245e66ca687ca7c5b4f00de71afea392cda124893746ddd4e6
+TAG: db5ad3b398513fe5c8d868e68becd5a8
+
+KEY: d1473c528b8426a582995929a1499e9a
+NONCE: d8780c8d63d0ab4149c09f57
+IN: 2c614b4745914474e7c7c9882e5386fd9f92ec489c8fde2be2cf97e74e932d4ed87da44102952ef94b02b805249bac80e6f614
+AD: 55bfac8308a2d40d8c8451178082355c9e940fea2f582950a70d5a
+CT: bdbec524ca37355074899f01b7247b1abc24565b997e000f231f0664be655d8cb75f18112cfaa722e1b2e261710036ff919014
+TAG: 45b9ece29df0dd93941f9454404c8d87
+
+KEY: 1db2316fd568378da107b52b0da55210
+NONCE: cc1c1b0abde3b2f204d1e9f8
+IN: b06bc47f9745b3d1ae06556fb6aa7890bebc18fe6b3db4da3d57aa94842b9803a96e07fb6de71860f762ebfbd08284e421702de0de18baa9c9596291b08466f37de21c7f
+AD: f901cfe8a69615a93fdf7a98cad481796245709fb18853f68d833640e42a3c02c25b6486
+CT: d75a5a40ae0ac4343f1a52ee16108332b3563616c207c2b22be277a219e497b7e5bbd5bdecaed87a5216e3e49149ac50a7959957264c222577a07c73fc81f0e579a0fa93
+TAG: b70c26c56e34c7740824f9dfcb8ae6e4
+
+KEY: 9e146d7b233987bddfc240871d7576f7
+NONCE: 028ec6eb5ea7e298342a94d4
+IN: b202b370ef9768ec6561c4fe6b7e7296fa859c2159058b1f0fe91433a5bdc20e214eab7fecef4454a10ef0657df21ac73c535de192eaed3822a2fbbe2ca9dfc88255e14a661b8aa82cc54236093bbc23688089e555
+AD: 40db1872504e1cced532ce4159b035277d4dfbb7db62968b13cd4eec734320ccc9d9bbbb19cb81b2af4ecbc3e7
+CT: 23dea4fb871ab1df6cfb674d2e7efbc969033a11d694c6580aa3e780e4d1db5f1145924b974ce98ea041ecca53c36207fa644b0ae789965084d1ef845cae33aff734113b3eb4d9f1863b780b0f97fb5e3c5ea991cf
+TAG: 81da1dfc98517d4cee3ee885a266e814
+
+KEY: 2834321f7aa0f70b7282b4f33df23f16
+NONCE: 7541ac15c8417abaf17a282a
+IN: c7a57252ff224ae7911a905b8c699b20e40c1e9569a6b2aa0232d4b10bb6f20406135861c19795b95f9597f9b72c20931c41164f1b469b0901f2b5da3a956a6e278c940e82593eb58f56f6d3681fb00dedf7f612c4cb3193b73ab35f9a5a9cc8d13aa27ff1de
+AD: a3b2a7d832ed8ab959d82ee795df8e1ef530cc6fd9a1f10543b44c49383921d74fe0c71d50da4adb9e9c7e5491a488ceb5c384ebafad
+CT: 06d3e558b2f7f8e225d76a41a11122aa29eef02c226616f5264c9c1b821748a8115dd4868dfeacc5d167ceedc824f1f7136e7d7fae783bad83dec468c98747524fc2fcd7b86cbfd1c07078fd1b4b9caaae970c729ee3f2ecfebf048c5aba174fc4eab117bacf
+TAG: 5ece142ce1074a09ab8ce810222a471d
+
+KEY: f0f484fae982019a8ea22efd1358adf7
+NONCE: ad4f5fa0d2acd2f1ee095cdf
+IN: c13310241243fa53b8c2610d1924b1d55cb6d9cb6a5b98a72127255967b8ff23623c5453e61cecf9e624e5c803250c382481d3c10febfa54d03894ba8f9ed72637fcf5631f7b7312cc74e6ff63ecb240349a575f2cd817f2afbaaf21815bf08ac1e8f87520244b4a3fc492c7120296607ef64d0adb4c74
+AD: b73839e13455fd91ddf7f81d460034b9c41eaf0cc6040a84e17e6108372f1ca50656793554ea1d05181310711d0e60d4d556b2bedb24d7b622c01fe8025119
+CT: 90046c5ca4a6db850c5cddb14227b5902257e7ed8bc55f85ca24f51558f95037a0567d485b7606d2ec1802de069926e4f69e5ade9453080f84c045438d890290ed69b5e140788d07ed3d38b067900c222ad55b298e240590cb816d90a43ec52203f11ff9496b3dc32d7ac316ac8465496e41b4be5200dd
+TAG: 76ae0503f7b43b1d2db24817f2b61ee7
+
+KEY: ae0c8a20b679dc40c9908f88fecfafd6
+NONCE: 88b0ebec6a2ac13421012874
+IN: c80685c481b41323a1724ea96c1df644a595e8cc73955e6f661e0fa30737d78e7cec11629b8f1fa4bbd8e8e655f50019859514dbc4cbcf944f95084e45337d9d9d8972bd8da92b4eb5a75c0b284305601de859f8d1fac6d6b3fdd42210fdcf696119e436006a5a863859d5b70806197fdb9f0da3e4c31b0c7545809808bf7683757cd11b9d0f8621
+AD: 664df31eb95b5e17567d680b1a26980772e8ad3e9b2e2de537414368c4f97adff1408d36c1dfee65b78375c7361c91452e7d463338474a400ef9efcaa648e93f
+CT: f729ca77733cca181ba8801e001924e20a1d164cc4440a6217a1178dd6b1210837367cf84aa41f92f4123d6740910586f819389d5c750ab15768aed1b163bde5b1fe8862d1621b11485b47182d32bd304ddbf275524c4ece4cfb1361db53dd63e21ac62bb54a77bb5063c869b5f5de1f1b4356845aac79ee6f66d21ff271e02e8bbbae1372b4b8ff
+TAG: 52856b3369ecbb7201b1b0f75872e5e2
+
+KEY: 38f8784a1598bca461211195d7844de5
+NONCE: 6b91cccc96d89e6471bca6b7
+IN: 374aa5ec4b2f5fba66c17a435970411f2af3d6e33c0d094f74fcb77beb6cbbac1f3a8a19f69ca087f94a5b80d5e3692e0d10ec34aa67269c824b382d6238bcfaaed586177b852f816c31e9966744188f02647d881990d98c3eabd477557a739262bb3f682f64d2208faf98097586053a32cbf37e78413a2d89613a81966e8d654cac0aa34107947a036f403bda53e74bc524e7bc2d2c51dc42
+AD: 6b38c308cc574839129e5e6251f41dec9cff7ccf256c38e4994e15ca976d3185ae17030ad3751e56367f86886acc32e27fe04d0b89cc89b0206f281aa2d80f9be19928dabf07417e76
+CT: 350bc8baf35cad823df06eadbb0e30e1e4b5bb8171d14c330e8c488f1076d94b8cb7baa3268a5bf164e23563180b9793ed06bb80079288cd348eeaa8eb33cf31ccf89dec998408baae4c3a7b3d3bd14aa76e99d645da0fba0c29a7ea4baeed741de3a5df5ff4044d9b057c4f3ef1825dd0a47aa0b5e92cfe0321c07333479dc86bed7b7b91e6ef368401392d973404e2914b7d2cb49448c55e
+TAG: c974e989ae2b86e92c5da9b0c9b068e0
+
+KEY: 59b17f09c56d170ed1ef10d2fadf01e0
+NONCE: c78473d06a1685ef0bb112e4
+IN: ec7e6ce0cbc601fc8a2dd64045c8fada4a28c0c6f0ec98542e365279d00ffdf5e2eae3b663c4b79342f2f265db30a86d6e1b325318d7f7a622b36e746875b71165defd5ca1afc0a92db6ef4fb9e20b81018a5293899f1e0d06b18a2e65f7616638f79a0db3f2cfdcc0eac2ee1e2e454958e2e6d214a20ad13156f97d0f2cf4276b09f5945c11f6b20b7bede26d6c2f0e5cf2786eea66e18d6ece02156f9233bdfc57c75b1a8a8b1f4ab8
+AD: 5be5a4a089f0ac762060a336aa502f5a1df1e0a647fb9d5d932dc0654e0725122f6a567681a7d1cb7625ed0404d540d8b3145c911280d2a0ff9d1c53e27677be0436faeb39009fe5751c0b37c7a5f1137a26
+CT: 6b07754b096556462756de94e5941610f1bfd93e6222899516e00eb1830f557d6f629bc61abe0c247ab6aa0f4f816f79544ceb034b5d9e86ab8679ad67f6dbef521f6180a07b0bbbcf174cd9234848f18b8ebba7d6ae3d607e027cb220c7582eb6d496a980ae3883fab88a1dd9e5312842450fcf68640546b49c24a3ffc0c8c4f539e8f9a34a3bbff44b1bb4cdb339d8879fa4e0c2145954e34fbede7483d25a0494c1b9e5b1f70aee7e
+TAG: 064c9d25f8795d8151b33f9d32d3ac6d
+
+KEY: 995577faa109071bee1c87d5e6772ca5
+NONCE: 5fdec02348a625b49c3c881a
+IN: ab162f20ba0b834e8159d9bf20ee0c5d14da0221961c4fc7d9b44c7822f32298d30775cf974172ebfdb36cfb2881ccb15e5f69ed27880b920f4a092815357e03d982f75590af08b447f0f8466b031ed2409e9f5eb479affd9e18017a369486914c63a7494168d91df157f5e56fbc4ab6ee5a8f3af1fbe1bf9324338a1f4acad45fc7137676797c89620b15feb8512544771f280f322cbaac9c4d7cfb4c326824825ba5b5f5190fcde0d399ef1f52b82abb5a8b1e5f2eea2c79702d
+AD: ec4cfbee3d1f5cc11e085d2254f8b37f8030bd285d6aa1cc53868d18ecfdd963153485dce5a3e3e8cb0a3cf8074571f7a2e9e841229466463f506a2bc90f2d6413128efee043e01eccb930fbc002563510e499457161083ed7997e
+CT: 0610980d938c2f2619bb8b4408156fb53f595d857feae649a6700af296d0411cbb80a6c0b7e2447cc54c3bd3bcfae38b7bb10fa5b91e25686d4482b14a2b62d386175f9f247e48fc3b2215b2da1c065bb00f9f59e8afafc9ef205f5245d27085021f41b9e40c00abaea48286fd914e558f822659207e965855eabf52723148d84b0a2692c48d76f30f3cb530b1beb58ffc4824517cb6772e957bd56394c1d8b70c9fa2b70a670f3fe36d8802b2043905e469b558575c75012901dc
+TAG: cb51baaa4672b8ae9745ecee08784d3b
+
+KEY: 58ebf03ce7ed2f8d5487936311922884
+NONCE: bfd31cf828f3d0ce78f3c698
+IN: 1932268108a369048cdc0a75c062c0ed02e27bbd11754e621ff67c511ed98c6fadc3e95e7100644ebe1aa147a7e99f25ce5c2edb8ab6446749441027a211b8d04a6247299dfea9d75eab257a625aeb51f74e0b47b302fb5c0475ab23e99f4d93ecf07694497ff6b27c9848805af93a5615bc71486b26fc9da67cf60c8d3a396bc0164985fab2c64bbaa4dd0fdc22c9d9e433e8c70dcdeeebf230c7a3cb3e5d0d48573a64b068daf90f56b15579767ecdd420c0858fabe23abc0b313b97a9c1ceddcb59d5322e47a85cc58e75
+AD: 3f00d6f0d032d4c5110c8f22e98895279a30a86da0ef71cea6ef2738fe3e747ee54d2e96e3afb8916281f6369ab1a397ca0a18c6c0e9a0c4edeaa4190ce6422bd116ac254a12235eb66fb5cc7ef55b721d3d2db4c67c38bbbb0bcac9234ea7d733f200e6
+CT: b741fd48fa7634435db2cb05392004d0b588bc7e9ddf79526706e575415c8b3d48a606c5f155130deb77ec7aff93719396797bf6628531d9d061727bcea2b348060b64122cd1a94f999ad1f681847e57c05da0deabd2fe010212dc60ec980ed0ba78ee9160b3776ae9174c6f8b7231d6754a4143c8af129411063315c6517134ca26d5a94a2e8c6e8b7ad9b8e78b694d5251deb34dabc455dd9f2a2b3fb6f67222de61e917a645d366462d6d94cd265f919f237f06f1986fac17bfaf3a97c24b99af884d0fca5d3307caf9bd
+TAG: 35777ae50d32c572cb0cd778cbaf55e1
+
+KEY: b86fc55f4abb9b65ee1897c262533ccc
+NONCE: d118b0f493c849a7aa7f35d2
+IN: 43f9438f1858da62bdd03fd5a8c7b01d8097d7ce319a41f80104968a46599e9a3289a29a16b245877898f345f92fa70d3e613c38e6e4ebbf0bcb64c1c41f8b83ec8e9f159d4b830d9a1b79f2ad90db067856eb8621e52ab3060e8d72dfe782b62364c163fa00b49aa6fbe4210fb7208c642b7a6735b1a8b2f1dbc4b3d4952985ef207a3eb0a07b1341700762e9f9d1c3438fc6633da2fbade15844cb1813d258aa5bfa4ac129d693792a89622a0c686f05d87019a266f91387d96bf2baae0262782b9c23162f5271cfa3144265deefe2c569e82911e842e5c9ae8fb79b
+AD: ecf42c3afe389acfdc9a34bec7b45705ba68e205b83b33f50b7852fbb7f4ae5dfdfdfb3cfee8a03c96a036388aa8f7809bd47eaa073f92905d0d5f199d466cc0ebd9bceb207f4209bf9925c6109973194742dc8d813f3cb212bbd8d92d7eef645fb0f8245811876dee5f241763
+CT: 87454e6cefc24ba38f01bb791333dd0006cfce165a4247833b182efcdb484b0818aa80f70f29d0ec093455344b8f169262f17be2d1635293bdcca90e21f2c210146f90398f44b35e3f2203c7b5bfecdbd973b568d8ed8444d43cba08d44984a295f62c174ca9ca69c173bb7c43f103ff53a886284af46fde5cbe07b391f9c0b82eec218faecb43dc75372478f2ee1bb267602672a4ff5989ec7251034dd2cfb49677fc82c8b209820be1ed2c429a0491beedbe8c1fc78bd62590ba71fd5da363d6da000e8b7e5bae223c0cf8397d3b5ce7141e8b301ea5a737ae480dc9
+TAG: ad696ab700dd5b71d79f4f6f69034185
+
+KEY: edaf7d79c1b83d973f9ba3b29a9b9408
+NONCE: 418f73743ff0546f0d929001
+IN: 0cf3a665c443b85255759ec6248021e4b6eb825c398b5af7b5257efb7afc481abc20d90249bed5b30d44f725c78ad0ce2821f86838874dceb6b6207ad6fa34579126de720ce34bdfd2058d92b8bbbb3f1bec607de3f0a028d8f6e13d0d4d2d3861e1a26d79cb68d3fef68127e8458eb599915022da751e271cd047cc712fae5b0459ae7815a24f4edf806889fc462c83181111f4de5bbb7e66a701460f508eaf73798c3ca9c08cc1a046472f4b18c69b7ed249a96f9bfa05a276499a5f499c586027c64ad6a68dcb52a50aa6d1b1d4d202e6f184f01daa08fbd643523f4f73ae6b8d764a7f567087a5fec5ad1ee3
+AD: e4be5b677b87109e69eae9a635ac2ea185ba08ebce3ba4be06d53b2da081c5030f5a746fea7bbdda340e10eccd47238340b9244b9442c0efae7644cff53c7abd8445163e891cf30bc8e26eea01f0c461b4796c2106e1ffdfdd1bac29f7d3c72c8ca7f625008d8d333d2a2092c08ef83c8002ed90e2ad
+CT: 9372586624f9a52a91e7ce12f380ca13840f11fad8d9edf10c869042c29514515673b3dfcfe956e8d3550baae1815bb4cd41ed27c7485c723354e557d18119b27431d7527f0d84c6e76baf9afa35a215624c339ad888f27c338240e603b232cd247e77eb1475adcb87d0443265ac0de45b16c67fdab07a0c0dd203d97ac2e19248492c561912e9087cd5fb73445695b43b8dd8c7515f9c958dc64068e31d3cb615038f5eea84a74b5d0c3415b6b1309ea8092614f2bd944a6c3a9e002a95e524efa497c9d3cbdaa764f8cf8aa9fcc7f7d68a623930bebb74e5c234322651edda21e20eb12c16a76839f31f3b30d6
+TAG: 33a31cae0292d0185aa10ba1c2288cda
+
+KEY: 01dadfe4cc0681384b489f38d25e83c2
+NONCE: c563485fb361f81d44aea205
+IN: e5bb4c1912d00d8f99f8d7a931e55ae72f749147fbd97699ec730bfb01b8261f1f94696278fc703263cc789b283460af9d74647a8c039ad2184674e78f6a355a26eefc6fcd4cd32d96d245d583836312652fd9e6694ac5644eeb4c2bd667b52e5af14bcb108c8e277728d6d6116e8ed1981993771b8bb783bb351982f9f8c2a0e7c20a5a863c6d71b7145b73d7e6d84d47780d66847244d0b8ef559f2297f39e26501d8a2aae8c36189580292da842c4d0d06a21d21ab175e34589e3b814d8a00ac1d8a3b2eca2a91b21e36c55fc6dad8c0a1b2cc7bcb2108b2e21fafeaa26a2d4881b183b899210b474bdc43a8f0b8464075d86a2ba1e9cd195a8ecadd315
+AD: 870d5740c4e22eab0783de87d541fa834647c3fc6543c60d5df31c19c6ca38707649fa8dcfc3c0ccc16b1bb60283d7ae2778a8f83ba07b905e23cb06d5656f614f1efcb346f34e190bcc636cdca229b64af9ae4b1f05b58f1ffd1a077a51bbf9ede69ac3954de7daf569cc8de12282cac09b9a49dfb92dcc409b8c63f2ae4a
+CT: 119f74936eaffdc3e5e7e072ce81e0e1ca91054cbfca127b8c4a94ada042a2452b39cdd02ab897da765cc0f8d84089a8cc5af662c1c96aefafeead785ad042b506fc72556182566263e90009a86503595dca0924d87ea6ac61d4e931025420436a8716d0ce379c5e3437b26a12531c0a1abb3a693f3202f5770f1dd7ec1eada8c2d6c747a7161d19ffbb897710a17e7740fc232fcc244f456e962ebe71f7ded8ca73e07dd44f00fbd023b8a72f9005f9bd4d0d44135294258ec14665309e9edcc82d98227474a9202552d31f1d2e7374d49929c2885696e5e3edc1983432f1dbad351f9cae3cd56855878d9a076c6d3a27f2718e32658f2392215915c020db
+TAG: 5689d9a73d52266977bfe5c1bb1bca09
+
+KEY: 34091633f4aaf225aa02ba9c57b910a7
+NONCE: 6535f0cba67fbab0e6fa0bc8
+IN: 76217fc9a546a97dabc9be41209bdb582d8d8a62865df7398d4f7e9ac681bcd102e31bfd40cfb8e9352b1e8ff7a7b81cfe2a62849e8b77dcfb645d2046404a83442133e245bd1df35d69dba9ee097dbc867cde7b431565c72fec31719318dd27c3e47dc5f8729ea794668d8724a1d4115adcee0725e4c1e3ce16ed9e31bd5a409cd074c0277e21a0b431d3b30ddd361ecd176a8d86927c2f6693105d7d3c47d9be8bd90d0b2fb20587623b2e838624b590a5c9f0e6d519b35eb5332b16bd2c2f9534e376ba68316efdb963d63e2c87cb0716973297d986bbd885a7306e2bdca0855447b57817285801341c10baf67bb5f71b75a11856d2551eb47e60025a0021
+AD: b9948afd8818888585a6957eb59680a55a5c42458f2d0e0f39bcbada0ba0b6e72340193500e22d243e32be0e7d7bc5c632ef3dc7e79ad5acc895cbba3111d8d1faa69bfe2ce634fc0d7b12242dd8bb105c6ce54cc9718921378c906ff5e61f48fa259b25bd10fee96856a206a928b450a0098089d5cb7378c2935c4537172076
+CT: 3260de6acddb17f93ff06dc7a8955f5d363bcee255bfd40fe5e92e13c7a1c682c6385736284c5cd858ce6ed251b92f5eb10f83970525f56a1ba0b8edba790ddb015307cce877c53a831aaf56f375fb20e58199f6ddb91efdf9983f263c9a746fa2d66bd4790531f85e7ad9a07cbcc00e9c122ddba77b1cc2b37b734a0ffbc29188685227ff42bf33c2e912eb592de1a45381cf6c5c9a36af93af26168c376e8902299e810e07a8ba2e23670c5221110ad4296a581151185553fe366bb4057e61b7a788f12cdfa635d9d6b8ca47a5596a765d58bb7f877242c2e0145d47c300175d7af62a29846830922308b6b69cce8413810184b27a8184bca2d8ef16316f13
+TAG: 7dc47ef9283971e1745fa3ff698c6a04
+
+KEY: d829975798d4f24ad243e4aad474fd5e
+NONCE: 59e25a6dd133944918709e33
+IN: f84b4daf4bc6d3ba1e0b9e364dcad5834024066ab5c8e672a999bbf23a83956623943e0011e3a2883d23a767b280ad84e2d7fe5811099395edd269077162310481ff304128271d4ce5c84ea738fde318cb2528bc5cd448c67837cb7dedb632d47e8f90e351b0a8942da2f78e2065cdf827a85f510e22156bfd971ab3f123e9774bf3ff7c224af19bc79e812839eeb3f1c14f89e5666c16c44a5483efbe449237508ab2436939098640931fe3b928cb3a9378b6b9fc2a54c6bf59f34b16f06d5ef132ae2a7161034f26a6e07badc61ea51a94a20e4692a0a0525726f3de9bd1d6151fa6a0ea3acef3634847cfbc98d2e0bb9ae89e4f91a78c56558ac92b4f33fb1d96b1ade26cf4b2fec779bfbf6709e531
+AD: ce0e6219f75c4c31873d4915b1af3a51c2ef5e89218ac4060dd12be216654eff2991e8d7bce6f6a437966f80c59c527679b8983e75c617c917fa9b63bc60748f5ca179645afdfe6a126a73d3fbcd41a9df6d734e8783aff3a5134ecacbb289f93febbd8eb493693264026f8678e9fdb779038ac13199459caf9c4e86f4cf8306af6dc04d9dbb678d3c
+CT: 98bfa05d1dc27d721378bcc25af4899c9c88fcd54d56662282f9b820e540444dbdc57bdc63b60680262aaeb8387e149fc2a759c0246f771dd9a13209c4eaae9f8c7e43439535afd85c9b12fbfc10f8f9f417079857b9e061cd24b7099726528f4ef529d14097239bafdce4d9b51860ad091c8a7d1faf39d44523973cd1df0377339485a89036d62cad090ffb9d05c7c7d79b01a22b7ee5e485e76ca9be9f037a94366968003b73915b027b161ab90fbc6ab78f6ef261ec5789d668fa2b28b1b1937da1d2337507997fd0d80387495d6953b08ac0a3fcd24f1fbea3df9218a9f0f1112d7bd4bb03ffb9dc790306db5e03d67201ab904df0e4ae283ab3d62bf48a6d79a5faac2ab33aa0599c0a6de5677ca0
+TAG: 767e68b063ed300e63df9933d6e10f2e
+
+KEY: e9e41d154c4c1bca018bbc4d744655af
+NONCE: 04ee2cd524db41170f0946df
+IN: 225d156dcdca3e52139561b61c26bfc56bc90c21cffa69468863afb66c3e1524303f8f42103e435fa2fe2c2956feffe5b06ed20bdba730d675166f13118a193b06d7985d54d46e4150468df1252d7cd144afc99ce99b93ce9526ea4dec2cde1d0d72fb82f55db65ec2035e387e7923d98490cacc793046afaa2e49bed34cd7e4eaa52e75bac5e86f9e9eb81028cbe8a515870edb9a151334e1f961949855565abc51af9a1bbac0222e9bd217d3e3a642b0f3df8e7c47c2c9d5a801cc8028c425b3becbe31df39d30637c38f981d268017da818010189c93d2d135024f239407623496c5435f04f9cae86e63ef46fcf9787c946b400249d8476f82dee274cc0cd3714973f1b6e0ebc443d681af25ee26a8ed475136ed8bfaeaa8315a4cd198961518c
+AD: 7bc7b15c68437005a4973a06818738adcaa250949af910aeb807096595b3af54bacbedd966f83f784f651f7a2044461a94f1a6925e6d2064e72319dae75d3883a50afb6be1395d429f24029dc9b8cc021f15e305e5418d844aa4a89ddd299bf2e8c698a8f6a6cf0165c37bcf2e5885d73bb81ca15a33ea75da5946678dfcd546d475149dd1a2dab0e11cc8b07c0b06105a49
+CT: e3a3521e3e99ec595a3d9d0839d8d0cb4c0929e44f693df016da34e0d8a1f3f6aae28fa0ac0f38d46ef06a683adb04df301ebcd6ef0abf9ae3cc220cfdbf36ce8c023714d203ba785e9abb05095c4bf7f07a13f9409a5759428e6c97cd4a8b2e1a471676807cf76131ae471fa4e8d15225e9996ce4c7630c4b0a5ebd85db4bcbd79bdcb641a626773560b591adae5bf582f3e92299a60d081aacac117235d6d8094e97b034d120c6759394ede2a8b67e47864e1f50669e8e926ab6fc5cc696e70bb016de92707d4800b25ad14f9c457baa1e21b4bfef0dfa6d849e0951c81583a711242ba2383efc85381ec7228b8e7950a375df405f820ab5dec8b37572897c6af443667e09d48a18c9bca0322efa409e04f57741305ea7d51ed9018cb5d0f00b5d
+TAG: 8aa9505e89a01281f033e9658ddb35c1
+
+KEY: 7b1fdb1a720b9510d7d8819b6d946dd8
+NONCE: 5c73be515c6ec00a10a69661
+IN: c59fcd7a005dd08f3cad722bf3560f356c624404f3be55a02b3301ed756f557a51593ba90d18a1c13e227c8d5180fefdde4957484dcb81d08ee3331a6fa74c9c549ae13b2dc2a80ca0435710eb9f0dc2c908d896957b87325180d397c37ea7cf65db45960c4d791bf8cf798bd7626b13bc5e6b45b45be1a8ff687572ece86d1f5361abaedc1a7f9d9ff8003bca97af7dcc42b4399f9da4a0e7e829c0e12f4d41607303f60d1df5949fca0dd9ef171678e013b88789ac1f51a8160687d842c273a2dda93c5fba1eb5bed7476ba96a12e70cabba43d509b311e9d000212c81c483b7e9e7bae1d9869a125558b2c7ef8f838bdfe97af413b460bd9dc5e372afcb105832ee4c406d74781d3e9f2aa581ba4fe458989a03679744edb73ba31c7d9d37920d4d57a766104afc9c96650e5a602ba885d2
+AD: 078f1c67d44d6e86eff0c96a146bad3420c7dd0c64d800ea5ab7ff472d0f61bdf2e5634e06cb4f3c022dff8c4b46f2a47fdca2d04572b67f24125c66a551a1f150a02f635e1e99895807efa8001f46388365c48e4afe49c04f6681510f7e4cdfa02deb3e60eed745cf6d7ca6b773e1537d057a043cf517e5388dbbc44ff4bd68d2a7243587f8929ef07df5d001a6099bebedf8f26f49323209496d
+CT: db79e91f4458befa47953312aeaf6aad01c3fb6e2cfa19b0ba21ce6698896e62e7ad2cef344cd324b3f0d317d9fe7ce713d4cf1743adcbfefb65e61ab6b323c5f16762ac527882f214539e034719047f9d3c0bc80480b7f76481e2fa26262b0bf426f1599d3d0947492769ccd65433fe70340d8f74fe31540b48c053eab97984f5f670651746b68617f603ef23117e9a8df0266851ef895b58b847e911508dcdc590f6188aabf37be430bbc72746ed7f5f47f45c90e2400d5be0e323824c5b86a2a0ea7c2156f482f7e0ff42923d6f7efc7f4f2cc77915bf85091216bb0f8c35f5274c0c8469ef03ee78b82cb6a5b510e16793f38fa2582ce249370ddf480e212f1cbcd77f89810b41effc9c87b0a80e5a22059b36e1dad294cd158f03d80ef3ed31b5f3b095cacbe5782986a69d5ff7621609
+TAG: 221274b4be8a4fcc765c2ac319b5186e
+
+KEY: 50109c383071e4a61ce18f495d98b6c4
+NONCE: bcffd0fc2496b7eb0ba612e2
+IN: a4cca8eee2a3daa0c21d854d49ca73cf5b24b38940dc2b44a2a6623e8404fc30c4e3aaf759425ebff85cb1c661744adf34c6c5d538f3210dcd0270a3d12784effc48734b53c1a228db291e2e5573b6ba2aed0a7296c1bbfdd1f4a86d6057d5534675a3f4897fe3a1200c54af7e09b97b0a2ab9f25d5ed375e7bac921f28f7b6983a41580362dcf0820a2dfe82989ccf0a998286623617453722bea0b6e8fba504b93cd043c7e6c7cccfbccea43f7e87502026f94cc7035c5e84cc14a5fef9bf2be53dc379053725a9a29c4e86252369bf6dfd3cf2801af7447fd0529e94beba961ed65dcfd492398123faa55346edfc3ecff720966b74fd0ff28f443ca67f88b8f5a4a73007f79ef782bef601a0827888c4c74f7777279c625de8a4b51db94f94f846474f8563001339afb3db339ab997cd1eb1eb7b03b228162a480e129c66ad47dbd18
+AD: b4c98f6d51fee205805a50c163beb176b754366e13c57c18433228a81089be18b534ee5f9567d529c802d34bbca36807bf845a9d14dd141c5de85607a4b4c5521e5aa717f78fe78612b770a4677cacd77a425e2496ae50ab2e559526c37ea723f2b8d14bd8314e4cc3727bfb835ea4062e87870b13d94d52c25f0c631668292f184fc048dfeed7a9d1a88cc5c4662030700cd8c257784009b4da9039909f73840b600eaf
+CT: e7a4a201f58f66ddc0b8dfdf95c859879144dfa896406f43cbdc6adc148e0ea8f9a82170c5ab54c77dd0fa6dc209b623f0f5cd4ae358af96ec27c78e7245855e94ed1a1182f9d26d45e0872da3fab9fa9ee3e58aa168925d7f779feb77608067ff45b7ec7f2ef7a48a06ee22747ab96e1b485ce144bb3cf97d1e3cd28823628a2f8e3785d9af28b76c53c3d4c741d1ec56f2bd10939f6c79578c308c5e509ba8b13c820f5912d4ae169da4e04f86ff9b1cb9faa432545f7999ca1014f77c08ae9033712dbbc0e99db6eb604e774d5df8f6b928a0bb59e4c662d778d195aa95194a0cdf7688b309abe223048937691440e5a78cfe0cb75d229634aa49ee54a81fc9a6478c8fa310d524bb15ee8f54f572dee30e44eeb9603c8593f8a7007a1b0dcf2e301becf300f20d2e868b104154651446316414b5b5e9432134c0eba97b4cefb90c32
+TAG: f304266924eef673246b3c14389a82a9
+
+KEY: 670cd4d988845b1d41cfeeb1ea740db1
+NONCE: 29c12f66a74e6234ebccf4df
+IN: 706ed30fc736cb5cc0db17ed108229e87d6b039da5c4f0568a4cbef9d513dfbc0af9313f02d5129cf616487934f741a0a60bf11fdc8d29ec81eb37577726f54f3e35bb10ef98b1d15bd5726fe501a9249e409eccae128df61762447962ba2a63f30b59ea25e18895d2fd11431606caf6b45b908b08cf2e150c031e20e6cc649699fed5785cfc6a0e22bd8bd8c6d25221e9c9a8d2869d236388fdcdcff990cc940ddefd06da0524a351ae6113b29db9822adf9cb548d92f23e3951ae8522ab113579232e58578e80bd2fe3e1d06414a27ce0ae2e40d87745a8991dd5bd2e8ecbcad8b903195c15ac2eaf9bfe0104bae32f772a7d7416c5671350524419a6df6ed5e1df32b961ea39b164eb7e1353b046100998ba6853674ebd5ba011691a270c046096143daa84752f872e1ae32ac07c4f0d2a048362d12b108943a7007bb6cc117135b165cbf42b92df2f191f06085518ebd1a9a2e
+AD: fffbc936ddfedc527b2c9cb69345e0c497cc4951aae5be2748209607a51a1380fd389a14ede9cd4cbacbf822597b1c500cb0549f08a35bb0b1a00c5e25c175318dc771b03501bbe45fc52b2ceb4c04b8213fdce3882e0967ba268cf786ea0acdfca0a7f3f2f4f9ed5f499ff70230158adeb5a741da266573742c527bcc8de42747df891f58632f92a110a981a29052bd17979be21e53067de3baf4c34bfbaf56ef5b3171efa1ae60a1a51f51e0
+CT: cc573518606d6416256cb233c66352086706f7f321fb5d69dc75dc6e11b9f7d053bd722b8d74f6edb023e283ac048570dc23dc34e1d344619dc648199b6bd3627590c7acfc738f10d896c0e3fbc3d3b9ef75c20c616d1dc96a6c3661b4f245ace3083590b1d97b936ede9994b08bf19189f573919eceeff80c25ba1584a1a8744efc1b2efcc264afa045dad460d4a97553d33aadbf6dde24790853a342349446741d65d3551ed343e9dce6b6cf6131c9bb3524597d0ce95e6971c01581fa140caf86ee4b53d17befeeeda4f5ce5b255a429c27a169aa075153bd4f1924df1750332aecbd365d8f65a2fd17f6abe9a054b3a2abf02a5b2031282715386c166dcce653bf3f3fb67aa119459bd5ef3bad4ea97aef40335884175d7fb9bbb3bb7f3114cd68c8136e8d02aa204d282403a34a89305725e2e022a9db9857112350e965d51b7b3de7339cfd3f202d18a07155b5bbd11fd64b
+TAG: e3c4a624a012f660f21be3776f20b440
+
+KEY: fc5b726bbc23a67015c35a1be5dd125a
+NONCE: f812b7661106827f31a1e4c7
+IN: e0bc265efe59c9d6620387755a0bc17a11527fe136b765895e6386b9939c548bbe6d3b35eb92a90c05d0931e5dabad4d42ebee5af45be0106aa68888375a2619f7418a14570d1dedb76e8ab52a0a87eda2570d2c1d903ed9ecfdc62c23c47cb7e234dc617af0843a9f375a58f930337a88379b2b0553c4db974ad74eb46d637ea4e7c7aaafce16971682b772e1d85bb4a7272bc56be9bbb55625a5085e601a5dd60701bb07f69c755a57808d022ca0a407bc3d35c848d6fbfa6bf816d470d9a82d43511c13fd0f496e59646e65c84d7652589c542ae2e73c5b7aee83b9ee8381af1ea1f930444676d8e3335b271cb354e9cd3b17e7f1511787fb618aae930c14cd302bdf3a55b2bb12a61e7b930dc39aeef36447bbb2f4d9f5fb55797627fe1d0b94c04c6817de6cf1e7d6e2660c6f49c0ab4b31cd5b367b912933d3d1f0a6b8b9556fc6f8e9ab310482ee241fc221634b5094481ea232931d696c889d3d37e1c53cf74a3d5b
+AD: dc41779816b352803f282410580b0c03e861f4f7fc98f8a4cd9a4fec0c0b27d92023c081c7927e7599cdf59031444e74fc15dfc12d3c144762b8e448b7ef6772612a2e7bc34a048bc33dc56e99949d569df7e296b66cbb37c66dfd2ad8e7aadc350f8350cd68e8c4e2461290e30f9449dbaf4fdc89221cd75493d33f903d365ec418b327e3dd6fc381a8e06c48868823a42bcd082ab16b2c666b71038273427ba1ceaa57905c655f0ec4d25401c07c679ff5367a9755
+CT: d64bf4eddf29f08aff3db1225ccc9df5fa92315d70bec762a001a21f564483c43d9fc25e26ef1cd8426f215f4fba46a4fdf5ea96e6ebafddfbbe15ec5a7f8aa6058f8f3b5c48339fae17738b374bda2ae9f0b95d721342d968ccaf1ded6cc9e0d25e4074b722c876565c73a80f9ac25c8ab7c9967b79e5f924697b65ac4f6cd8f1dd6adb5a3c943c5b43d0563ce8656dbe39dacf220e600b82af2b5ef9de009b51fe6ac5707d3b0a15e87ac4c27501e88e9fa4fb84d10cc489b2738fcc751ee5aef230d4b9e4529cd3c580e2c248ce92184fdcccf8d94a5da4ac34acb13156dbc3e676bd26c68e1065990a73adefaa4a58db57dfab709af8539f449d3c49e7172c6ae686e494a92386ab28caf37ebd026d0e670ea85a010a6fe8312fe5a71fe6f0c7c52dc80b2dc39489ccc39c10a7d3d64ad66ccd44638c8c9d83e1b88930d8da56e978090dffb1e04a08303fccf1dbdb1bb160e0f80d4493eccebd984f898ce877454f84b0
+TAG: d69dab4de29ca8e91f2e74888f80b841
+
+KEY: e63611c19ca5deb1db80f97a3f5149a8
+NONCE: ad2cd6491caceee3e19782e6
+IN: 6354b76422dd47ba1e715dbd271a07fcdf69b5240e58186b82b1ac443000cca1b0c79dede1cf998643565650e998bf4760dafa08afde120368ff9fdcc2311f78d803c8324e385ade4ccd2eb2ef51aa1884a496ec024221566c8c882992fbb830d4923a5c5d7b99c7e6e7a8aae5926d143e19bed7faeaf7c77bfe7c9f05fdddf75df3df2425bb94a63f54bfb1320bd32e7fc2774be67a22f2410ff3c295cbc3fe566b8c9710807722198f03f56f0abb02ca55de5174d7f9ffa61c0bffb88730886c028451062d6220586bdbf5ff91ad6b1033f2c9d6cf3c3c7bb58a070e8bb1c3a39e3d04952961849cf55e64033ec929f30b9ead497d14b6c89ff6a4c008dab0104e7e20df6d6f11474ab680e5bec789623b2b693950a5d17dbc5b49cf80ab033b1910a9afc4231254f88ca13f37f1214753f32547ee0decad4bb93fe229b6c8a14564081d8ce5d47cd45022bb74475a709d84dc5fb0fd2e46ebc9940ccebcce3b674a6934d4dd57ce0fba9a1407beb06af6d1f6d70275
+AD: fa9f177cd36c990d4b22ff63aca475feb17de03d3a52b4119f9b277649f6f53f223e29e03493c938688be81151e268928380b407039fb38494cf235ddc823e8cb12f42b50b2feb52be05a38893d154b37cd1cf2f635413d7819354e29e195bd01517992b51efcc91e10932dd6f8a859c5bfd77f2e3efda25caf034a91053da8936e1975fcbecf2ee9784bfae7f903df4ad32e088a869aade322c7d14fc4143c50c59112c8178d00a0424f4003748d28956c9d3a6c57a8e0405d6509147b50e
+CT: c22ffa587dd3b6425b81890f8eff36af3c64549c5a5f3e1deb44a7f14c6a179b1f76dd01d546a4273fd6d47b6f9e3ac5e9b641982d1002fda49af071d1dcd88ae5d0ad778d846d3db243ee067f17a91bfd808ddca26bfb67ad28303be8f582de507fb89bfc79c10513327c883bb4c6b97729c1d4aa32ce50703636b2fda0f592174f2ea36b26691e6355ad20bd116619dc728895bbc0cd281f58aff68d39e16087d3cc02ef04dcc93e9bf7695cb15a8f2db51df2e22a2f04be96021b4008f50c94cef256995207ef1dd9c0137d4cf63aba4a0d28aa5ff7240bf20895f8e9585c8c16437edb41e51f6ce5a4f965f0abae8bdb7c7abba2ba82eb5ba1dffe56411e51aa87617c62f7f6af3189647340865f92a16987ab784b1d6549099b1a02b369198ae9f8339e9e197f41e2798076b5b5fa61aa7fd7620bbcb8828b2332829d554f21b83d018b59f785e3a2db359b36fea9a8f085cfb668b3a7d80ad38b85e24472e72916bfa2887036d480f6ca48acfcc7c0f471a9501e
+TAG: bd674531985fa355e1ef3b3dbf8f70b3
+
+KEY: bd7d9a251a127a4dd736d0f74e68755c
+NONCE: 4226110c276cb7870cf1c7b8
+IN: 6617944662737762aa77bb255d24ef951b69adc74314c72f37f32dc091ccfff067a89b834b1cf0b58cc22f7dd6970104dffa1f60b2ba837ca6ff834d07c71ac4eb40416f0f50303dbf6d0b4b0b9d9afa8da46c6753008f093a188cefe67f051c8bb3b6121841e2ba25b8b801db329b8da7d0bfffc29a3810d2d165e854a9eb34b6fcfc7c05bcdecf8f20b12c69f5641441156dd85b910557d1355e9d07030278b494691433bd5de2858d8bbe2e3071ff450f113ca78f385cf77e6dc0a6c3888e3144be91404deed2afe438240270e9493811343c62c2ef0e785921f1ccb2d2d029c5f0365f46bd55bfa8f89d1d4c30c5f6598fe3f9111df847b27a06f7641494e4eb7dba8a5296f90bcee8cf11c1f1fc16c52868e8f2db2dea75b91dbfa023d5555371e1461283e3f1695e028ea00bb35b6e81bff8f128af2d81df6fd2c7f6f42bbe9dab30a59ea4788a53cf9d6a2b1e9cdcc9f1883b37c91eb8bea7659fab41d47f6fb5e453777b589188805e883e9e15ae1de4e80860bffaef45a1e0a01f88b5d7d948e63eabbd
+AD: d2f357cff8c172e6652cd3b420533b8527a6ef26c8ed75d349dca2106050d80cb22835c15861a22d8c7cf8c2c2df9407eccb0c21dc7078de4b8b91e82d94a9916c9a284c7e49c8c7d001721a9031530474452588e09411c66023c9c81b7891ed271d371d60dc70f0c04ac93bc694e5b638f7ce901011e1a17059892a98d596666d102d9f7e0de426449906081651f88157063729176f4608f2d506c9637086f8a56821538a6241d8ba5e0f37ad3ebfd0b9f3b3bf0ce18c095c4533cfe33f6a98
+CT: 7db6315e1ce8ae23774c2e8826811bc31b2d17c869691248a5b49398465319576c56c2a64e22ab0108c92b52d9a6096f33841643099cf47aa1defed63b7855f3a4586dfb8691c982eaf102aa87888d09b6dade960bf166e48d58999dd08a0802e109186495833a8d8bc5d6d3159824d1b89d4084cb831b8526dfd1c620b4fb6000e45bfc1a101984f3cc51d54c793ab8f034066922905c532dd60c7d96f06989d10c82844f4b20e872538f27333e6d8656b46fd819936124617cddddac8a64d2a81a0cbf21fe91293c8ad6af63536d10c11a63297b620350a6f76e76afbbf2d8c63428d46c9ca123b5022e6d67fccba1011b57aceb10da0878bd873422438cd949df47533eebacee697f9856222344bc9c4876f8435e0b999676d141135a6f42ace8f99b16d86e427f1ea4d4ef524835385ee1cda9f4049c3f6f9226a69b08528bc3970166f6f9067ac30f9d24b7da6bbec4e58286b3b1c5a7711ea7965ecabd02375b38a603d49c12131019a9b2affb801c91d54896c8c29e09f62a5fc0b100b80ed54b70f568d7
+TAG: 9fb615a8c354e10560c3cd37ceb3c3d7
+
+KEY: 71bd6158a17dbba101f840c6638ca058
+NONCE: 9434c5b842d5dc501c774114
+IN: 2982cde70d98014e925eb46493b0bf91a569139be22c42cd33ba1f8c2bc884b2501a0f49d6309344874325345a98481287ccc6d29978d1e5be73740fdf2f3a3fdd0d7c0642be7a22e0c98f0886ed51bac87ceb0f2caa79cf702ffe880daea115b8af6546a7bc18469e07a3f8d8b8a825648684e2b4e9412cfa0f895cfa162ae0fbc11f8cc4a3252b2acf89e8ac67de0adb91e36dd510f9d8ed4eef92047d015b2ebaed1f3f0412d81fb5bc82f548dca18d5205995c22beae86894c88aa7b50cc82029abff7c8a56d0a6a594fb502ac9f11cf10f8ba9967497e0b70551a6440e15285d53befaaeea2dd2e743cc056bbee79e47350bfb49178454aee0c78372db372d99ddb910dfa8db6556b61d64e8ec833fe4737b13269583459a39bba6a1202fc709595fc0161f537bd825b3245bfc238a6c7d3b2295d1857129df86db0891e022199c793b319ae965cff94b078e467343796992992d388aa210d50599a3b2bbea36250ace162989e3c21249115a402c544aa82c0bf7b2cdf2d0ee20653b1e07cb42f9d1d0575ea7220ec01bb31deed93fafd126cc8d0d268
+AD: 16561102778d04ba7d68de3d942d313a63f1ee6c3a37397348f01bc83fb878bb1035748038047cca0c07710b9d76e129f9b881037786907560e4ae9592c02967df22af893b3ad409a3b9587454afe0375846cc8ad94963c7dc61849ee4ec1406dc7915ee5477bb73a43035d67e822e45d3169db88b269824228149abd333af8e41d2be455bfa449bc2ef48f0fbcaeade0f6b62d99e318a2ca44506670fb1397c47d1931136cffc72ea33a0e1e97745e938ce654b9b961fd4680117388dabdbfa134c9dec8206797e72
+CT: 6da55c8a9c5a29eaf8dd627d7048f0e6cf1d52063bd0a7f8d073e66fc406f37fb397f789e4bea1da21a94ef944a2a0fb9a35a7acee3d3687d8d713090a1f2dc3d118ca10c85f5542f9f6f40a4a79bd8816efc75cddd4a7adc9ba91483ca70daea0c65e975be46f690a2182602b29d7c04991d2fb61f154f8bedc194ffec5983b12c4f4d9abc0a415a517f4b8923a2ccf1d5213952133b82621dfd4a8379cca916f6ed9e58dc94baaa1c1c7d8491c3341e0751d90d131f20722bf2c44d097dfcb6eb49385dfb8c86dc47a7dce3ffc3eb89f32b4f106bf48c0d69aab448ba315145dd7ebadeff3798bfd004369595f48c9e7be596fc181bac4573d994f6d7a778f353e3aff64c3bd5169e8525edb96f1e97a5617345fbac9f58c0885d52ba25a019a4e01deb3ac14c4739c0bc73f28d4a05bc5b0be11477395f706d45ca0f7fd92697e6a8c5eae587dc9cadf62c4e8c283041211c3e51a23b84bf00d3bd4be490cbe9277268fff3f652ac9eea2734fcb016639f3b673b0eddb2691b10713fd5bd606deda19d9429ab17539dfac05b5ef87c018564cea21fcce7a
+TAG: 9f64a1a1ec8b09b1e64b258744ac5f7e
+
+KEY: bb5e6c7b672e7c5d720c2035dfe8d42e
+NONCE: daa56f54bd2dab11ce5ebc2f
+IN: 95ef01bf080ee82e8ebda43598dca58db3acabd7b3cfbf5183d07bbdae49004f5154d6bafbe1114baaf4c624688178234a6176756718e79bde83422752e7a9ee87648b182f8ebdd96213b640b76118b577064f871d627d2a7218ad19d45499ed3d4d9bddefdc282e66d1d708daaa558ced4edf38ee6f3a9add0f2126e94a707261234932d0e3674fa085a7e2688b854bbb9bedb328940b5d35fd0eb85f5a56f1406d7a8eb7316a17eafdd7b87ee85d812a740041c8ff6057a462ea51bd07df0a0b0374f5b4ff65ba48587cb83d20010e67f36106e99a5b733b8627d541ddc084ad0374432ac165b4e81c8601e7c180850e54d8db89c092d356dd617439f36d65422a45d116914390320eb1ed0736e47afd5131b7422234a36c5efc5fd578fd6674176a7ac0f73b63a3f5188aa9a7773a27f50e103c2faf3e0488acd1265055999bab1150ebf49bf03728bce3ceb49307e2af7bd5f9ac307a8d249f55514325a6ab58fd2daa5194b07fab933db72806ff4159075e140d89fc3e5d6b684be014b5f0ea1c857a97196f184755c637c4f3b8bdeac41fe1bb892b86047e88facc04e2d88532b6f584f4ab378a
+AD: 3dc7d6102a17877db95465015e3122681258437f11d14b83f1159a52486b4c3bc6037ed33de9e856d3c89fc5838aee587c606cc0dbed9a58faad042d51042e086545fd9639b18650bd531065684076cd188f11508d48e2a7ee585e8c8e9061970a2d381374e0bb5ccfc8972a01d9587872ff0c925315d10ccd8b9cc6b1450c5400cee4e2edf25ad952f31da22c7f241f97d966bf491ff2b8f889dc798a24e184c64290656711a826290917db99e2c2bc679c92d309a1856867d9428ca2fe5ed2a3d0476810cca53b18526de0e88508a67c67
+CT: d5c7b4282f37776c03c6efe2af410b10caef49943001460800fdb6408f3c7a9f7f32d8db36dcdd0694170975536447d84c56f84c966c28decdd607237bc7ddb15176ca20be0993f309d2749db68666b2efbeb4c68cb3982a68f67114c0dab61eb9d4cf4c23f1847fc36bd561b0469ace73c80b0347af5e88f051ec6cb19ff8335dc56cd3bc6cc81893c9234457c0d8189cf1234a6c8a262926402eef262c4c5149fb68053480ab2b1512a91d50c48dabe637aa410d6a164dbe4f8c1e1c0efce8687dc858386c92ed7fd8b8692d67ddf453558d28998ca1b57a6c178f12f4b64479b3367e8dfe53f809fa7baaf8d1efbe3c9e2d83b0377cffd8d8dc172a1eb260762c873af724248011d9e0cef6971ec12e81d70aec923664ff7f7cda9d60b3464ab14488b243930845e38e93a8683787641b85476816dc73d17a593b68935e4cf71d81ed7dcc9202db65e235dd69c1f2ad4fde4d566970923a24bdee799258a3198ff2e126870252584a1949439b7e32318af204ba164f9f3488a669800703f988fe56ea6b0b2cf662c43e103e2e63b377a85fd8024d3b40ff47f30fd3dd6a0e07e751d07d5b0e4afea2
+TAG: ab140e2a4dfe81a064944610e0cda2cb
+
+KEY: 97b507a2e09cbf5c31f7be6dffc78d88
+NONCE: 3f607f0ec3ddbaaae6b087e8
+IN: 731cebc792dc840ba136374a9b654b5d61735d2d85a70646be9c470918201b9c8f756e971cfc12e0a93acf386809f769ed64a19f47f266f3504d47725672b2aafa611456987fd1db71d16a4d1289ad442f0877da4f192d814f9302a1207a8e8e48ed90f6b5434b35d47dac6a0446156781ca1fa41f7bb772d1eee48919b4e8371cf49fbf452187245a16b51daf82e35b77e80869eb84ee9ecd90312dd3e6e6023ebec1a21b4279bdf21402969101cd1dfefd0a730d3341571bdcfd36abc675744f96bc7445f77f90f261b1ae207f93d17828d39eafae394ecc2e65bca79562a706c279bcc6d038edb9d7a344ab1a5021f9a597b223d7a1a99e1268dceab20c23e0208b9a898e99d83b2e788c1b7faaff2aa6145f8918f53cba3168db274d65f2e419fc233927599f7ad96890bc1cd4f983276b126f7d10b894a67237c7b67e8d633d62b39d788cc43b2f8a05d87e656ba86feaa3a729b0be2abec99bb40d177900f20b559c4e0ae2034409bc9b86c54644cab932e997fe0554e7eaef7b247aa00f9e1ec07aa9af3a86470075324d02c32425309bbcf5462aa20caa950ec9653939b043c2e94f0ede1b91df0068fdc903431008fe16670d77b08988
+AD: 0c962e558fa573b2052d3106dafe00e3acca3df673fa559f950bdf9972e20b9612b5c4c96d50997261be7f2fa978b793d5b61e74b82541c8c02305431a6b7495f948622075b5d18992d976737e1f6f38aadf90bfb46f7bb9a7871620218564360729844329f4cd2f0c77bbbf17661529f88c80d1e000eafdbb937411cbd4295ae697baaa6c9a31206c5711bcf31f2dcb50cddb4619d48388a57475df684f4a00d432560540ea4d4d337ce0284467851e86447b1f04246fb2167625a0b3cc16873841d23551653aa1678ba76689664e16c7354c87d5fb7d40287894
+CT: ff28b33337262980b3adc761b8713f01770dabbc1f458516c721c6a19317ed1f1d6520fa7b2859cc577fd92fa3525273f4a87c99575940e941914ed586e7aa5637c4fd2d98e7d198b52924619dd68a214389cd486fbf006ed9c72e6066d92d2278abf1fbf4b4ea1f3d945bb1653eb3c217d7201d5aa40d34c8488532d9818b06e4c0e97c4cca7c9e2ef19ab5a397db27d4465f41585ab60342a3102837cf43c95db008f0689ae7a7970c2ce9fd685e2811393931a4d169701068b6575b47e88bbfba48281ad4b297fc3b265c0590be6b0208f6a27594b0454e55893c68203233b60d08e25fa66d63e76a869a4b84d153c81f1faf46f9a3130f7ba4718a75366af23e4377d60901b960a4926b850f4d4052d6ef1a5c54ffb388acbabecf069a5841a76cf15ced838239a8392149ab2d904b482bc661b3cbf4c74b711778cd61bc38499120b87f0f45f8a5aad51c84595b991d7fe37582b1ff963063770cd0ec9d98d78ef323c8bc939cf3b6035a5e1f5d54cf9af44d49f9cb01b7d1e91c2e0da110a33e372b07402605ae81bb4ef5505ef51b3dc23ef5e48f3f16711d2d72bea5ac90e85a37c97ba2d1a4f5117a616b3865d97a65a08265ea0c8fbf
+TAG: fd76a9ef5ce12640f3e782a40c6d0fa4
+
+KEY: f46e56f5394bacb222b30fcb3f5d5547
+NONCE: 6fc37c122d6865751212d4f5
+IN: 7651092066aa20eb70114f269b08e4ece1b804fa3f2c5e4b94981d41b3503fd127fb21c1ba24cb871dc6f19c2a674561900f73e292f618e1b3a285ec79bc7784e3481cfe36e1117fc620aabeb088585aef6632a7228a5f901c62f248b9ae12c7a6e7e5052d9739bfe303758989af254b78d5a42c74b13def0516611a1c0323e18070147f67cf0613cb22d83dc29c176b6823166c35202c46e85484640221fea9441b1e9f4ddfa4c0a2f4b2599c6fc73856e3c18a5905f85dc919883f3fe9dbbffc50e89e8b71b9a36c74290718e0b89aef1ec21fae49d280d3776d3ef79368634716cafc8f2eefb3f449c438c14deebb705a42e85274cecd11932c9a84f0dee48e8a2175b57820c1042adcfc42ac9a39341af5ff6edab2d25eba8f0219d3737bd4e7ebcfb3883877130c85e5be6a7b87cdaf4d37075eb2f0bd0d1a61567a362e8f66302e56668590b49b5c76eef962d1c310f8bbfdf8f57f3f82b9b2f72ef49cf487a4e8618476db71c6e0813e908126f9958ed5453067c6797eadb432d07de49dc2e50a266eaf6174cd1b18ab707a53dd47b564518b7bda452bc451a25ad2aaed6f2e7a3509f704954bff2b50f5cabd420148967ff830b0c4804ad5081b42f842276c6addae1c3199da8877
+AD: 8d920a6c79114e667faf28fce2f7924c4288399e5b4968c711f03d721e885fea0668574ae965e9996aab6b30b6eac785cdebc45a305b806ea90663927b8dbe8116292ddcc56938c0b1b1639e8068db1e4cfd101af5478dd63fe0209125ce92e3f7f7fa43dffecc07ae1621f32af975dcbe3f34f1dc75c75fcbc4c23ee8b8900c2719f4a9f50e57b1f9a9d9172fc746112f12b17b85b0371d0472d3c193c37e837d8201fe7d3ce588ab7e27e8457c34d399edfe3af2142a2baae6c6ec74863f6415ce30b17c17599860bf9a59be41a6011104b9cd0b8241ca52d1f7910cd3a3ae8693e47f
+CT: 4877203ae9162588de263a70fd978343e6e2c7efc107064c1a314e210e01633eab9cc234a86f0815e515eb2148fe67023dc7c67616a575c0c1adff2ca1bd7867ca351963728cbcb6a41b5928e83b6ad97e458773e543138f87698c86e6a84725cc6330e3550d40dd3103d0aca5139b2e7f7f7060e34c383280a9276aa44d915460cb664d132056955b2df063a03fe4f844122bc02455ff1558377d8c15419e34417e3c0d5d69b69943027fe32384cd53e121f885293f17cb3f2637261f3c9bf6321406f3f4e59dcd37972e3073573aa5d9f78e021d07b7036405f193c65a2f8d47f9a2193623d403706364f514b1beda6930925c1afa9f294ae625673e41647a94830dbfc45a4d9029d5e028e8997d9f251aa7da65b48e1abe8bca5453482aa6d1dc1168bf4a6ab5644d623ba15dbf10b0f46536b35e30fcc5086184d0eda2af5016f370c9931f1634331458c51b575553686b511f073a2650a1ae9cd2a64d8ccb14194a659bd533e91cac42690d661c5038d0182cd8e52bc751662508d2253460fcfcc4428ba7a55f1db80bc11af7576e6b9ac2a35929bed35ca82fe497a65c24d04c96e6d9fb3bd66fb54f01483b766b614a97e370ff406713d4b811e1327fa52692355e1d307fd2ac67a4
+TAG: e7208823f0abf2571f81c015eac317d9
+
+KEY: 4675ade296a8c507fba35f62c82d9230
+NONCE: 51fa718d52a0279ba9971490
+IN: 32b3a91b1dae9cddd5a89400de90ffad1e1a126c41459c512c261f089787fcc18c4583abd4c9e8b7844389db3d13e8bd5fdb68bd76c3878344241eca6916049795716b257636f1d25230db71bb10725fe4b9217d5643ea14754a69739cb62c7e99c5157bfb8c153cd754a2ed10bbd574c718b8dad2a556793e00d8d5a59bdd486e768f2e61ea822822532f8b4d77b3446eff2cdfb7d88d37b3e7ab0686679e02497abc04ef7a240d456bf999cff4268bfa6e366831559de7775ed6a6d4f02d489d4c305f25cd96f2239f2725961d5cd823d72dea41a1c1f1611fbab63d339a8dd47a3a31b7790a605d3bbddfdfb66ca6277a9a3e4036e8662d6560d05a7ee8a674e33d6433aed82fa26e5a1f5a2f47c28092ced2d182eabb9962aa8b10a567ec3705be6889e1415713b9ef08731393cee91370cb1d3bcbadf5710eb841d37992a7aa3573facad94e806d0019194b2cf9c41db281f6ea462e2ab7364b8660b956e145a13b77962c3191b2e46ab764392910cb7410d740aec3ff2ab8b643ae7e65d34f895189bb41902fbf2c5476301600932728008ce33380845f22b7db3a7b9accc8cf0793bf6ba37d405a6bcc8cc622f1cb205cd0b6e7fcbf3a6eb1d3bf2fb91e98593959077e8bb76adecdee2fcb008cfc335d5465e4e10e9cedaa39
+AD: db35fdd7b9533c5b8f2e5bdb427d8bf42c5b83cc11d2ac5ac96f6cf95090c5f439bc5d4828238a86c5d444ba0aad7b6c5917f673010f0717007a77064bc4d29dca0ae96b381cc89d04d5731a0f985a1e8071a0fff733889d0f2475ae9277b0ac5f7b68a0533f16f904ca15969cb24c24faf7a155ad51917187c5ec8cfc95352481f0e9002eee9467035b3d618b7f6cf9faae1de33af239e6ed4038706b735431195f355a27d1e7098ddd1f34fbb0bd3449b8c7a069b486984d09d50a90a099934eecec7372fc137b5274afe57bc0cd6f49b1e17638fdc8602d31fa975c4f0223349d40a86c36fcbf43124a4726
+CT: e1e44ceef4e08b85ca5fddf58c4d6eeb9785e0ed50be7856e74dc1cfcfcfe92f0e59a4fa62db0ca641b0be4da12a70fb443ffc46c8f5f28ce467cb484a7a302dde2d459da83d8ca6707fb0c6eda6312e37c095276f9e65b44fc9a0ed7546e0224d639a7ae396403b0db8be55276fbc380181cfb32c357e99a4ce0c33e464d1feab4a409651752a05f2dacaf85125005b92a195628bd314205b8d2aa1aba19d32c789d91e565944478e90cd1d4e10c475b79ee5e7f7aa22456773febc5d0684ee0a26ab27cd391fbfa1168ad28f46b114d31c7a3794cc216626eb41655990ecdd93f97a7594330a78426da7f2e8aa21871a1207f769dad7db7dd794382a0f50dd8dc76ec3245576b99a32314d3b6a4046a56fbe178fc4cdf8bf39c86a6ef320f4cc63e5abb6ac53f6b336fff96a22dbe2e836c3ea9f4b39ed58d01d45937c8b5af0df6a44bb78bdd59c1f1ac6643fc710e27a4fcfca031b6435ec2850289605e29db5911cd2b930a4fc28bce98b30cb2b6b9504ebd561e65efa52759e64b435b99ad26b7653c6bdd21c964d20c5761bc3eac9e2986cee13068c627721a90862fe387382af2895efde343e3c9f13a3ed019a144533af765424c7c80795cb30ec132e7aeb9a0c0c75f2b885a4024325a491eabbd30f81592377e040cb9034
+TAG: 5100a3a60ed7d5837ed8adaf78c625b3
+
+KEY: e198729362ba96f79d5e0d89fc404b38
+NONCE: 36737445756c6060d9e95d16
+IN: 38a030ee5fd954f5a9cc662014ce7420fcddd9f2ab800823246ad30ff0d0f7789fe11807703a731675ceaa31b5835ae039fc0d111f5725ce4df0b9a075a8bd1c1112f90bd64c668d1d9e794228aaec7c17dc664ac88668cd06ef9c425f2815891ee4b737b18b138001eb6c353bd5fb7ec26b2d26a12ad2fa707adafd884be4251bfcf5e5e8f3979e46d90a57107e7e4d04c658f6224d1a288bdafe8e34df1541c702f29a1db2af2279380d49109f17abc4161a6052f4ef0f6657c7322eee44f4cae949dbca447cbbceb9f10c5be6de1d8886766794a3eddd736ac7acd3bb87cf11e88f246fcec505f595902d1121f68557657f81340261684fde901c079dd73f7c9e1d4bdf90613e7790f334884b668ee04c29750d2baa21ba94f2407a512dbd8450ad4dfc0de22dcbb291045e0fe43fde0cf1396cd3bb959f2dcc1f7ea681d0e7cbcc73e7fffdea35f6dbde8ba0079ad97c8767bf76aa008864375aa0b02b89d8bf2ce7aecb2403648e6069e209f7283f1cc180c166786d02d984afdc4f8eb9479522362fce0633996c758d99049b25c89a79f7257627e2a9557363a290a0a3673407a298ac1cc034793cb7ff44833c569780bb8be9e937a3a758f1c570ec1c4865efe85940c08a09430a9fd36376e28e127f81789e8a605405de9c452cf8c7131cbe37597c9a73eb47abcd2aec
+AD: 1b2a8522f154e672ae25f8494ff35d2573b343213a2fbb07a417d8a60510e7eb1ac5ecf229429f330809c84b0c1ac8f7e28c7f7414db905be8f5fdb5a2f818ba8440b8c9c20f8951b8e9b75eccee79b096ab09f4ec99ec394c7295b30d29060790d3dfc17d1321b8288f3be38b17901a48470784d00c5b53f895fecd4053de78d074fffc16c302a4f2718327bd96445318ad247c99c0ad4d06405b6509ba8f6bf47755f0b297c4616790b25edbac2fddc89b8d509d6955cdf66d30f2bdccac6f856a3206c53c550a9970ec450097ae4cb6f5606e64c750042060c477203479aa4da10edd4d28ad3df96d613194646abde78eee871638
+CT: 500fd0ba2adea1fc2ced2dce635c5296edc590f961c26c6fe285f4ad84f6e85719ea6bbefff398991c03a423931ff493ea47f97a8aafcb1ec7a34101ee8a378dac29f027c312306f74b6f92a6eabc829c3117ff77b6859e67b37d05d48b2c12bd30251d32ef30ddaa17894373063e2a593ad5139fba87d38a045e2e4e0470dd4c5555ffe6fc70e564502be523737bcd392d0c41e70a594b29f949838f9bfdb6e87fba327c430b75164555d7a01d7bccc33f2736864a2200e4b2c4d7b7192cd22f7549a9dc3ddda269d78a4d98a344cec44508bd930a14edffafbd1f25cfab8a29b75d07d705c3291de774af867e2e595ca8fa2bfb9fb3cf2511552f1c872fcc8b0878c4eec0fd079c7b17bcac2931181897ad50c03880102109a42c34c70d64ae942c73693f85a6d1230a734fb35f70c02c93813700e21b2abc304631ea9d5392c67864eeb47948b7e377bb51e3a5070524aa0abcbe0a624038f6e1b3c062b7661e1471d6cc3dd18143d6237c0e32e80791d39becf94974bd765bcf6bc5a3d764584b025317f64a67d13234399e8e9d10dfee9a77ba887cce119e09c812661b487561acbc718bd200ef97f76a4664fffe64b367bc36f7d03930f020e0b1db0d8d36103da1dc8dc6e0df00b2276d25c8312222c13d8a070b108a1b3a83247d41940681c59e08243a12c623c2f2d2a
+TAG: 7c3eba9d36b26d27a7a0325d8c23923b
+
+KEY: 2167ee6f77730766fe8b4ca6c8f02708
+NONCE: 96bcf14cca5d7c2184dc6eef
+IN: 47bf9fffa3f4815f8fd7838c0fec7e9c08bca51970460bc013145f2d651bac1cbceda192014a5f27c991ed3e7127903fd49a5b3a4dea1194ccc10eb62f911586314ada3aab0f8a5d53c90560da3681bd9157892ffb1a381ed33afe203e3c09748487a0b71b8703f6e5f84d9195db08e4c4338343fb8e968d9f5a5b1606b6b20fe60cec3b54b49ef7bfc81bdbb2926ccc79697d916c3b622871dfe9344699c509f9b2775abc12c486e71a008cd525d8610f51948f75bf96bb94c59c98f2e9f35e8513e43898754f7338d7fffb87e538fe6512832e5c2b08cfe952985fac27b0e81a4edf9fe8b9f2eb79758a99fed7907343e6be072bc93fbfb5a539142a18af4e4710283deeeba4e0c1c1cdde7e886e7d04f817a5efbe89d12cabb34153856af1cc98c4df21cbc1da3e34f0ab74842a8757a189336487d3ec77f842b10e2efe3e1e232fc1dc89d16dec865cf6e9f422e7b9d7a4e421d79657eafec5451e04174b3372340d6fa8cbd23fc0215e9b6d70a9781ff3b8ae049bd31a363d3fd465f235ce463f720e4bca114d21d3dc407a66f28df01549d168544478404256715161cacaf06d955f525546d384a44ee0570d8c70319bd33aa07b5ce0a891c467957d5ca4d2523d9958a8b4b3e5d3b0dbd1f6a1df3acd38888d8383ca76d177685ea6d2d65bd717203ccf794d613b2f4d50894cb12754bc95fc19c449bfc10443c5c1
+AD: 6388d98f7a8343cc89faa48882e8a60f83e817f17f68eb338289e2deeacc6bb5ab6d25635b9e0d29fa87ab97e5f29ecc47641e5a4e0d5f11d04bb25c7dcf21e7a93de1880ad022c838b5c957616764bcd2a66f1098ae4926a93e1726384171cbd9503e03b72c77a2721003d3b391f2aadcb32bd62e492528ea3ef5e85761cec47b846d32988468391db2f23fbfeee39cd89a45e71e4d4b29c6fdd8abd1399faef491211e902b0a99b451c58211c56b1a63dc2e8a57e6efab94ca95818a78fdbdb533f286b83725980b9bbac766d3b3ebfde01532e7ab1414eb6d52ad3b1908cf58ba67449cff1d605708d5fe6b21c769f99874249d98ecbb3c62956ebf6f47
+CT: 73c6a7d5e4fe14e991680acff32d660639e46cd0ec231ad155750e53d6597bec3070f5e828e420cc2044d5bdaea5acfb48cba1e9dc52258fcc5e937861e9a970cbd04f10fec4bebd6d8cf81a8925e5ae48d8024f7c62e35aa370994760c827a534e0a309655b3085a2ed8619dd0dfe0560c7dd5e175fc5a5971cdd50aeffa073e206d81d1932f350d9b3f40d4eb6929bf7957d25b1b12d6eeade7aae4b7277b6a1896aa0983ad5a5e5cb5e8e86b1eff15ed0b48149872ee4439acfc6fd6381f3d9527f1d1a1452927beaa3e3ff188681408041aea39f28bea779ac28b83a4eaff7406b08df2e60d66121c853800e56b3659329503bc122e6c47c1e1dab53986b2058685409c4a81b057fb6655de0f84ca770ed5600db097efbadc14f07d80cb892ef3ab12ff72e9d60718dfab82625a79168ac262b4069c0ff14bc5ea3baaa4c0559ef23f2535ab273e3bee0b2d1b4049f20e708fac2430af82a1a5d148164c19a956a3db8e44c8fc7c51af9458c066719884f0a192464c668d37372d5ffa4e2a4eff429cd57eff1b374d501e06b9d3cbf8480642bbd141b208ead6fe46d436507099ce460000aa033528a8d813f3cda11c8c03b427228c5b24b1f0fd15f704d7958aebc580bd5d3034667853a67fa51eef18d102d65507047b12a939f8a2cac8bedc027db855f89ffdad34bc726f6c6641e3c8ac8041003f65cce96cac54d
+TAG: d93bb140c5ad0362ef819fe04daf051f
+
+KEY: 1b63e84a8114f73f918aba186239947b
+NONCE: bbe2973181d9b48e801e3a55
+IN: 97b01d166bd2ec933b48bb7376ef131fb792f2a26edd267a713570c1dcac5a223646f6b52b0774ce323efe526b12f1ae59ec70bf6ff62f857374299cf4ae182015cc0cc2545b68d483689c82f4356dd8a06cae383848cbe75f08c5deb198c7effb10973b21fcb72cd53f6baeea5e23b7bf4508825111ab94535ed5ab9b51266d6eee98faf47b6a3acfee64c4a6598baacf1831a0549105d47b72434f498d54ca59041f07d22f3d6b177fe53b5bd874548daff7acab799c3253435551d963110d49fe1d2212b7e17df5b98a0884d9b7153253ebb73c0fe44485d78821a07b5e69bd446eae170e8aa718709f258a2a2476886757fc36fda2cd5230288b9a47d4a94b96c8cce880d1d06466aa1b331c0b893504fb8d6047b82549bfe807401d795d784584d608e419a7be990bf099694c788f11c29cb9655057ff12b4ee4b579bf7a52a36e9be42f06fd3ea2a8774cf70c946407db105cc88bd95f5b1f347bb8b4467e08058153edc70fe78bc8fc06f462ba5b16c5a56ce8a357700b43ce1fc8210c17af00f0ac8a19f8a73fb47815113c960138b2238031a74b610a1c45e3769155f6cdb7749d801b8f90ab5cd658f8f28443de9bd2e92098ad7915a6c68342255cc5f1abd5bba34316a297246dd2bc0f3975bf0037c3d17ceb9d9c9262b0797a6b5a90c72d4af4e662935bc7de08739ed8340397b78f0f7dd4f96a2fe50579a1e
+AD: 7754de0ce06145d6b247742ab582584c3b9c868cb0311b02273fe15f7a87403140b7b3bb49342cf26a5e68226a2927457c0f6b06f429c6cf5746b91ce5220e3b20cfca713664f5ec98b972fc3bb098f52c973a917f3b68dffe955a4fc670fa9c2ce686ceda47e060b291fc5a39fafc9489d18c3c3c08e580e492e35f058682e75e06c4141c38fd94b23eaf1048557c668f26da84f08718d850d65f8ab7a4e94c66fca8bf5ca345e8a966dff970fefbbcb88f3cc6b791ac03cad7708492675a2b4c54198b3f5f8906f3bcf2a56ba04666698c820309745aac83b45fa89e794d56a16fb3d00c923632c1d68fce42296729aba6ca2fdb2155a8000baf146e461c9c
+CT: c1e60f8dbda68c60024730deae746fe9fdcbfb9a3c1f26301a87a3c6bea9f8807ae294b62cb48ebacb01943818bbec06f1c842a3d42aed5a75c8103e07180d76f7e17377afdc4ed56905522be60c9dc5eabd5bd8b9a720b661f631dc214ec1a387016f57085ee3472df5a0d0366210aabfdb1ce23ed9480f8f1eead8780e33af36f9a49b8050749507a8b34b0695606b2cb78788c3da4ef316ecbf9500c257e8acfd36bf600a7ec4f8d2c690db5af0809c5799dc7b7788199601573d8d1a91a7c08cd4bee88885d73998c554ce520fdfe4153af13bcaa485477bcb5f55fffa54a4c71c5e61e1c3551ff7fa39cacafffc5cb00608be2b2d803bdfe43bfc256a7c04f536f4a9c383e6b4a3a0695d7e386f6ca8c8a35a77fc9b1d14e202bab53bfe6bd1d1efe3a4715bd150369403b6696374b4498186fed144f5a6edb9e3a863cdb4de5a6a404a0fc3702192cacfb36538e832b4aebba8c3726224f781c51c1529722d905286a1e01a9bebc54001980acfb9922d91122c9b125d4f6376599f0280651fe9efefad310e97fb06670f4b42df4b3ab1a078df2bf9b880fb91b292984416b70809c09e001e30d285a027f9b370e0764715187b797cb4965e7639a9bbaf915456cc4cc45505853ddfc54a38dc46743adf92afe7f37b174f0108468d772fb2b7ea00e8276663f6c29d3d83f3bf47ed8b1cc86bbe8639a564d936a3b065c4
+TAG: 0a6307fd5192f65b8786f7bef96c17b4
+
+KEY: c1ead957027a7303f01622d129eeb876
+NONCE: 04daa5b792d6d2cc4ba08cab
+IN: 47c3a0209195dc19edd01f1a4b54fbeec73c422b1c06558f3d70a2f96651db1e0364b7aab14d496a81b169e244f0f0657254faea172e9409bee2934fc622a7b2079f8368f53313790e1c06144f7f140468266fd6269b4f442a06606bdc9097d4547665f7fa192f67f0a14ff3a9f04092386d705a0a7d3a566b7c2e2b6ec9b6e6caa258ed2bef1ea747c6c80c0b494a5fc66906f5bec5da4aa884d38a6dc74af82aa94083106f6b8e182b529f94f4c389d6730b313ee8e656637ac064fed06561ea32b4dd3a3a128f3458c6e9b500cf3e578011e6b1ece6ed3fbd896119511f89db1e1719ca22a30b779c26803b278dadb4446fe28b5f96d3c91d0280dfb3976508eda8e803de1205ef65b3f7e4a41005165c5f3267b60a679095c25deb7c229ae7631c9df61ed198a9e7d9f6267bf288ecb88ab82dc3f210867490cf9c248828c73db475a757979894c16382fa1a9e5a06c081fec99aba123f6ebda65e07378026986b97a75e0f3bb74cc26f4b813d73c4c7fbdbfd5fdc4903a51d3064783309e497d14db09564a75551adc83197a30e3584a258722dc95fc187964f3207579f5d0caaa98d9dbd547cf2b854c4e820ee2fb4c4a1c83ef814e6bc48ad7cef6efb11b7dfdd41de49f1ba2317849f153115457b6dd839b6b5c84e8bd11419c553d51cb00bfc28e7c82718db654b4f8cc7f37b4ba96d09513c60bebaa087fefe7934112ead9e90d8599e184692ce235fbf5327
+AD: dacc20b8d41590570fd882012b1207ef4f33e3526fa3c64c4cb725091dd621bd6f2ce69c29ca39aaf172f05400ddc7af2af0fdab161af935409e3d5b9a8fb915a4ff8b7c0d4baf8f0a103be99ee7d21eed37e258bf79e18a81cd42fef0dfa465e04cb70fd8165f16203e8ed49bc2c3e88476aec77b466debaa6d888cf8cf013e8672d781fc5a8bbcddadf023d7208ed5f6f0ee2e3418158b653431fef54f821f38a69202897126f9a24a5793cb38fe5e8b3f77034e080dd8e4acc7fd22a12ab64a47f98f588e756fe691ab4c7f4557dd9b77e28f997d687a068925d18fab49f3acc072b33fb4d8c7a60f9a639b4b1d785c062e5d386261ff9e7066ed81cebf6f483466c0747dc22126
+CT: 1f2614433c137c7579ff19ed5be8e7897eca62f05797266174d4edb5fa4a22c11466b17d97d961564dbf9d1c45d9b6568d330761b9bc04dfdd31da08d3ddd4e5efd3924f53128ed541a6aab87912af60615da6dfc925b67b1aa3f1d285e25514f502eb5e92c7521da3492043fb06172ca74796b811ca42b349e337615f898233944644d229d05f133e35f879471a04efc3321094716c10b6f81ac7d0604096f287655362439e47641307ef49338a70bc87402b1c5ebd931300be51980ae8dec0345beefc59bd250bc53d39b7eed62f93087f3ba83b29ab094ab8d3143b63e905d209150c544e433d5ce41f00b65e0a976f5138db6ba5193245056734c7209ffb256a2f1ac9840f1bbe2e82c04120f591da86e253acf25b3876ab9e6f434489c43f606f264d1672cfd8a43282b41c34357497aa4f3a8c318f93694b4a04f1a0773ed064d4f426350dc7bdf4a59be0fd4154097c09841ec0df9c0e8f2dd31abd8513925d5d3da72624567a609975a815e9ba51df408bee244b4619f8ce981a6be726da484513cac67c2a4f597f6ac8ab0e96d86394cfcb5b6ccf2440a53a7181788a3de730c2e84e64a4131d0e02b8db2ec11f2af61218ce1255310756d98a0d594f09bd1440adea74720ff2745db30741e8f4f7bae0701443f55a078ee3c3bb63411fac0d7c7c0d0cb05ea56f40cf4137de20d9c5224fd4e6c4c6e8a5868116dc850ab713b001713d13e6ae5098c379b72e
+TAG: f1271cba346522f88ce93726cfde016f
+
+KEY: 2a7e7959ff156f3e69dcf4c3db8ccc25
+NONCE: 6d666d3700475874d600d6e7
+IN: f69a2d094c9c55669bb4b1f72583d23aeea9b858372c61516fb3f096736cccc3ecd74b98606a404a5a6195fe0899916c463092a749274e91831ef63b254a4c70b737bd8bc070b805ee42e5714b07dd4fa39da758de787340c0109e55ff4aaa19b05eb8e2b2ce171e4f9854d6aa56536b35359a7163557056ccca870012954737810bcc6ba226f6f38b774da0edd4c3e2d64ba4d6415d6528d7227a5a0ab222092c7035a8fabd3897bf9f59eca8692373b676b817d57f83aeb4f866c553b2ae1def7d7760cd152d18d43178b351ab4e23272bf157ec2832fd92b4d4e9085cf51da487779d82011745d0982ddc348613d55143bfecafa431a4b7cca9db82856c297682e62ecd1794a6ffe02a9e9b69814a6cebe50418e9bfc9e494b04afb9c0d6db479a8bf1c5d88be4c6b81246d8f4ecde7e3d4c6aa777277f705ef81962ff56d8174255519c00ccca0098e9370b675f736c86816dab838d7887b1d9bd638613a07b7122a9d55b4a7cedddda3b2337d3ec7bd20e499daa467c04a9d52ca1a02d119a62c6dade203a0bba45d3f9366e3f59a4abcaa62b6c08255d60798b9b0bd6205f2e24253dc75e8aedcc1bb3a525548479fa5363bc8176075ab004e7e73d0ac5f5e8717d3389f3287eea904f91fe63b5cd860091a42a101c1a1e6b13b31e2a7382f718dde735feba88ecb1ab41d042c4ce0106fc78b2397eeab842a8e0e5eb83b31d212501f265508ce73dddb94729433f2388d1925992f4cc6ce78d9be734466b6
+AD: 6d3a702bcf31e90cd2ff6a350a94689aad4381aa79708817b7e8110cb9a8fc8cfb42a277210526da057e93d32c609be4efb1fa4254c1cba3cb3c2bcb5dcd23d1acfe671c4fbc2b632dcb8ebaa952d7f6ee68e52a59d4933e27a54363c24f4cdb4c4f7ad2cb7c666f9afb811c06df7bfdc93f25edabc314a9a1118c2e0a7cfd219c10a28b5de83dfc3114dda3fd31a3256fc3c915714f1b7e83c6e66273b28944f7e9668de94b8e2536701ead59f9f7f7043070ffad0ff6fddea1d9f92a7af2ce3fb8d130203d0e9550d29785063562c59fe2a699172f32126f6176e9313376203cc1ed15812dce9e304582533a212b3eaf209ea16c8f83db448686c0fcdf5dcfd957fface636fc31ecf5be0072e19e93250e
+CT: bce5fbc1719b18299c54d224c2a0212cc904f9f58e7c0d8bbf1b09df0c2c08347cb36f2c8d145b5ebc4896a398b6aeeb2db0ba5aa3df6624a64bce91db2ce843a7549714a20404e869497e593990a1a6e62edaa9827288464bd7b37d2d2f8ecb6d67137f2113982d4ea3c23cb0f4609f04bfd73efddd2e4f05c4561fdd3615d82ccef83c940d39f4f7d548cac2ed181e4a60d1f280e25ef8b617796580069ab2fe8caa3ae4e3722eae649e390d9375b6f1b153e6c542a84eb70241e2272f2530940fa3e0df70528ba07747866fe51c3f844c050cc110cbba10d1f8d3321958e1e833c3f4543d4f8b3d20c8fbb7eb1fec4de7e99464c52d97e7bae8608419f1920c27ea0f479bcbbc61cd5cea10971ae2aac0a73daf4e90c47a023d620c2cb246d5e35908535bb5a0fcad54250a29fe53c1a0090794091fb5b3704c6ed52c8fef11271836250f39d8fd9ac5977cc91175e285192f07fd163d62216fd5530da9a048ea458c47efce109723029992b155809eb73a34b8bd24fa647b006a17e1e315b8a6fcb0e5af6871b4bc6f5d690b3edd10fdcc5391648a64d05f3355bc2a13cbb74d1892eafaad1611c23ff96e7e80f0df0819999977f9a2097617cfd13e8fbef089bedb532b331146d793d224d8f12bf8fa63b3b3d9fa8414d63a7618ce7a4f9c52d8c1b2ccd019e4510dbb3bf71f14c2e13452dc7cf859d18f54d6edad075c37a6ed2f05ce6dfa48421670b757d6a138813503a6ea964707560658861a5b95330e
+TAG: 85713c984bb8b5acea392525719dc9c1
+
+KEY: 5de639113d920e239a0d1581e179f9e9
+NONCE: 0b5bc077c27b08427f0ec327
+IN: 545c1a235b88be7e8451a5bf405d0dd66664a3bd284f74e4393f969380bb63010081457effe00a972bc6e4895ff82dd4a50e302261734da0efd66b0db1dee74601aa414cd9e2a4c149956bfd63fe0fd1f63f3dabbb6aaa2c651405e36286d00bd0a3c9bcdb8932c6e01300f453ec1ec28724b8934d26c1405f311b67fb8e97ee14624e2d6837bdd38a491a019592526095ca9169b4657d65486470ec12dbc793a42df7d7d9cae29135bbc499425775996633ea60ca5c6711e3aafdbef89ff1bc41d20550c219c82a8841ebbb8e152fdcc55dd689c7768a97720e23a7f9a80b173e679c0e2986e4dc00970fad5f8706a674bfc71901952b7b02189e95dc7207902abc673d09046fe2326168dd702a76328ca26fc1abffef071f58f968c165700845a997a2013b71c5d83cf6b6ed8d76a1b6d1417d22fe63691e88d3774ddf4ee205f352b765dce99ca0a996d33f95f853ba54f2f9ac3e6d1c068567695d06ee8f3c9865f034dc4b397a15cda23a872a075257c10ad8e2c6d3017ca9183ac2d8b80068a88ffa995045b96df11faeaceb7b41ad716122f08cdf72f9d4970e5315a8bdbe6e93316fb0dd8d1b805ea4861e99cf67a5c8cd3d24eeff142cae3c53eae387b4f51a45bbd808b7ca1c3b69042c33c8a4dfc93246e07dd93bd12c40dc532f3738084e47d38983f6b529e3f61ab8b17e0b588da524d0ca67092112be6868d5ae35102478ebd35213e7b545c859effd6a8240e0428bd480abeda17764af5b6ed4902977f21fd06e53061ed8b5bf49ea381cc5
+AD: 846f6eb4aa086447f4a7e5e8eef4997366a2f8f827238ed0cb5b691154f345b4586e1911469c0c81df93859ff0a39ffaf4930bd39aad2bdeed92d4580523e5244640b9e6d3609b022e4b4d0c631669e00571f8d602938eca0b3bf874c0706966e3d07902e392a6721b7dc57028b0bae7d93c40c803a03968b2142965ff03f92d6e729a0e079a9dde3bb30c9c10ce6a5627bb476cf1f879a51104f3ea6d0599bb288d2ba5e0103352372db8ad379cb629c82d212c1d1c6543a8070fb01f61f509c597e92a05f83ed49f2a1c1b3ecc64ad0a7d5884320f481dee5211716fc1c6ef96f34926cb5ea86eae04e934c6c0214eca8369928f2b0bc93c0865cc4e165f2eb1c381642560ade7956e5d69381537b796a11786e8f20d264f0dab
+CT: 04c79662edd08ad017cd48a6dc415f564a67d3d9eb48f1c7910074e6c3ae2d253a5acfa661377ec6ca3ba6693e77f2c97a9484bfbbc3bd261fdd25512a9c1e0d2058b0cd365fdab9c14f602945e142025009f87c13dd1dda03b0c49f76cbc3a93d928eee67627efcd146ab2fbc19d26955a646201800366fb17efa420b7c148399b262164c598cf1b011308989b7dcb699110338649603b58af4cdb5e7c2a306164d7e588fe115b4751ba0a83cf849c869b0155b3f934ebe5382e46db1d2d977769caa63dcbbee9f33568261c6c89856f75d597973d3b2a48508f2773d19252e04350b3c88a6696c3af860f9dc7cfc35e6e96279c92591c09dee7c23c02078e3a51af668ece6c870b7f0f65f6b0f38018be91876011b616fc5630d12ce936b6ab725b808108a472ffe55a5ddce340e5de8a279974c39c64a7f5986ec1e48116bec1b6d040e4e291f429c522ff61dfe74f2f4a075e0a6912bb6a6aa945db933eaa90d9165dfacf087a58245b54c2814086ad5f54795f1c9125988dcf15f906671bdf25da87d145dfb22c0683636c61c44ea9b3120d894e02b0d6f8d021ed8423b0c533a043f263ea3b1b06b5d5d7dba17bcccb1485cc5830e7e5b8520f9a1943a3560083e65806f9a633baa6aa7d5b99e5c5d69db446cb39716c415dde4ba0be14108ce32fbe50ec0605b0845e9469aca76dff75ae1f847dc5e14ce8b5455af8c2f6bbabf889efe1dd6ab408d983f51b143558c73fafd09132e22113b36426535b53ff2294acefa9258a58893d7b3a252f5a7d4
+TAG: 07153351dc975adbfb8b30d77c1be155
+
+KEY: f0f31be89acf8d7fcdb2a063de5a9812
+NONCE: a3d6aca502708d448a869bcb
+IN: bd3449eb7e893e3c96cd76039ca41036c8fa9e365709afa301c30b5430e004dd08900d75815936deaf9e7753d8efdbebe09c27426b55161bc0ab3fb00973d093ff6088ab6f309cdb1e40cd40d3f933e0023f0c210cc7ddeef2d29d82e0955019e482782462542e186467bdf9b866998a731583b0906ffb0174cb44499d2d5e3d1fa3577f7344c21362f77e94cfa981913d6592ad1f537c13067f8e7af921db28e93673ee38de0dfcd497d77162fcefc7868ee3f27c07b0d818eb553fdf7acae2db4eaf657853a26b0a760954331b8c91e763f568d65e658c6eb53a69ac6bc582c33f8146f6c8ad66d8a454be952425f3c0130e658bc1934db754d70774d73b40512e7a9782c4478e1f9bece80281dd6d8eed2cbca8d4bb08df65feaf79e9a35d075b18e69dd39ba1f47cbb694173432f5f0ef125a9b1902ca97820b6024ae5b49a880ee9e12ecf561ab5abdef81366019a8be495af1d664970178df68f38cd83b416d0076a522a9f3f795e2d2c19c75ada025cb1ef41513cf2c29df9a01e16379c101197da782066f9318d4fa0325bd584b04b1f9597070cc551693c964b2100191e1ed949c426fd2befebe5914cb567adf7518aa4574921516576bc33673e6ffe422c831e616bf6d03476af169d9c4208d7975460873e2792c209c089af7014768c0ae9fa8011c533fc890e366b04d1b79ee7d7aeec0fe89ddc7400d6fb8878ada40a76f65df17bf34919fb5ff7711ed698bbcd3ee4aa8dce8f879959011612a3661c5bee1a9d7db69fa33107543f111a1c416c92bb873bee9f01564b44922beb1c8158
+AD: 2c9c6974f2442b87c02cb723f5f3c05c78a22b7ba6c3387fea2d07ff58ad55c67aa9ada12563fb296812d087ef3b2d47ea1adb6a7dab646bfd1aa9288c85685c7b41c14eed3c5a34e0642b20888c8d51a65a1c332f1cb5779296051065211e5ec624930f1a2bfb6c10d479059063a2a4614999b0327d00f875162440c29627f817057f5151ba9c9364f0a6a9be85fe7fb911efdfd5cbfd741bfc63564f0d73eaa7bbf4fa16de77fd807bb27a9afd9e62c86e7033b8a969cb0ba9a2240de1a8e8a3463c2fae49c89b3cbc97e59eb30c2ae35834c36c22bc056a34cbd339ea469f3d8f032b5ae10eb00003025e55d42c12d9738ea74703308633f2772e8cd3421d8fc9d334c2845870a2c68c553f4dacdbada3af4ea8f20df3891aab8db9510c299db2bfcc
+CT: 57e32933293f67159efa04c375a4d7b8c8a050b0cc39031a3df3bd4bc82839ae1210da5f10b0723e111ce7d1699c78143671d7986f83fff90992ccfe9fa4367ef9c944cd571a3057a65cc1ae7fd7ccf2c722f11a9ae6756ef0a422ba7cb15a02e27aac6faf78fa2c2b08b228b1be5d3e62a5e995f9d3c5f1cbda1a6ed3f551581cf6693d678f2323e2ca7437715dad965024c8d5eabf68e7ee3ec090f56deadb47dff68e93fd8a38ec2b34d0e774f07793cb03d38921632e42b4a092175f6d602ec637aeb1f134067fb54594f33be2d9dbbae16ec25ea7b86a1a88346e0335d7bd2822a3d209a6561ea396c6128a86307da1c14d25b45e593504fbe38bae1a42689b2b53cf17bca92b4896c2fbdb4625d960bc03da9072910eae59aa17070a368a30e69d072cccc53fca2824fcd83ebf6d65e78c44dcf3333a00cf7eea5b3d311a674be8f46b696376f1fc5d70b727773582bd4a59111cdc41d69d58c52505e51e08e46d75372999f27628631c5d7497607adf4a1c27caf618a6dde1039dd33aa7834eb5164e67a208d473f558b97c3442ab23d22081ce024fe616e00e09a7d14386ec3e0089a0feedac7e6c841da57a13358712b75280f72afd0a28a3f5555e024b59d14ed108ea4fb77510c031fb438e6cdc7b4b6125a387e76081ab8568216a6776b7b52d311f48e882d62abc81453d65c0f5effc4abacec68dda303ecd225ed8afcd5638a9c4f5488d9f8963624934c1abb56ba0071bf11d64a52443aa0f3b607557ff340937a53fa50031775550925b2e8f40c744c36317797a952d70207cff0646
+TAG: 429a50441cf373d8d1cc4b37e15266df
+
+KEY: e4ffeb5ff128eb3c798dcdec4c665a4e
+NONCE: 7b30ac120aace497d03de3d7
+IN: 26638db82034a19df83e60cedacfdd511a937ed73adeb1565661a201197eaa7fe817bcd9b83a19052461f56c3480c0e0d3314c57aad4f02a9e10afb967f752fb144bb1ecce66ea05608ddc7c876ba95698b04e79a429d36739d31b52e47fb032b18e7686923700e735750628ac0effa74298bdf7b75c115c6ea30634a9636c7ec5a02aa467fd53292d8991fd2cd45078471ac3bd8dbe47ad901047522e82cadde3b4f9d0a1e2b8c6faec2da532a09c58acaf7207fa49c1de10f377bcadc903a3df381a10ebf7556465096a0506e7ea0e7f11e00411f226bf2897f85791d6e34641d8cd049d95d996bae9dee6b2417f558f102a04d758897c484e930cc97d13f540c00f950a1b384ae5139dfaad258e1315fe76b22a601f7a11d852a080c228065f423c380393ae13ba817f18afaf48f7df08ae376d62e770b0c98e49298bc1f6f1cd07b586128c42d2196d26bc6752fdb375a0edef255d139b35841f426f090f270d5153efe6dcbcc2f4d4fe19258284b98cf70483996003889958a7c993fce98ada15a8bf16137624a2e078fe16060b640155615ed55df21d9bd736df51970f11b06775760116ed1a624588052787f6e95c93cde1c4661c9efafa2d2f217e86dc941263c176bc9e15af02b922e23a1839cb4148f82e8d8888de16e17db10f659112ae0f28cee8c062f34f44304e32fd3713cfbc830699e6aab24aa1c829bd582d39c4262c625c45bcc81b5e07289eec77fdd1613a7e4955aa96ba05c45676e973b609aa6136f5e516e338d183db9523c3e2fa6d7f603bab7b77e7acaf5f144e9a301a221111ae8a3130b0a77f638dee2e05d4ebf3
+AD: 14fd627004e9a78d1334822040ceb4863196a75e5c5ee70861381d6cdf1363a893db2bdb201357c908284b91d690770205be495f788afec67f205edbcf47b78fdfb6e1ca53dfea501ef7fd48008ab05a58b65ef8e3b25cd3617dbe7482d0e846d04d00508192373abad114b6e5713f84de6928339d5c57e4abe88f0c0f0913324bdcc661fc85f391aaec28772df8faed4069573ab9ce2868039b7971b510e8b9239eeb066ddce13e2fc2579b159b08ca564de01fcc32abf19f388f0a8e810fb4de96e19d02010b75ca55d4d6db6c1a0d83d36a9d30a980f51e8263bbdf18cb768c5d912cb1ee8394763dbc7e9276830eecd1c92541ec53e9fcb5be036e8fc2da7c51e9b7978a7fb8e24182825d8a219167bb925dbf639edf4a25c42ab08a7ac8013696f7e10cf0efb57ce49107
+CT: 7ef2888ba3ecb4c9e0b96414504cd46365885b6fca375534e3dc43d4fe31b61acff2cf2d0b698061ecc1addc1519e00b1f3e59756cf70380e9d83352ebde4fd680fd995157fc12054376c690ee01a11875b3e833de136a8e16ae08e80101caac4e7a43042abd81cae91d2d0f98ec0b6fd7e6232fe351df92aa847cc11044a3e07f3f4d8b8b64f039fac77c95f9057cfefa11cc795fec334051a81dfb7e08cc09496934508423cb75f8b051b811179e37ee63346ff3ce1f1012117b0ad3c03fd113f7f932da558244d5809e6af429084e70b206f4dcddcdfd549246a548d51df1fa68274416b27cc2c12b3a6a86d9bb80184d41a3971c9dc0ed906aec4ec85e9eaf4e8dab1704f6ac3f7602b0aadd1ae4ad91755ef9a08e231535eeab932524b2c228d10b9cca1f88215ab56bf776183b9c14b2888dc7dca590f48ba6fc7e974352da98077d0d3f5de4159025270eae300fba5457611cfc4b52846ea1fdfb29ebe4c260ef2d0d61de644cf8c7390a66d15f806299ecfdac0d6ca83def3873f960bd5b41d05e9a718fa0329e2304dd210f20228d7da87f08bf477deabeb93304133eb38439f49e821ca66474ba065c8c6ceff51717b36297eb17bc739feb166455b79d83ef6b12506c5a877f9e7237ace4e451a17969de2ccefb65af407a1df71ac99856d485aebc6492441366fbabdd11c9ca559bade381672c8497cdc86175d2f186272c9b675cecb365f97dd547d14ebb2bd306d80d83b40e3d4a5ec37812b787b31b2464917aca278bc5c3ac7e78ba6ea0bf3744b70012ba4cb5f1b91703504ab5b0134d5c8071ce1f16218c51207448c894cc1b
+TAG: d338cecd6bdd210923d8ed507612ff85
+
+KEY: 58ac0726e0bca5d30bf4d0a231fd1242
+NONCE: 0b9b60c3a690e0ce0106c1bc
+IN: fc47121253347bde0b02845afe64a46c74a401fea9f81cfa02d47f3c6008be65031e26b07d05253d0fbabed865397284b44ce2c38b2117f90f7d3bc60a0d9b04c6ec4b5108da61ff7f6d30083a33528281bf2b543bbb2eec909bc8706c892844e0702f224cafa9f2070adba7e3942023645427abbef47ffdb9ebf43b24aa7367deb7d05241cc5ffc0d1e07554545ddf0f6bdfad4657222fa561f3f92c83fbdcd5b0b93921842d2545b386eaced2fe37d0e5601bdb969125b006b21a8283d8cb5264ca2d8765d2bfe24fc04f8feac32293d88bf6a3bd7764847c72b07a9c3caadb47b96eea17199713eb48d03a8b37897defce70b258328f0547392e7e82e2a1be53c8e40d58235f610ced56019a0696b77b16ed8bcacde1c142bc3afee168755db6b8d81754dea34e20f6a0e35ed9da60bca3957a054916e0072e3c5329ebbe2bf8f224efe6d501e0105614f72c8e37f2cb7cef644baaf7bf32975cba8e519034427b49bd589d076e3a79b2a9c90170d1e503256389ea444036523d36486bc2d3a94c73afff7bb2b48d0d74b7607c3db43186b9f85102a49d4c0e3cfff1dcf8b5c0cba5ab2f28e1dcbfc858f57f585d5e7d4ee92eec6ebe152e4b160db923cb8d9c154b631e3340b61272e0726cbd88298a4a6dd1d01fabf67d9c66c4681019e13a0e0280e91dbc3cf20e583b4a401dfc57cd3bed42d7e889182a0b75072fb08f1be187b3c7990f9f17bd29d61b8d2bc93f1a78e84fc8c38c4184afac57f3c6915dfefb3e194afa3919fddb1efc685931e49129e3afa230681fa6e7c1d6a69be66d0317d0497a937c827b1591931dd17e83207cdbd56f1ec1270b14d9a7b1e2bed3e10628630
+AD: 0bfdb282f9e2db0a43c18132b08093892211a8f7b210bcf36120851314cbd8a56f80f26dbfdcdf944fca9148c1d013844e897b034843fc0c8701120062102ae6a00aab0063a1651e0aa36aaf8acbc221ee7575748562288c08050a9a562ec43be7fb3e54dae418ae89476a1d5f81debb13eb6c5e0b4796abc8310e70a5e4a6619923dd6230a7b2a8dd36fbe3a29aff8a2ef35820ca68b07e00f63623db10a648014028d314e01cb537973d03420938dac988e7af001d571fdd7b1606a06430b5fa1770b2f30f53cb439a02771140e44356c3bdb7ebd5e7af10c344396bb3bacd58d32f07a26768afa741a2dae4e91cd8dec01505edf362f38b0fb06c40b8441746a8ec31d9aca6437d1b75b5afa120856e3d87d79ea5b71352edfb56a873d206e8fdc5d5f0bcf91c0ef1beb06718006bceb35f71dc0b
+CT: b03db471a65de5cf871ac198ddfedd14e66b6fcb6c42c782a4d3c156beb2024a1dd2cf5efbd87884b029f42c94067a42a165c1e00018f11cbd79f65da02c62fb443ea8a345c34b6411112844eff3572427e45e061913bd578624100e33908ab9737140ae0fea83069fd008af952c776459c6cbd4ab9b02156b3992c0691614567056865b9f39b526f28d11b7707f35ad09d1eb0d2f6adc7c66f8832d8783478166036d082af1a44025a733781cb389612e3c124c31c35ea2a7833bddd053625d96d2ac3fdc69dbb64b9b7fcbcff6c6fb891d974184734d3bb4081d7609d7206067157954b4c6ab68e4a450f01f5941e1702830a58667b947352f1931ef721739be452aa083ea17344cc0a3b5820a90b35bf45ea00fc06df7229080b82b79c3930067f6045c619624958f77096f304d9f31effe42ef405ee4745f1b6c101225062a5bb38665efc428313038a3db8863dcc72de12c8ae41eb1a7b8eb02bd5bfb1f1ccdb1db877ecff08606963d97958ee7cb85b99c5f2ac4f91a922e180d7f3a3b265168d02829b98b7a72c2a2910c0c8c654e354f2e19a53618e4e46501ba8c13e8ee0081901108a75d6b7f601385cf6dbe3f74b3634331aed8eb903119ee96877f90d491dd5d38abd5f002c3cdbd57b04a7ed13fa09c9e2058744e1fa24d3fd87a863a7dd73cca389e40b7aad29a95d6f7eb705827f7308aa4ec9b07b1c98c225f366cc33586bd08e20773bbe0878711b6210392900b8fc933a6a661b8d6fd1a8338d06ec364f9025f1a79ff94bf448b998908c22be5cd6c1aff929037af9b642ff228865137dbe2f3f3813923245c3edc8edd76eefa02d40e7850e502e92e9511571f85fb17
+TAG: 34213558263a230e66e80c4095fbab97
+
+KEY: 7b9f65509a00841930c4087093c0e049
+NONCE: 45003751c40e59eeb10f62ec
+IN: 33f7a6d16717804519e930bccfce78c316cb720e109a75b30e11415fc5b398b76cebcdd758535798465a8662486745b6ee098f9008d0cccbf8ce2066b12ceed80cfac806178068d2ccdc00ab32d73faac0cba72b5ae75150c13dd0c16d85332d934e56c8f96bfa942fec689e9847283a307ab775ae09cdcdf1c0635f749186868537dcf0123baa295e29601052297aa4b3fbf16b31620aeacc12d08345df8d879343c098372a04d32fcd2470f4bdb3aeeac7afcdd8f95695796c64cd41bb0052905c8b95edbd0bca3e9115f119d29e109198e91b9a024c8a4d67ee864b71eab16d4545862403bdd0720346c43e94793b1ad3f02946989c6e30c978e4c62660c4b1120bd49017203c86f5b9f02bea17a249d6396e390df1abcb508388c735565ae471a3d24293cc33aeb1cfb05025fd4f17b9382a391d73a2611784358a9a003c1ba16f493f020b1f1545555ca165c00e3bb4a2b855d99a91d4f95534424d3b8b32ba66fbf3de63694b18efb4e0aa62e438eb3a7f50b0551ccb19eba8b63e19bef0e6468ea84b2fa62d0deb181e8c3b00a55198eb69ab7eee2352989013fbadbb26d1c1f5033b26f1ea886a0d1af6c76a78cd09a8b1f247d6f81d7d4e521f6649de7fa5b32b45be2cd803a1adc6fa89eea3a9d876ed1df0534890c9b41627556103964aba36e277d1cbe56bc14458e75c365a58646b7e498325bbe815e645a19bb33d2765a36a61e74eefc32ee9fef4162eb77574638dea2cbb9753e50b85eef07284ff84996a5969af62090ea20c6af307c1b2e56486f50c13d5c4087ed471dc737c4e40b7bdbe9d74ecbd6c8dd0892449496d0cba16e97c864307a55f341121b5e35c47530a9c3059db7000688bb568f4a87be8eb8ff9
+AD: 7b4f599c829e412edfae60ec1dc53e15d608021b6afa827f48869b9c9ca017a394d10f814c3172b38ff27ffce750085c288e257b6a2d7ffbbcce9e7acfb12cfcb630c84448329483739be37ecc1ad122603a4f286a48474134550b12ed8dfff73419494a8d251a98fdcf7c329b0e31b0f9379faa6bba2e4adbd429b199b7cc31d2805250082a88f94d3a120a3b07d0229d4a49e45f2729885e55cbb9ae08c88b65576fcb8a96ef23b629422ddbe7497fc2d4baf812bd03a7d5c03e79cf522938337ebd1c9cf3a61d331aba6b436c21ef47b030447e839b94b23e6ab10ac09a1243081544081a09cf35f6c7da3149fe3c8e41f90da05d88e31b32744214ac3a8a0a9098b11a38abbf01da170d3115fd4243f2be6eb8295b921e687755d0baa3fdddc1fd9e8d78992f08c50ea9caef49989872bf00b7f86c78293896dbe25eff
+CT: 5ba4306c0fc5cbc0028d54a82d2ec3039f78ecefbf3ed98f5b4f83d1b562be3c5ae66756dcd2027a515360274837682ed07c5f1a0dedcfe3d1e63457f9d4020d2b3d57d63401284eac89ef0cd16bef79aa949a5b3c76dab5342e8042e2e0d411816d311aaabd8aa10bd6c18f72620f824156bc71add704e0ac4bc1d4761f9bd1e31f800d0487f3bec7a788b0cea75cc0bb4ebb927e824bbc718236b089c752de68b4fb5b4bc1ca67e166c23274de9992fd30e0752ca561a4c5f469dd123ad45870dc013a47247396afa45ca5b02fbda0fa1c2a89180214814c5bce704ac4dda5be49af225f3a745391d669d7877d1ce173058433b02b714b7f9b43095820b73069e8c3fe621c45e00e41152a413e15bc750fdc517568f021645b6ccc541a9d61237090cfa6e374942adaa1f18d073e627195164fe981853e324d2e97c35819a00cc4d668ab1b8dc86188ba2f5fa76b3ba2303bcad2ce06195d6e853f7e0d257e386764067f244020d9660ce04bea8d61c5a940f502bb68ab6a62fe2e7492c3aaf355d313f4e2e2ca148fa46673848e59d744567bbbf38ab0ec0c799712053d0bc25532ff00f02a3149e6bd9df268ef8e1fa31762efab8102f6fed5768b9abd9bbbac89b40000394158c4c5d2bfe5f3dcbcb5126afb0f753e2a60c8aecc67782fe64f2f35fcc45e6ca4b6751c40adea4998140048456944bb8e2345daa95e989ce48378f8c607182d76b25d12f731b5029c245e804ae19d170a27f35634c64a1bcdd48a6b573959521d388e023650f427cd1839c77e0d56b4511d1986dbafda63cf43b6fe929129602a5314d6216e662cd1659d8d7bc6c271589aa4e01ce45970efd85297f00eb2470567e69a67bdd20fa4ed8b497879fb
+TAG: 15966db2d710d52510c55082f0c3cdb9
+
+KEY: b4cba7822382ec3aa42a95221eda5980
+NONCE: c488bf7ad0031e1ed9870968
+IN: 19cd01ddbd03500b348a15fda2f9cb9a870df388e2e7f84386fa33fffd5287f1cb795fcce3a24fe371ce42f2f34dd8db9d1826b6a454082ecd0dc684bdf35d3d7e7a9606cb5336c67238509f0386275d58cc3ce7fc98fd20c77ecd1bdd463ee40e612cc5b9082f3c12b83f16c32072834a64552549289ca767acb23c61b4030227277e0df6ee9acebddb0c3bd538040398ae57767c850066b40ac0c1d7f5de22747051d237f898306beee05273a99b20165c2d7267f65b5451605ad4301a82bc80268b49e3084957d8ea8fab59a6b31f47f76405f5575df8a16a5811a976a84ec23479daf4d1d2c1ef428a9ed39faeb5a625ecd25e04d37736230cf144eeab686180cc71aa713d522c9f2007aae4eab486171ab3a9c338265193d093fecd6feb1cc1d91d10a5f2dca9243d12747b5fd3ed809c06f52872136814aed50d61ac932fdfcac2e9ceef817034647b2f4d61f5a0bde8ef9bef2789a49da799ad1b9bba440a29e3e15e4d97b99c0fa2abcf5cf0e05acc89da732eb79585cf1d6c11a6c65c2087f902ce230208b5f1ce6cde34711646b9db725858cecd3716906853acb06c30c7dcc3901eb407efe6c3a8e1e9f9aebfb1d7217cfc6571fdc4b86d17d66d6e392ebf03be924c0076b8d1f8bff15e192cc5e351351fdb6b26364d883581c3f8e769e9a5689d0ab2f308a1dc47d7032de91124b1ca3d42aa3a8d57ed92a97a2aedba2409b38023c55954d4d5d2630c4dcd5ac7277fabc3408f0265560d3de4114eeb0b10db4d5270725f4454dcb1c7fcc1e36013a155b03181e1a315aaa251e9ab00dfca8e9ef787799a23529fbe8f0f993dbc2338b9f300ed18a67bf92c600f22d8039a5b03db114ff04aef285642be0d552cca24b615bc1467ccf9818929c06e96599fe335e0
+AD: 6fff534915999ba3c3e7ee9f964ff4c3774c1c63ceddf8674c9c43cd4874f34e22c5912e6f8eac3e889779e7b4ecb2af711665489274c3201a68d8bfe7c61e6e8134aa08d71ac2a23289eea43d1dee5b4fc4caa3cfb666d59b09c554bd924b6522cfaed157519de12d9bfa37b55fe8158d763e3c79b7b10db45bdae4ba18af925bc8528fc19e9af54ac81588682299cf0997eb9710fcc3597564d8f0b71e3249089673b3771ca110a28c1aad49f32301e0921286fe0cfdaed8f64956a4e2c0b22011bbeef46ecc6bfc29ce023b361b2db0488a2cdab32bb94024e757abccebcfa0a672acd77f9ba622a665314c4b520746ba4fa07488e9dc662f755311535f1f98558dfb2be88a86119850c49d4a0bc92e70994ab5d7f410ad20d61fdc93a08e460ff9628a5b242038a1d2905137d4729fa77ac0f74bf1d32fa7b025cc16f800
+CT: 0fd6ce7a1a51060fd105fc1e5d7c8fcaf4550de865dc0f990217c9e32d354a951bee16f53be1f9768f48d7f76c9f2ece7fc56b9e8c27ede94b5a3250ef27874eeb2dd09d2e50810afb7b9a50985fe28b7aee74303b178a0b74c5422d4f46a59e55bf55d7eb0d16314668b13952998205eb422daedb9f99dc7e04e11e8e077289d1402a1d12608e096afc6283643ca77813730bcee2321cf769c5cdbe5c80836db9814843a0ec72d49ea89ddf5e48e27f1e172423412b78fd91da54b776a132df29fffc5c8b41615fc491c43ffa4596430e55806bacb7e88abde1e20ae43260a1258e7d89ba46fecd08b7330409a08449ade364fb84ad1dff4e71434a3369a1d20158d02949edb9716b021271f73517bd985949d2dd62474a36e57b2682218ffa2d5a982c668a52776343d06ec4bd122d5a1bd5ab5b691e4462d8c52226f834290258a83ecf0847246c92d4339ada867f107589bd8af55cb96461aae47a879f5d81c3931fd653d68cd5139be7ea9b98ad8feb9b453f617cf7b8a4c9def78335d009d4139e66e10f642030b5a66fb44d2c07c8c689383136d580b399f685137b3054e40fd7c90f37ea30d52e09832b66251cc9c31156729e9cc5fa37463d89bf3b61a8f8657f6501ddc3cf1505fad36d4d9075f7a366050de98eeeae0c407b31a5ade0b29b1a7a3cc251ec8a918cc8239c3208b377f2e9a7df8aba3e086c33390bbdb4498ee5d194e43a67206e797d22a7c64849d1eb3921a8323d8a0c7d242f3ad65e52b992007c996dc642b858fb7ea7b1d8d6cb10ed3e9af7595367c26d4b01d6c178a15179ed45d44d83d7709503c85985bc1e2cf6200f4d0ff02e57ae4c53c012633935871028e3c7bf0f5035140290f4cc02afce10718198dac233a6dd7ab4065f07242e173b
+TAG: 8ba94213b2a8696d7e203e6bfefc1c99
+
+KEY: 4233eba54fe7537d0127b1a062526d33
+NONCE: fed44fbd3475daf5c046123b
+IN: efcb6ee574ffb9620fec7644a10643908a2d3e283864e3011704c4b16dab7c5333545c60ec83b0f7c3e2dc8022ee5d1b8124f766bbd8fc95ae1a5bbbd2ba7eb5c41780627553b8ad99643d8abd43c56a32bc159ab97f1fa4622cba34b283317cabf0bc98931980f207efcfe6d4c4312cd9daff8d46b1f9eca45e0af42bb8b8ab25a9fe0caf1c61b40b1a8a3b35680abf456de109f42d87ef277ca178b4471936748f3232f9075b58c64c89614dde8a75dea86d3b9c2a6c4a71ccebf388becb7a2cbedd92b4ef95d2b72357b4d2ec099a3ff9fa9ebdfd1d9adff3329b0a4ab854f84e8c729538b0e65773a116a3e50685c96e52162e1b98367114d84e5476291fea3173ac3a846529d5af6ddd0d2272b54f534d4430179ce5bee98c3a9d3f6e9cd4d7cef5c79560674ed0b5418e21e9cf7ced787a9db3427d6153ed69d84ee4ca06c515d3822c6338868dbd97d0a21406275c003f493475d4350660a4f3afe49deacd9f299fc05aeab4029f57d05e21cff132cabf6de6ccb3082e0d8811dbe5188749a2ec8ad6b1c1efffc4031605c407e0c2ce57478b37a4834bff670b4dcfe8a32e6d09a0c80c7c99f7cc41378efdc0231901c7643bc8e0575040d1ac1bf4a79ba4c10bae1c0135ec4469bc8b6413a068ff97e88c4be959f8e426abf3cafa2bef9925aec0c1ee69eb60c7427dbf79656fb3846ae4ff059852e7686311b2778d06b5a7eab71ef92bd086ab0de7dc2a3d4c6070436991a68d81ef5b1c6eb024ccc6b2668c98e9b2ce452ab4751dbd57c2794798f5d9262e2df48788d92045b23a455a135c112e3baf06f2938a485f874a7d5a251770160dd9bf9c93c4e2a789edd07b8a7a4262adb303ff6ce9c551be29dc69f99dc75a4cdd53afbef565031529cbce2ebbc5f98b71315ea7dcdea17c88e7c8b3c20da68ee6ee
+AD: 4e0126b67d2a31e1755e532178b048b572f806ab4bfb398247b393dff9c653a452a5ff88cec05ba1ee8ebf23e91b61b1f9adaaf771f448a57f4572d460b8304f8a2d6ba8a8b89e55d13e474233cc8da704c244c6862adba31219d994f302ac7161604d324100241fe6762ac262a5f7b5a07c67cf3f647d2d60846ade2dd33f886ebb59c50d95a4a0ae103438a65bc192d03f351e3e56b6da169480def2db510c83b6ca91534683cf334134afb2491026f7aa45978aa38b38d6a8d193e9609d3d0b3526a14f7b131f9371f56818247ce4fc6e1b17ec6e99b67123e7e34faaa8a8c63c1fb9004604e5ddb32702f9be2246ed7496dd27fa90ba90d90575c0cc45c0b9fcc945f21bfefbfbc82c53dba1feac88db291f74b6512d45cd7a4c5c886a458947f0a30ee04a6866ff5472f6c921d1949b8ddfd623f744bbe5f47950dc0c7c213545f7ab63e88124
+CT: 4b9b468ed1b1b3ff8242f0d2f204e94b0312443ffce789fa9be7c56054c2392868d8826129462bba1b715d87d58eb5521a258af3e9e06d90e26702106242ad01ac6b64908f747306dc4ca142597d3021df591b60cfc2d260d9883f01078ce4db4b11eca4b7b4329962a6e5445857423776b22b802bd0eea8d7ce7d1d47d49a805d9f557b8d67926848668d8bd04cd2a9eaa0b118b9e680e23266785f3641630d2649d952501972d92f2c6e5e7ff9e8805ab3fea94e4d069487ab6767da42a6312c74a7191310cbf58995a94158987a0d3e6778f3f44f21c9e6c1b08029d368daaada4fbefbccca7f49e2f8c6d754286287ea93f69c72f3234acb2e4059aee4ff341730c9deccdda06fb67ab67b81cf5e5213b7c86b03c00ad8e447915284d5fe4e30ee2fe0fb2ac2e5a58c0623c80b40e6ebc2b96a2d5e045419fad0dbd611fc136ca032e71ba2523b5cc45f115389a9c9ef0a28d9b949b84ba637a32fcd3a8687c70c7d0bc4f27949b37d20ed349ad0bf1985e33f74b6974dff70ff72205085c766469b4c32bbd93365e207110b55d477347db18fd003c925b64aa4366212585e882fb5a5643d79cb6a9057e977b554948bf8129ae67ab02ca57d5052cfec2949e86f3c6fbf7fe0e1aeee3ccba5752bac7abce9a396fb6e5ea3af059ecb15937f34aba7fc8edb267ad1ee18c49e5e6f057ea5b0156093c6b042d2e7b2b29bfc9548f91515a6272aa8b2bebc5a0b0d9d610b6c911a69c38d15c2ab3b1d774d68c6d5515012a083dd0cc2fbb420456b8aa174be28502c2bf22c7af3a89686e2997f2015eeb7c33ba40b676b61c84702a3c5c51120dc290e58724d082281b496881a54839e6f0d622dfafec125b381da4823240cd960d63a6890c11fdb9f56a9fc8dc172c98a3764eedf804d1f5f56d4d9fad2d414bc4c58466f
+TAG: cd1e49972dc4c4e0ad3bcdcf16e692e8
+
+KEY: f79000afa6ad2a10b0dbfa4f34e47542
+NONCE: 0437dd10d487f42d2cc40041
+IN: af9ef3a4f52f80c9cb25970a4a4af8bc7dbd8fa566fa588d57bcb446b399336fe43ebac2a913d74d0a9f7d97044213390372d4272317fa41a62c50bc2b4d736a759c85124562323d86f1de14fbc3899472a0686a5dae4a3e429efb05681a1d7a36d397741270b2d97aefcc3d90309365a64a0e244d62a4fd3f288f706fb60557d9ba2bc8e29b4d68a299f13ee93d3c4ce0efb7fb26a3d2f828c1268a04d48e5ed520c5334ccad9df4799cb58ebe15284a41aec4c2b9157bd2851f968a279653b3c9a522df5e2752f75a3819d4610ceb4da666d19b347f09dde571ccf14b435569b9624d3f3207ba49b05f40bd818c7ffa733103f9210cb821ae8ce1fd5bb80a6d3d8dba865015b52ad9af765a8190713d13890440ef64474b61a840618759160c4c692b5bfae7cab08f941d633a22b92d8be39a614903ce0f96d05e83596b9ab4cbfae18e4e8bf4ed0cc481ac402f27fc81a0b62b7843ed4387f2e994799e0c9532a1187fa6706d3179cd8e3bbde209f85836a176e43caa2dae384f0331092292872474d24fcdbe72be3067f542e7b099d31a0b09e0f2c31bd16caad1fe1af0f25845084268431b930685f6a16fab6a401a80590895a3422b94d056038935b1182ca3e6f4ededc86813d651efb0fa80e40700a0ceb602f3a67784b60b8d5c8522e42519c83e6f788d8133044061095806506cbd0bf3a7fb94e1d59435d3a5cd9a5a24db98f20035f0feed9b12b6cb4cc3e18c97aa890d61acfa167338b1cf79868f2a14711fcc241290709e800babf3ba7a868a528d44be867cca23f4f80b1f914ebc6abd630b4254c1b8e01241fcd817171e2d9969d2ba7c3f410a9d5b157ae0069b97ba1c973d944f11208777cdab373131ab5ebaa1304e394770c1d277913c54e7cf00c13e877fa5e8e0572f237b646f783db2f30274ba46c51d72d751c3bd4ef9ea32b0a22b260ad
+AD: 3ffa73ff1c5c481d15ea2246b6da59e6271801edcbe277591b188386946abead76ac40d6f2f08a26129895e97ef25b59ac345f8d060d4d21819d78402279238541534d8734ca66427ecc2baa6741fd093a5895446979e30ca15eda06addb67bec10cf809081ce8a70af92b03f72536a8a11a1e9e3d257352cc284f41e2fc4a91d1bd1774512e09bdd150d1830be260ea418fd384be30f9da23fafdc2c0b5c632ea7fc7a6ea87d69139e9d104d634530a02c4ddae3a2e6854118369e5304202206c4d8fc963a61bb4f42ba6f937ce8281429db4103ef222c3a015f08fef15eb5b407b56165260dcdad08f1196e3d698ac5b7ddd403c28593329db77fad8ab7aacc450636a4f7f6714bbc6dbe10c421d151a7c135926c5388a56d2b66ffeae0508706ee55899aeceb3525367234e29c25dd5bb8b187ca4dd14f68ad317ee5ab3027b68b5b405880528bd35eda7f9c65eef9b37
+CT: 47d6bd87f0ed8dd258b32f01e5c72457dd1d17982f1671310cb329e18fef89f25826f7a6a9abb54d4d216ba214503aed4d7fe36daba69482e4ace4b7c7a91de5a93774732e0bfa001947d8c403165473d77b6b0d53bece68a76cf544583980084ea5ad532b599206b2d618be4e56cc22be645a727a93fd73c434239bc9c0b2d1621e3ba63e625327cdbfb8f7b13997c3d981c340182aa59a4e8cd204c5c86e8c531019f4900410c6870a1bce9c5e4f81bd8134c983f203f7644577da19117a7432c9a7713cf1bfd3bcb055b8601f4f44d33b1191ae1e32ae868bb37ff5efb1a7f67d94d993c0c50074346a6b41da521633be46e299916425fd46bbf4593b1c02df98f68debfcb43fff6a1d7ad6c4b48296207d74a9504670b50368f2f6a2d89f6fa98b39e13cd46fcfa746dc533c8327a0b07cc89b654ff8ceee471eb42f1f07b0abde3ab49478563501e076622c0248bf8e82576e968657fb0efa23a03c3e3013098e86e44a40d21fe0e640cae3da3a461038907f9610d6dce7a1242417bd43d26ba6aeb1e6e3d0e54c1b9839d019ed409eaf801ebb6fb25949a4961b35fbdcac81c9f87ba8e4f7103984ca6d8fbd3d3aa7b13a9ef1bcdfbe4f6d4e6cc48e5cddcb057027f98ffad2a90a7d4fae9427be8e77fb6c30ac38cae71a36b28fb47045fda28a027b1301fa5071a262c5d1e0a695d3244218a88c7182590698b690c42a3cae97ece7b7266aca88dd8fa8f56ef08c28d806e7398691c31f292caf1443508c494007f5de45a95643534f3f0fdd20790f0aff8d9bb432cce36bc857884a28d2dfca0667a2d7a0b0255fe68a2f9cbc28cacfa489fad9d3101a5a6bac3c39fab9a8223bf5de787fc3d9849626cc50466355df2da389c5ed8301e24d2fb6ce3e8081d32340739326b706466897cd40265cbc347121b6e12e04c218420ab7ee760e9eb6b43fb4e4c530
+TAG: a2d58dfc6f1a7aabcc28cdcda713735a
+
+KEY: 5dacb5173b30a28c99e00eb11181879c
+NONCE: bf1fb59bee4e3964b300ce57
+IN: b597b958c63a056758714d69c241da18b480acab2bddaf692f4a57abf2265a0fb09b3352eceb6b26a667668363a615b5d078a4962c48658e3c92e43ca83dd0f71ada43a48d52b793a48e17b66097d06f9e3804202e3a8e832409d45f8b33762edb9982e79948fcbf7213118121cdfe834931feb8d6d5e3a677e3c35d6bdd1a0a51c9c0141dab8dc0ca83c7606f7a31084b9a9a985da6b93e23b215fe4373e597574357435cf7aae309c11ddef6b0f24437df2149ec8e8861e3546f2a950f900d74a8d736a96ca82b35bdf9548d6eb6c6235ec2d98ff0f196fd389234bb44de0a2718302a3c7110ffbad0451f4dce3eb2a189f63d52683509003cd6e0574b94c3db904f9b3113eb44725a5aae93aaf299d05b8aa942bb635cf5e68107a3277b8a70534e90976275809428e77e5163c18edb02334d739095da33d32502fc5b12c6b14acd316404d7c70f81cd5a035472154e92e8a8831a22c5b34ff4b40e2648df0e6b411ec8bbdd985da9992e3df5d1ebf2b912a1b250fd08553322b7f894cfde69cc37bc794b7de6b5136afb01f8377e0b293b57a50eca913320a0eb324a6009d41dfee2a416e6b9be33b55a2e85d59a88dac4d587e95e7352f004637bb3a798dda6d3a7164597a73e13819dd2be988c698bc7eafe6d7d32dd416e2cb252e21a7eb26ac4baea46a5ceb7b19db842b20d5998c5bc4b78836d0c6dcbf3ac8e2399b82d097232c553b837774960fade6bec8d0f452ba20bf72916117045596f4b83422b026c6b187c16e560ecb2d5dba5b6b0d7709c7b8e8b4d199d19fa0bbff8319dca9b308a836d0c1eb0c6f2a14c13c820d3b7213104491e6df75a1e61621a5c7be94f388afb47d7c5c211621fbabedda16ea22c837903b1088e6cc8751dece86bd749ea66126c1139d98d489dbdb93e6d8ae9061ab6dffc716e27c3dec83e2bc2dce5192f3fcd3fc5f3b394885164f501afe5fd42bdf685c73f9c
+AD: 31abdf1d28419a911203ca879905ce7d0edf1c29f3874d02cf2b799163c9204149b96a19f7c0eecd64b6ba2bb686eb1d6f79e420d130fce85edc6bd6b07257427a9107bda792de711025d05962dca533c52a2a379ab8516010107bc7879bdb2447973f6d356cd3905e253023a863a3175f65e1988b3f8b92af2ee9b5717d87705649127dfc9c7388c9ddfff5e0dd7564fa76f9b3272000ab7722becf46c1c2d99a51db96dd32fc5fcadd683fb4f7d57eceaf332910e8d275c5f955f27e899eba77b87784968e889dfffd77367c3a4c2711a87e1aa5dce4025ec7aa3908b96cc5fe05de319ba6de6d57b170561b32d0fe4217b0739393fe730f4f62058fd3f950bc5ef151732e06fb92987302c684557befbfca5d15b72a22dc0a3a16bc128698a6fef64511d7945cb1ec973d66e81e2f6481316640afb0344d605cde7280e9e6107131d1b2fdcdb93c29673d0822b8fd1ae0f22fdd17b6f654a651
+CT: 173cedc6203b5de9f4950c055399328756c886ba5f8eb4d3dc4cfb5e7681aec1c9ae238d0dbff2af21fdcfc244d20fc310ab0f53894d0f9d7204de4c3fe8d366b3fe075d7c7bddc79a256d54125d493426f56c0f56b0688921a0f9c6128ea6ccb405e7551750780d03f1e4c5d9ed1daa253a35178e85f5214684ed17614dfa8cbbc17c3620b080531dcf8434b7b38d1d45b45759f2f0e1c694d39e9387479aed05dfdada1672b8fb01935ea13a057884341ea164f1e59f8069aa5578845ce60775e4a6166b99eae120212cfaa30de04ed140759dd071c15a3536421b0e0dde31e6cb7d8e7e71aef462db4564803d1f8301f0cd5befffc1c0afd74ee5957d76c0a6bf85e2e57711c0ecde9427cbae0c214a09b69fe55ec49857df822ceee98d3d2cc2194b48fff88d5c4209b8a5aaedaf5c289884f442db3e5a8e441a4da134c3453665e8309b61dfb007cd48fe7f2c1bc612853917a06370cfbf3cff5c6c4d745f134cd5952986ab100dc17436cef8daf917096adb9a0d49889b75cf0306d31b6d6902817e747918ff92f479bee78bf2070a0011aab7c0e734395430604e6c8c2a73c17c4bf10a1146ebde04b04bb12fc6a189faf983e6cab5553ffb92f34a89e8166ecd024d89115e6b77395eec93d62aa3daa2f5b6db3723d25ac747f0833ba89350b23c2f874181a6e64fd3ecf4c07396c8d90be0cc78139d20891eb729e5f22f99d07758fdc00e76e9b082cb456c1e5a7b7704153e16b564f0bddd142d47b51e63a3c540dff5f32eeb786c48b3256b9d655f3098e649af178dcca88413ba50f0f332001d4d686f566250fcec1eaa4b3615604c9f3e8fb1704018d609904af5d2558117f43ffa74171722974053fd468e02f047703224cad8f7eeca77f8aabf9adcdb2e3e6df4f805b2a900591977b7180a029c8b359fe41b31cdce8a748f6967872355688e932bc64a43a12222001bbb4d83fab619db8f933e
+TAG: 5609b0874958433df52176247da18dac
+
+KEY: 87b8cd45737c8446b21301be1d5d02ca
+NONCE: 6af5432cffee125756ae7bbe
+IN: 2993033150f6ef19022bc5bd11c9ff9ac8ca8b17c594151ecb5ddadf8465c73969c432f4c273596d9cf7c53187932d3be41a145fbd6485ceb80b196079d89e3b5528c61946ba503844ce538a1892e62457abf4b6f90efde91d1747fb5bca839149814f757d418b9787822c76ad2ec6e5c84a07b0d7eab9f918b71e075cceab5d6ae5dccf54d4a15db9e415e44963c8ba68101df5894fc1664844c7ec11c300ae11cccb4ecee60431e36a2c4516db234378579638b758f10d80ed372da218123449a66aeafbb41bb8ff6564cbbc9c9f734daa1a9e409fa89decdd619ec8d1fa5918d3ffa0c780c0521eb514b2f23a4e95704f6a22657e7203bd1cc15332340414d02f7265023e0c9906147240d0495739bd33f7dee280e2cf905a706dcc838bc2fcea7e4afd823ae2dd3e2a98ff55f3ccc2b0f789e4d5019b93f213722ffe27aa583f6b9f77cabc4ee5358324f765547daecb7e2d4b371e1f77debc01b18be41313387181537b360f1090bcd9647ac7694907ca521f84f7865c3c82388c6aa80627ca9e4de08a163391b228be2a642df333374ec7182604bb80770f4a839aad778dceda56764f5888a95e88afbea46cd9eb4f506882cda4407461b1ea2f31a88bc7529fa923ed9387ff03dfaec545dd796243b7578640e0b8025aea75ce1b9ba918ab04572ef65463699d32125f71966242fbab007730e7f490338c60ed9ddefa539cc88d39b254e300b56da3c832065a35d961f74982fc895021fbee01e03e9534e54686376d8f9061cd4d033491b081f15639cb2056047d79f0dd7447c899b2aefc7d6bd03e57a1d7cd996fa282ad7493201920130df3007d13782f197b26ae0cf7d62cbc642d10b4202e1887b43faa4b71694b05d19daab60cf37b6a9b50c7d32b04138efc84414e87f6caca8626c2f764a945a26fca57907486c0db54ba1d898e2bea16e6d8c1f25bae57962529532ce48be6c1cdf0451deb047a1d27faa680f972148e9a0bc6c897d4fd
+AD: c82bf439bae425cbebcf21c29c3cdfccd82245ccfae0524e2dc0b7164682891c85c9d6814c80fce1a63d588928b38dcc987d9df32f2a42ae4a1f9e8ac6bcf285bb08d164afef3ebfe6b299332f207409d271460847e9279d2f0b5c4638cdd989f868b4f0dab1f324e9b18c35e3bc5f798962b7d4f3b6bed6fc1c57055c489032a600951f8d06c14f5ce852d29be001592ff5c3678c0bd8251c883b333d5c670e52072fd68fd8d53e1a2f48dfd2880394541f4df82a9b6adf525c527550161e0d7dcd5d0bafaa4abdf1cc7ae189ada0a61890831eca952cd6e505d4df44650ed533591fc72a9cda1fdb1c4be99a31ac10d8f011ebbcbd8d83caf5d8c33a659d032d4e454ef069b2dd414fe19706681f83a479078f01d6330e2f57c2a3720e5caf67e44ffdbe461d967060e29f11d4661f23b27e90d521c1a9f4f03413ffe794cd9e39dc4c81f43d38778fac476585975b72e26dec8658f9cf6e4e028bc87c8d5d1fe47bd3
+CT: cfc53c8980c557908f7d3a2c15e7f65da940cd319594b7d8baed9ad7edba0a46987775b004b5fd0c10306677eefeb8105cf124d0c64a2dac05364138fa2c4e49dfccb963a89956f97bb0340a14573e559d9f937b51fda46206f7ec3361ce566ac2ccb418290e070ff2655cbe89e762466c1559fba756c62de1c963afa1ad18ea47a1cf3d021f46bae6c060b19aaebabc900229086dc26fae9fc9da70af5af3acb02b6d5a570e95ba0d2f789fa077fe06553670ddd0c4e8965a3f5532e93e7fb0ab7e0b9f90cc9b483f1fb79ffa67d0cf53596eac25679ab4f8ea75b93f3bd84d8b8270d6d5ae62a5fe8995e9b0384365ad813edbe7fd9743665338cde61f8d0bf82481b9da29f6682795e7178fc79e676c8e3ff641ae25c667f92c849a642abe974d97718f0aca305b57ce7974172477e90e16d804c450b332339c61c327d78abccdba272b85f4da54154f59ce8dd5bd89e38a515bbca07d1526eac34437c66496f05e8582ce654ced3ee07d4e770da1799aa9b6fd42402a47c6d5e0c61592f11e798cfa3bfc20dd601e86e05fe6ed45a475a1b54261f368877e1207029f50b6d54e19c132c5732ec34552c2c559c135ebbebc7be00233126d5e0dc5e20b7bb37f6b25df2ae5ff44ab390ddfa91435c6d8ec09c4916ce8dd3e10509094cb4fab2ee9f67c3eb351ef221f3e67b7ff3dd7292ce01eab7e298343de449a2d4a0a168860bedfa0754717bf6fa0f5e37930db0e70c66976d34c0afd3ed623df2a10b9c02b2e9220534688e640de5d53f3707c2c9ea3de7d339e5530504b3a821cd3097784f325ababae463e9e1b34ab0830d5411c9e04bd48a321be1f8b973fbbc6dc03dc7ca2c31b3d9a800ec9d425881468dd9d8ca7f67ba2ed500d1674118d42ccaa6bb18f0a2c4e5ead86234255d850f58f9ee7ef7f70e2eacba6a053ec2e78c27a45faeb4c90e28687ce0d7cd7f8146a6ce8ab3887408e85563889373b606cd5c968437bddb632d69e8e8fdb
+TAG: dce7df76d7d0c0be7f560dcb5a4a00cb
+
+KEY: ad3ff84d1442224006550f6006be543f
+NONCE: 7712c5edceaaeb3360ac7ae2
+IN: e3618e093a797223283e0b9c36a841308146c122e3df15a43417bec5dc4224a10ab962fb11c53e3331f0a9967c008541bfd7d1beeed4b80c2371d5ab62cd098fcbed6f96f01fe9cb9f9f7b039bb010551e504252d0752afacdec2f2984d4ceaff99dfef99d57b4d4b1fa969a4e70aa0d868993474f7d4bdea01b9178feea95ce30c0f6b78f22c70da57d26677549e9284bb4a6717596c2c3b1a513ee888915b910c93cf1d94aa4013e891e1da11c41254af3c76a1f63d67f74a07f3176744f7e558f03a3525b4a385fc64e6ae48e5d96779d64b5f557ff453fd44cbe46a2ad96fb2f79ee6720e08bc8e463abe2a9f662540b5105e1252917d7ff63011106cb7a47829c86d374aba8536d1bdac2250045e098987f185ac00faa0b81630d94a41ac935088bd5829e46ea17bd0e19001fbd25208fb312b86349a9c60540dc2b5091c3b0902eda0254b9e8a447d4983ce8e1f58832d2e9591c5b15a96f1fdbe23b608ca5ef909a656877d36f16ce276e38744ef11768030b479a4b2bec453dcdce933c78e3d4e7bd7e7a906eb74bf321fa75f307861ddc1be310289dedc87a8e325a3e4c6dceb1bdc6a02d1df4598f343ae8a06729502f5abe458be2325ff985b3cea0a166ab7530a560d1971c57c566197b5e004d9d38d831abec067235c0d2ead91b9319d6ed20e6bced57d71dd2dea6a2ec22efd29b146bd31617c9c08cbd26e9dd53e045d6f29a7dce57c61b3a5f6410dfea52c30baedd587cc15993be3ca8e125f61272150a02138c8c3b46922be9ae2d31ab7f25526b86cc0c73cdc400b5506dcd94bb783a97f39d37db162519549e642f9f087c3f41c8234fe01dc1cc8fb0ab3099fe2b8efc1017049d79b5b6ab9f57ba86d2ef73e2c694c180d2860766a4010d76407b15afe28a3866e48b6b688228d2f1fdbbfdfac9de426186e9f7121d1a98b11caa6193f9445939403cc960f2df0ce5d7d4a30afa6fe8b9ed0add15bc78ca371cf34d6feaf94bb7f6520b4379e7bfbf836acfa3e2adfcb7f880
+AD: c53c1a8b8fdfbf5272fc29b2be7d69ff0741df1ebba02e0525e29cf45063e5da740f6c33b1deffea0eb2323035a21b18fa010c6c3ca7cc0c8194627d828fd5a9898e2b55266d4377233badeaffa7c703fd710441e250d9a5d94d954911d66caa836e2413b190917c1802c3e587d514184498ff2e6e3df5405829262b36fa8971cf8595bd1cd87801ac4c99357da70e2e55ffc012a30cca44e4f5538ba92f17aed8c8a48f85c501df2f0639ac88a39cc024fdb6d29aac368728865db1a30ddb36d366927f04f00f8dd2229e1fe76db8e7ded1fd886a9342308ba99d80f86704c974da156d96c272b806aec6c0268378652c26bad18ab249e117f8643d234b965d45067f42b857f0888ec68aab64b3ebde8a55ee38464e5f35f8653c7f0ba7598ad26f9772b574d7e060377a4174922b1f8ce6b72a83f3a20d20625132ad7cb1429e26865ecce2a47e29740cef1a3d85bdb3e800d46692d6ef926395aefba588294ff410dd523db596a7c17bf7d4
+CT: f59b5a5d01cf45a8d91c8c53b3d8feb5440b6cb9537d9feb0da69c33827d1a5542e1d2db34f25c399714324b7d31476022778a82a10668a281bcf6e5ef368a2c525a7bc59f46fb9e747424741e8894f86fc157dd748370212f848d23b13dd658c1e2ac1bf99abdf93b53a35b5bcd89cc4406953376187af45ab811e99db9ac2a367f8a55b0fb4acac9a9bcbc1858061860230508de9a777bbfb0f74b2c69a79dc332a4f03d156596576792f43dac2099b1d4af11fa6088a086a25364f62c24969a515e74f29661cc4764842a47cbeda7ff9ef515c7510c16566536273d62109397626a3c2b601bf272e31462ada51a01a69e6fe174082966fc25b6b8b034add7d394717f08df992771696bd51c25c8feb47ce637e23e89feac9679dc753eae62c0ffe7b62d9855ec470904df6bf7b6fb246cd6ca77bf2848f1074f146652461307c5d51b46977ac39c42ac5857b64f9b347a45062500de41a19f2bb03fdb241b309a5b685f408aa4e38e60c667fd4bad4fc3ab9d8b4f2a8735b50d2fb7d7177d2ef9e5c783ccdbbc8e923832117d3ea8cabf40891e8c912d703f37649096ed0e41e0e53cdb19da6467bb1ace8064c7862b6c4829959f7a0780860a598f3c725f3f956259ffd20e9088dcc639a0c947d85a51f6c77e911355ba77fe43e49a1137fccf2d951d4083c7232d095f2e2d003bce91ef9cc9aaeeb046a35bf1b548c78719c553e6ebac55a77509a3f02d71a9fb84ee16a8fdc6b8b1c917f800e053e655860ab17c0254327cfc3dcc9267e2b78dc2082e54895faea0349d9df3eab4b0bd62f5d6114903d8851aa3cc9068f6b03d7924dd6c4fcc08237f05551d528c01f33720c53867cdd375fec867f71fb3b4688eb18ac3647baaa94d2a72391f47e819b4f41e98904322d1b57d4a485fe9c966d4e0967eb415feff49d1baa38ed2505dee1b76bf1fad013918bc282761f9431b1ea4b3ae826470ef72399c86643a308043a2206df7eb354671846962693183df96ba170898fbf304b0ed34b1fd
+TAG: 90f99dbe53f5a8531b2a0e8dca2b7492
+
+KEY: 39ef8200a13e35000b40e9b0b392c982
+NONCE: a4377557abca18c1f3bf774f
+IN: 4bf8ab0b9080dceb2323953aa0e621954d87737bba6f562dbb0de271d6f1b88d7c1a712f613b099d2bbe0784a8304467cb168ffde2625edd9f38be5660020ed3e95b49e0a0ca9dc2bd0de2e40fb275b4813289327de0926df3c73865e7689fbad0a6c79ea615fc84345529cf2ef68b37b7e9fa5d538f4dd848ba66adb4745079acabac63de8d2ce9a2b19cc718162e9fdce49de7fa4b820043ae234d8afd23a45ee3a5db124e0f9252111c367beebfab55b2c784581b63a1caf4ab24bf5af45b986f457ddafbe87791788e7c7536595d965d5fcf21e3b13873b00357dfd7851f9e0f198ff950d69979157089be26b22800c3dfc713a5147b0ca4905793a2817281fb112deac286c41ffeb2bfb3fe1ddc9aaf4fb41fd5faf1df2e6e809f54b09f99bb8b61b555efdf4d8cb559fbe57a905d30184c2de6e154d501bc91f6033eb97295d96c1085b510cd57631e40e9ea3225e175162629b4c44ede0ab5643af425a8f8614e621a581b559f0e7fb63f0c8ca09cc58c244ab2e0f750c6135fc26e433710351802c329edbe97877f912bdad914a051d859c588af925674f1f455a322671793887420bc79a11541589082ef12c975dfd0528294ccb086ecca86ca940ba05f937fb2eb91b4b925713e8ef7d10305bc937aa976c5eefb4142b0c18c1ecc6be979621c437c64e1bcfe6ae86d28a29fc894120da6ddba1e56181b6f54a9e9810a83c3b44b6fba10959139787a491f367658ede40e1289148f66d4677d0281ea3615ab399c7dd9e6e05b8a68fc8724089825fd5f6a38406b3eaf01b8dcb62afe181ed963a0d940f1521f4f501d3349e6aec453edee70f1cc640ba3bedf78ec91acabe75f7de38ab98253dcd18c6a866f4c2b8a94072b1f141c9ee3c43beed8a08d09c2f35f142b8352cf776c57d6684898fdf6653997dbcb2cfcdcc43d63b1d287beb8a17ebc74eb3c3875af2ee0446b2d75052ef95d37315fd55e346c3e8dff45f17cb28f523592ba049b5de3963baaf0eac3cd75f0f0543e0dab651061bac4e3ea3679bb9a78d035bd8ea9e8
+AD: ad709f6c13ae2d4638dbebe6b4cc0ff606af9720c708c20dc2d6f0e4ba002a0b41e136d2b10dd6a2f8d9fe8cbe91943339fad0c52a2881b188611955771d3f9a621af08b95dbb77879bf508963fe294c8b8807fb9d8458a56d7fa2a4c5d995113ea8a86da07c28dab43c997e9277f98009d67fcf2ba171016cdb7e6c449f6996d21563b4ab22e933ddfad5c50e9036db19adf88761150b2226e73043a49a8e9934094eb4363d61bfddb791f4c5bca194d451023aeb879092eb2d8c8c3a2a5b8a832db6d73804c0c078c50a1414b684184780278cc90ac42618bb4144d5a415f582a77b247e4e8236bcb0692620757960f5103887683fd54f78095e8b098506c81008a7b443a533a0a71fae3f08bb4c28c7142576f459b1a2ccb5f65425515e691852e0da343291ca414c28c90426f7d5f9d7c78f84ad6eedc600137c4d86fa7db53b1d3fe9b16874b31275a740b5f640fffcb4351e4e32cd6bb7b6fc11f104b2513c0814c370b6a7558d7fc07c355da505a1777a2176
+CT: c1545634e7b0db1afb8a166c9f0d81a561841a583d04fec4f1994c7764582f7b11f832ec2de523e4f6ea3a7c1608e1d1a037b7975bea51524bc8f001ea34a2387f7510967cd57be0436529c08144c232ba1f532863255a55b2ea6f860b7db366ec8ea366e62187837ee8aa47cd9a8d687fafc31680c4af60493da7adb7ccb8f751ce6a6e30ec1f78bd169571fcc0f208d3966cd90660b8f7c2969bcaa8368172cff0d0fd27d732d9f7869d764efb36e55ffb96a1f3d8f1e6e5916e3e97e1f5a12f8dd965466a26274804f19dcbc7ec872cf662854501f37ef5fe348c543511feb61dfd96c5d429c83c7ed70a1d5beafc241c697a564897c9fa9819fe91dce3234d7632ffe73dd1f7c3cf0bf6d170334d2c4104a6ff5dd92038ad91e69f2685ccc380a9fdbdfe7f9f47c3a05ed97be25e299b8e71905f71c68b492be8545433c99b64f2d53a9239dde92359cfadb7fed301b8d8162baea533be9c9ea11964ca6f34e4d81b968546988afba059fa4b4e6d9e436137a9d991cfb867949c1bf87b1d61a5429d4bf549e66ca88b309cc65963baccc5449361dcab294d8c817717f848b942dd11fb1a8015a89e9bed4cdf51b4ff3ace0ab474fcfe16ba2da81b59a5dd7958913c92b4f6f067d2d350111c23c477138ebb40a99e0e55e6f609d74565c77bf8460e6360f4bb54220176baffdc96e4c37529ca3a38b3ef959d3ddb3b2759141032e54aaa8e6b2bdc928f01974f1311fdb15ace49d7d5a026e77fcdb5e9d7442f7bfd04584078804fb3aff740af89401771047af2483153b4c79923980cbc5695ebcfebc32ddc522f9da5b1220961555aeeaa2d578538691ef8b9f12b5833cc4f3b18d7c0d8b068e294c82efb95badbf590a3b4094c38f334d7ed32934f7012b87ec4a49bc0c2b7fb98365f22962d1e45d99e190655ce4213275b1e422976bbe36104027b96ce3e52ff931548e10e006c75747c59e3f7136db301eada16585ef15f4589180b368babe64b114e36686282d195d622e89f04d56f17c718d72bc6c577796a639e634a97e7877258
+TAG: 9563db087214b10c64e7cbbb9dd21a83
+
+KEY: abbe5e520c0ee79153c976d71e5c6dd5
+NONCE: 76f4857ba2d63e04d6b69a2d
+IN: 5a3ad1a3cb88733fdbca5b027ae04137f917a650b4a556b5fff90f17bc12a890aaa8d61029f0c6663eba8326c1bfba5d9221876ce3365bfddb714e884bced0f1675b6ffee2b1e22929f23893f3dadf967b006e9cb7a9a0972422c74a0393a29f9c4e06c2586f393786ba078cc52499ca6e911e323915ebca1d1dd203189cda3af76f785538d9f1cf5e5dc5758a490cea8710a9610790f426a0c76e262eeb9facfcd7730b72802084152f71adcc2cd6a2bcdd0fec76ee3228947d2f9b1b6f614a7e609c8f250fd02e19a487365b0db8f2d53cc6843d0d2a2abf3cd2ce33125558046fe9ea2eadca7dcb9d0a20fb3ee274fd92360f8772a53937625b5aaf9f10e9c9452426cb42dce78cdfa2628aeb58c295b01e12b12ece1fc5f66e33cec966b52d6593e1d1e93ba3abbe0c917dda7c2b6b5d45fb4cf6588908208e9b264f7e8ff87cc5090f4ea9b1a5205c852c308783a6c5ba0629cacfdd38b50706097f3496b4171a3199a485cfb32fae763dd77234dd9e2c6544f057c9885e914325efa4ccc25099f81c95a4e968e5e031747422cbd48ebfed3236f878a2832b7fc6aad4db734868ba2623899e9e0689e618bac700ce17e6d0114a0f5b94d6a0c3373f803ba2337d530fb706b8afbe482eeb9e0f5582b2f502d3c774b2ba98ce5400a20cb7d9a32a351401bffc2214392166208de9fc8a6d329b7dccf10734b5b74ce122f2454fa551b586dea96fcad2c45b1bf562bd5751b757da829d57cfdfd8ecbcc410c00aff69764a4e532545838b38011f92e464d192ba315ef239dcd5041448f165a14d503a865a85dfe81c5d4dfd37fa6c316c09eb403bfdc2a8c1a0618477a5fede92cbb2abb71b425e201c6361b5509288675a4541f44b7fe052acb25d1d87660eecef0beed7851a2966947dbfb8714038621b6f34ca2874751aebe9e8084f6ed854ed5f151f81533614cb1fdc08d2f51e47537f6229e0b64d10b498f773fb67bde258cb74a78843256913cad2727f9dbc3a8bd51daac9ed308ed0d77d86aa657a6ea7f9c35e120553d26b2d3fad1bc256f1f71c7550220b0b5f3c6fa8db73
+AD: 16337934937b996d7a501a3d1fa7f6321369747329fa6bce98f68c769dfb3df84b2b1e14f1a58c3f6b65e03377b7058fda3c26adbc370ec72e58ccc953ff157d4863057e0df89328efb5023c1b79f0e29be2d7cac9f903bb782c4c8720e2ccffe83710871642e2acae2071ba2a0af880f14f41ebdf61a3e5449dec6e61e103385971b8300a31b652053496e9b3a2db7a7bfb03a054fcd912e3e1791f84cf484370e553d67cf99c6b1c9b93bbe6ad4a93c47ba9ef73d9f8506400a49a5609e7eae5e3ee9efc657729d1e615a592a8c9f14ba37f5d91649a8c59ade56769c3bcef0c004c7444c3dd24223ef7bc6a2ba2e5927608692d1fbbd3868d7fee0fd11ee40312ae06d20704e29a97ecd4265556432173d6248e9f273363211b5d505de9861eaf402a001ac18b485c7ad0e442bb5e648e20e0884ffcbbd2dda9b3aece535d964d2cfcd6f99a31a4f24d878575fc3ad7a7c19e76771929c45d0965702625cbdd2e99371147e41e950ef70a7393084682a2ee6ca9b611f3c7b38ca4f5fdf2
+CT: 76e3480cee9d48b31d5b1e9a01e79e713cfeb73d742f1fc1e8f99c8e0cd82e267c45f4270077e86996a7e5440a781861dbfdb9759a6ce3991fbe6006d0de04658423f54154c8e5945dad96addb8bee044308cdf062ef21fcab25eb9a91f100945f347c865211a1087c01f245448322e77b826a22287df3434af7bee91d7a278fa59689656f7d93270898fc68594a4bea223d365aae03f0dd18a2e525f0c142b28776bd9f66fa2c046e57394488d5526fda62704e90f50e9752bf9d7652b010f8407de91eeb3068b830d0cc9294bee9629161df4cc7a1a216e55dae077864999ae72020346e813ca8fcdf99e417f26b82653908d0d6eb50ec65814f61b1825cc29c4679a9097e9afe294775e498489ca6839096f7bf0b60d3ebd016d83076184b272db1775f5eb3205015fd45fabf0bba9a990518c8d6d0c478221768fd83776253dc843eea8bfb66fbd2b9977632ca0aac7efc9528115fe4394f460d91c1b74fceed2952c6abc46b61fed85eb7414410731106e1a7be792eeac86fd4bf2b1ff2e496417fd8c0c2865e80837b2b73a690a6d9b7fea83687adb3a004a0d9fc9791c572d916a1b72f3ff5485f7d24e08c65a86079dc2bea698c43a3b2f2e5a8f335da4376aeae4d7fcb509bedbfa0e8fd25a711af45225d764534edcee4bca8e1470cc7d187b0bd9c26866baf8169289653aeae9b36277ca22c2a0ce3f69b3a40dd55e745b0b7467c2ef6a8a10151297eac1365ee475239d8f254806c8d92354757df8cb12d3dcfba83e05c303bc157c7be49da40ee072774ea7e4ac7044768418e64d965eb76d14bbd73be18d14701cdb6f8ee32cc1fef468047ef0ac649fb77843f0bb751f543339922bf34eeddb8140220e6b45ef1cd180697c651a352d05c77b705436f61ec9d35f185c5ce83b210c4a4336483f49ecd538dcc42a22b4f77ecdbb8cc36b8a499ed5c39de1fb6e03b0769639670fb2517c57f183eaf56148e1625adea1efb9b888e8fc3d83ba05c35f8509bd4e16285911462d77d9b270ae278cb902f6ff7970211cd53f1c310cd14a1787009cfd041c29933edb6e672d1d5
+TAG: 8954449b3f6a09e92ef2e33cb57c695d
+
+KEY: 100c6c8d1e88b842aed09cd16a5d78d4
+NONCE: e2d7712e40234292dd1aa27e
+IN: cbe63c433804b0111a2cc469e4f012d55e95e251139f5d6dbfc6dc8e8fb6bf5ecdd8dc89fcb6b2964755d1de9d8a0dc9d648619e185169ae5ccd61a6c2266c5177d8569ba4a09d4c231d48b8f8017365a411714be669fd31f5d17738739c75ba5abfc19d1eca16558cd69bf33f63f50417c92c29dd44ced6e9d9509057ce53a37cfd956bc33c6128fcaaa441fe3016389cf69bb589d323f18fce0a6cc7e77d9e33868ae21ecf8e491019f175f10013392c8fce3e6de3dbe9bb20ab69c2996967d171ea48b46abd36b9f4015723ec99ab940156e6b13ac06ec0f4a8ef74ee304e3072d9e14e844d2fef1e6fff116fbe9a74a7d90e79958a2f14c364418b7cc0d135e0fb8e68600f2e7aa26f9e15431ac9e5cf380b5fae8d715d1dbce4c0225e5c61e747029f62f4ea5de277bccb75580d6f5e5eff710ac8bed37e98b15677462946b2fb3fc0ffe720ea7c6bb70baa0e998fad6b747d5493506ffe69133608f2819d3fd9c8ef903de215b72677076dabb98cb1059d7d1b352f95a2d2c2903dff63743ec314e0313e46095197f6aeb2967c5a60f7f043b5167de03ffd320b64291bb7162b495f8379c883f17d642bd8bcad4caec8ac05150a5d449a22185058fd5c3a87a9f39b8a76afa529bb9e22641c8811c78fe3d3aaf2acbb88c47a1ac40dd686b80828fcbef0937e57a6272dc2e3ee18fb99410ac33a96d0800bf07dfea59e707cdc633c938feaa179a8d46940d1182fede7e1b9a3687548a0ca19bf53a641082da37082f257fe2fc83188c46cc58ff44a111ad32b6745dcacc4720dd960d2325443cb70615a4437eea2a409ee70c7fa3967a2fe97915ae852cbecd21d44b8db03d3d631c90e834a83428568e8250f5b8e2422007e8cefc12cfc28fc7f9a73f93afc1c3d2083e4c5cf6204753ef7fc4199c0d877859a90a1d3b16ddec6de134689accdca001fb1dbaca4fd492854446c4897afeeb68181890914744a387c198674d37ad98c4ff3fbb34ed656add39879af2e336e529c362d15399e40d2eedd9fca1f07c117304024e03ccb6e4e35d4c2508014742ed3639e8d0d0a73b4e99c
+AD: 0e2825fa3a69b798030cadfb168a1f88dbe56896bfb9a41e901a1bb61b8a95cfbb343266e894f101767efe874d9d45b4540d2d77e701e1d42fb03c32ca4b965d836b3fd34ea3ca2e958aa54f1b71e8c442783924c023c1b9fe0a45c88f4b66453fd335db8102e1de765ccfd7fd415ab7a08fe4e0b3d2a14f1564ffa3157a7da7cc9981029a45edf19bac8dc0f97286038b38fca85f280ff9a98eba85e328be65a657291692413319e0f045c07c657c903e51c0bf72093c615cdfa18368992cbfd4e11bd64054d34405d00bbfbdce63e315e3e99fccde073823c17d9790cced43408ba71e48b06f9bed959818d939f7c84b2d6c3861dd17e424dee0cd7942320c5